diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 8b18fbf554a4c..33896f3f6162b 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -59,6 +59,11 @@ use core::ops::{Deref, DerefMut}; use core::ptr::Unique; use core::raw::TraitObject; +#[cfg(not(stage0))] // SNAP c64d671 +use core::marker::Unsize; +#[cfg(not(stage0))] // SNAP c64d671 +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. /// @@ -327,3 +332,6 @@ impl<'a, E: Error + 'a> FromError for Box { Box::new(err) } } + +#[cfg(not(stage0))] // SNAP c64d671 +impl, U: ?Sized> CoerceUnsized> for Box {} diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index eb3c5c167268b..936596fd17f77 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -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::{min_align_of, size_of, forget}; use core::nonzero::NonZero; use core::ops::{Deref, Drop}; @@ -170,12 +170,21 @@ use core::result::Result; use core::result::Result::{Ok, Err}; use core::intrinsics::assume; +#[cfg(not(stage0))] // SNAP c64d671 +use core::intrinsics::drop_in_place; +#[cfg(not(stage0))] // SNAP c64d671 +use core::marker::Unsize; +#[cfg(not(stage0))] // SNAP c64d671 +use core::mem::{min_align_of_val, size_of_val}; +#[cfg(not(stage0))] // SNAP c64d671 +use core::ops::CoerceUnsized; + use heap::deallocate; -struct RcBox { - value: T, +struct RcBox { strong: Cell, - weak: Cell + weak: Cell, + value: T } /// A reference-counted pointer type over an immutable value. @@ -183,15 +192,18 @@ struct RcBox { /// See the [module level documentation](./index.html) for more details. #[unsafe_no_drop_flag] #[stable(feature = "rust1", since = "1.0.0")] -pub struct Rc { +pub struct Rc { // FIXME #12808: strange names to try to avoid interfering with field // accesses of the contained type via Deref _ptr: NonZero<*mut RcBox>, } -impl !marker::Send for Rc {} +impl !marker::Send for Rc {} + +impl !marker::Sync for Rc {} -impl !marker::Sync for Rc {} +#[cfg(not(stage0))] // SNAP c64d671 +impl, U: ?Sized> CoerceUnsized> for Rc {} impl Rc { /// Constructs a new `Rc`. @@ -212,14 +224,16 @@ impl Rc { // 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 })), } } } +} +impl Rc { /// Downgrades the `Rc` to a `Weak` reference. /// /// # Examples @@ -243,12 +257,12 @@ impl Rc { /// Get the number of weak references to this value. #[inline] #[unstable(feature = "alloc")] -pub fn weak_count(this: &Rc) -> usize { this.weak() - 1 } +pub fn weak_count(this: &Rc) -> usize { this.weak() - 1 } /// Get the number of strong references to this value. #[inline] #[unstable(feature = "alloc")] -pub fn strong_count(this: &Rc) -> usize { this.strong() } +pub fn strong_count(this: &Rc) -> usize { this.strong() } /// Returns true if there are no other `Rc` or `Weak` values that share the /// same inner value. @@ -366,7 +380,7 @@ impl Rc { } #[stable(feature = "rust1", since = "1.0.0")] -impl Deref for Rc { +impl Deref for Rc { type Target = T; #[inline(always)] @@ -375,6 +389,7 @@ impl Deref for Rc { } } +#[cfg(stage0)] // SNAP c64d671 #[unsafe_destructor] #[stable(feature = "rust1", since = "1.0.0")] impl Drop for Rc { @@ -426,8 +441,61 @@ impl Drop for Rc { } } +#[cfg(not(stage0))] // SNAP c64d671 +#[unsafe_destructor] +#[stable(feature = "rust1", since = "1.0.0")] +impl Drop for Rc { + /// Drops the `Rc`. + /// + /// This will decrement the strong reference count. If the strong reference + /// count becomes zero and the only other references are `Weak` 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() { + 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)) + } + } + } + } + } +} + #[stable(feature = "rust1", since = "1.0.0")] -impl Clone for Rc { +impl Clone for Rc { /// Makes a clone of the `Rc`. /// @@ -613,21 +681,21 @@ impl Ord for Rc { // FIXME (#18248) Make `T` `Sized?` #[stable(feature = "rust1", since = "1.0.0")] -impl Hash for Rc { +impl Hash for Rc { fn hash(&self, state: &mut H) { (**self).hash(state); } } #[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Display for Rc { +impl fmt::Display for Rc { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&**self, f) } } #[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for Rc { +impl fmt::Debug for Rc { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(&**self, f) } @@ -642,20 +710,20 @@ impl fmt::Debug for Rc { #[unsafe_no_drop_flag] #[unstable(feature = "alloc", reason = "Weak pointers may not belong in this module.")] -pub struct Weak { +pub struct Weak { // FIXME #12808: strange names to try to avoid interfering with // field accesses of the contained type via Deref _ptr: NonZero<*mut RcBox>, } -impl !marker::Send for Weak {} +impl !marker::Send for Weak {} -impl !marker::Sync for Weak {} +impl !marker::Sync for Weak {} #[unstable(feature = "alloc", reason = "Weak pointers may not belong in this module.")] -impl Weak { +impl Weak { /// Upgrades a weak reference to a strong reference. /// @@ -686,6 +754,7 @@ impl Weak { } } +#[cfg(stage0)] // SNAP c64d671 #[unsafe_destructor] #[stable(feature = "rust1", since = "1.0.0")] impl Drop for Weak { @@ -731,9 +800,55 @@ impl Drop for Weak { } } +#[cfg(not(stage0))] // SNAP c64d671 +#[unsafe_destructor] +#[stable(feature = "rust1", since = "1.0.0")] +impl Drop for Weak { + /// Drops the `Weak`. + /// + /// 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() { + 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)) + } + } + } + } +} + #[unstable(feature = "alloc", reason = "Weak pointers may not belong in this module.")] -impl Clone for Weak { +impl Clone for Weak { /// Makes a clone of the `Weak`. /// @@ -757,14 +872,14 @@ impl Clone for Weak { } #[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for Weak { +impl fmt::Debug for Weak { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "(Weak)") } } #[doc(hidden)] -trait RcBoxPtr { +trait RcBoxPtr { fn inner(&self) -> &RcBox; #[inline] @@ -786,7 +901,7 @@ trait RcBoxPtr { fn dec_weak(&self) { self.inner().weak.set(self.weak() - 1); } } -impl RcBoxPtr for Rc { +impl RcBoxPtr for Rc { #[inline(always)] fn inner(&self) -> &RcBox { unsafe { @@ -794,13 +909,13 @@ impl RcBoxPtr for Rc { // 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) } } } -impl RcBoxPtr for Weak { +impl RcBoxPtr for Weak { #[inline(always)] fn inner(&self) -> &RcBox { unsafe { @@ -808,7 +923,7 @@ impl RcBoxPtr for Weak { // 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) } } diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 1f1044b0b2152..89c0b5473c63e 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -182,8 +182,15 @@ extern "rust-intrinsic" { pub fn min_align_of() -> usize; pub fn pref_align_of() -> usize; + #[cfg(not(stage0))] // SNAP c64d671 + pub fn size_of_val(_: &T) -> usize; + #[cfg(not(stage0))] // SNAP c64d671 + pub fn min_align_of_val(_: &T) -> usize; + #[cfg(not(stage0))] // SNAP c64d671 + pub fn drop_in_place(_: *mut T); + /// Gets a static string slice containing the name of a type. - #[cfg(not(stage0))] + #[cfg(not(stage0))] // SNAP c64d671 pub fn type_name() -> &'static str; /// Gets an identifier which is globally unique to the specified type. This diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index 88c10e3661e7a..60f21a526330f 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -53,6 +53,14 @@ pub trait Sized : MarkerTrait { // Empty. } +/// Types that can be "unsized" to a dynamically sized type. +#[unstable(feature = "core")] +#[cfg(not(stage0))] // SNAP c64d671 +#[lang="unsize"] +pub trait Unsize : PhantomFn { + // Empty. +} + /// Types that can be copied by simply copying bits (i.e. `memcpy`). /// /// By default, variable bindings have 'move semantics.' In other diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 1e6fb51a8a528..03636bbb1ec64 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -47,6 +47,22 @@ pub fn size_of() -> usize { unsafe { intrinsics::size_of::() } } +/// 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))] // SNAP c64d671 +#[inline] +#[stable(feature = "rust1", since = "1.0.0")] +pub fn size_of_val(val: &T) -> usize { + unsafe { intrinsics::size_of_val(val) } +} + /// Returns the size of the type that `_val` points to in bytes. /// /// # Examples @@ -56,6 +72,7 @@ pub fn size_of() -> usize { /// /// assert_eq!(4, mem::size_of_val(&5i32)); /// ``` +#[cfg(stage0)] // SNAP c64d671 #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn size_of_val(_val: &T) -> usize { @@ -79,6 +96,22 @@ pub fn min_align_of() -> usize { unsafe { intrinsics::min_align_of::() } } +/// 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))] // SNAP c64d671 +#[inline] +#[stable(feature = "rust1", since = "1.0.0")] +pub fn min_align_of_val(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 @@ -88,6 +121,7 @@ pub fn min_align_of() -> usize { /// /// assert_eq!(4, mem::min_align_of_val(&5i32)); /// ``` +#[cfg(stage0)] // SNAP c64d671 #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn min_align_of_val(_val: &T) -> usize { diff --git a/src/libcore/nonzero.rs b/src/libcore/nonzero.rs index 230587b726fd1..cd1ce63aa79f6 100644 --- a/src/libcore/nonzero.rs +++ b/src/libcore/nonzero.rs @@ -12,6 +12,8 @@ use marker::{Sized, MarkerTrait}; use ops::Deref; +#[cfg(not(stage0))] // SNAP c64d671 +use ops::CoerceUnsized; /// Unsafe trait to indicate what types are usable with the NonZero struct pub unsafe trait Zeroable : MarkerTrait {} @@ -54,3 +56,6 @@ impl Deref for NonZero { inner } } + +#[cfg(not(stage0))] // SNAP c64d671 +impl, U: Zeroable> CoerceUnsized> for NonZero {} diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index fee40115f3952..26a32f38c7acc 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -67,9 +67,12 @@ #![stable(feature = "rust1", since = "1.0.0")] -use marker::Sized; +use marker::{PhantomFn, Sized}; use fmt; +#[cfg(not(stage0))] // SNAP c64d671 +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'. /// @@ -1223,3 +1226,34 @@ impl FnOnce for F self.call_mut(args) } } + +/// 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))] // SNAP c64d671 +#[lang="coerce_unsized"] +pub trait CoerceUnsized : PhantomFn { + // Empty. +} + +#[cfg(not(stage0))] // SNAP c64d671 +impl<'a, 'b: 'a, T: ?Sized+Unsize, U: ?Sized> CoerceUnsized<&'a mut U> for &'b mut T {} +#[cfg(not(stage0))] // SNAP c64d671 +impl<'a, 'b: 'a, T: ?Sized+Unsize, U: ?Sized> CoerceUnsized<&'a U> for &'b mut T {} +#[cfg(not(stage0))] // SNAP c64d671 +impl<'a, T: ?Sized+Unsize, U: ?Sized> CoerceUnsized<*const U> for &'a mut T {} +#[cfg(not(stage0))] // SNAP c64d671 +impl<'a, T: ?Sized+Unsize, U: ?Sized> CoerceUnsized<*mut U> for &'a mut T {} + +#[cfg(not(stage0))] // SNAP c64d671 +impl<'a, 'b: 'a, T: ?Sized+Unsize, U: ?Sized> CoerceUnsized<&'a U> for &'b T {} +#[cfg(not(stage0))] // SNAP c64d671 +impl<'a, T: ?Sized+Unsize, U: ?Sized> CoerceUnsized<*const U> for &'a T {} + +#[cfg(not(stage0))] // SNAP c64d671 +impl, U: ?Sized> CoerceUnsized<*const U> for *mut T {} +#[cfg(not(stage0))] // SNAP c64d671 +impl, U: ?Sized> CoerceUnsized<*mut U> for *mut T {} + +#[cfg(not(stage0))] // SNAP c64d671 +impl, U: ?Sized> CoerceUnsized<*const U> for *const T {} diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 70303bb3410b7..dc4aaf6be783a 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -68,6 +68,7 @@ register_diagnostics! { E0019, E0020, E0022, + E0038, E0109, E0110, E0133, diff --git a/src/librustc/metadata/common.rs b/src/librustc/metadata/common.rs index 081c64ecae881..9fa46e7c38690 100644 --- a/src/librustc/metadata/common.rs +++ b/src/librustc/metadata/common.rs @@ -256,3 +256,5 @@ pub const tag_codemap_filemap: uint = 0xa2; pub const tag_item_super_predicates: uint = 0xa3; pub const tag_defaulted_trait: uint = 0xa4; + +pub const tag_impl_coerce_unsized_kind: uint = 0xa5; diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs index ca8ae83ab80a8..541cd373924f3 100644 --- a/src/librustc/metadata/csearch.rs +++ b/src/librustc/metadata/csearch.rs @@ -272,6 +272,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 { + 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>, diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index c0bad80ab594a..8d54602577975 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -470,6 +470,16 @@ pub fn get_impl_polarity<'tcx>(cdata: Cmd, } } +pub fn get_custom_coerce_unsized_kind<'tcx>(cdata: Cmd, + id: ast::NodeId) + -> Option { + 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>) diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index fa8d0b2a56e4e..9836bcb759ebd 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -1186,6 +1186,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 ident = path.segments.last().unwrap().identifier; diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index 801350e8a1e9c..baa9be9e774a2 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -597,18 +597,18 @@ impl tr for ty::UpvarCapture { trait read_method_callee_helper<'tcx> { fn read_method_callee<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) - -> (ty::ExprAdjustment, MethodCallee<'tcx>); + -> (u32, MethodCallee<'tcx>); } fn encode_method_callee<'a, 'tcx>(ecx: &e::EncodeContext<'a, 'tcx>, rbml_w: &mut Encoder, - adjustment: ty::ExprAdjustment, + autoderef: u32, method: &MethodCallee<'tcx>) { use serialize::Encoder; rbml_w.emit_struct("MethodCallee", 4, |rbml_w| { - rbml_w.emit_struct_field("adjustment", 0, |rbml_w| { - adjustment.encode(rbml_w) + rbml_w.emit_struct_field("autoderef", 0, |rbml_w| { + autoderef.encode(rbml_w) }); rbml_w.emit_struct_field("origin", 1, |rbml_w| { Ok(rbml_w.emit_method_origin(ecx, &method.origin)) @@ -624,13 +624,13 @@ fn encode_method_callee<'a, 'tcx>(ecx: &e::EncodeContext<'a, 'tcx>, impl<'a, 'tcx> read_method_callee_helper<'tcx> for reader::Decoder<'a> { fn read_method_callee<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) - -> (ty::ExprAdjustment, MethodCallee<'tcx>) { + -> (u32, MethodCallee<'tcx>) { self.read_struct("MethodCallee", 4, |this| { - let adjustment = this.read_struct_field("adjustment", 0, |this| { + let autoderef = this.read_struct_field("autoderef", 0, |this| { Decodable::decode(this) }).unwrap(); - Ok((adjustment, MethodCallee { + Ok((autoderef, MethodCallee { origin: this.read_struct_field("origin", 1, |this| { Ok(this.read_method_origin(dcx)) }).unwrap(), @@ -684,7 +684,7 @@ pub trait vtable_decoder_helpers<'tcx> { fn read_vtable_res_with_key(&mut self, tcx: &ty::ctxt<'tcx>, cdata: &cstore::crate_metadata) - -> (ty::ExprAdjustment, ty::vtable_res<'tcx>); + -> (u32, ty::vtable_res<'tcx>); fn read_vtable_res(&mut self, tcx: &ty::ctxt<'tcx>, cdata: &cstore::crate_metadata) -> ty::vtable_res<'tcx>; @@ -709,12 +709,12 @@ impl<'tcx, 'a> vtable_decoder_helpers<'tcx> for reader::Decoder<'a> { fn read_vtable_res_with_key(&mut self, tcx: &ty::ctxt<'tcx>, cdata: &cstore::crate_metadata) - -> (ty::ExprAdjustment, ty::vtable_res<'tcx>) { + -> (u32, ty::vtable_res<'tcx>) { self.read_struct("VtableWithKey", 2, |this| { - let adjustment = this.read_struct_field("adjustment", 0, |this| { + let autoderef = this.read_struct_field("autoderef", 0, |this| { Decodable::decode(this) }).unwrap(); - Ok((adjustment, this.read_struct_field("vtable_res", 1, |this| { + Ok((autoderef, this.read_struct_field("vtable_res", 1, |this| { Ok(this.read_vtable_res(tcx, cdata)) }).unwrap())) }).unwrap() @@ -841,12 +841,9 @@ trait rbml_writer_helpers<'tcx> { fn emit_builtin_bounds(&mut self, ecx: &e::EncodeContext, bounds: &ty::BuiltinBounds); fn emit_auto_adjustment<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, adj: &ty::AutoAdjustment<'tcx>); - fn emit_autoref<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, - autoref: &ty::AutoRef<'tcx>); + fn emit_autoref<'a>(&mut self, autoref: &ty::AutoRef<'tcx>); fn emit_auto_deref_ref<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, auto_deref_ref: &ty::AutoDerefRef<'tcx>); - fn emit_unsize_kind<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, - uk: &ty::UnsizeKind<'tcx>); } impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> { @@ -1008,10 +1005,8 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> { self.emit_enum("AutoAdjustment", |this| { match *adj { - ty::AdjustReifyFnPointer(def_id) => { - this.emit_enum_variant("AdjustReifyFnPointer", 1, 2, |this| { - this.emit_enum_variant_arg(0, |this| def_id.encode(this)) - }) + ty::AdjustReifyFnPointer=> { + this.emit_enum_variant("AdjustReifyFnPointer", 1, 0, |_| Ok(())) } ty::AdjustUnsafeFnPointer => { @@ -1030,50 +1025,20 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> { }); } - fn emit_autoref<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>, - autoref: &ty::AutoRef<'tcx>) { + fn emit_autoref<'b>(&mut self, autoref: &ty::AutoRef<'tcx>) { use serialize::Encoder; self.emit_enum("AutoRef", |this| { match autoref { - &ty::AutoPtr(r, m, None) => { - this.emit_enum_variant("AutoPtr", 0, 3, |this| { - this.emit_enum_variant_arg(0, |this| r.encode(this)); - this.emit_enum_variant_arg(1, |this| m.encode(this)); - this.emit_enum_variant_arg(2, - |this| this.emit_option(|this| this.emit_option_none())) - }) - } - &ty::AutoPtr(r, m, Some(box ref a)) => { - this.emit_enum_variant("AutoPtr", 0, 3, |this| { + &ty::AutoPtr(r, m) => { + this.emit_enum_variant("AutoPtr", 0, 2, |this| { this.emit_enum_variant_arg(0, |this| r.encode(this)); - this.emit_enum_variant_arg(1, |this| m.encode(this)); - this.emit_enum_variant_arg(2, |this| this.emit_option( - |this| this.emit_option_some(|this| Ok(this.emit_autoref(ecx, a))))) - }) - } - &ty::AutoUnsize(ref uk) => { - this.emit_enum_variant("AutoUnsize", 1, 1, |this| { - this.emit_enum_variant_arg(0, |this| Ok(this.emit_unsize_kind(ecx, uk))) + this.emit_enum_variant_arg(1, |this| m.encode(this)) }) } - &ty::AutoUnsizeUniq(ref uk) => { - this.emit_enum_variant("AutoUnsizeUniq", 2, 1, |this| { - this.emit_enum_variant_arg(0, |this| Ok(this.emit_unsize_kind(ecx, uk))) - }) - } - &ty::AutoUnsafe(m, None) => { - this.emit_enum_variant("AutoUnsafe", 3, 2, |this| { - this.emit_enum_variant_arg(0, |this| m.encode(this)); - this.emit_enum_variant_arg(1, - |this| this.emit_option(|this| this.emit_option_none())) - }) - } - &ty::AutoUnsafe(m, Some(box ref a)) => { - this.emit_enum_variant("AutoUnsafe", 3, 2, |this| { - this.emit_enum_variant_arg(0, |this| m.encode(this)); - this.emit_enum_variant_arg(1, |this| this.emit_option( - |this| this.emit_option_some(|this| Ok(this.emit_autoref(ecx, a))))) + &ty::AutoUnsafe(m) => { + this.emit_enum_variant("AutoUnsafe", 1, 1, |this| { + this.emit_enum_variant_arg(0, |this| m.encode(this)) }) } } @@ -1086,55 +1051,26 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> { self.emit_struct("AutoDerefRef", 2, |this| { this.emit_struct_field("autoderefs", 0, |this| auto_deref_ref.autoderefs.encode(this)); + this.emit_struct_field("autoref", 1, |this| { this.emit_option(|this| { match auto_deref_ref.autoref { None => this.emit_option_none(), - Some(ref a) => this.emit_option_some(|this| Ok(this.emit_autoref(ecx, a))), + Some(ref a) => this.emit_option_some(|this| Ok(this.emit_autoref(a))), } }) - }) - }); - } - - fn emit_unsize_kind<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>, - uk: &ty::UnsizeKind<'tcx>) { - use serialize::Encoder; + }); - self.emit_enum("UnsizeKind", |this| { - match *uk { - ty::UnsizeLength(len) => { - this.emit_enum_variant("UnsizeLength", 0, 1, |this| { - this.emit_enum_variant_arg(0, |this| len.encode(this)) - }) - } - ty::UnsizeStruct(box ref uk, idx) => { - this.emit_enum_variant("UnsizeStruct", 1, 2, |this| { - this.emit_enum_variant_arg(0, |this| Ok(this.emit_unsize_kind(ecx, uk))); - this.emit_enum_variant_arg(1, |this| idx.encode(this)) - }) - } - ty::UnsizeVtable(ty::TyTrait { ref principal, - bounds: ref b }, - self_ty) => { - this.emit_enum_variant("UnsizeVtable", 2, 4, |this| { - this.emit_enum_variant_arg(0, |this| { - try!(this.emit_struct_field("principal", 0, |this| { - Ok(this.emit_trait_ref(ecx, &*principal.0)) - })); - this.emit_struct_field("bounds", 1, |this| { - Ok(this.emit_existential_bounds(ecx, b)) - }) - }); - this.emit_enum_variant_arg(1, |this| Ok(this.emit_ty(ecx, self_ty))) - }) - } - ty::UnsizeUpcast(target_ty) => { - this.emit_enum_variant("UnsizeUpcast", 3, 1, |this| { - this.emit_enum_variant_arg(0, |this| Ok(this.emit_ty(ecx, target_ty))) - }) - } - } + this.emit_struct_field("unsize", 2, |this| { + this.emit_option(|this| { + match auto_deref_ref.unsize { + None => this.emit_option_none(), + Some(target) => this.emit_option_some(|this| { + Ok(this.emit_ty(ecx, target)) + }) + } + }) + }) }); } } @@ -1254,7 +1190,7 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext, if let Some(method) = tcx.method_map.borrow().get(&method_call) { rbml_w.tag(c::tag_table_method_map, |rbml_w| { rbml_w.id(id); - encode_method_callee(ecx, rbml_w, method_call.adjustment, method) + encode_method_callee(ecx, rbml_w, method_call.autoderef, method) }) } @@ -1267,31 +1203,19 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext, if let Some(adjustment) = tcx.adjustments.borrow().get(&id) { match *adjustment { - _ if ty::adjust_is_object(adjustment) => { - let method_call = MethodCall::autoobject(id); - if let Some(method) = tcx.method_map.borrow().get(&method_call) { - rbml_w.tag(c::tag_table_method_map, |rbml_w| { - rbml_w.id(id); - encode_method_callee(ecx, rbml_w, method_call.adjustment, method) - }) - } - } ty::AdjustDerefRef(ref adj) => { - assert!(!ty::adjust_is_object(adjustment)); for autoderef in 0..adj.autoderefs { - let method_call = MethodCall::autoderef(id, autoderef); + let method_call = MethodCall::autoderef(id, autoderef as u32); if let Some(method) = tcx.method_map.borrow().get(&method_call) { rbml_w.tag(c::tag_table_method_map, |rbml_w| { rbml_w.id(id); encode_method_callee(ecx, rbml_w, - method_call.adjustment, method) + method_call.autoderef, method) }) } } } - _ => { - assert!(!ty::adjust_is_object(adjustment)); - } + _ => {} } rbml_w.tag(c::tag_table_adjustments, |rbml_w| { @@ -1363,8 +1287,6 @@ trait rbml_decoder_decoder_helpers<'tcx> { -> ty::AutoDerefRef<'tcx>; fn read_autoref<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) -> ty::AutoRef<'tcx>; - fn read_unsize_kind<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) - -> ty::UnsizeKind<'tcx>; fn convert_def_id(&mut self, dcx: &DecodeContext, source: DefIdSource, @@ -1636,18 +1558,11 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { fn read_auto_adjustment<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) -> ty::AutoAdjustment<'tcx> { self.read_enum("AutoAdjustment", |this| { - let variants = ["AutoAddEnv", "AutoDerefRef"]; + let variants = ["AdjustReifyFnPointer", "AdjustUnsafeFnPointer", "AdjustDerefRef"]; this.read_enum_variant(&variants, |this, i| { Ok(match i { - 1 => { - let def_id: ast::DefId = - this.read_def_id(dcx); - - ty::AdjustReifyFnPointer(def_id) - } - 2 => { - ty::AdjustUnsafeFnPointer - } + 1 => ty::AdjustReifyFnPointer, + 2 => ty::AdjustUnsafeFnPointer, 3 => { let auto_deref_ref: ty::AutoDerefRef = this.read_enum_variant_arg(0, @@ -1677,16 +1592,23 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { } }) }).unwrap(), + unsize: this.read_struct_field("unsize", 2, |this| { + this.read_option(|this, b| { + if b { + Ok(Some(this.read_ty(dcx))) + } else { + Ok(None) + } + }) + }).unwrap(), }) }).unwrap() } - fn read_autoref<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) -> ty::AutoRef<'tcx> { + fn read_autoref<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) + -> ty::AutoRef<'tcx> { self.read_enum("AutoRef", |this| { - let variants = ["AutoPtr", - "AutoUnsize", - "AutoUnsizeUniq", - "AutoUnsafe"]; + let variants = ["AutoPtr", "AutoUnsafe"]; this.read_enum_variant(&variants, |this, i| { Ok(match i { 0 => { @@ -1694,94 +1616,16 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { this.read_enum_variant_arg(0, |this| Decodable::decode(this)).unwrap(); let m: ast::Mutability = this.read_enum_variant_arg(1, |this| Decodable::decode(this)).unwrap(); - let a: Option> = - this.read_enum_variant_arg(2, |this| this.read_option(|this, b| { - if b { - Ok(Some(box this.read_autoref(dcx))) - } else { - Ok(None) - } - })).unwrap(); - - ty::AutoPtr(r.tr(dcx), m, a) - } - 1 => { - let uk: ty::UnsizeKind = - this.read_enum_variant_arg(0, - |this| Ok(this.read_unsize_kind(dcx))).unwrap(); - - ty::AutoUnsize(uk) - } - 2 => { - let uk: ty::UnsizeKind = - this.read_enum_variant_arg(0, - |this| Ok(this.read_unsize_kind(dcx))).unwrap(); - ty::AutoUnsizeUniq(uk) + ty::AutoPtr(dcx.tcx.mk_region(r.tr(dcx)), m) } - 3 => { + 1 => { let m: ast::Mutability = this.read_enum_variant_arg(0, |this| Decodable::decode(this)).unwrap(); - let a: Option> = - this.read_enum_variant_arg(1, |this| this.read_option(|this, b| { - if b { - Ok(Some(box this.read_autoref(dcx))) - } else { - Ok(None) - } - })).unwrap(); - - ty::AutoUnsafe(m, a) - } - _ => panic!("bad enum variant for ty::AutoRef") - }) - }) - }).unwrap() - } - - fn read_unsize_kind<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) - -> ty::UnsizeKind<'tcx> { - self.read_enum("UnsizeKind", |this| { - let variants = &["UnsizeLength", "UnsizeStruct", "UnsizeVtable", "UnsizeUpcast"]; - this.read_enum_variant(variants, |this, i| { - Ok(match i { - 0 => { - let len: uint = - this.read_enum_variant_arg(0, |this| Decodable::decode(this)).unwrap(); - - ty::UnsizeLength(len) - } - 1 => { - let uk: ty::UnsizeKind = - this.read_enum_variant_arg(0, - |this| Ok(this.read_unsize_kind(dcx))).unwrap(); - let idx: uint = - this.read_enum_variant_arg(1, |this| Decodable::decode(this)).unwrap(); - ty::UnsizeStruct(box uk, idx) - } - 2 => { - let ty_trait = try!(this.read_enum_variant_arg(0, |this| { - let principal = try!(this.read_struct_field("principal", 0, |this| { - Ok(this.read_poly_trait_ref(dcx)) - })); - Ok(ty::TyTrait { - principal: principal, - bounds: try!(this.read_struct_field("bounds", 1, |this| { - Ok(this.read_existential_bounds(dcx)) - })), - }) - })); - let self_ty = - this.read_enum_variant_arg(1, |this| Ok(this.read_ty(dcx))).unwrap(); - ty::UnsizeVtable(ty_trait, self_ty) + ty::AutoUnsafe(m) } - 3 => { - let target_ty = - this.read_enum_variant_arg(0, |this| Ok(this.read_ty(dcx))).unwrap(); - ty::UnsizeUpcast(target_ty) - } - _ => panic!("bad enum variant for ty::UnsizeKind") + _ => panic!("bad enum variant for ty::AutoRef") }) }) }).unwrap() @@ -1918,10 +1762,10 @@ fn decode_side_tables(dcx: &DecodeContext, dcx.tcx.ty_param_defs.borrow_mut().insert(id, bounds); } c::tag_table_method_map => { - let (adjustment, method) = val_dsr.read_method_callee(dcx); + let (autoderef, method) = val_dsr.read_method_callee(dcx); let method_call = MethodCall { expr_id: id, - adjustment: adjustment + autoderef: autoderef }; dcx.tcx.method_map.borrow_mut().insert(method_call, method); } diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 97314b57ef656..af2d71428623d 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -786,33 +786,30 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { // process. fn walk_adjustment(&mut self, expr: &ast::Expr) { let typer = self.typer; - match typer.adjustments().borrow().get(&expr.id) { - None => { } - Some(adjustment) => { - match *adjustment { - ty::AdjustReifyFnPointer(..) | - ty::AdjustUnsafeFnPointer(..) => { - // Creating a closure/fn-pointer consumes the - // input and stores it into the resulting - // rvalue. - debug!("walk_adjustment(AutoAddEnv|AdjustReifyFnPointer)"); + if let Some(adjustment) = typer.adjustments().borrow().get(&expr.id) { + match *adjustment { + ty::AdjustReifyFnPointer | + ty::AdjustUnsafeFnPointer => { + // Creating a closure/fn-pointer or unsizing consumes + // the input and stores it into the resulting rvalue. + debug!("walk_adjustment(AdjustReifyFnPointer|AdjustUnsafeFnPointer)"); + let cmt_unadjusted = + return_if_err!(self.mc.cat_expr_unadjusted(expr)); + self.delegate_consume(expr.id, expr.span, cmt_unadjusted); + } + ty::AdjustDerefRef(ref adj) => { + self.walk_autoderefs(expr, adj.autoderefs); + if let Some(ref r) = adj.autoref { + self.walk_autoref(expr, r, adj.autoderefs); + } else if adj.unsize.is_some() { + assert!(adj.autoderefs == 0, + format!("Expected no derefs with \ + unsize AutoRefs, found: {}", + adj.repr(self.tcx()))); let cmt_unadjusted = return_if_err!(self.mc.cat_expr_unadjusted(expr)); self.delegate_consume(expr.id, expr.span, cmt_unadjusted); } - ty::AdjustDerefRef(ty::AutoDerefRef { - autoref: ref opt_autoref, - autoderefs: n - }) => { - self.walk_autoderefs(expr, n); - - match *opt_autoref { - None => { } - Some(ref r) => { - self.walk_autoref(expr, r, n); - } - } - } } } } @@ -827,7 +824,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { debug!("walk_autoderefs expr={} autoderefs={}", expr.repr(self.tcx()), autoderefs); for i in 0..autoderefs { - let deref_id = ty::MethodCall::autoderef(expr.id, i); + let deref_id = ty::MethodCall::autoderef(expr.id, i as u32); match self.typer.node_method_ty(deref_id) { None => {} Some(method_ty) => { @@ -858,30 +855,21 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { n: uint) { debug!("walk_autoref expr={}", expr.repr(self.tcx())); - match *autoref { - ty::AutoPtr(r, m, _) => { - let cmt_derefd = return_if_err!( - self.mc.cat_expr_autoderefd(expr, n)); - debug!("walk_adjustment: cmt_derefd={}", - cmt_derefd.repr(self.tcx())); + let cmt_derefd = return_if_err!( + self.mc.cat_expr_autoderefd(expr, n)); + debug!("walk_adjustment: cmt_derefd={}", + cmt_derefd.repr(self.tcx())); + match *autoref { + ty::AutoPtr(r, m) => { self.delegate.borrow(expr.id, expr.span, cmt_derefd, - r, + *r, ty::BorrowKind::from_mutbl(m), AutoRef); } - ty::AutoUnsize(_) | - ty::AutoUnsizeUniq(_) => { - assert!(n == 1, format!("Expected exactly 1 deref with Uniq \ - AutoRefs, found: {}", n)); - let cmt_unadjusted = - return_if_err!(self.mc.cat_expr_unadjusted(expr)); - self.delegate_consume(expr.id, expr.span, cmt_unadjusted); - } - ty::AutoUnsafe(..) => { - } + ty::AutoUnsafe(..) => {} } } diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index 73d31a1f6201d..19aac1da6046b 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -259,11 +259,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; diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index bdcfc67f92b99..905a429ce8d06 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -428,33 +428,23 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> { Some(adjustment) => { match *adjustment { - ty::AdjustReifyFnPointer(..) | - ty::AdjustUnsafeFnPointer(..) => { - debug!("cat_expr(AdjustReifyFnPointer): {}", - expr.repr(self.tcx())); - // Convert a bare fn to a closure by adding NULL env. - // Result is an rvalue. - let expr_ty = try!(self.expr_ty_adjusted(expr)); - Ok(self.cat_rvalue_node(expr.id(), expr.span(), expr_ty)) - } - ty::AdjustDerefRef( ty::AutoDerefRef { - autoref: Some(_), ..}) => { - debug!("cat_expr(AdjustDerefRef): {}", + autoref: None, unsize: None, autoderefs, ..}) => { + // Equivalent to *expr or something similar. + self.cat_expr_autoderefd(expr, autoderefs) + } + + ty::AdjustReifyFnPointer | + ty::AdjustUnsafeFnPointer | + ty::AdjustDerefRef(_) => { + debug!("cat_expr({}): {}", + adjustment.repr(self.tcx()), expr.repr(self.tcx())); - // Equivalent to &*expr or something similar. // Result is an rvalue. let expr_ty = try!(self.expr_ty_adjusted(expr)); Ok(self.cat_rvalue_node(expr.id(), expr.span(), expr_ty)) } - - ty::AdjustDerefRef( - ty::AutoDerefRef { - autoref: None, autoderefs}) => { - // Equivalent to *expr or something similar. - self.cat_expr_autoderefd(expr, autoderefs) - } } } } @@ -887,15 +877,9 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> { deref_cnt: uint, deref_context: DerefKindContext) -> McResult> { - let adjustment = match self.typer.adjustments().borrow().get(&node.id()) { - Some(adj) if ty::adjust_is_object(adj) => ty::AutoObject, - _ if deref_cnt != 0 => ty::AutoDeref(deref_cnt), - _ => ty::NoAdjustment - }; - let method_call = ty::MethodCall { expr_id: node.id(), - adjustment: adjustment + autoderef: deref_cnt as u32 }; let method_ty = self.typer.node_method_ty(method_call); diff --git a/src/librustc/middle/traits/error_reporting.rs b/src/librustc/middle/traits/error_reporting.rs index d10ff060418cc..f0f99a4a118a9 100644 --- a/src/librustc/middle/traits/error_reporting.rs +++ b/src/librustc/middle/traits/error_reporting.rs @@ -15,8 +15,12 @@ use super::{ Obligation, ObligationCauseCode, OutputTypeParameterMismatch, + TraitNotObjectSafe, PredicateObligation, SelectionError, + ObjectSafetyViolation, + MethodViolationCode, + object_safety_violations, }; use fmt_macros::{Parser, Piece, Position}; @@ -246,6 +250,55 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, note_obligation_cause(infcx, obligation); } } + + TraitNotObjectSafe(ref trait_ref) => { + 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, trait_ref.def_id())); + + for violation in object_safety_violations(infcx.tcx, trait_ref.clone()) { + 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))); + } + } + } + + } } } @@ -397,10 +450,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`"); diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs index 24b201c960f16..bafc244dbd95d 100644 --- a/src/librustc/middle/traits/mod.rs +++ b/src/librustc/middle/traits/mod.rs @@ -27,6 +27,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; @@ -46,6 +47,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::transitive_bounds; @@ -117,9 +119,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, @@ -155,6 +154,7 @@ pub enum SelectionError<'tcx> { OutputTypeParameterMismatch(ty::PolyTraitRef<'tcx>, ty::PolyTraitRef<'tcx>, ty::type_err<'tcx>), + TraitNotObjectSafe(ty::PolyTraitRef<'tcx>), } pub struct FulfillmentError<'tcx> { @@ -531,7 +531,9 @@ impl<'tcx, N> Vtable<'tcx, N> { } } - pub fn map_nested(&self, op: F) -> Vtable<'tcx, M> where F: FnMut(&N) -> M { + pub fn map_nested(&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)), diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index 0d6a1f7df5e56..cdefe9dd72444 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -24,6 +24,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, @@ -34,7 +36,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; @@ -155,6 +157,8 @@ enum SelectionCandidate<'tcx> { BuiltinObjectCandidate, + BuiltinUnsizeCandidate, + ErrorCandidate, } @@ -834,6 +838,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 => { @@ -1265,6 +1274,63 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } + /// Search for unsizing that might apply to `obligation`. + fn assemble_candidates_for_unsizing(&mut self, + obligation: &TraitObligation<'tcx>, + candidates: &mut SelectionCandidateSet<'tcx>) { + let source = self.infcx.shallow_resolve(obligation.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 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 -> Struct. + (&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 // @@ -1320,6 +1386,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { (&ClosureCandidate(..), &ParamCandidate(..)) | (&FnPointerCandidate(..), &ParamCandidate(..)) | (&BuiltinObjectCandidate(..), &ParamCandidate(_)) | + (&BuiltinUnsizeCandidate(..), &ParamCandidate(_)) | (&BuiltinCandidate(..), &ParamCandidate(..)) => { // We basically prefer always prefer to use a // where-clause over another option. Where clauses @@ -1747,12 +1814,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { derived_cause.clone(), trait_def_id, obligation.recursion_depth + 1, - skol_ty); - match skol_predicate { - Ok(skol_predicate) => Ok(self.infcx().plug_leaks(skol_map, snapshot, - &skol_predicate)), - Err(ErrorReported) => Err(ErrorReported) - } + skol_ty, + vec![]); + Ok(self.infcx().plug_leaks(skol_map, snapshot, &skol_predicate)) }) }).collect::>, _>>(); @@ -1837,6 +1901,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.confirm_projection_candidate(obligation); Ok(VtableParam(Vec::new())) } + + BuiltinUnsizeCandidate => { + self.infcx.try(|_| { + self.confirm_builtin_unsize_candidate(obligation) + }) + } } } @@ -2168,6 +2238,158 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } + fn confirm_builtin_unsize_candidate(&mut self, + obligation: &TraitObligation<'tcx>,) + -> Result, + SelectionError<'tcx>> { + let tcx = self.tcx(); + + let source = self.infcx.shallow_resolve(obligation.self_ty()); + 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 = data.principal_trait_ref_with_self_ty(tcx, tcx.types.err); + if !object_safety::is_object_safe(tcx, object.clone()) { + return Err(TraitNotObjectSafe(object)); + } + + 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 -> Struct. + (&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::>(); + + // 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 and Struct. + 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 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(VtableBuiltin(VtableBuiltinData { + nested: VecPerParamSpace::new(nested, vec![], vec![]) + })) + } + /////////////////////////////////////////////////////////////////////////// // Matching // @@ -2527,6 +2749,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), @@ -2580,7 +2803,8 @@ impl<'tcx> EvaluationResult<'tcx> { match *self { EvaluatedToOk | EvaluatedToAmbig | - EvaluatedToErr(OutputTypeParameterMismatch(..)) => + EvaluatedToErr(OutputTypeParameterMismatch(..)) | + EvaluatedToErr(TraitNotObjectSafe(_)) => true, EvaluatedToErr(Unimplemented) => diff --git a/src/librustc/middle/traits/util.rs b/src/librustc/middle/traits/util.rs index 965aaf12044ec..73e6edc3252d2 100644 --- a/src/librustc/middle/traits/util.rs +++ b/src/librustc/middle/traits/util.rs @@ -313,17 +313,17 @@ pub fn trait_ref_for_builtin_bound<'tcx>( } -pub fn predicate_for_trait_ref<'tcx>( +fn predicate_for_trait_ref<'tcx>( cause: ObligationCause<'tcx>, trait_ref: Rc>, recursion_depth: uint) - -> Result, ErrorReported> + -> PredicateObligation<'tcx> { - Ok(Obligation { + Obligation { cause: cause, recursion_depth: recursion_depth, predicate: trait_ref.as_predicate(), - }) + } } pub fn predicate_for_trait_def<'tcx>( @@ -331,12 +331,13 @@ pub fn predicate_for_trait_def<'tcx>( cause: ObligationCause<'tcx>, trait_def_id: ast::DefId, recursion_depth: uint, - param_ty: Ty<'tcx>) - -> Result, ErrorReported> + param_ty: Ty<'tcx>, + ty_params: Vec>) + -> PredicateObligation<'tcx> { let trait_ref = Rc::new(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) } @@ -350,7 +351,7 @@ pub fn predicate_for_builtin_bound<'tcx>( -> Result, 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 @@ -522,6 +523,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)) } } } diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 92b444e85d8c3..cf39f5aea1546 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -20,7 +20,6 @@ pub use self::ClosureKind::*; pub use self::Variance::*; pub use self::AutoAdjustment::*; pub use self::Representability::*; -pub use self::UnsizeKind::*; pub use self::AutoRef::*; pub use self::ExprKind::*; pub use self::DtorKind::*; @@ -33,7 +32,6 @@ pub use self::ImplOrTraitItem::*; pub use self::BoundRegion::*; pub use self::sty::*; pub use self::IntVarValue::*; -pub use self::ExprAdjustment::*; pub use self::vtable_origin::*; pub use self::MethodOrigin::*; pub use self::CopyImplementationError::*; @@ -279,145 +277,40 @@ pub enum Variance { Bivariant, // T <: T -- e.g., unused type parameter } -#[derive(Clone, Debug)] +#[derive(Copy, Clone, Debug)] pub enum AutoAdjustment<'tcx> { - AdjustReifyFnPointer(ast::DefId), // go from a fn-item type to a fn-pointer type + AdjustReifyFnPointer, // go from a fn-item type to a fn-pointer type AdjustUnsafeFnPointer, // go from a safe fn pointer to an unsafe fn pointer - AdjustDerefRef(AutoDerefRef<'tcx>) -} - -#[derive(Clone, PartialEq, Debug)] -pub enum UnsizeKind<'tcx> { - // [T, ..n] -> [T], the uint field is n. - UnsizeLength(uint), - // An unsize coercion applied to the tail field of a struct. - // The uint is the index of the type parameter which is unsized. - UnsizeStruct(Box>, uint), - UnsizeVtable(TyTrait<'tcx>, /* the self type of the trait */ Ty<'tcx>), - UnsizeUpcast(Ty<'tcx>), + AdjustDerefRef(AutoDerefRef<'tcx>), } -#[derive(Clone, Debug)] +#[derive(Copy, Clone, Debug)] pub struct AutoDerefRef<'tcx> { + /// Apply a number of dereferences, producing an lvalue. pub autoderefs: uint, - pub autoref: Option> + + /// Produce a pointer/reference from the value. + pub autoref: Option>, + + /// Unsize a pointer/reference value, e.g. &[T; n] to &[T]. + /// The stored type is the target pointer type. + pub unsize: Option>, } -#[derive(Clone, PartialEq, Debug)] +#[derive(Copy, Clone, PartialEq, Debug)] pub enum AutoRef<'tcx> { /// Convert from T to &T - /// The third field allows us to wrap other AutoRef adjustments. - AutoPtr(Region, ast::Mutability, Option>>), - - /// Convert [T, ..n] to [T] (or similar, depending on the kind) - AutoUnsize(UnsizeKind<'tcx>), - - /// Convert Box<[T, ..n]> to Box<[T]> or something similar in a Box. - /// With DST and Box a library type, this should be replaced by UnsizeStruct. - AutoUnsizeUniq(UnsizeKind<'tcx>), + AutoPtr(&'tcx Region, ast::Mutability), /// Convert from T to *T /// Value to thin pointer - /// The second field allows us to wrap other AutoRef adjustments. - AutoUnsafe(ast::Mutability, Option>>), -} - -// Ugly little helper function. The first bool in the returned tuple is true if -// there is an 'unsize to trait object' adjustment at the bottom of the -// adjustment. If that is surrounded by an AutoPtr, then we also return the -// region of the AutoPtr (in the third argument). The second bool is true if the -// adjustment is unique. -fn autoref_object_region(autoref: &AutoRef) -> (bool, bool, Option) { - fn unsize_kind_is_object(k: &UnsizeKind) -> bool { - match k { - &UnsizeVtable(..) => true, - &UnsizeStruct(box ref k, _) => unsize_kind_is_object(k), - _ => false - } - } - - match autoref { - &AutoUnsize(ref k) => (unsize_kind_is_object(k), false, None), - &AutoUnsizeUniq(ref k) => (unsize_kind_is_object(k), true, None), - &AutoPtr(adj_r, _, Some(box ref autoref)) => { - let (b, u, r) = autoref_object_region(autoref); - if r.is_some() || u { - (b, u, r) - } else { - (b, u, Some(adj_r)) - } - } - &AutoUnsafe(_, Some(box ref autoref)) => autoref_object_region(autoref), - _ => (false, false, None) - } -} - -// If the adjustment introduces a borrowed reference to a trait object, then -// returns the region of the borrowed reference. -pub fn adjusted_object_region(adj: &AutoAdjustment) -> Option { - match adj { - &AdjustDerefRef(AutoDerefRef{autoref: Some(ref autoref), ..}) => { - let (b, _, r) = autoref_object_region(autoref); - if b { - r - } else { - None - } - } - _ => None - } -} - -// Returns true if there is a trait cast at the bottom of the adjustment. -pub fn adjust_is_object(adj: &AutoAdjustment) -> bool { - match adj { - &AdjustDerefRef(AutoDerefRef{autoref: Some(ref autoref), ..}) => { - let (b, _, _) = autoref_object_region(autoref); - b - } - _ => false - } + AutoUnsafe(ast::Mutability), } -// If possible, returns the type expected from the given adjustment. This is not -// possible if the adjustment depends on the type of the adjusted expression. -pub fn type_of_adjust<'tcx>(cx: &ctxt<'tcx>, adj: &AutoAdjustment<'tcx>) -> Option> { - fn type_of_autoref<'tcx>(cx: &ctxt<'tcx>, autoref: &AutoRef<'tcx>) -> Option> { - match autoref { - &AutoUnsize(ref k) => match k { - &UnsizeVtable(TyTrait { ref principal, ref bounds }, _) => { - Some(mk_trait(cx, principal.clone(), bounds.clone())) - } - _ => None - }, - &AutoUnsizeUniq(ref k) => match k { - &UnsizeVtable(TyTrait { ref principal, ref bounds }, _) => { - Some(mk_uniq(cx, mk_trait(cx, principal.clone(), bounds.clone()))) - } - _ => None - }, - &AutoPtr(r, m, Some(box ref autoref)) => { - match type_of_autoref(cx, autoref) { - Some(ty) => Some(mk_rptr(cx, cx.mk_region(r), mt {mutbl: m, ty: ty})), - None => None - } - } - &AutoUnsafe(m, Some(box ref autoref)) => { - match type_of_autoref(cx, autoref) { - Some(ty) => Some(mk_ptr(cx, mt {mutbl: m, ty: ty})), - None => None - } - } - _ => None - } - } - - match adj { - &AdjustDerefRef(AutoDerefRef{autoref: Some(ref autoref), ..}) => { - type_of_autoref(cx, autoref) - } - _ => None - } +#[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)] @@ -505,35 +398,21 @@ pub struct MethodCallee<'tcx> { #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] pub struct MethodCall { pub expr_id: ast::NodeId, - pub adjustment: ExprAdjustment -} - -#[derive(Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable, Copy)] -pub enum ExprAdjustment { - NoAdjustment, - AutoDeref(uint), - AutoObject + pub autoderef: u32 } impl MethodCall { pub fn expr(id: ast::NodeId) -> MethodCall { MethodCall { expr_id: id, - adjustment: NoAdjustment - } - } - - pub fn autoobject(id: ast::NodeId) -> MethodCall { - MethodCall { - expr_id: id, - adjustment: AutoObject + autoderef: 0 } } - pub fn autoderef(expr_id: ast::NodeId, autoderef: uint) -> MethodCall { + pub fn autoderef(expr_id: ast::NodeId, autoderef: u32) -> MethodCall { MethodCall { expr_id: expr_id, - adjustment: AutoDeref(1 + autoderef) + autoderef: 1 + autoderef } } } @@ -848,6 +727,9 @@ pub struct ctxt<'tcx> { /// Maps Expr NodeId's to their constant qualification. pub const_qualif_map: RefCell>, + + /// Caches CoerceUnsized kinds for impls on custom types. + pub custom_coerce_unsized_kinds: RefCell>, } // Flags that we track on types. These flags are propagated upwards @@ -2640,6 +2522,7 @@ pub fn mk_ctxt<'tcx>(s: Session, type_impls_sized_cache: RefCell::new(HashMap::new()), object_safety_cache: RefCell::new(DefIdMap()), const_qualif_map: RefCell::new(NodeMap()), + custom_coerce_unsized_kinds: RefCell::new(DefIdMap()), } } @@ -4550,16 +4433,15 @@ pub fn adjust_ty<'tcx, F>(cx: &ctxt<'tcx>, return match adjustment { Some(adjustment) => { match *adjustment { - AdjustReifyFnPointer(_) => { + AdjustReifyFnPointer => { match unadjusted_ty.sty { ty::ty_bare_fn(Some(_), b) => { ty::mk_bare_fn(cx, None, b) } - ref b => { + _ => { cx.sess.bug( &format!("AdjustReifyFnPointer adjustment on non-fn-item: \ - {:?}", - b)); + {}", unadjusted_ty.repr(cx))); } } } @@ -4581,7 +4463,7 @@ pub fn adjust_ty<'tcx, F>(cx: &ctxt<'tcx>, if !ty::type_is_error(adjusted_ty) { for i in 0..adj.autoderefs { - let method_call = MethodCall::autoderef(expr_id, i); + let method_call = MethodCall::autoderef(expr_id, i as u32); match method_type(method_call) { Some(method_ty) => { // overloaded deref operators have all late-bound @@ -4608,7 +4490,11 @@ pub fn adjust_ty<'tcx, F>(cx: &ctxt<'tcx>, } } - adjust_ty_for_autoref(cx, span, adjusted_ty, adj.autoref.as_ref()) + if let Some(target) = adj.unsize { + target + } else { + adjust_ty_for_autoref(cx, adjusted_ty, adj.autoref) + } } } } @@ -4617,73 +4503,16 @@ pub fn adjust_ty<'tcx, F>(cx: &ctxt<'tcx>, } pub fn adjust_ty_for_autoref<'tcx>(cx: &ctxt<'tcx>, - span: Span, ty: Ty<'tcx>, - autoref: Option<&AutoRef<'tcx>>) - -> Ty<'tcx> -{ + autoref: Option>) + -> Ty<'tcx> { match autoref { None => ty, - - Some(&AutoPtr(r, m, ref a)) => { - let adjusted_ty = match a { - &Some(box ref a) => adjust_ty_for_autoref(cx, span, ty, Some(a)), - &None => ty - }; - mk_rptr(cx, cx.mk_region(r), mt { - ty: adjusted_ty, - mutbl: m - }) - } - - Some(&AutoUnsafe(m, ref a)) => { - let adjusted_ty = match a { - &Some(box ref a) => adjust_ty_for_autoref(cx, span, ty, Some(a)), - &None => ty - }; - mk_ptr(cx, mt {ty: adjusted_ty, mutbl: m}) - } - - Some(&AutoUnsize(ref k)) => unsize_ty(cx, ty, k, span), - - Some(&AutoUnsizeUniq(ref k)) => ty::mk_uniq(cx, unsize_ty(cx, ty, k, span)), - } -} - -// Take a sized type and a sizing adjustment and produce an unsized version of -// the type. -pub fn unsize_ty<'tcx>(cx: &ctxt<'tcx>, - ty: Ty<'tcx>, - kind: &UnsizeKind<'tcx>, - span: Span) - -> Ty<'tcx> { - match kind { - &UnsizeLength(len) => match ty.sty { - ty_vec(ty, Some(n)) => { - assert!(len == n); - mk_vec(cx, ty, None) - } - _ => cx.sess.span_bug(span, - &format!("UnsizeLength with bad sty: {:?}", - ty_to_string(cx, ty))) - }, - &UnsizeStruct(box ref k, tp_index) => match ty.sty { - ty_struct(did, substs) => { - let ty_substs = substs.types.get_slice(subst::TypeSpace); - let new_ty = unsize_ty(cx, ty_substs[tp_index], k, span); - let mut unsized_substs = substs.clone(); - unsized_substs.types.get_mut_slice(subst::TypeSpace)[tp_index] = new_ty; - mk_struct(cx, did, cx.mk_substs(unsized_substs)) - } - _ => cx.sess.span_bug(span, - &format!("UnsizeStruct with bad sty: {:?}", - ty_to_string(cx, ty))) - }, - &UnsizeVtable(TyTrait { ref principal, ref bounds }, _) => { - mk_trait(cx, principal.clone(), bounds.clone()) + Some(AutoPtr(r, m)) => { + mk_rptr(cx, r, mt { ty: ty, mutbl: m }) } - &UnsizeUpcast(target_ty) => { - target_ty + Some(AutoUnsafe(m)) => { + mk_ptr(cx, mt { ty: ty, mutbl: m }) } } } @@ -5203,6 +5032,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", @@ -5659,21 +5508,28 @@ pub fn lookup_repr_hints(tcx: &ctxt, did: DefId) -> Rc> { } // 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>, - struct_id: DefId, - id: DefId, - substs: &Substs<'tcx>) - -> Ty<'tcx> { - let ty = if id.krate == ast::LOCAL_CRATE { +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(); let pty = tcache.entry(id).get().unwrap_or_else( |vacant_entry| vacant_entry.insert(csearch::get_field_type(tcx, struct_id, id))); pty.ty - }; - ty.subst(tcx, substs) + } +} + +// 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>, + struct_id: DefId, + id: DefId, + substs: &Substs<'tcx>) + -> Ty<'tcx> { + lookup_field_type_unsubstituted(tcx, struct_id, id).subst(tcx, substs) } // Look up the list of field names and IDs for a given struct. @@ -5728,6 +5584,47 @@ pub fn tup_fields<'tcx>(v: &[Ty<'tcx>]) -> Vec> { }).collect() } +/// Returns the deeply last field of nested structures, or the same type, +/// if not a structure at all. Corresponds to the only possible unsized +/// field, and its type can be used to determine unsizing strategy. +pub fn struct_tail<'tcx>(cx: &ctxt<'tcx>, mut ty: Ty<'tcx>) -> Ty<'tcx> { + while let ty_struct(def_id, substs) = ty.sty { + match struct_fields(cx, def_id, substs).last() { + Some(f) => ty = f.mt.ty, + None => break + } + } + ty +} + +/// Same as applying struct_tail on `source` and `target`, but only +/// keeps going as long as the two types are instances of the same +/// structure definitions. +/// For `(Foo>, Foo)`, the result will be `(Foo, Trait)`, +/// whereas struct_tail produces `T`, and `Trait`, respectively. +pub fn struct_lockstep_tails<'tcx>(cx: &ctxt<'tcx>, + source: Ty<'tcx>, + target: Ty<'tcx>) + -> (Ty<'tcx>, Ty<'tcx>) { + let (mut a, mut b) = (source, target); + while let (&ty_struct(a_did, a_substs), &ty_struct(b_did, b_substs)) = (&a.sty, &b.sty) { + if a_did != b_did { + continue; + } + if let Some(a_f) = struct_fields(cx, a_did, a_substs).last() { + if let Some(b_f) = struct_fields(cx, b_did, b_substs).last() { + a = a_f.mt.ty; + b = b_f.mt.ty; + } else { + break; + } + } else { + break; + } + } + (a, b) +} + #[derive(Copy, Clone)] pub struct ClosureUpvar<'tcx> { pub def: def::Def, @@ -6709,8 +6606,8 @@ pub fn with_freevars(tcx: &ty::ctxt, fid: ast::NodeId, f: F) -> T where impl<'tcx> AutoAdjustment<'tcx> { pub fn is_identity(&self) -> bool { match *self { - AdjustReifyFnPointer(..) => false, - AdjustUnsafeFnPointer(..) => false, + AdjustReifyFnPointer | + AdjustUnsafeFnPointer => false, AdjustDerefRef(ref r) => r.is_identity(), } } @@ -6718,7 +6615,7 @@ impl<'tcx> AutoAdjustment<'tcx> { impl<'tcx> AutoDerefRef<'tcx> { pub fn is_identity(&self) -> bool { - self.autoderefs == 0 && self.autoref.is_none() + self.autoderefs == 0 && self.unsize.is_none() && self.autoref.is_none() } } @@ -6857,8 +6754,8 @@ impl DebruijnIndex { impl<'tcx> Repr<'tcx> for AutoAdjustment<'tcx> { fn repr(&self, tcx: &ctxt<'tcx>) -> String { match *self { - AdjustReifyFnPointer(def_id) => { - format!("AdjustReifyFnPointer({})", def_id.repr(tcx)) + AdjustReifyFnPointer => { + format!("AdjustReifyFnPointer") } AdjustUnsafeFnPointer => { format!("AdjustUnsafeFnPointer") @@ -6870,37 +6767,21 @@ impl<'tcx> Repr<'tcx> for AutoAdjustment<'tcx> { } } -impl<'tcx> Repr<'tcx> for UnsizeKind<'tcx> { - fn repr(&self, tcx: &ctxt<'tcx>) -> String { - match *self { - UnsizeLength(n) => format!("UnsizeLength({})", n), - UnsizeStruct(ref k, n) => format!("UnsizeStruct({},{})", k.repr(tcx), n), - UnsizeVtable(ref a, ref b) => format!("UnsizeVtable({},{})", a.repr(tcx), b.repr(tcx)), - UnsizeUpcast(ref a) => format!("UnsizeUpcast({})", a.repr(tcx)), - } - } -} - impl<'tcx> Repr<'tcx> for AutoDerefRef<'tcx> { fn repr(&self, tcx: &ctxt<'tcx>) -> String { - format!("AutoDerefRef({}, {})", self.autoderefs, self.autoref.repr(tcx)) + format!("AutoDerefRef({}, unsize={}, {})", + self.autoderefs, self.unsize.repr(tcx), self.autoref.repr(tcx)) } } impl<'tcx> Repr<'tcx> for AutoRef<'tcx> { fn repr(&self, tcx: &ctxt<'tcx>) -> String { match *self { - AutoPtr(a, b, ref c) => { - format!("AutoPtr({},{:?},{})", a.repr(tcx), b, c.repr(tcx)) - } - AutoUnsize(ref a) => { - format!("AutoUnsize({})", a.repr(tcx)) - } - AutoUnsizeUniq(ref a) => { - format!("AutoUnsizeUniq({})", a.repr(tcx)) + AutoPtr(a, b) => { + format!("AutoPtr({},{:?})", a.repr(tcx), b) } - AutoUnsafe(ref a, ref b) => { - format!("AutoUnsafe({:?},{})", a, b.repr(tcx)) + AutoUnsafe(ref a) => { + format!("AutoUnsafe({:?})", a) } } } diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs index f17ba78007bb2..21802a70ee6c4 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -467,24 +467,6 @@ impl<'tcx> TypeFoldable<'tcx> for ty::InstantiatedPredicates<'tcx> { } } -impl<'tcx> TypeFoldable<'tcx> for ty::UnsizeKind<'tcx> { - fn fold_with>(&self, folder: &mut F) -> ty::UnsizeKind<'tcx> { - match *self { - ty::UnsizeLength(len) => ty::UnsizeLength(len), - ty::UnsizeStruct(box ref k, n) => ty::UnsizeStruct(box k.fold_with(folder), n), - ty::UnsizeVtable(ty::TyTrait{ref principal, ref bounds}, self_ty) => { - ty::UnsizeVtable( - ty::TyTrait { - principal: principal.fold_with(folder), - bounds: bounds.fold_with(folder), - }, - self_ty.fold_with(folder)) - } - ty::UnsizeUpcast(t) => ty::UnsizeUpcast(t.fold_with(folder)), - } - } -} - impl<'tcx,O> TypeFoldable<'tcx> for traits::Obligation<'tcx,O> where O : TypeFoldable<'tcx> { @@ -758,16 +740,11 @@ pub fn super_fold_autoref<'tcx, T: TypeFolder<'tcx>>(this: &mut T, -> ty::AutoRef<'tcx> { match *autoref { - ty::AutoPtr(r, m, None) => ty::AutoPtr(this.fold_region(r), m, None), - ty::AutoPtr(r, m, Some(ref a)) => { - ty::AutoPtr(this.fold_region(r), m, Some(box super_fold_autoref(this, &**a))) - } - ty::AutoUnsafe(m, None) => ty::AutoUnsafe(m, None), - ty::AutoUnsafe(m, Some(ref a)) => { - ty::AutoUnsafe(m, Some(box super_fold_autoref(this, &**a))) + ty::AutoPtr(r, m) => { + let r = r.fold_with(this); + ty::AutoPtr(this.tcx().mk_region(r), m) } - ty::AutoUnsize(ref k) => ty::AutoUnsize(k.fold_with(this)), - ty::AutoUnsizeUniq(ref k) => ty::AutoUnsizeUniq(k.fold_with(this)), + ty::AutoUnsafe(m) => ty::AutoUnsafe(m) } } diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 8b57a48f3ce72..2b25829b2ff4c 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -1406,11 +1406,11 @@ impl LintPass for UnusedAllocation { if let Some(adjustment) = cx.tcx.adjustments.borrow().get(&e.id) { if let ty::AdjustDerefRef(ty::AutoDerefRef { ref autoref, .. }) = *adjustment { match autoref { - &Some(ty::AutoPtr(_, ast::MutImmutable, None)) => { + &Some(ty::AutoPtr(_, ast::MutImmutable)) => { cx.span_lint(UNUSED_ALLOCATION, e.span, "unnecessary allocation, use & instead"); } - &Some(ty::AutoPtr(_, ast::MutMutable, None)) => { + &Some(ty::AutoPtr(_, ast::MutMutable)) => { cx.span_lint(UNUSED_ALLOCATION, e.span, "unnecessary allocation, use &mut instead"); } diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs index 61cdde3bfbecd..13dcfda833989 100644 --- a/src/librustc_trans/trans/common.rs +++ b/src/librustc_trans/trans/common.rs @@ -146,33 +146,6 @@ pub fn type_is_fat_ptr<'tcx>(cx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool { } } -// Return the smallest part of `ty` which is unsized. Fails if `ty` is sized. -// 'Smallest' here means component of the static representation of the type; not -// the size of an object at runtime. -pub fn unsized_part_of_type<'tcx>(cx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { - match ty.sty { - ty::ty_str | ty::ty_trait(..) | ty::ty_vec(..) => ty, - ty::ty_struct(def_id, substs) => { - let unsized_fields: Vec<_> = - ty::struct_fields(cx, def_id, substs) - .iter() - .map(|f| f.mt.ty) - .filter(|ty| !type_is_sized(cx, *ty)) - .collect(); - - // Exactly one of the fields must be unsized. - assert!(unsized_fields.len() == 1); - - unsized_part_of_type(cx, unsized_fields[0]) - } - _ => { - assert!(type_is_sized(cx, ty), - "unsized_part_of_type failed even though ty is unsized"); - panic!("called unsized_part_of_type with sized ty"); - } - } -} - // Some things don't need cleanups during unwinding because the // task can free them all at once later. Currently only things // that only contain scalars and shared boxes can avoid unwind diff --git a/src/librustc_trans/trans/consts.rs b/src/librustc_trans/trans/consts.rs index 4b1a03e47e7ae..5e7bbef4a68db 100644 --- a/src/librustc_trans/trans/consts.rs +++ b/src/librustc_trans/trans/consts.rs @@ -242,7 +242,7 @@ pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, &ty::expr_ty_adjusted(cx.tcx(), e)); let opt_adj = cx.tcx().adjustments.borrow().get(&e.id).cloned(); match opt_adj { - Some(ty::AdjustReifyFnPointer(_def_id)) => { + Some(ty::AdjustReifyFnPointer) => { // FIXME(#19925) once fn item types are // zero-sized, we'll need to do something here } @@ -260,73 +260,56 @@ pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, } } - let second_autoref = match adj.autoref { - None => { - let (dv, dt) = const_deref(cx, llconst, ty); - llconst = dv; - - // If we derefed a fat pointer then we will have an - // open type here. So we need to update the type with - // the one returned from const_deref. - ety_adjusted = dt; - None - } - Some(ty::AutoUnsafe(_, opt_autoref)) | - Some(ty::AutoPtr(_, _, opt_autoref)) => { - if adj.autoderefs == 0 { - // Don't copy data to do a deref+ref - // (i.e., skip the last auto-deref). - llconst = addr_of(cx, llconst, "autoref", e.id); - } else { - // Seeing as we are deref'ing here and take a reference - // again to make the pointer part of the far pointer below, - // we just skip the whole thing. We still need the type - // though. This works even if we don't need to deref - // because of byref semantics. Note that this is not just - // an optimisation, it is necessary for mutable vectors to - // work properly. - ty = match ty::deref(ty, true) { - Some(mt) => mt.ty, - None => { - cx.sess().bug(&format!("unexpected dereferenceable type {}", - ty_to_string(cx.tcx(), ty))) - } - } - } - opt_autoref - } - Some(autoref) => { - cx.sess().span_bug(e.span, - &format!("unimplemented const first autoref {:?}", autoref)) - } - }; - match second_autoref { - None => {} - Some(box ty::AutoUnsafe(_, None)) | - Some(box ty::AutoPtr(_, _, None)) => { + if adj.autoref.is_some() { + if adj.autoderefs == 0 { + // Don't copy data to do a deref+ref + // (i.e., skip the last auto-deref). llconst = addr_of(cx, llconst, "autoref", e.id); + ty = ty::mk_imm_rptr(cx.tcx(), cx.tcx().mk_region(ty::ReStatic), ty); } - Some(box ty::AutoUnsize(ref k)) => { - let info = - expr::unsized_info( - cx, k, e.id, ty, param_substs, - || const_get_elt(cx, llconst, &[abi::FAT_PTR_EXTRA as u32])); - - let unsized_ty = ty::unsize_ty(cx.tcx(), ty, k, e.span); - let ptr_ty = type_of::in_memory_type_of(cx, unsized_ty).ptr_to(); - let base = ptrcast(llconst, ptr_ty); - - let prev_const = cx.const_unsized().borrow_mut() - .insert(base, llconst); - assert!(prev_const.is_none() || prev_const == Some(llconst)); - assert_eq!(abi::FAT_PTR_ADDR, 0); - assert_eq!(abi::FAT_PTR_EXTRA, 1); - llconst = C_struct(cx, &[base, info], false); - } - Some(autoref) => { - cx.sess().span_bug(e.span, - &format!("unimplemented const second autoref {:?}", autoref)) - } + } else { + let (dv, dt) = const_deref(cx, llconst, ty); + llconst = dv; + + // If we derefed a fat pointer then we will have an + // open type here. So we need to update the type with + // the one returned from const_deref. + ety_adjusted = dt; + } + + if let Some(target) = adj.unsize { + let target = monomorphize::apply_param_substs(cx.tcx(), + param_substs, + &target); + + let pointee_ty = ty::deref(ty, true) + .expect("consts: unsizing got non-pointer type").ty; + let (base, old_info) = if !type_is_sized(cx.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. + (const_get_elt(cx, llconst, &[abi::FAT_PTR_ADDR as u32]), + Some(const_get_elt(cx, llconst, &[abi::FAT_PTR_EXTRA as u32]))) + } else { + (llconst, None) + }; + + let unsized_ty = ty::deref(target, true) + .expect("consts: unsizing got non-pointer target type").ty; + let ptr_ty = type_of::in_memory_type_of(cx, unsized_ty).ptr_to(); + let base = ptrcast(base, ptr_ty); + let info = expr::unsized_info(cx, pointee_ty, unsized_ty, + old_info, param_substs); + + let prev_const = cx.const_unsized().borrow_mut() + .insert(base, llconst); + assert!(prev_const.is_none() || prev_const == Some(llconst)); + assert_eq!(abi::FAT_PTR_ADDR, 0); + assert_eq!(abi::FAT_PTR_EXTRA, 1); + llconst = C_struct(cx, &[base, info], false); } } None => {} diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs index 4d7431a20b707..4933b1a25f934 100644 --- a/src/librustc_trans/trans/expr.rs +++ b/src/librustc_trans/trans/expr.rs @@ -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::{Subst, Substs, VecPerParamSpace}; +use middle::traits; use trans::{_match, adt, asm, base, callee, closure, consts, controlflow}; use trans::base::*; use trans::build::*; @@ -72,8 +74,7 @@ use trans::monomorphize; use trans::tvec; use trans::type_of; use middle::ty::{struct_fields, tup_fields}; -use middle::ty::{AdjustDerefRef, AdjustReifyFnPointer, AdjustUnsafeFnPointer, AutoUnsafe}; -use middle::ty::{AutoPtr}; +use middle::ty::{AdjustDerefRef, AdjustReifyFnPointer, AdjustUnsafeFnPointer}; use middle::ty::{self, Ty}; use middle::ty::MethodCall; use util::common::indenter; @@ -290,72 +291,39 @@ pub fn copy_fat_ptr(bcx: Block, src_ptr: ValueRef, dst_ptr: ValueRef) { Store(bcx, Load(bcx, get_len(bcx, src_ptr)), get_len(bcx, dst_ptr)); } -// Retrieve the information we are losing (making dynamic) in an unsizing -// adjustment. -// -// The `unadjusted_val` argument is a bit funny. It is intended -// for use in an upcast, where the new vtable for an object will -// be drived from the old one. Hence it is a pointer to the fat -// pointer. -pub fn unsized_info_bcx<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - kind: &ty::UnsizeKind<'tcx>, - id: ast::NodeId, - unadjusted_ty: Ty<'tcx>, - unadjusted_val: ValueRef, // see above (*) - param_substs: &'tcx subst::Substs<'tcx>) - -> ValueRef { - unsized_info( - bcx.ccx(), - kind, - id, - unadjusted_ty, - param_substs, - || Load(bcx, GEPi(bcx, unadjusted_val, &[0, abi::FAT_PTR_EXTRA]))) -} - -// Same as `unsize_info_bcx`, but does not require a bcx -- instead it -// takes an extra closure to compute the upcast vtable. -pub fn unsized_info<'ccx, 'tcx, MK_UPCAST_VTABLE>( - ccx: &CrateContext<'ccx, 'tcx>, - kind: &ty::UnsizeKind<'tcx>, - id: ast::NodeId, - unadjusted_ty: Ty<'tcx>, - param_substs: &'tcx subst::Substs<'tcx>, - mk_upcast_vtable: MK_UPCAST_VTABLE) // see notes above - -> ValueRef - where MK_UPCAST_VTABLE: FnOnce() -> ValueRef -{ - debug!("unsized_info(kind={:?}, id={}, unadjusted_ty={})", - kind, id, unadjusted_ty.repr(ccx.tcx())); - match kind { - &ty::UnsizeLength(len) => C_uint(ccx, len), - &ty::UnsizeStruct(box ref k, tp_index) => match unadjusted_ty.sty { - ty::ty_struct(_, ref substs) => { - let ty_substs = substs.types.get_slice(subst::TypeSpace); - unsized_info(ccx, k, id, ty_substs[tp_index], param_substs, - mk_upcast_vtable) - } - _ => ccx.sess().bug(&format!("UnsizeStruct with bad sty: {}", - unadjusted_ty.repr(ccx.tcx()))) - }, - &ty::UnsizeVtable(ty::TyTrait { ref principal, .. }, _) => { +/// Retrieve the information we are losing (making dynamic) in an unsizing +/// adjustment. +/// +/// The `old_info` argument is a bit funny. It is intended for use +/// in an upcast, where the new vtable for an object will be drived +/// from the old one. +pub fn unsized_info<'ccx, 'tcx>(ccx: &CrateContext<'ccx, 'tcx>, + source: Ty<'tcx>, + target: Ty<'tcx>, + old_info: Option, + param_substs: &'tcx Substs<'tcx>) + -> ValueRef { + let (source, target) = ty::struct_lockstep_tails(ccx.tcx(), source, target); + match (&source.sty, &target.sty) { + (&ty::ty_vec(_, Some(len)), &ty::ty_vec(_, None)) => C_uint(ccx, len), + (&ty::ty_trait(_), &ty::ty_trait(_)) => { + // For now, upcasts are limited to changes in marker + // traits, and hence never actually require an actual + // change to the vtable. + old_info.expect("unsized_info: missing old info for trait upcast") + } + (_, &ty::ty_trait(box ty::TyTrait { ref principal, .. })) => { // Note that we preserve binding levels here: - let substs = principal.0.substs.with_self_ty(unadjusted_ty).erase_regions(); + let substs = principal.0.substs.with_self_ty(source).erase_regions(); let substs = ccx.tcx().mk_substs(substs); let trait_ref = ty::Binder(Rc::new(ty::TraitRef { def_id: principal.def_id(), - substs: substs })); - let trait_ref = monomorphize::apply_param_substs(ccx.tcx(), - param_substs, - &trait_ref); + substs: substs })); consts::ptrcast(meth::get_vtable(ccx, trait_ref, param_substs), Type::vtable_ptr(ccx)) } - &ty::UnsizeUpcast(_) => { - // For now, upcasts are limited to changes in marker - // traits, and hence never actually require an actual - // change to the vtable. - mk_upcast_vtable() - } + _ => ccx.sess().bug(&format!("unsized_info: invalid unsizing {} -> {}", + source.repr(ccx.tcx()), + target.repr(ccx.tcx()))) } } @@ -379,7 +347,7 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, datum.to_string(bcx.ccx()), adjustment); match adjustment { - AdjustReifyFnPointer(_def_id) => { + AdjustReifyFnPointer => { // FIXME(#19925) once fn item types are // zero-sized, we'll need to do something here } @@ -387,203 +355,187 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, // purely a type-level thing } AdjustDerefRef(ref adj) => { - let (autoderefs, use_autoref) = match adj.autoref { - // Extracting a value from a box counts as a deref, but if we are - // just converting Box<[T, ..n]> to Box<[T]> we aren't really doing - // a deref (and wouldn't if we could treat Box like a normal struct). - Some(ty::AutoUnsizeUniq(..)) => (adj.autoderefs - 1, true), + let skip_reborrows = if adj.autoderefs == 1 && adj.autoref.is_some() { // We are a bit paranoid about adjustments and thus might have a re- // borrow here which merely derefs and then refs again (it might have - // a different region or mutability, but we don't care here. It might - // also be just in case we need to unsize. But if there are no nested - // adjustments then it should be a no-op). - Some(ty::AutoPtr(_, _, None)) | - Some(ty::AutoUnsafe(_, None)) if adj.autoderefs == 1 => { - match datum.ty.sty { - // Don't skip a conversion from Box to &T, etc. - ty::ty_rptr(..) => { - let method_call = MethodCall::autoderef(expr.id, adj.autoderefs-1); - let method = bcx.tcx().method_map.borrow().get(&method_call).is_some(); - if method { - // Don't skip an overloaded deref. - (adj.autoderefs, true) - } else { - (adj.autoderefs - 1, false) - } + // a different region or mutability, but we don't care here). + match datum.ty.sty { + // Don't skip a conversion from Box to &T, etc. + ty::ty_rptr(..) => { + let method_call = MethodCall::autoderef(expr.id, 0); + if bcx.tcx().method_map.borrow().contains_key(&method_call) { + // Don't skip an overloaded deref. + 0 + } else { + 1 } - _ => (adj.autoderefs, true), } + _ => 0 } - _ => (adj.autoderefs, true) + } else { + 0 }; - if autoderefs > 0 { + if adj.autoderefs > skip_reborrows { // Schedule cleanup. let lval = unpack_datum!(bcx, datum.to_lvalue_datum(bcx, "auto_deref", expr.id)); - datum = unpack_datum!( - bcx, deref_multiple(bcx, expr, lval.to_expr_datum(), autoderefs)); + datum = unpack_datum!(bcx, deref_multiple(bcx, expr, + lval.to_expr_datum(), + adj.autoderefs - skip_reborrows)); } // (You might think there is a more elegant way to do this than a - // use_autoref bool, but then you remember that the borrow checker exists). - if let (true, &Some(ref a)) = (use_autoref, &adj.autoref) { - datum = unpack_datum!(bcx, apply_autoref(a, - bcx, - expr, - datum)); - } - } - } - debug!("after adjustments, datum={}", datum.to_string(bcx.ccx())); - return DatumBlock::new(bcx, datum); - - fn apply_autoref<'blk, 'tcx>(autoref: &ty::AutoRef<'tcx>, - bcx: Block<'blk, 'tcx>, - expr: &ast::Expr, - datum: Datum<'tcx, Expr>) - -> DatumBlock<'blk, 'tcx, Expr> { - let mut bcx = bcx; - let mut datum = datum; - - let datum = match autoref { - &AutoPtr(_, _, ref a) | &AutoUnsafe(_, ref a) => { - debug!(" AutoPtr"); - if let &Some(box ref a) = a { - datum = unpack_datum!(bcx, apply_autoref(a, bcx, expr, datum)); - } + // skip_reborrows bool, but then you remember that the borrow checker exists). + if skip_reborrows == 0 && adj.autoref.is_some() { 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)); - unpack_datum!(bcx, ref_fat_ptr(bcx, lval)) + datum = unpack_datum!(bcx, ref_fat_ptr(bcx, lval)); } else { - unpack_datum!(bcx, auto_ref(bcx, datum, expr)) + datum = unpack_datum!(bcx, auto_ref(bcx, datum, expr)); } } - &ty::AutoUnsize(ref k) => { - debug!(" AutoUnsize"); - unpack_datum!(bcx, unsize_expr(bcx, expr, datum, k)) - } - &ty::AutoUnsizeUniq(ty::UnsizeLength(len)) => { - debug!(" AutoUnsizeUniq(UnsizeLength)"); - unpack_datum!(bcx, unsize_unique_vec(bcx, expr, datum, len)) - } - &ty::AutoUnsizeUniq(ref k) => { - debug!(" AutoUnsizeUniq"); - unpack_datum!(bcx, unsize_unique_expr(bcx, expr, datum, k)) - } - }; - DatumBlock::new(bcx, datum) + if let Some(target) = adj.unsize { + // 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())); + DatumBlock::new(bcx, datum) +} - fn unsize_expr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - expr: &ast::Expr, - datum: Datum<'tcx, Expr>, - k: &ty::UnsizeKind<'tcx>) - -> DatumBlock<'blk, 'tcx, Expr> { - let mut bcx = bcx; - let tcx = bcx.tcx(); - let datum_ty = datum.ty; - let unsized_ty = ty::unsize_ty(tcx, datum_ty, k, expr.span); - debug!("unsized_ty={}", unsized_ty.repr(bcx.tcx())); - - let info = unsized_info_bcx(bcx, k, expr.id, datum_ty, datum.val, bcx.fcx.param_substs); - - // Arrange cleanup - let lval = unpack_datum!(bcx, datum.to_lvalue_datum(bcx, "into_fat_ptr", expr.id)); - - // 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 = if !type_is_sized(bcx.tcx(), lval.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, lval.val)) - } else { - lval.val - }; - let base = PointerCast(bcx, base, ptr_ty); +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())); + + 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 llty = type_of::type_of(bcx.ccx(), unsized_ty); - // 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)); + let info = unsized_info(bcx.ccx(), inner_source, inner_target, + old_info, bcx.fcx.param_substs); - DatumBlock::new(bcx, Datum::new(scratch, unsized_ty, LvalueExpr)) - } + // 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); - fn unsize_unique_vec<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - expr: &ast::Expr, - datum: Datum<'tcx, Expr>, - len: uint) - -> DatumBlock<'blk, 'tcx, Expr> { - let mut bcx = bcx; - let tcx = bcx.tcx(); - - let datum_ty = datum.ty; - - debug!("unsize_unique_vec expr.id={} datum_ty={} len={}", - expr.id, datum_ty.repr(tcx), len); - - // We do not arrange cleanup ourselves; if we already are an - // L-value, then cleanup will have already been scheduled (and - // the `datum.store_to` 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 ll_len = C_uint(bcx.ccx(), len); - let unit_ty = ty::sequence_element_type(tcx, ty::type_content(datum_ty)); - let vec_ty = ty::mk_uniq(tcx, ty::mk_vec(tcx, unit_ty, None)); - let scratch = rvalue_scratch_datum(bcx, vec_ty, "__unsize_unique"); - - let base = get_dataptr(bcx, scratch.val); - let base = PointerCast(bcx, - base, - type_of::type_of(bcx.ccx(), datum_ty).ptr_to()); - bcx = datum.store_to(bcx, base); - - Store(bcx, ll_len, get_len(bcx, scratch.val)); - DatumBlock::new(bcx, scratch.to_expr_datum()) - } + Store(bcx, base, get_dataptr(bcx, target.val)); + Store(bcx, info, get_len(bcx, target.val)); + } - fn unsize_unique_expr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - expr: &ast::Expr, - datum: Datum<'tcx, Expr>, - k: &ty::UnsizeKind<'tcx>) - -> DatumBlock<'blk, 'tcx, Expr> { - let mut bcx = bcx; - let tcx = bcx.tcx(); - - let datum_ty = datum.ty; - let unboxed_ty = match datum_ty.sty { - ty::ty_uniq(t) => t, - _ => bcx.sess().bug(&format!("Expected ty_uniq, found {}", - bcx.ty_to_string(datum_ty))) - }; - let result_ty = ty::mk_uniq(tcx, ty::unsize_ty(tcx, unboxed_ty, k, expr.span)); + // This can be extended to enums and tuples in the future. + // (&ty::ty_enum(def_id_a, substs_a), &ty::ty_enum(def_id_b, substs_b)) | + (&ty::ty_struct(def_id_a, substs_a), &ty::ty_struct(def_id_b, substs_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()); - // We do not arrange cleanup ourselves; if we already are an - // L-value, then cleanup will have already been scheduled (and - // the `datum.store_to` 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 trait_substs = Substs::erased(VecPerParamSpace::new(vec![target.ty], + vec![source.ty], + Vec::new())); + let trait_ref = ty::Binder(Rc::new(ty::TraitRef { + def_id: langcall(bcx, Some(span), "coercion", + CoerceUnsizedTraitLangItem), + substs: bcx.tcx().mk_substs(trait_substs) + })); - let scratch = rvalue_scratch_datum(bcx, result_ty, "__uniq_fat_ptr"); - let llbox_ty = type_of::type_of(bcx.ccx(), datum_ty); - let base = PointerCast(bcx, get_dataptr(bcx, scratch.val), llbox_ty.ptr_to()); - bcx = datum.store_to(bcx, base); + 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 info = unsized_info_bcx(bcx, k, expr.id, unboxed_ty, base, bcx.fcx.param_substs); - Store(bcx, info, get_len(bcx, scratch.val)); + let repr_source = adt::represent_type(bcx.ccx(), source.ty); + let repr_target = adt::represent_type(bcx.ccx(), target.ty); + let fields = ty::lookup_struct_fields(bcx.tcx(), def_id_a); - DatumBlock::new(bcx, scratch.to_expr_datum()) + let coerce_index = match kind { + ty::CustomCoerceUnsized::Struct(i) => i + }; + assert!(coerce_index < fields.len()); + + for (i, field) in fields.iter().enumerate() { + 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); + + let ty = ty::lookup_field_type_unsubstituted(bcx.tcx(), + def_id_a, + field.id); + let field_source = ty.subst(bcx.tcx(), substs_a); + let field_target = ty.subst(bcx.tcx(), substs_b); + + // If this is the field we need to coerce, recurse on it. + if i == coerce_index { + coerce_unsized(bcx, span, + Datum::new(ll_source, field_source, + Rvalue::new(ByRef)), + Datum::new(ll_target, field_target, + Rvalue::new(ByRef))); + } else { + // Otherwise, simply copy the data from the source. + assert_eq!(field_source, field_target); + memcpy_ty(bcx, ll_target, ll_source, field_source); + } + } + } + _ => bcx.sess().bug(&format!("coerce_unsized: invalid coercion {} -> {}", + source.ty.repr(bcx.tcx()), + target.ty.repr(bcx.tcx()))) } + bcx } /// Translates an expression in "lvalue" mode -- meaning that it returns a reference to the memory @@ -1297,7 +1249,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"); @@ -2227,7 +2179,7 @@ fn deref_multiple<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let mut bcx = bcx; let mut datum = datum; for i in 0..times { - let method_call = MethodCall::autoderef(expr.id, i); + let method_call = MethodCall::autoderef(expr.id, i as u32); datum = unpack_datum!(bcx, deref_once(bcx, expr, datum, method_call)); } DatumBlock { bcx: bcx, datum: datum } @@ -2259,10 +2211,11 @@ fn deref_once<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, // converts from the `Smaht` pointer that we have into // a `&T` pointer. We can then proceed down the normal // path (below) to dereference that `&T`. - let datum = match method_call.adjustment { + let datum = if method_call.autoderef == 0 { + datum + } else { // Always perform an AutoPtr when applying an overloaded auto-deref - ty::AutoDeref(_) => unpack_datum!(bcx, auto_ref(bcx, datum, expr)), - _ => datum + unpack_datum!(bcx, auto_ref(bcx, datum, expr)) }; let ref_ty = // invoked methods have their LB regions instantiated diff --git a/src/librustc_trans/trans/glue.rs b/src/librustc_trans/trans/glue.rs index b2de8435f641b..c1557a6f27ba6 100644 --- a/src/librustc_trans/trans/glue.rs +++ b/src/librustc_trans/trans/glue.rs @@ -328,8 +328,8 @@ fn trans_struct_drop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, }) } -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) { diff --git a/src/librustc_trans/trans/intrinsic.rs b/src/librustc_trans/trans/intrinsic.rs index f714c5800c57b..90d37721d5115 100644 --- a/src/librustc_trans/trans/intrinsic.rs +++ b/src/librustc_trans/trans/intrinsic.rs @@ -322,10 +322,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); @@ -347,6 +368,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)); diff --git a/src/librustc_trans/trans/type_of.rs b/src/librustc_trans/trans/type_of.rs index 8d228c22c3cfa..b93fed22a77e5 100644 --- a/src/librustc_trans/trans/type_of.rs +++ b/src/librustc_trans/trans/type_of.rs @@ -358,14 +358,14 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> cx.tn().find_type("str_slice").unwrap() } else { let ptr_ty = in_memory_type_of(cx, ty).ptr_to(); - let unsized_part = unsized_part_of_type(cx.tcx(), ty); + let unsized_part = ty::struct_tail(cx.tcx(), ty); let info_ty = match unsized_part.sty { ty::ty_str | ty::ty_vec(..) => { Type::uint_from_ty(cx, ast::TyUs(false)) } ty::ty_trait(_) => Type::vtable_ptr(cx), _ => panic!("Unexpected type returned from \ - unsized_part_of_type: {} for ty={}", + struct_tail: {} for ty={}", unsized_part.repr(cx.tcx()), ty.repr(cx.tcx())) }; Type::struct_(cx, &[ptr_ty, info_ty], false) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index e9de8bd879e20..5db7e474dd2a0 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -59,6 +59,7 @@ use middle::ty::{self, RegionEscape, Ty}; use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope, ObjectLifetimeDefaultRscope, ShiftedRscope, BindingRscope}; use util::common::{ErrorReported, FN_OUTPUT_NAME}; +use util::nodemap::FnvHashSet; use util::ppaux::{self, Repr, UserString}; use std::iter::{repeat, AdditiveIterator}; @@ -1026,13 +1027,58 @@ fn trait_ref_to_object_type<'tcx>(this: &AstConv<'tcx>, projection_bounds, bounds); - let result = ty::mk_trait(this.tcx(), trait_ref, existential_bounds); + let result = make_object_type(this, span, trait_ref, existential_bounds); debug!("trait_ref_to_object_type: result={}", result.repr(this.tcx())); result } +fn make_object_type<'tcx>(this: &AstConv<'tcx>, + span: Span, + principal: ty::PolyTraitRef<'tcx>, + bounds: ty::ExistentialBounds<'tcx>) + -> Ty<'tcx> { + let tcx = this.tcx(); + let object = ty::TyTrait { + principal: principal, + bounds: bounds + }; + let object_trait_ref = + object.principal_trait_ref_with_self_ty(tcx, tcx.types.err); + + // ensure the super predicates and stop if we encountered an error + if this.ensure_super_predicates(span, object.principal_def_id()).is_err() { + return tcx.types.err; + } + + let mut associated_types: FnvHashSet<(ast::DefId, ast::Name)> = + traits::supertraits(tcx, object_trait_ref) + .flat_map(|tr| { + let trait_def = ty::lookup_trait_def(tcx, tr.def_id()); + trait_def.associated_type_names + .clone() + .into_iter() + .map(move |associated_type_name| (tr.def_id(), associated_type_name)) + }) + .collect(); + + for projection_bound in &object.bounds.projection_bounds { + let pair = (projection_bound.0.projection_ty.trait_ref.def_id, + projection_bound.0.projection_ty.item_name); + associated_types.remove(&pair); + } + + for (trait_def_id, name) in associated_types { + span_err!(tcx.sess, span, E0191, + "the value of the associated type `{}` (from the trait `{}`) must be specified", + name.user_string(tcx), + ty::item_path_str(tcx, trait_def_id)); + } + + ty::mk_trait(tcx, object.principal, object.bounds) +} + fn report_ambiguous_associated_type(tcx: &ty::ctxt, span: Span, type_str: &str, @@ -1785,7 +1831,7 @@ fn conv_ty_poly_trait_ref<'tcx>( projection_bounds, partitioned_bounds); - ty::mk_trait(this.tcx(), main_trait_bound, bounds) + make_object_type(this, span, main_trait_bound, bounds) } pub fn conv_existential_bounds_from_partitioned_bounds<'tcx>( diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index 6ba21e25e1fe5..153ec5c5fc571 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -83,11 +83,8 @@ pub fn check_call<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, Some(callee_expr), UnresolvedTypeAction::Error, LvaluePreference::NoPreference, - |adj_ty, idx| { - let autoderefref = ty::AutoDerefRef { autoderefs: idx, autoref: None }; - try_overloaded_call_step(fcx, call_expr, callee_expr, - adj_ty, autoderefref) - }); + |adj_ty, idx| try_overloaded_call_step(fcx, call_expr, callee_expr, + adj_ty, idx)); match result { None => { @@ -120,20 +117,18 @@ fn try_overloaded_call_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, call_expr: &'tcx ast::Expr, callee_expr: &'tcx ast::Expr, adjusted_ty: Ty<'tcx>, - autoderefref: ty::AutoDerefRef<'tcx>) + autoderefs: usize) -> Option> { - debug!("try_overloaded_call_step(call_expr={}, adjusted_ty={}, autoderefref={})", + debug!("try_overloaded_call_step(call_expr={}, adjusted_ty={}, autoderefs={})", call_expr.repr(fcx.tcx()), adjusted_ty.repr(fcx.tcx()), - autoderefref.repr(fcx.tcx())); + autoderefs); // If the callee is a bare function or a closure, then we're all set. match structurally_resolved_type(fcx, callee_expr.span, adjusted_ty).sty { ty::ty_bare_fn(..) => { - fcx.write_adjustment(callee_expr.id, - callee_expr.span, - ty::AdjustDerefRef(autoderefref)); + fcx.write_autoderef_adjustment(callee_expr.id, autoderefs); return Some(CallStep::Builtin); } @@ -150,14 +145,14 @@ fn try_overloaded_call_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, fcx.infcx().replace_late_bound_regions_with_fresh_var(call_expr.span, infer::FnCall, &closure_ty.sig).0; - fcx.record_deferred_call_resolution( - def_id, - Box::new(CallResolution {call_expr: call_expr, - callee_expr: callee_expr, - adjusted_ty: adjusted_ty, - autoderefref: autoderefref, - fn_sig: fn_sig.clone(), - closure_def_id: def_id})); + fcx.record_deferred_call_resolution(def_id, Box::new(CallResolution { + call_expr: call_expr, + callee_expr: callee_expr, + adjusted_ty: adjusted_ty, + autoderefs: autoderefs, + fn_sig: fn_sig.clone(), + closure_def_id: def_id + })); return Some(CallStep::DeferredClosure(fn_sig)); } } @@ -165,7 +160,7 @@ fn try_overloaded_call_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, _ => {} } - try_overloaded_call_traits(fcx, call_expr, callee_expr, adjusted_ty, autoderefref) + try_overloaded_call_traits(fcx, call_expr, callee_expr, adjusted_ty, autoderefs) .map(|method_callee| CallStep::Overloaded(method_callee)) } @@ -173,7 +168,7 @@ fn try_overloaded_call_traits<'a,'tcx>(fcx: &FnCtxt<'a, 'tcx>, call_expr: &ast::Expr, callee_expr: &ast::Expr, adjusted_ty: Ty<'tcx>, - autoderefref: ty::AutoDerefRef<'tcx>) + autoderefs: usize) -> Option> { // Try the options that are least restrictive on the caller first. @@ -192,7 +187,8 @@ fn try_overloaded_call_traits<'a,'tcx>(fcx: &FnCtxt<'a, 'tcx>, Some(&*callee_expr), method_name, trait_def_id, - autoderefref.clone(), + autoderefs, + false, adjusted_ty, None) { None => continue, @@ -327,7 +323,7 @@ struct CallResolution<'tcx> { call_expr: &'tcx ast::Expr, callee_expr: &'tcx ast::Expr, adjusted_ty: Ty<'tcx>, - autoderefref: ty::AutoDerefRef<'tcx>, + autoderefs: usize, fn_sig: ty::FnSig<'tcx>, closure_def_id: ast::DefId, } @@ -335,11 +331,11 @@ struct CallResolution<'tcx> { impl<'tcx> Repr<'tcx> for CallResolution<'tcx> { fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String { format!("CallResolution(call_expr={}, callee_expr={}, adjusted_ty={}, \ - autoderefref={}, fn_sig={}, closure_def_id={})", + autoderefs={}, fn_sig={}, closure_def_id={})", self.call_expr.repr(tcx), self.callee_expr.repr(tcx), self.adjusted_ty.repr(tcx), - self.autoderefref.repr(tcx), + self.autoderefs, self.fn_sig.repr(tcx), self.closure_def_id.repr(tcx)) } @@ -356,7 +352,7 @@ impl<'tcx> DeferredCallResolution<'tcx> for CallResolution<'tcx> { // We may now know enough to figure out fn vs fnmut etc. match try_overloaded_call_traits(fcx, self.call_expr, self.callee_expr, - self.adjusted_ty, self.autoderefref.clone()) { + self.adjusted_ty, self.autoderefs) { Some(method_callee) => { // One problem is that when we get here, we are going // to have a newly instantiated function signature diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index ae1dbbb1b00ad..71be85211434d 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -65,18 +65,21 @@ use check::{autoderef, FnCtxt, NoPreference, PreferMutLvalue, UnresolvedTypeActi use middle::infer::{self, cres, Coercion, TypeTrace}; use middle::infer::combine::Combine; use middle::infer::sub::Sub; -use middle::subst; -use middle::ty::{AutoPtr, AutoDerefRef, AdjustDerefRef, AutoUnsize, AutoUnsafe}; +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 util::common::indent; -use util::ppaux; use util::ppaux::Repr; +use std::cell::RefCell; +use std::collections::VecDeque; use syntax::ast; struct Coerce<'a, 'tcx: 'a> { fcx: &'a FnCtxt<'a, 'tcx>, - trace: TypeTrace<'tcx> + trace: TypeTrace<'tcx>, + unsizing_obligations: RefCell>> } type CoerceResult<'tcx> = cres<'tcx, Option>>; @@ -92,12 +95,6 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { Ok(None) // No coercion required. } - fn outlives(&self, a: ty::Region, b: ty::Region) -> cres<'tcx, ()> { - let sub = Sub(self.fcx.infcx().combine_fields(false, self.trace.clone())); - try!(sub.regions(b, a)); - Ok(()) - } - fn unpack_actual_value(&self, a: Ty<'tcx>, f: F) -> T where F: FnOnce(Ty<'tcx>) -> T, { @@ -143,11 +140,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { self.unpack_actual_value(a, |a| { match a.sty { - ty::ty_bare_fn(Some(a_def_id), a_f) => { + ty::ty_bare_fn(Some(_), a_f) => { // Function items are coercible to any closure // type; function pointers are not (that would // require double indirection). - self.coerce_from_fn_item(a, a_def_id, a_f, b) + self.coerce_from_fn_item(a, a_f, b) } ty::ty_bare_fn(None, a_f) => { // We permit coercion of fn pointers to drop the @@ -183,18 +180,16 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { match a.sty { ty::ty_rptr(_, mt_a) => { - if !can_coerce_mutbls(mt_a.mutbl, mutbl_b) { - return Err(ty::terr_mutability); - } + try!(coerce_mutbls(mt_a.mutbl, mutbl_b)); } _ => return self.subtype(a, b) } let coercion = Coercion(self.trace.clone()); let r_borrow = self.fcx.infcx().next_region_var(coercion); - let autoref = Some(AutoPtr(r_borrow, mutbl_b, None)); - let r_borrow = self.tcx().mk_region(r_borrow); + let autoref = Some(ty::AutoPtr(r_borrow, mutbl_b)); + let lvalue_pref = match mutbl_b { ast::MutMutable => PreferMutLvalue, ast::MutImmutable => NoPreference @@ -228,7 +223,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { Some(_) => { Ok(Some(AdjustDerefRef(AutoDerefRef { autoderefs: autoderefs, - autoref: autoref + autoref: autoref, + unsize: None }))) } None => { @@ -244,194 +240,96 @@ 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 { + 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. - - match (&a.sty, &b.sty) { - (&ty::ty_rptr(_, ty::mt{ty: t_a, mutbl: mutbl_a}), &ty::ty_rptr(_, mt_b)) => { - match self.unsize_ty(t_a, mt_b.ty) { - Some((ty, kind)) => { - if !can_coerce_mutbls(mutbl_a, mt_b.mutbl) { - return Err(ty::terr_mutability); - } - - let coercion = Coercion(self.trace.clone()); - let r_borrow = self.fcx.infcx().next_region_var(coercion); - let ty = ty::mk_rptr(self.tcx(), - self.tcx().mk_region(r_borrow), - ty::mt{ty: ty, mutbl: mt_b.mutbl}); - try!(self.fcx.infcx().try(|_| self.subtype(ty, b))); - debug!("Success, coerced with AutoDerefRef(1, \ - AutoPtr(AutoUnsize({:?})))", kind); - Ok(Some(AdjustDerefRef(AutoDerefRef { - autoderefs: 1, - autoref: Some(ty::AutoPtr(r_borrow, mt_b.mutbl, - Some(box AutoUnsize(kind)))) - }))) - } - _ => Err(ty::terr_mismatch) - } + // that, at which point we will need extra checks on the target here. + + // Handle reborrows before selecting `Source: CoerceUnsized`. + let (source, reborrow) = match (&source.sty, &target.sty) { + (&ty::ty_rptr(_, mt_a), &ty::ty_rptr(_, mt_b)) => { + try!(coerce_mutbls(mt_a.mutbl, mt_b.mutbl)); + + let coercion = Coercion(self.trace.clone()); + 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(_, ty::mt{ty: t_a, mutbl: mutbl_a}), &ty::ty_ptr(mt_b)) => { - match self.unsize_ty(t_a, mt_b.ty) { - Some((ty, kind)) => { - if !can_coerce_mutbls(mutbl_a, mt_b.mutbl) { - return Err(ty::terr_mutability); - } - - let ty = ty::mk_ptr(self.tcx(), - ty::mt{ty: ty, mutbl: mt_b.mutbl}); - try!(self.fcx.infcx().try(|_| self.subtype(ty, b))); - debug!("Success, coerced with AutoDerefRef(1, \ - AutoPtr(AutoUnsize({:?})))", kind); - Ok(Some(AdjustDerefRef(AutoDerefRef { - autoderefs: 1, - autoref: Some(ty::AutoUnsafe(mt_b.mutbl, - Some(box AutoUnsize(kind)))) - }))) - } - _ => 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`. + let cause = ObligationCause::misc(self.trace.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() { + let trait_ref = match obligation.predicate { + ty::Predicate::Trait(ref tr) if traits.contains(&tr.def_id()) => { + tr.clone() } - } - (&ty::ty_uniq(t_a), &ty::ty_uniq(t_b)) => { - match self.unsize_ty(t_a, t_b) { - Some((ty, kind)) => { - let ty = ty::mk_uniq(self.tcx(), ty); - try!(self.fcx.infcx().try(|_| self.subtype(ty, b))); - debug!("Success, coerced with AutoDerefRef(1, \ - AutoUnsizeUniq({:?}))", kind); - Ok(Some(AdjustDerefRef(AutoDerefRef { - autoderefs: 1, - autoref: Some(ty::AutoUnsizeUniq(kind)) - }))) - } - _ => Err(ty::terr_mismatch) + _ => { + leftover_predicates.push(obligation); + continue; + } + }; + match selcx.select(&obligation.with(trait_ref)) { + // Uncertain or unimplemented. + Ok(None) | Err(traits::Unimplemented) => { + 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)); } } - _ => Err(ty::terr_mismatch) } - } - // Takes a type and returns an unsized version along with the adjustment - // performed to unsize it. - // E.g., `[T, ..n]` -> `([T], UnsizeLength(n))` - fn unsize_ty(&self, - ty_a: Ty<'tcx>, - ty_b: Ty<'tcx>) - -> Option<(Ty<'tcx>, ty::UnsizeKind<'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(len)), &ty::ty_vec(_, None)) => { - let ty = ty::mk_vec(tcx, t_a, None); - Some((ty, ty::UnsizeLength(len))) - } - (&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().try(|_| { - // it's ok to upcast from Foo+'a to Foo+'b so long as 'a : 'b - try!(self.outlives(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, ty::UnsizeUpcast(ty_b))), - Err(_) => None, - } - } else { - None - } - } - (_, &ty::ty_trait(ref data)) => { - Some((ty_b, ty::UnsizeVtable(ty::TyTrait { - principal: data.principal.clone(), - bounds: data.bounds.clone() - }, - ty_a))) - } - (&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 mut result = None; - let tps = ty_substs_a.iter().zip(ty_substs_b.iter()).enumerate(); - for (i, (tp_a, tp_b)) in tps { - if self.fcx.infcx().try(|_| self.subtype(*tp_a, *tp_b)).is_ok() { - continue; - } - match self.unsize_ty(*tp_a, *tp_b) { - Some((new_tp, k)) => { - // 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.fcx.infcx().try(|_| 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; - } - - result = Some((ty, ty::UnsizeStruct(box k, i))); - break; - } - None => {} - } - } - result - } - _ => None - } - }) - }) + let mut obligations = self.unsizing_obligations.borrow_mut(); + assert!(obligations.is_empty()); + *obligations = leftover_predicates; + + let adjustment = AutoDerefRef { + autoderefs: if reborrow.is_some() { 1 } else { 0 }, + autoref: reborrow, + unsize: Some(target) + }; + debug!("Success, coerced with {}", adjustment.repr(self.tcx())); + Ok(Some(AdjustDerefRef(adjustment))) } fn coerce_from_fn_pointer(&self, @@ -449,29 +347,22 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { debug!("coerce_from_fn_pointer(a={}, b={})", a.repr(self.tcx()), b.repr(self.tcx())); - match b.sty { - ty::ty_bare_fn(None, fn_ty_b) => { - match (fn_ty_a.unsafety, fn_ty_b.unsafety) { - (ast::Unsafety::Normal, ast::Unsafety::Unsafe) => { - let unsafe_a = self.tcx().safe_to_unsafe_fn_ty(fn_ty_a); - try!(self.subtype(unsafe_a, b)); - Ok(Some(ty::AdjustUnsafeFnPointer)) - } - _ => { - self.subtype(a, b) - } + if let ty::ty_bare_fn(None, fn_ty_b) = b.sty { + match (fn_ty_a.unsafety, fn_ty_b.unsafety) { + (ast::Unsafety::Normal, ast::Unsafety::Unsafe) => { + let unsafe_a = self.tcx().safe_to_unsafe_fn_ty(fn_ty_a); + try!(self.subtype(unsafe_a, b)); + return Ok(Some(ty::AdjustUnsafeFnPointer)); } - } - _ => { - return self.subtype(a, b) + _ => {} } } + self.subtype(a, b) }) } fn coerce_from_fn_item(&self, a: Ty<'tcx>, - fn_def_id_a: ast::DefId, fn_ty_a: &'tcx ty::BareFnTy<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { @@ -488,11 +379,9 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { ty::ty_bare_fn(None, _) => { let a_fn_pointer = ty::mk_bare_fn(self.tcx(), None, fn_ty_a); try!(self.subtype(a_fn_pointer, b)); - Ok(Some(ty::AdjustReifyFnPointer(fn_def_id_a))) - } - _ => { - return self.subtype(a, b) + Ok(Some(ty::AdjustReifyFnPointer)) } + _ => self.subtype(a, b) } }) } @@ -516,16 +405,15 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // Check that the types which they point at are compatible. let a_unsafe = ty::mk_ptr(self.tcx(), ty::mt{ mutbl: mutbl_b, ty: mt_a.ty }); try!(self.subtype(a_unsafe, b)); - if !can_coerce_mutbls(mt_a.mutbl, mutbl_b) { - return Err(ty::terr_mutability); - } + try!(coerce_mutbls(mt_a.mutbl, mutbl_b)); // Although references and unsafe ptrs have the same // representation, we still register an AutoDerefRef so that // regionck knows that the region for `a` must be valid here. Ok(Some(AdjustDerefRef(AutoDerefRef { autoderefs: 1, - autoref: Some(ty::AutoUnsafe(mutbl_b, None)) + autoref: Some(ty::AutoUnsafe(mutbl_b)), + unsize: None }))) } } @@ -536,28 +424,43 @@ pub fn mk_assignty<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, b: Ty<'tcx>) -> cres<'tcx, ()> { debug!("mk_assignty({} -> {})", a.repr(fcx.tcx()), b.repr(fcx.tcx())); + let mut unsizing_obligations = vec![]; let adjustment = try!(indent(|| { fcx.infcx().commit_if_ok(|| { let origin = infer::ExprAssignable(expr.span); - Coerce { + let coerce = Coerce { fcx: fcx, - trace: infer::TypeTrace::types(origin, false, a, b) - }.coerce(expr, a, b) + trace: infer::TypeTrace::types(origin, false, a, b), + unsizing_obligations: RefCell::new(vec![]) + }; + let adjustment = try!(coerce.coerce(expr, a, b)); + unsizing_obligations = coerce.unsizing_obligations.into_inner(); + Ok(adjustment) }) })); + + if let Some(AdjustDerefRef(auto)) = adjustment { + if auto.unsize.is_some() { + for obligation in unsizing_obligations { + fcx.register_predicate(obligation); + } + } + } + if let Some(adjustment) = adjustment { - fcx.write_adjustment(expr.id, expr.span, adjustment); + debug!("Success, coerced with {}", adjustment.repr(fcx.tcx())); + fcx.write_adjustment(expr.id, adjustment); } Ok(()) } -fn can_coerce_mutbls(from_mutbl: ast::Mutability, - to_mutbl: ast::Mutability) - -> bool { +fn coerce_mutbls<'tcx>(from_mutbl: ast::Mutability, + to_mutbl: ast::Mutability) + -> CoerceResult<'tcx> { match (from_mutbl, to_mutbl) { - (ast::MutMutable, ast::MutMutable) => true, - (ast::MutImmutable, ast::MutImmutable) => true, - (ast::MutMutable, ast::MutImmutable) => true, - (ast::MutImmutable, ast::MutMutable) => false, + (ast::MutMutable, ast::MutMutable) | + (ast::MutImmutable, ast::MutImmutable) | + (ast::MutMutable, ast::MutImmutable) => Ok(None), + (ast::MutImmutable, ast::MutMutable) => Err(ty::terr_mutability) } } diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 6aefcf5a47cc6..4e62542854fa8 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -24,7 +24,6 @@ use middle::infer::InferCtxt; use syntax::ast; use syntax::codemap::Span; use std::rc::Rc; -use std::mem; use std::iter::repeat; use util::ppaux::Repr; @@ -84,7 +83,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { -> MethodCallee<'tcx> { // Adjust the self expression the user provided and obtain the adjusted type. - let self_ty = self.adjust_self_ty(unadjusted_self_ty, &pick.adjustment); + let self_ty = self.adjust_self_ty(unadjusted_self_ty, &pick); // Make sure nobody calls `drop()` explicitly. self.enforce_illegal_method_limitations(&pick); @@ -134,11 +133,20 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { fn adjust_self_ty(&mut self, unadjusted_self_ty: Ty<'tcx>, - adjustment: &probe::PickAdjustment) + pick: &probe::Pick<'tcx>) -> Ty<'tcx> { - // Construct the actual adjustment and write it into the table - let auto_deref_ref = self.create_ty_adjustment(adjustment); + let (autoref, unsize) = if let Some(mutbl) = pick.autoref { + let region = self.infcx().next_region_var(infer::Autoref(self.span)); + let autoref = ty::AutoPtr(self.tcx().mk_region(region), mutbl); + (Some(autoref), pick.unsize.map(|target| { + ty::adjust_ty_for_autoref(self.tcx(), target, Some(autoref)) + })) + } else { + // No unsizing should be performed without autoref. + assert!(pick.unsize.is_none()); + (None, None) + }; // Commit the autoderefs by calling `autoderef again, but this // time writing the results into the various tables. @@ -149,47 +157,27 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { UnresolvedTypeAction::Error, NoPreference, |_, n| { - if n == auto_deref_ref.autoderefs { + if n == pick.autoderefs { Some(()) } else { None } }); - assert_eq!(n, auto_deref_ref.autoderefs); + assert_eq!(n, pick.autoderefs); assert_eq!(result, Some(())); - let final_ty = - ty::adjust_ty_for_autoref(self.tcx(), self.span, autoderefd_ty, - auto_deref_ref.autoref.as_ref()); - // Write out the final adjustment. - self.fcx.write_adjustment(self.self_expr.id, self.span, ty::AdjustDerefRef(auto_deref_ref)); - - final_ty - } + self.fcx.write_adjustment(self.self_expr.id, + ty::AdjustDerefRef(ty::AutoDerefRef { + autoderefs: pick.autoderefs, + autoref: autoref, + unsize: unsize + })); - fn create_ty_adjustment(&mut self, - adjustment: &probe::PickAdjustment) - -> ty::AutoDerefRef<'tcx> - { - match *adjustment { - probe::AutoDeref(num) => { - ty::AutoDerefRef { - autoderefs: num, - autoref: None, - } - } - probe::AutoUnsizeLength(autoderefs, len) => { - ty::AutoDerefRef { - autoderefs: autoderefs, - autoref: Some(ty::AutoUnsize(ty::UnsizeLength(len))), - } - } - probe::AutoRef(mutability, ref sub_adjustment) => { - let deref = self.create_ty_adjustment(&**sub_adjustment); - let region = self.infcx().next_region_var(infer::Autoref(self.span)); - wrap_autoref(deref, |base| ty::AutoPtr(region, mutability, base)) - } + if let Some(target) = unsize { + target + } else { + ty::adjust_ty_for_autoref(self.tcx(), autoderefd_ty, autoref) } } @@ -499,10 +487,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { .adjustments .borrow() .get(&expr.id) { - Some(&ty::AdjustDerefRef(ty::AutoDerefRef { - autoderefs: autoderef_count, - autoref: _ - })) => autoderef_count, + Some(&ty::AdjustDerefRef(ref adj)) => adj.autoderefs, Some(_) | None => 0, }; @@ -529,17 +514,6 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { if i != 0 { match expr.node { ast::ExprIndex(ref base_expr, ref index_expr) => { - let mut base_adjustment = - match self.fcx.inh.adjustments.borrow().get(&base_expr.id) { - Some(&ty::AdjustDerefRef(ref adr)) => (*adr).clone(), - None => ty::AutoDerefRef { autoderefs: 0, autoref: None }, - Some(_) => { - self.tcx().sess.span_bug( - base_expr.span, - "unexpected adjustment type"); - } - }; - // If this is an overloaded index, the // adjustment will include an extra layer of // autoref because the method is an &self/&mut @@ -548,21 +522,44 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { // expects. This is annoying and horrible. We // ought to recode this routine so it doesn't // (ab)use the normal type checking paths. - base_adjustment.autoref = match base_adjustment.autoref { - None => { None } - Some(ty::AutoPtr(_, _, None)) => { None } - Some(ty::AutoPtr(_, _, Some(box r))) => { Some(r) } + let adj = self.fcx.inh.adjustments.borrow().get(&base_expr.id).cloned(); + let (autoderefs, unsize) = match adj { + Some(ty::AdjustDerefRef(adr)) => match adr.autoref { + None => { + assert!(adr.unsize.is_none()); + (adr.autoderefs, None) + } + Some(ty::AutoPtr(_, _)) => { + (adr.autoderefs, adr.unsize.map(|target| { + ty::deref(target, false) + .expect("fixup: AutoPtr is not &T").ty + })) + } + Some(_) => { + self.tcx().sess.span_bug( + base_expr.span, + &format!("unexpected adjustment autoref {}", + adr.repr(self.tcx()))); + } + }, + None => (0, None), Some(_) => { self.tcx().sess.span_bug( base_expr.span, - "unexpected adjustment autoref"); + "unexpected adjustment type"); } }; - let adjusted_base_ty = - self.fcx.adjust_expr_ty( - &**base_expr, - Some(&ty::AdjustDerefRef(base_adjustment.clone()))); + let (adjusted_base_ty, unsize) = if let Some(target) = unsize { + (target, true) + } else { + (self.fcx.adjust_expr_ty(base_expr, + Some(&ty::AdjustDerefRef(ty::AutoDerefRef { + autoderefs: autoderefs, + autoref: None, + unsize: None + }))), false) + }; let index_expr_ty = self.fcx.expr_ty(&**index_expr); let result = check::try_index_step( @@ -571,7 +568,8 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { expr, &**base_expr, adjusted_base_ty, - base_adjustment, + autoderefs, + unsize, PreferMutLvalue, index_expr_ty); @@ -658,14 +656,3 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { self.span, infer::FnCall, value).0 } } - -fn wrap_autoref<'tcx, F>(mut deref: ty::AutoDerefRef<'tcx>, - base_fn: F) - -> ty::AutoDerefRef<'tcx> where - F: FnOnce(Option>>) -> ty::AutoRef<'tcx>, -{ - let autoref = mem::replace(&mut deref.autoref, None); - let autoref = autoref.map(|r| box r); - deref.autoref = Some(base_fn(autoref)); - deref -} diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index 7ef2db2c28d88..800c4b43fe1bd 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -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; @@ -122,8 +120,7 @@ pub fn lookup_in_trait<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, -> Option> { lookup_in_trait_adjusted(fcx, span, self_expr, m_name, trait_def_id, - ty::AutoDerefRef { autoderefs: 0, autoref: None }, - self_ty, opt_input_types) + 0, false, self_ty, opt_input_types) } /// `lookup_in_trait_adjusted` is used for overloaded operators. It does a very narrow slice of @@ -140,7 +137,8 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, self_expr: Option<&ast::Expr>, m_name: ast::Name, trait_def_id: DefId, - autoderefref: ty::AutoDerefRef<'tcx>, + autoderefs: usize, + unsize: bool, self_ty: Ty<'tcx>, opt_input_types: Option>>) -> Option> @@ -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 { @@ -241,18 +239,15 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, Some(self_expr) => { debug!("lookup_in_trait_adjusted: inserting adjustment if needed \ - (self-id={}, base adjustment={:?}, explicit_self={:?})", - self_expr.id, autoderefref, method_ty.explicit_self); + (self-id={}, autoderefs={}, unsize={}, explicit_self={:?})", + self_expr.id, autoderefs, unsize, + method_ty.explicit_self); match method_ty.explicit_self { ty::ByValueExplicitSelfCategory => { // Trait method is fn(self), no transformation needed. - if !autoderefref.is_identity() { - fcx.write_adjustment( - self_expr.id, - span, - ty::AdjustDerefRef(autoderefref)); - } + assert!(!unsize); + fcx.write_autoderef_adjustment(self_expr.id, autoderefs); } ty::ByReferenceExplicitSelfCategory(..) => { @@ -260,14 +255,15 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // autoref. Pull the region etc out of the type of first argument. match transformed_self_ty.sty { ty::ty_rptr(region, ty::mt { mutbl, ty: _ }) => { - let ty::AutoDerefRef { autoderefs, autoref } = autoderefref; - let autoref = autoref.map(|r| box r); - fcx.write_adjustment( - self_expr.id, - span, + fcx.write_adjustment(self_expr.id, ty::AdjustDerefRef(ty::AutoDerefRef { autoderefs: autoderefs, - autoref: Some(ty::AutoPtr(*region, mutbl, autoref)) + autoref: Some(ty::AutoPtr(region, mutbl)), + unsize: if unsize { + Some(transformed_self_ty) + } else { + None + } })); } diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index b95e0ce8cb3c5..cd6142355a1ad 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -31,7 +31,6 @@ use std::rc::Rc; use util::ppaux::Repr; use self::CandidateKind::*; -pub use self::PickAdjustment::*; pub use self::PickKind::*; struct ProbeContext<'a, 'tcx:'a> { @@ -49,7 +48,8 @@ struct ProbeContext<'a, 'tcx:'a> { struct CandidateStep<'tcx> { self_ty: Ty<'tcx>, - adjustment: PickAdjustment, + autoderefs: usize, + unsize: bool } struct Candidate<'tcx> { @@ -70,8 +70,24 @@ enum CandidateKind<'tcx> { pub struct Pick<'tcx> { pub method_ty: Rc>, - pub adjustment: PickAdjustment, pub kind: PickKind<'tcx>, + + // Indicates that the source expression should be autoderef'd N times + // + // A = expr | *expr | **expr | ... + pub autoderefs: usize, + + // Indicates that an autoref is applied after the optional autoderefs + // + // B = A | &A | &mut A + pub autoref: Option, + + // Indicates that the source expression should be "unsized" to a + // target type. This should probably eventually go away in favor + // of just coercing method receivers. + // + // C = B | unsize(B) + pub unsize: Option>, } #[derive(Clone,Debug)] @@ -85,30 +101,6 @@ pub enum PickKind<'tcx> { pub type PickResult<'tcx> = Result, MethodError>; -// This is a kind of "abstracted" version of ty::AutoAdjustment. The -// difference is that it doesn't embed any regions or other -// specifics. The "confirmation" step recreates those details as -// needed. -#[derive(Clone,Debug)] -pub enum PickAdjustment { - // Indicates that the source expression should be autoderef'd N times - // - // A = expr | *expr | **expr - AutoDeref(uint), - - // Indicates that the source expression should be autoderef'd N - // times and then "unsized". This should probably eventually go - // away in favor of just coercing method receivers. - // - // A = unsize(expr | *expr | **expr) - AutoUnsizeLength(/* number of autoderefs */ uint, /* length*/ uint), - - // Indicates that an autoref is applied after some number of other adjustments - // - // A = &A | &mut A - AutoRef(ast::Mutability, Box), -} - #[derive(PartialEq, Eq, Copy)] pub enum Mode { // An expression of the form `receiver.method_name(...)`. @@ -149,7 +141,8 @@ pub fn probe<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } else { vec![CandidateStep { self_ty: self_ty, - adjustment: AutoDeref(0) + autoderefs: 0, + unsize: false }] }; @@ -200,16 +193,21 @@ fn create_steps<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, UnresolvedTypeAction::Error, NoPreference, |t, d| { - let adjustment = AutoDeref(d); - steps.push(CandidateStep { self_ty: t, adjustment: adjustment }); + steps.push(CandidateStep { + self_ty: t, + autoderefs: d, + unsize: false + }); None::<()> // keep iterating until we can't anymore }); match final_ty.sty { - ty::ty_vec(elem_ty, Some(len)) => { + ty::ty_vec(elem_ty, Some(_)) => { + let slice_ty = ty::mk_vec(fcx.tcx(), elem_ty, None); steps.push(CandidateStep { - self_ty: ty::mk_vec(fcx.tcx(), elem_ty, None), - adjustment: AutoUnsizeLength(dereferences, len), + self_ty: slice_ty, + autoderefs: dereferences, + unsize: true }); } ty::ty_err => return None, @@ -926,20 +924,21 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { * consuming them for their entire lifetime. */ - let adjustment = match step.adjustment { - AutoDeref(d) => consider_reborrow(step.self_ty, d), - AutoUnsizeLength(..) | AutoRef(..) => step.adjustment.clone(), - }; + if step.unsize { + return None; + } - return self.pick_method(step.self_ty).map(|r| self.adjust(r, adjustment.clone())); + self.pick_method(step.self_ty).map(|r| r.map(|mut pick| { + pick.autoderefs = step.autoderefs; - fn consider_reborrow<'tcx>(ty: Ty<'tcx>, d: uint) -> PickAdjustment { // Insert a `&*` or `&mut *` if this is a reference type: - match ty.sty { - ty::ty_rptr(_, ref mt) => AutoRef(mt.mutbl, box AutoDeref(d+1)), - _ => AutoDeref(d), + if let ty::ty_rptr(_, mt) = step.self_ty.sty { + pick.autoderefs += 1; + pick.autoref = Some(mt.mutbl); } - } + + pick + })) } fn pick_autorefd_method(&mut self, @@ -947,46 +946,28 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { -> Option> { let tcx = self.tcx(); - self.search_mutabilities( - |m| AutoRef(m, box step.adjustment.clone()), - |m,r| ty::mk_rptr(tcx, tcx.mk_region(r), ty::mt {ty:step.self_ty, mutbl:m})) - } - fn search_mutabilities(&mut self, - mut mk_adjustment: F, - mut mk_autoref_ty: G) - -> Option> where - F: FnMut(ast::Mutability) -> PickAdjustment, - G: FnMut(ast::Mutability, ty::Region) -> Ty<'tcx>, - { // In general, during probing we erase regions. See // `impl_self_ty()` for an explanation. - let region = ty::ReStatic; + let region = tcx.mk_region(ty::ReStatic); // Search through mutabilities in order to find one where pick works: - [ast::MutImmutable, ast::MutMutable] - .iter() - .flat_map(|&m| { - let autoref_ty = mk_autoref_ty(m, region); - self.pick_method(autoref_ty) - .map(|r| self.adjust(r, mk_adjustment(m))) - .into_iter() - }) - .nth(0) - } - - fn adjust(&mut self, - result: PickResult<'tcx>, - adjustment: PickAdjustment) - -> PickResult<'tcx> - { - match result { - Err(e) => Err(e), - Ok(mut pick) => { - pick.adjustment = adjustment; - Ok(pick) - } - } + [ast::MutImmutable, ast::MutMutable].iter().filter_map(|&m| { + let autoref_ty = ty::mk_rptr(tcx, region, ty::mt { + ty: step.self_ty, + mutbl: m + }); + self.pick_method(autoref_ty).map(|r| r.map(|mut pick| { + pick.autoderefs = step.autoderefs; + pick.autoref = Some(m); + pick.unsize = if step.unsize { + Some(step.self_ty) + } else { + None + }; + pick + })) + }).nth(0) } fn pick_method(&mut self, self_ty: Ty<'tcx>) -> Option> { @@ -1122,8 +1103,10 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { let method_ty = probes[0].method_ty.clone(); Some(Pick { method_ty: method_ty, - adjustment: AutoDeref(0), - kind: TraitPick(trait_def_id, method_num) + kind: TraitPick(trait_def_id, method_num), + autoderefs: 0, + autoref: None, + unsize: None }) } @@ -1296,7 +1279,6 @@ impl<'tcx> Candidate<'tcx> { fn to_unadjusted_pick(&self) -> Pick<'tcx> { Pick { method_ty: self.method_ty.clone(), - adjustment: AutoDeref(0), kind: match self.kind { InherentImplCandidate(def_id, _) => { InherentImplPick(def_id) @@ -1323,7 +1305,10 @@ impl<'tcx> Candidate<'tcx> { ProjectionCandidate(def_id, index) => { TraitPick(def_id, index) } - } + }, + autoderefs: 0, + autoref: None, + unsize: None } } @@ -1392,15 +1377,10 @@ impl<'tcx> Repr<'tcx> for CandidateKind<'tcx> { impl<'tcx> Repr<'tcx> for CandidateStep<'tcx> { fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String { - format!("CandidateStep({},{:?})", + format!("CandidateStep({}, autoderefs={}, unsize={})", self.self_ty.repr(tcx), - self.adjustment) - } -} - -impl<'tcx> Repr<'tcx> for PickAdjustment { - fn repr(&self, _tcx: &ty::ctxt) -> String { - format!("{:?}", self) + self.autoderefs, + self.unsize) } } @@ -1412,9 +1392,12 @@ impl<'tcx> Repr<'tcx> for PickKind<'tcx> { impl<'tcx> Repr<'tcx> for Pick<'tcx> { fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String { - format!("Pick(method_ty={}, adjustment={:?}, kind={:?})", + format!("Pick(method_ty={}, autoderefs={}, + autoref={}, unsize={}, kind={:?})", self.method_ty.repr(tcx), - self.adjustment, + self.autoderefs, + self.autoref.repr(tcx), + self.unsize.repr(tcx), self.kind) } } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 1e38a7d2d9f94..770609788d464 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -94,7 +94,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, VariantInfo, TypeScheme}; use middle::ty::{Disr, ParamTy, ParameterEnvironment}; use middle::ty::{self, HasProjectionTypes, RegionEscape, ToPolyTraitRef, Ty}; @@ -131,7 +131,6 @@ use syntax::visit::{self, Visitor}; mod assoc; pub mod dropck; pub mod _match; -pub mod vtable; pub mod writeback; pub mod implicator; pub mod regionck; @@ -531,9 +530,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); @@ -1334,7 +1333,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) { return ty; @@ -1344,7 +1343,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(); self.infcx().resolve_type_vars_if_possible(&ty) } @@ -1436,21 +1435,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn write_autoderef_adjustment(&self, node_id: ast::NodeId, - span: Span, - derefs: uint) { - if derefs == 0 { return; } + derefs: usize) { self.write_adjustment( node_id, - span, ty::AdjustDerefRef(ty::AutoDerefRef { autoderefs: derefs, - autoref: None }) + autoref: None, + unsize: None + }) ); } pub fn write_adjustment(&self, node_id: ast::NodeId, - span: Span, adj: ty::AutoAdjustment<'tcx>) { debug!("write_adjustment(node_id={}, adj={})", node_id, adj.repr(self.tcx())); @@ -1458,13 +1455,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return; } - // Careful: adjustments can imply trait obligations if we are - // casting from a concrete type to an object type. I think - // it'd probably be nicer to move the logic that creates the - // obligation into the code that creates the adjustment, but - // that's a bit awkward, so instead we go digging and pull the - // obligation out here. - self.register_adjustment_obligations(span, &adj); self.inh.adjustments.borrow_mut().insert(node_id, adj); } @@ -1527,74 +1517,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { cause) } - fn register_adjustment_obligations(&self, - span: Span, - adj: &ty::AutoAdjustment<'tcx>) { - match *adj { - ty::AdjustReifyFnPointer(..) => { } - ty::AdjustUnsafeFnPointer => { } - ty::AdjustDerefRef(ref d_r) => { - match d_r.autoref { - Some(ref a_r) => { - self.register_autoref_obligations(span, a_r); - } - None => {} - } - } - } - } - - fn register_autoref_obligations(&self, - span: Span, - autoref: &ty::AutoRef<'tcx>) { - match *autoref { - ty::AutoUnsize(ref unsize) => { - self.register_unsize_obligations(span, unsize); - } - ty::AutoPtr(_, _, None) | - ty::AutoUnsafe(_, None) => { - } - ty::AutoPtr(_, _, Some(ref a_r)) | - ty::AutoUnsafe(_, Some(ref a_r)) => { - self.register_autoref_obligations(span, &**a_r) - } - ty::AutoUnsizeUniq(ref unsize) => { - self.register_unsize_obligations(span, unsize); - } - } - } - - fn register_unsize_obligations(&self, - span: Span, - unsize: &ty::UnsizeKind<'tcx>) { - debug!("register_unsize_obligations: unsize={:?}", unsize); - - match *unsize { - ty::UnsizeLength(..) => {} - ty::UnsizeStruct(ref u, _) => { - self.register_unsize_obligations(span, &**u) - } - ty::UnsizeVtable(ref ty_trait, self_ty) => { - vtable::check_object_safety(self.tcx(), ty_trait, span); - - // If the type is `Foo+'a`, ensures that the type - // being cast to `Foo+'a` implements `Foo`: - vtable::register_object_cast_obligations(self, - span, - ty_trait, - self_ty); - - // If the type is `Foo+'a`, ensures that the type - // being cast to `Foo+'a` outlives `'a`: - let cause = traits::ObligationCause { span: span, - body_id: self.body_id, - code: traits::ObjectCastObligation(self_ty) }; - self.register_region_obligation(self_ty, ty_trait.bounds.region_bound, cause); - } - ty::UnsizeUpcast(_) => { } - } - } - /// Returns the type of `def_id` with all generics replaced by by fresh type/region variables. /// Also returns the substitution from the type parameters on `def_id` to the fresh variables. /// Registers any trait obligations specified on `def_id` at the same time. @@ -1931,6 +1853,56 @@ 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> { @@ -2018,7 +1990,8 @@ pub fn autoderef<'a, 'tcx, T, F>(fcx: &FnCtxt<'a, 'tcx>, let mt = match ty::deref(resolved_t, false) { Some(mt) => Some(mt), None => { - let method_call = opt_expr.map(|expr| MethodCall::autoderef(expr.id, autoderefs)); + let method_call = + opt_expr.map(|expr| MethodCall::autoderef(expr.id, autoderefs as u32)); // Super subtle: it might seem as though we should // pass `opt_expr` to `try_overloaded_deref`, so that @@ -2116,13 +2089,13 @@ fn make_overloaded_lvalue_return_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } } -fn autoderef_for_index<'a, 'tcx, T, F>(fcx: &FnCtxt<'a, 'tcx>, - base_expr: &ast::Expr, - base_ty: Ty<'tcx>, - lvalue_pref: LvaluePreference, - mut step: F) - -> Option where - F: FnMut(Ty<'tcx>, ty::AutoDerefRef<'tcx>) -> Option, +fn lookup_indexing<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, + expr: &ast::Expr, + base_expr: &'tcx ast::Expr, + base_ty: Ty<'tcx>, + idx_ty: Ty<'tcx>, + lvalue_pref: LvaluePreference) + -> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)> { // FIXME(#18741) -- this is almost but not quite the same as the // autoderef that normal method probing does. They could likely be @@ -2135,9 +2108,9 @@ fn autoderef_for_index<'a, 'tcx, T, F>(fcx: &FnCtxt<'a, 'tcx>, UnresolvedTypeAction::Error, lvalue_pref, |adj_ty, idx| { - let autoderefref = ty::AutoDerefRef { autoderefs: idx, autoref: None }; - step(adj_ty, autoderefref) - }); + try_index_step(fcx, MethodCall::expr(expr.id), expr, base_expr, + adj_ty, idx, false, lvalue_pref, idx_ty) + }); if final_mt.is_some() { return final_mt; @@ -2145,41 +2118,38 @@ fn autoderef_for_index<'a, 'tcx, T, F>(fcx: &FnCtxt<'a, 'tcx>, // After we have fully autoderef'd, if the resulting type is [T, ..n], then // do a final unsized coercion to yield [T]. - match ty.sty { - ty::ty_vec(element_ty, Some(n)) => { - let adjusted_ty = ty::mk_vec(fcx.tcx(), element_ty, None); - let autoderefref = ty::AutoDerefRef { - autoderefs: autoderefs, - autoref: Some(ty::AutoUnsize(ty::UnsizeLength(n))) - }; - step(adjusted_ty, autoderefref) - } - _ => { - None - } + if let ty::ty_vec(element_ty, Some(_)) = ty.sty { + let adjusted_ty = ty::mk_vec(fcx.tcx(), element_ty, None); + try_index_step(fcx, MethodCall::expr(expr.id), expr, base_expr, + adjusted_ty, autoderefs, true, lvalue_pref, idx_ty) + } else { + None } } /// To type-check `base_expr[index_expr]`, we progressively autoderef (and otherwise adjust) /// `base_expr`, looking for a type which either supports builtin indexing or overloaded indexing. /// This loop implements one step in that search; the autoderef loop is implemented by -/// `autoderef_for_index`. +/// `lookup_indexing`. fn try_index_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, method_call: MethodCall, expr: &ast::Expr, base_expr: &'tcx ast::Expr, adjusted_ty: Ty<'tcx>, - adjustment: ty::AutoDerefRef<'tcx>, + autoderefs: usize, + unsize: bool, lvalue_pref: LvaluePreference, index_ty: Ty<'tcx>) -> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)> { let tcx = fcx.tcx(); - debug!("try_index_step(expr={}, base_expr.id={}, adjusted_ty={}, adjustment={:?}, index_ty={})", + debug!("try_index_step(expr={}, base_expr.id={}, adjusted_ty={}, \ + autoderefs={}, unsize={}, index_ty={})", expr.repr(tcx), base_expr.repr(tcx), adjusted_ty.repr(tcx), - adjustment, + autoderefs, + unsize, index_ty.repr(tcx)); let input_ty = fcx.infcx().next_ty_var(); @@ -2188,7 +2158,9 @@ fn try_index_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, match (ty::index(adjusted_ty), &index_ty.sty) { (Some(ty), &ty::ty_uint(ast::TyUs(_))) | (Some(ty), &ty::ty_infer(ty::IntVar(_))) => { debug!("try_index_step: success, using built-in indexing"); - fcx.write_adjustment(base_expr.id, base_expr.span, ty::AdjustDerefRef(adjustment)); + // If we had `[T; N]`, we should've caught it before unsizing to `[T]`. + assert!(!unsize); + fcx.write_autoderef_adjustment(base_expr.id, autoderefs); return Some((tcx.types.uint, ty)); } _ => {} @@ -2202,7 +2174,8 @@ fn try_index_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, Some(&*base_expr), token::intern("index_mut"), trait_did, - adjustment.clone(), + autoderefs, + unsize, adjusted_ty, Some(vec![input_ty])) } @@ -2217,7 +2190,8 @@ fn try_index_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, Some(&*base_expr), token::intern("index"), trait_did, - adjustment.clone(), + autoderefs, + unsize, adjusted_ty, Some(vec![input_ty])) } @@ -2386,7 +2360,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 @@ -2820,36 +2794,8 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, { let method = match trait_did { Some(trait_did) => { - // We do eager coercions to make using operators - // more ergonomic: - // - // - If the input is of type &'a T (resp. &'a mut T), - // then reborrow it to &'b T (resp. &'b mut T) where - // 'b <= 'a. This makes things like `x == y`, where - // `x` and `y` are both region pointers, work. We - // could also solve this with variance or different - // traits that don't force left and right to have same - // type. - let (adj_ty, adjustment) = match lhs_ty.sty { - ty::ty_rptr(r_in, mt) => { - let r_adj = fcx.infcx().next_region_var(infer::Autoref(lhs.span)); - fcx.mk_subr(infer::Reborrow(lhs.span), r_adj, *r_in); - let adjusted_ty = ty::mk_rptr(fcx.tcx(), fcx.tcx().mk_region(r_adj), mt); - let autoptr = ty::AutoPtr(r_adj, mt.mutbl, None); - let adjustment = ty::AutoDerefRef { autoderefs: 1, autoref: Some(autoptr) }; - (adjusted_ty, adjustment) - } - _ => { - (lhs_ty, ty::AutoDerefRef { autoderefs: 0, autoref: None }) - } - }; - - debug!("adjusted_ty={} adjustment={:?}", - adj_ty.repr(fcx.tcx()), - adjustment); - method::lookup_in_trait_adjusted(fcx, op_ex.span, Some(lhs), opname, - trait_did, adjustment, adj_ty, None) + trait_did, 0, false, lhs_ty, None) } None => None }; @@ -3109,7 +3055,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, match field_ty { Some(field_ty) => { fcx.write_ty(expr.id, field_ty); - fcx.write_autoderef_adjustment(base.id, base.span, autoderefs); + fcx.write_autoderef_adjustment(base.id, autoderefs); return; } None => {} @@ -3220,7 +3166,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, match field_ty { Some(field_ty) => { fcx.write_ty(expr.id, field_ty); - fcx.write_autoderef_adjustment(base.id, base.span, autoderefs); + fcx.write_autoderef_adjustment(base.id, autoderefs); return; } None => {} @@ -4059,27 +4005,14 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, fcx.write_ty(id, idx_t); } else { let base_t = structurally_resolved_type(fcx, expr.span, base_t); - - let result = - autoderef_for_index(fcx, &**base, base_t, lvalue_pref, |adj_ty, adj| { - try_index_step(fcx, - MethodCall::expr(expr.id), - expr, - &**base, - adj_ty, - adj, - lvalue_pref, - idx_t) - }); - - match result { + match lookup_indexing(fcx, expr, base, base_t, idx_t, lvalue_pref) { Some((index_ty, element_ty)) => { // FIXME: we've already checked idx above, we should // probably just demand subtype or something here. check_expr_has_type(fcx, &**idx, index_ty); fcx.write_ty(id, element_ty); } - _ => { + None => { check_expr_has_type(fcx, &**idx, fcx.tcx().types.err); fcx.type_error_message( expr.span, @@ -4494,7 +4427,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); @@ -5384,6 +5317,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.uint), + "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.uint) + } "init" => (1, Vec::new(), param(ccx, 0)), "uninit" => (1, Vec::new(), param(ccx, 0)), "forget" => (1, vec!( param(ccx, 0) ), ty::mk_nil(tcx)), @@ -5399,6 +5340,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), "owns_managed" => (1, Vec::new(), ccx.tcx.types.bool), diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 5a4ccc0b7b410..25f5be342608a 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -86,7 +86,6 @@ use astconv::AstConv; use check::dropck; use check::FnCtxt; use check::implicator; -use check::vtable; use middle::mem_categorization as mc; use middle::region::CodeExtent; use middle::subst::Substs; @@ -294,7 +293,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. @@ -499,10 +498,10 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) { if let Some(adjustment) = rcx.fcx.inh.adjustments.borrow().get(&expr.id) { debug!("adjustment={:?}", adjustment); match *adjustment { - ty::AdjustDerefRef(ty::AutoDerefRef {autoderefs, autoref: ref opt_autoref}) => { + ty::AdjustDerefRef(ty::AutoDerefRef {autoderefs, ref autoref, ..}) => { let expr_ty = rcx.resolve_node_type(expr.id); constrain_autoderefs(rcx, expr, autoderefs, expr_ty); - if let Some(ref autoref) = *opt_autoref { + if let Some(ref autoref) = *autoref { link_autoref(rcx, expr, autoderefs, autoref); // Require that the resulting region encompasses @@ -872,7 +871,7 @@ fn constrain_autoderefs<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>, let r_deref_expr = ty::ReScope(CodeExtent::from_node_id(deref_expr.id)); for i in 0..derefs { - let method_call = MethodCall::autoderef(deref_expr.id, i); + let method_call = MethodCall::autoderef(deref_expr.id, i as u32); debug!("constrain_autoderefs: method_call={:?} (of {:?} total)", method_call, derefs); derefd_ty = match rcx.fcx.inh.method_map.borrow().get(&method_call) { @@ -904,7 +903,7 @@ fn constrain_autoderefs<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>, let self_cmt = ignore_err!(mc.cat_expr_autoderefd(deref_expr, i)); debug!("constrain_autoderefs: self_cmt={:?}", self_cmt.repr(rcx.tcx())); - link_region(rcx, deref_expr.span, *r, + link_region(rcx, deref_expr.span, r, ty::BorrowKind::from_mutbl(m), self_cmt); } @@ -1102,7 +1101,7 @@ fn link_pattern<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>, ast::PatVec(_, Some(ref slice_pat), _) => { match mc.cat_slice_pattern(sub_cmt, &**slice_pat) { Ok((slice_cmt, slice_mutbl, slice_r)) => { - link_region(rcx, sub_pat.span, slice_r, + link_region(rcx, sub_pat.span, &slice_r, ty::BorrowKind::from_mutbl(slice_mutbl), slice_cmt); } @@ -1127,12 +1126,12 @@ fn link_autoref(rcx: &Rcx, debug!("expr_cmt={}", expr_cmt.repr(rcx.tcx())); match *autoref { - ty::AutoPtr(r, m, _) => { + ty::AutoPtr(r, m) => { link_region(rcx, expr.span, r, ty::BorrowKind::from_mutbl(m), expr_cmt); } - ty::AutoUnsafe(..) | ty::AutoUnsizeUniq(_) | ty::AutoUnsize(_) => {} + ty::AutoUnsafe(_) => {} } } @@ -1147,7 +1146,7 @@ fn link_by_ref(rcx: &Rcx, let mc = mc::MemCategorizationContext::new(rcx.fcx); let expr_cmt = ignore_err!(mc.cat_expr(expr)); let borrow_region = ty::ReScope(callee_scope); - link_region(rcx, expr.span, borrow_region, ty::ImmBorrow, expr_cmt); + link_region(rcx, expr.span, &borrow_region, ty::ImmBorrow, expr_cmt); } /// Like `link_region()`, except that the region is extracted from the type of `id`, which must be @@ -1165,7 +1164,7 @@ fn link_region_from_node_type<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>, let tcx = rcx.fcx.ccx.tcx; debug!("rptr_ty={}", ty_to_string(tcx, rptr_ty)); let r = ty::ty_region(tcx, span, rptr_ty); - link_region(rcx, span, r, ty::BorrowKind::from_mutbl(mutbl), + link_region(rcx, span, &r, ty::BorrowKind::from_mutbl(mutbl), cmt_borrowed); } } @@ -1175,7 +1174,7 @@ fn link_region_from_node_type<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>, /// between regions, as explained in `link_reborrowed_region()`. fn link_region<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>, span: Span, - borrow_region: ty::Region, + borrow_region: &ty::Region, borrow_kind: ty::BorrowKind, borrow_cmt: mc::cmt<'tcx>) { let mut borrow_cmt = borrow_cmt; @@ -1269,7 +1268,7 @@ fn link_region<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>, /// recurse and process `ref_cmt` (see case 2 above). fn link_reborrowed_region<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>, span: Span, - borrow_region: ty::Region, + borrow_region: &ty::Region, borrow_kind: ty::BorrowKind, ref_cmt: mc::cmt<'tcx>, ref_region: ty::Region, @@ -1314,7 +1313,7 @@ fn link_reborrowed_region<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>, debug!("link_reborrowed_region: {} <= {}", borrow_region.repr(rcx.tcx()), ref_region.repr(rcx.tcx())); - rcx.fcx.mk_subr(cause, borrow_region, ref_region); + rcx.fcx.mk_subr(cause, *borrow_region, ref_region); // If we end up needing to recurse and establish a region link // with `ref_cmt`, calculate what borrow kind we will end up diff --git a/src/librustc_typeck/check/vtable.rs b/src/librustc_typeck/check/vtable.rs deleted file mode 100644 index 2858dc9b569fe..0000000000000 --- a/src/librustc_typeck/check/vtable.rs +++ /dev/null @@ -1,226 +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 or the MIT license -// , 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::ast; -use syntax::codemap::Span; -use util::nodemap::FnvHashSet; -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 object_trait_ref = - object_trait.principal_trait_ref_with_self_ty(tcx, tcx.types.err); - - if traits::is_object_safe(tcx, object_trait_ref.clone()) { - return; - } - - span_err!(tcx.sess, span, E0038, - "cannot convert to a trait object because trait `{}` is not object-safe", - ty::item_path_str(tcx, object_trait_ref.def_id())); - - let violations = traits::object_safety_violations(tcx, object_trait_ref.clone()); - 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); - } - - // Finally, check that there IS a projection predicate for every associated type. - check_object_type_binds_all_associated_types(fcx.tcx(), - span, - object_trait); - - object_trait_ref -} - -fn check_object_type_binds_all_associated_types<'tcx>(tcx: &ty::ctxt<'tcx>, - span: Span, - object_trait: &ty::TyTrait<'tcx>) -{ - let object_trait_ref = - object_trait.principal_trait_ref_with_self_ty(tcx, tcx.types.err); - - let mut associated_types: FnvHashSet<(ast::DefId, ast::Name)> = - traits::supertraits(tcx, object_trait_ref.clone()) - .flat_map(|tr| { - let trait_def = ty::lookup_trait_def(tcx, tr.def_id()); - trait_def.associated_type_names - .clone() - .into_iter() - .map(move |associated_type_name| (tr.def_id(), associated_type_name)) - }) - .collect(); - - for projection_bound in &object_trait.bounds.projection_bounds { - let pair = (projection_bound.0.projection_ty.trait_ref.def_id, - projection_bound.0.projection_ty.item_name); - associated_types.remove(&pair); - } - - for (trait_def_id, name) in associated_types { - span_err!(tcx.sess, span, E0191, - "the value of the associated type `{}` (from the trait `{}`) must be specified", - name.user_string(tcx), - ty::item_path_str(tcx, trait_def_id)); - } -} - -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); } - } -} diff --git a/src/librustc_typeck/check/wf.rs b/src/librustc_typeck/check/wf.rs index adbf4c6b210e8..0cac0222dfe4b 100644 --- a/src/librustc_typeck/check/wf.rs +++ b/src/librustc_typeck/check/wf.rs @@ -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; use CrateCtxt; use middle::region; @@ -157,7 +157,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); } diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 2537f9362bf31..05e0557d9ec0e 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -259,11 +259,8 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { } Some(adjustment) => { - let adj_object = ty::adjust_is_object(&adjustment); let resolved_adjustment = match adjustment { - ty::AdjustReifyFnPointer(def_id) => { - ty::AdjustReifyFnPointer(def_id) - } + ty::AdjustReifyFnPointer => ty::AdjustReifyFnPointer, ty::AdjustUnsafeFnPointer => { ty::AdjustUnsafeFnPointer @@ -271,18 +268,14 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { ty::AdjustDerefRef(adj) => { for autoderef in 0..adj.autoderefs { - let method_call = MethodCall::autoderef(id, autoderef); - self.visit_method_map_entry(reason, method_call); - } - - if adj_object { - let method_call = MethodCall::autoobject(id); + let method_call = MethodCall::autoderef(id, autoderef as u32); self.visit_method_map_entry(reason, method_call); } ty::AdjustDerefRef(ty::AutoDerefRef { autoderefs: adj.autoderefs, autoref: self.resolve(&adj.autoref, reason), + unsize: self.resolve(&adj.unsize, reason), }) } }; diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index ffd99ff2eece0..6458667378b60 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -18,7 +18,9 @@ use metadata::csearch::{each_impl, get_impl_trait}; use metadata::csearch; +use middle::lang_items::UnsizeTraitLangItem; use middle::subst::{self, Subst}; +use middle::traits; use middle::ty::RegionEscape; use middle::ty::{ImplContainer, ImplOrTraitItemId, MethodTraitItemId}; use middle::ty::{ParameterEnvironment, TypeTraitItemId, lookup_item_type}; @@ -31,8 +33,7 @@ use middle::ty::{ty_projection}; use middle::ty; use CrateCtxt; use middle::infer::combine::Combine; -use middle::infer::InferCtxt; -use middle::infer::{new_infer_ctxt}; +use middle::infer::{self, InferCtxt, new_infer_ctxt}; use std::collections::{HashSet}; use std::cell::RefCell; use std::rc::Rc; @@ -142,6 +143,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>) { @@ -505,6 +510,169 @@ 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_impls = match tcx.trait_impls + .borrow() + .get(&coerce_unsized_trait) + .cloned() { + None => { + debug!("check_implementations_of_coerce_unsized(): no types \ + with implementations of `CoerceUnsized` found"); + return + } + Some(found_impls) => found_impls + }; + + // Clone first to avoid a double borrow error. + let trait_impls = trait_impls.borrow().clone(); + + for &impl_did in &trait_impls { + 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"); + continue + } + + let source = self.get_self_type_for_implementation(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, E0370, + "the trait `CoerceUnsized` may only be implemented \ + for a coercion between structures with the same \ + definition; expected {}, found {}", + source_path, target_path); + continue; + } + + 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.try(|_| infcx.sub_types(false, origin, b, a)).is_ok() { + None + } else { + Some((i, a, b)) + } + }).collect::>(); + + if diff_fields.is_empty() { + span_err!(tcx.sess, span, E0371, + "the trait `CoerceUnsized` may only be implemented \ + for a coercion between structures with one field \ + being coerced, none found"); + continue; + } else if diff_fields.len() > 1 { + span_err!(tcx.sess, span, E0372, + "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::>().connect(", ")); + continue; + } + + 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, E0373, + "the trait `CoerceUnsized` may only be implemented \ + for a coercion between structures"); + continue; + } + }; + + let mut fulfill_cx = traits::FulfillmentContext::new(); + + // Register an obligation for `A: Trait`. + 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. This catches wily misuses of lifetime + // parameters. + infcx.resolve_regions_and_report_errors(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) { diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs index ab694d26b155c..1a67a7fffbd32 100644 --- a/src/librustc_typeck/coherence/orphan.rs +++ b/src/librustc_typeck/coherence/orphan.rs @@ -320,12 +320,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, E0323, + "explicit impls for the `Unsize` trait are not permitted"); + return; + } } ast::ItemDefaultImpl(..) => { // "Trait" impl diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 95e06879fb223..32c7e319b5822 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -23,7 +23,6 @@ register_diagnostics! { E0034, E0035, E0036, - E0038, E0040, // explicit use of destructor method E0044, E0045, @@ -178,8 +177,18 @@ register_diagnostics! { E0320, // recursive overflow during dropck E0321, // extended coherence rules for defaulted traits violated E0322, // cannot implement Sized explicitly + E0323, // cannot implement Unsize explicitly E0366, // dropck forbid specialization to concrete type or region - E0367 // dropck forbid specialization to predicate not in struct/enum + E0367, // dropck forbid specialization to predicate not in struct/enum + E0370, // the trait `CoerceUnsized` may only be implemented for a coercion + // between structures with the same definition + E0371, // the trait `CoerceUnsized` may only be implemented for a coercion + // between structures with one field being coerced, none found + E0372, // the trait `CoerceUnsized` may only be implemented for a coercion + // between structures with one field being coerced, but multiple + // fields need coercions + E0373 // the trait `CoerceUnsized` may only be implemented for a coercion + // between structures } __build_diagnostic_array! { DIAGNOSTICS } diff --git a/src/test/compile-fail/associated-type-projection-from-multiple-supertraits.rs b/src/test/compile-fail/associated-type-projection-from-multiple-supertraits.rs index c55e24e81adc2..c18d72c445b37 100644 --- a/src/test/compile-fail/associated-type-projection-from-multiple-supertraits.rs +++ b/src/test/compile-fail/associated-type-projection-from-multiple-supertraits.rs @@ -34,6 +34,8 @@ fn dent(c: C, color: C::Color) { fn dent_object(c: BoxCar) { //~^ ERROR ambiguous associated type + //~| ERROR the associated type `Color` (from the trait `Box`) must be specified + //~| ERROR the associated type `Color` (from the trait `Vehicle`) must be specified } fn paint(c: C, d: C::Color) { diff --git a/src/test/compile-fail/dst-bad-coercions.rs b/src/test/compile-fail/dst-bad-coercions.rs index 8ec1034bc4d28..c0ddc15fb70c1 100644 --- a/src/test/compile-fail/dst-bad-coercions.rs +++ b/src/test/compile-fail/dst-bad-coercions.rs @@ -35,18 +35,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 = &Foo {f: S}; - let y: *const Foo = x; //~ ERROR mismatched types - - let x: *mut Foo = &mut Foo {f: S}; - let y: *mut Foo = x; //~ ERROR mismatched types } diff --git a/src/test/compile-fail/issue-18819.rs b/src/test/compile-fail/issue-18819.rs index 951d78410b814..01fc4fef03b1d 100644 --- a/src/test/compile-fail/issue-18819.rs +++ b/src/test/compile-fail/issue-18819.rs @@ -20,7 +20,7 @@ impl Foo for X { type Item = bool; } -fn print_x(_: &Foo, extra: &str) { +fn print_x(_: &Foo, extra: &str) { println!("{}", extra); } diff --git a/src/test/run-pass/issue-19121.rs b/src/test/compile-fail/issue-19482.rs similarity index 75% rename from src/test/run-pass/issue-19121.rs rename to src/test/compile-fail/issue-19482.rs index e02d001ee98ad..21a50f24d5e5c 100644 --- a/src/test/run-pass/issue-19121.rs +++ b/src/test/compile-fail/issue-19482.rs @@ -1,4 +1,4 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// 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. // @@ -9,7 +9,7 @@ // except according to those terms. // Test that a partially specified trait object with unspecified associated -// type does not ICE. +// type does not type-check. // pretty-expanded FIXME #23616 @@ -20,7 +20,6 @@ trait Foo { } fn bar(x: &Foo) {} -// FIXME(#19482) -- `Foo` should specify `A`, but this is not -// currently enforced except at object creation +//~^ ERROR the associated type `A` (from the trait `Foo`) must be specified pub fn main() {} diff --git a/src/test/compile-fail/object-lifetime-default-elision.rs b/src/test/compile-fail/object-lifetime-default-elision.rs index 0077d10e6ca82..5d962a90c1ebf 100644 --- a/src/test/compile-fail/object-lifetime-default-elision.rs +++ b/src/test/compile-fail/object-lifetime-default-elision.rs @@ -82,7 +82,7 @@ fn load3<'a,'b>(ss: &'a SomeTrait) -> &'b SomeTrait { ss //~^ ERROR cannot infer - //~| ERROR mismatched types + //~| ERROR lifetime bound not satisfied } fn main() { diff --git a/src/test/compile-fail/object-lifetime-default-from-box-error.rs b/src/test/compile-fail/object-lifetime-default-from-box-error.rs index 70752cbfda19f..dd94dfe1e0823 100644 --- a/src/test/compile-fail/object-lifetime-default-from-box-error.rs +++ b/src/test/compile-fail/object-lifetime-default-from-box-error.rs @@ -25,7 +25,7 @@ fn load(ss: &mut SomeStruct) -> Box { // `Box` defaults to a `'static` bound, so this return // is illegal. - ss.r //~ ERROR mismatched types + ss.r //~ ERROR lifetime bound not satisfied } fn store(ss: &mut SomeStruct, b: Box) { @@ -38,7 +38,7 @@ fn store(ss: &mut SomeStruct, b: Box) { fn store1<'b>(ss: &mut SomeStruct, b: Box) { // Here we override the lifetimes explicitly, and so naturally we get an error. - ss.r = b; //~ ERROR mismatched types + ss.r = b; //~ ERROR lifetime bound not satisfied } fn main() { diff --git a/src/test/compile-fail/regions-close-over-type-parameter-multiple.rs b/src/test/compile-fail/regions-close-over-type-parameter-multiple.rs index 0f8bc6d684f12..c74f0d6a48d9f 100644 --- a/src/test/compile-fail/regions-close-over-type-parameter-multiple.rs +++ b/src/test/compile-fail/regions-close-over-type-parameter-multiple.rs @@ -27,7 +27,8 @@ fn make_object_good2<'a,'b,A:SomeTrait+'a+'b>(v: A) -> Box { fn make_object_bad<'a,'b,'c,A:SomeTrait+'a+'b>(v: A) -> Box { // A outlives 'a AND 'b...but not 'c. - box v as Box //~ ERROR mismatched types + box v as Box + //~^ ERROR lifetime bound not satisfied } fn main() { diff --git a/src/test/compile-fail/regions-trait-object-subtyping.rs b/src/test/compile-fail/regions-trait-object-subtyping.rs index 8d05cb67e77b1..b4e527972e476 100644 --- a/src/test/compile-fail/regions-trait-object-subtyping.rs +++ b/src/test/compile-fail/regions-trait-object-subtyping.rs @@ -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 mismatched types + x //~ ERROR lifetime bound not satisfied //~^ ERROR cannot infer } diff --git a/src/test/compile-fail/retslot-cast.rs b/src/test/compile-fail/retslot-cast.rs index 4ef07ecb4382f..c5e26a26744df 100644 --- a/src/test/compile-fail/retslot-cast.rs +++ b/src/test/compile-fail/retslot-cast.rs @@ -11,7 +11,8 @@ #![feature(rustc_attrs)] #![allow(warnings)] -pub fn fail(x: Option<& (Iterator+Send)>) -> Option<&Iterator> { +pub fn fail(x: Option<&(Iterator+Send)>) + -> Option<&Iterator> { // This call used to trigger an LLVM assertion because the return // slot had type "Option<&Iterator>"* instead of // "Option<&(Iterator+Send)>"* -- but this now yields a @@ -23,7 +24,8 @@ pub fn fail(x: Option<& (Iterator+Send)>) -> Option<&Iterator> { inner(x) //~ ERROR mismatched types } -pub fn inner(x: Option<& (Iterator+Send)>) -> Option<&(Iterator+Send)> { +pub fn inner(x: Option<&(Iterator+Send)>) + -> Option<&(Iterator+Send)> { x } diff --git a/src/test/compile-fail/unboxed-closure-sugar-not-used-on-fn.rs b/src/test/compile-fail/unboxed-closure-sugar-not-used-on-fn.rs index 55156e28cd703..5a821ef1231cc 100644 --- a/src/test/compile-fail/unboxed-closure-sugar-not-used-on-fn.rs +++ b/src/test/compile-fail/unboxed-closure-sugar-not-used-on-fn.rs @@ -11,7 +11,7 @@ // Test that the `Fn` traits require `()` form without a feature gate. -fn bar1(x: &Fn<()>) { +fn bar1(x: &Fn<(), Output=()>) { //~^ ERROR angle-bracket notation is not stable when used with the `Fn` family }