diff options
Diffstat (limited to 'src')
116 files changed, 3243 insertions, 1822 deletions
diff --git a/src/liballoc/heap.rs b/src/liballoc/heap.rs index ab686cb01d6..38216fa5b59 100644 --- a/src/liballoc/heap.rs +++ b/src/liballoc/heap.rs @@ -12,6 +12,7 @@ // FIXME: #13996: mark the `allocate` and `reallocate` return value as `noalias` // and `nonnull` +use core::ptr::RawPtr; #[cfg(not(test))] use core::raw; #[cfg(not(test))] use util; @@ -69,6 +70,11 @@ pub unsafe fn reallocate_inplace(ptr: *mut u8, size: uint, align: uint, /// the value returned by `usable_size` for the requested size. #[inline] pub unsafe fn deallocate(ptr: *mut u8, size: uint, align: uint) { + // FIXME(14395) This is only required for DST ~[T], it should be removed once + // we fix that representation to not use null pointers. + if ptr.is_null() { + return; + } imp::deallocate(ptr, size, align) } diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index 55723ec10a0..71b9673d279 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -92,8 +92,6 @@ use core::iter::{range_step, MultiplicativeIterator}; use MutableSeq; use vec::Vec; -#[cfg(not(stage0))] -use raw::Slice; pub use core::slice::{Chunks, Slice, ImmutableSlice, ImmutablePartialEqSlice}; pub use core::slice::{ImmutableOrdSlice, MutableSlice, Items, MutItems}; @@ -284,64 +282,6 @@ pub trait CloneableVector<T> { impl<'a, T: Clone> CloneableVector<T> for &'a [T] { /// Returns a copy of `v`. - #[cfg(not(stage0))] - fn to_owned(&self) -> ~[T] { - use num::CheckedMul; - use option::Expect; - - let len = self.len(); - - if len == 0 { - unsafe { - let slice: Slice<T> = Slice{data: 0 as *T, len: 0}; - mem::transmute(slice) - } - } else { - let unit_size = mem::size_of::<T>(); - let data_size = if unit_size == 0 { - len - } else { - let data_size = len.checked_mul(&unit_size); - data_size.expect("overflow in from_iter()") - }; - - unsafe { - // this should pass the real required alignment - let ret = allocate(data_size, 8) as *mut T; - - if unit_size > 0 { - // Be careful with the following loop. We want it to be optimized - // to a memcpy (or something similarly fast) when T is Copy. LLVM - // is easily confused, so any extra operations during the loop can - // prevent this optimization. - let mut i = 0; - let p = &mut (*ret) as *mut _ as *mut T; - try_finally( - &mut i, (), - |i, ()| while *i < len { - mem::move_val_init( - &mut(*p.offset(*i as int)), - self.unsafe_ref(*i).clone()); - *i += 1; - }, - |i| if *i < len { - // we must be failing, clean up after ourselves - for j in range(0, *i as int) { - ptr::read(&*p.offset(j)); - } - // FIXME: #13994 (should pass align and size here) - deallocate(ret as *mut u8, 0, 8); - }); - } - let slice: Slice<T> = Slice{data: ret as *T, len: len}; - mem::transmute(slice) - } - } - } - - /// Returns a copy of `v`. - // NOTE: remove after snapshot - #[cfg(stage0)] #[inline] fn to_vec(&self) -> Vec<T> { Vec::from_slice(*self) } diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 84827c63572..4ecc1b8f45f 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -93,6 +93,8 @@ pub trait TyVisitor { fn visit_char(&mut self) -> bool; fn visit_estr_slice(&mut self) -> bool; + // NOTE: remove after snapshot + #[cfg(stage0)] fn visit_estr_fixed(&mut self, n: uint, sz: uint, align: uint) -> bool; fn visit_box(&mut self, mtbl: uint, inner: *const TyDesc) -> bool; @@ -101,8 +103,13 @@ pub trait TyVisitor { fn visit_rptr(&mut self, mtbl: uint, inner: *const TyDesc) -> bool; fn visit_evec_slice(&mut self, mtbl: uint, inner: *const TyDesc) -> bool; + // NOTE: remove after snapshot + #[cfg(stage0)] fn visit_evec_fixed(&mut self, n: uint, sz: uint, align: uint, mtbl: uint, inner: *const TyDesc) -> bool; + #[cfg(not(stage0))] + fn visit_evec_fixed(&mut self, n: uint, sz: uint, align: uint, + inner: *const TyDesc) -> bool; fn visit_enter_rec(&mut self, n_fields: uint, sz: uint, align: uint) -> bool; diff --git a/src/libcore/raw.rs b/src/libcore/raw.rs index da9fab0fc6f..aa8a4976867 100644 --- a/src/libcore/raw.rs +++ b/src/libcore/raw.rs @@ -51,10 +51,16 @@ pub struct Procedure { /// /// This struct does not have a `Repr` implementation /// because there is no way to refer to all trait objects generically. +#[cfg(stage0)] pub struct TraitObject { pub vtable: *mut (), pub data: *mut (), } +#[cfg(not(stage0))] +pub struct TraitObject { + pub data: *(), + pub vtable: *(), +} /// This trait is meant to map equivalences between raw structs and their /// corresponding rust values. diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs index 826f25101fb..8c55662f163 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice.rs @@ -1623,7 +1623,6 @@ pub mod bytes { - // // Boilerplate traits // diff --git a/src/libdebug/reflect.rs b/src/libdebug/reflect.rs index 0cbae6ee2d3..0d7209b5999 100644 --- a/src/libdebug/reflect.rs +++ b/src/libdebug/reflect.rs @@ -193,6 +193,8 @@ impl<V:TyVisitor + MovePtr> TyVisitor for MovePtrAdaptor<V> { true } + // NOTE: remove after snapshot + #[cfg(stage0)] fn visit_estr_fixed(&mut self, n: uint, sz: uint, align: uint) -> bool { @@ -237,6 +239,7 @@ impl<V:TyVisitor + MovePtr> TyVisitor for MovePtrAdaptor<V> { true } + #[cfg(stage0)] fn visit_evec_fixed(&mut self, n: uint, sz: uint, align: uint, mtbl: uint, inner: *const TyDesc) -> bool { self.align(align); @@ -246,6 +249,16 @@ impl<V:TyVisitor + MovePtr> TyVisitor for MovePtrAdaptor<V> { self.bump(sz); true } + #[cfg(not(stage0))] + fn visit_evec_fixed(&mut self, n: uint, sz: uint, align: uint, + inner: *TyDesc) -> bool { + self.align(align); + if ! self.inner.visit_evec_fixed(n, sz, align, inner) { + return false; + } + self.bump(sz); + true + } fn visit_enter_rec(&mut self, n_fields: uint, sz: uint, align: uint) -> bool { self.align(align); diff --git a/src/libdebug/repr.rs b/src/libdebug/repr.rs index b85097e6623..c810e1f6473 100644 --- a/src/libdebug/repr.rs +++ b/src/libdebug/repr.rs @@ -275,6 +275,8 @@ impl<'a> TyVisitor for ReprVisitor<'a> { } // Type no longer exists, vestigial function. + // NOTE: remove after snapshot + #[cfg(stage0)] fn visit_estr_fixed(&mut self, _n: uint, _sz: uint, _align: uint) -> bool { fail!(); } @@ -328,6 +330,8 @@ impl<'a> TyVisitor for ReprVisitor<'a> { }) } + // NOTE: remove after snapshot + #[cfg(stage0)] fn visit_evec_fixed(&mut self, n: uint, sz: uint, _align: uint, _: uint, inner: *const TyDesc) -> bool { let assumed_size = if sz == 0 { n } else { sz }; @@ -336,6 +340,16 @@ impl<'a> TyVisitor for ReprVisitor<'a> { }) } + #[cfg(not(stage0))] + fn visit_evec_fixed(&mut self, n: uint, sz: uint, _align: uint, + inner: *TyDesc) -> bool { + let assumed_size = if sz == 0 { n } else { sz }; + self.get::<()>(|this, b| { + this.write_vec_range(b, assumed_size, inner) + }) + } + + fn visit_enter_rec(&mut self, _n_fields: uint, _sz: uint, _align: uint) -> bool { try!(self, self.writer.write([b'{'])); diff --git a/src/libgreen/context.rs b/src/libgreen/context.rs index 64537ea12d9..296615e15ff 100644 --- a/src/libgreen/context.rs +++ b/src/libgreen/context.rs @@ -112,7 +112,7 @@ impl Context { // the stack limit to 0 to make morestack never fail None => stack::record_rust_managed_stack_bounds(0, uint::MAX), } - rust_swap_registers(out_regs, in_regs) + rust_swap_registers(out_regs, in_regs); } } } diff --git a/src/liblibc/lib.rs b/src/liblibc/lib.rs index 949dd08eaa3..265d1e37ec3 100644 --- a/src/liblibc/lib.rs +++ b/src/liblibc/lib.rs @@ -302,7 +302,7 @@ extern {} /// A wrapper for a nullable pointer. Don't use this except for interacting /// with libc. Basically Option, but without the dependence on libstd. // If/when libprim happens, this can be removed in favor of that -pub enum Nullable<T> { +pub enum Nullable<type T> { Null, NotNull(T) } diff --git a/src/librlibc/lib.rs b/src/librlibc/lib.rs index 739ec2cf43f..b43ad1eabf9 100644 --- a/src/librlibc/lib.rs +++ b/src/librlibc/lib.rs @@ -49,7 +49,7 @@ // implementations below. If pointer arithmetic is done through integers the // optimizations start to break down. extern "rust-intrinsic" { - fn offset<T>(dst: *const T, offset: int) -> *const T; + fn offset<type T>(dst: *const T, offset: int) -> *const T; } #[no_mangle] diff --git a/src/librustc/front/test.rs b/src/librustc/front/test.rs index ceb7dcc5456..9984aba8d08 100644 --- a/src/librustc/front/test.rs +++ b/src/librustc/front/test.rs @@ -477,13 +477,14 @@ fn mk_test_descs(cx: &TestCtxt) -> Gc<ast::Expr> { box(GC) ast::Expr { id: ast::DUMMY_NODE_ID, - node: ast::ExprVstore(box(GC) ast::Expr { - id: ast::DUMMY_NODE_ID, - node: ast::ExprVec(cx.testfns.iter().map(|test| { - mk_test_desc_and_fn_rec(cx, test) + node: ast::ExprAddrOf(box(GC) ast::MutImmutable, + box(GC) ast::Expr { + id: ast::DUMMY_NODE_ID, + node: ast::ExprVec(cx.testfns.borrow().iter().map(|test| { + mk_test_desc_and_fn_rec(cx, test) }).collect()), span: DUMMY_SP, - }, ast::ExprVstoreSlice), + }), span: DUMMY_SP, } } diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 80b47640146..6cc1c6a7b37 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -1240,18 +1240,8 @@ impl LintPass for UnnecessaryAllocation { } fn check_expr(&mut self, cx: &Context, e: &ast::Expr) { - // Warn if string and vector literals with sigils, or boxing expressions, - // are immediately borrowed. + // Warn if boxing expressions are immediately borrowed. let allocation = match e.node { - ast::ExprVstore(e2, ast::ExprVstoreUniq) => { - match e2.node { - ast::ExprLit(lit) if ast_util::lit_is_str(lit) => { - VectorAllocation - } - ast::ExprVec(..) => VectorAllocation, - _ => return - } - } ast::ExprUnary(ast::UnUniq, _) | ast::ExprUnary(ast::UnBox, _) => BoxAllocation, @@ -1261,19 +1251,19 @@ impl LintPass for UnnecessaryAllocation { match cx.tcx.adjustments.borrow().find(&e.id) { Some(adjustment) => { match *adjustment { - ty::AutoDerefRef(ty::AutoDerefRef { autoref, .. }) => { + ty::AutoDerefRef(ty::AutoDerefRef { ref autoref, .. }) => { match (allocation, autoref) { - (VectorAllocation, Some(ty::AutoBorrowVec(..))) => { + (VectorAllocation, &Some(ty::AutoPtr(_, _, None))) => { cx.span_lint(UNNECESSARY_ALLOCATION, e.span, "unnecessary allocation, the sigil can be removed"); } (BoxAllocation, - Some(ty::AutoPtr(_, ast::MutImmutable))) => { + &Some(ty::AutoPtr(_, ast::MutImmutable, None))) => { cx.span_lint(UNNECESSARY_ALLOCATION, e.span, "unnecessary allocation, use & instead"); } (BoxAllocation, - Some(ty::AutoPtr(_, ast::MutMutable))) => { + &Some(ty::AutoPtr(_, ast::MutMutable, None))) => { cx.span_lint(UNNECESSARY_ALLOCATION, e.span, "unnecessary allocation, use &mut instead"); } diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index b26a12d5cfc..2ef5675caa1 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -377,9 +377,9 @@ fn parse_ty(st: &mut PState, conv: conv_did) -> ty::t { return ty::mk_rptr(st.tcx, r, mt); } 'V' => { - let mt = parse_mt(st, |x,y| conv(x,y)); + let t = parse_ty(st, |x,y| conv(x,y)); let sz = parse_size(st); - return ty::mk_vec(st.tcx, mt, sz); + return ty::mk_vec(st.tcx, t, sz); } 'v' => { return ty::mk_str(st.tcx); diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index fc5e267aa90..84ee49c207b 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -254,9 +254,9 @@ fn enc_sty(w: &mut SeekableMemWriter, cx: &ctxt, st: &ty::sty) { enc_region(w, cx, r); enc_mt(w, cx, mt); } - ty::ty_vec(mt, sz) => { + ty::ty_vec(t, sz) => { mywrite!(w, "V"); - enc_mt(w, cx, mt); + enc_ty(w, cx, t); mywrite!(w, "/"); match sz { Some(n) => mywrite!(w, "{}|", n), @@ -292,6 +292,9 @@ fn enc_sty(w: &mut SeekableMemWriter, cx: &ctxt, st: &ty::sty) { ty::ty_err => { mywrite!(w, "e"); } + ty::ty_open(_) => { + cx.diag.handler().bug("unexpected type in enc_sty (ty_open)"); + } } } diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index 3359d7ed030..260e38f2070 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -495,25 +495,7 @@ impl tr for def::Def { } // ______________________________________________________________________ -// Encoding and decoding of adjustment information - -impl tr for ty::AutoDerefRef { - fn tr(&self, xcx: &ExtendedDecodeContext) -> ty::AutoDerefRef { - ty::AutoDerefRef { - autoderefs: self.autoderefs, - autoref: match self.autoref { - Some(ref autoref) => Some(autoref.tr(xcx)), - None => None - } - } - } -} - -impl tr for ty::AutoRef { - fn tr(&self, xcx: &ExtendedDecodeContext) -> ty::AutoRef { - self.map_region(|r| r.tr(xcx)) - } -} +// Encoding and decoding of ancillary information impl tr for ty::Region { fn tr(&self, xcx: &ExtendedDecodeContext) -> ty::Region { @@ -961,6 +943,9 @@ trait rbml_writer_helpers { pty: ty::Polytype); fn emit_substs(&mut self, ecx: &e::EncodeContext, substs: &subst::Substs); fn emit_auto_adjustment(&mut self, ecx: &e::EncodeContext, adj: &ty::AutoAdjustment); + fn emit_autoref(&mut self, ecx: &e::EncodeContext, autoref: &ty::AutoRef); + fn emit_auto_deref_ref(&mut self, ecx: &e::EncodeContext, auto_deref_ref: &ty::AutoDerefRef); + fn emit_unsize_kind(&mut self, ecx: &e::EncodeContext, uk: &ty::UnsizeKind); } impl<'a> rbml_writer_helpers for Encoder<'a> { @@ -1035,16 +1020,85 @@ impl<'a> rbml_writer_helpers for Encoder<'a> { ty::AutoDerefRef(ref auto_deref_ref) => { this.emit_enum_variant("AutoDerefRef", 1, 1, |this| { - this.emit_enum_variant_arg(0, |this| auto_deref_ref.encode(this)) + this.emit_enum_variant_arg(0, + |this| Ok(this.emit_auto_deref_ref(ecx, auto_deref_ref))) }) } + } + }); + } - ty::AutoObject(store, b, def_id, ref substs) => { - this.emit_enum_variant("AutoObject", 2, 4, |this| { - this.emit_enum_variant_arg(0, |this| store.encode(this)); - this.emit_enum_variant_arg(1, |this| b.encode(this)); - this.emit_enum_variant_arg(2, |this| def_id.encode(this)); - this.emit_enum_variant_arg(3, |this| Ok(this.emit_substs(ecx, substs))) + fn emit_autoref(&mut self, ecx: &e::EncodeContext, autoref: &ty::AutoRef) { + 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| { + 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))) + }) + } + &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) => { + this.emit_enum_variant("AutoUnsafe", 3, 1, |this| { + this.emit_enum_variant_arg(0, |this| m.encode(this)) + }) + } + } + }); + } + + fn emit_auto_deref_ref(&mut self, ecx: &e::EncodeContext, auto_deref_ref: &ty::AutoDerefRef) { + 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))), + } + }) + }) + }); + } + + fn emit_unsize_kind(&mut self, ecx: &e::EncodeContext, uk: &ty::UnsizeKind) { + 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(b, def_id, ref substs) => { + this.emit_enum_variant("UnsizeVtable", 2, 3, |this| { + this.emit_enum_variant_arg(0, |this| b.encode(this)); + this.emit_enum_variant_arg(1, |this| def_id.encode(this)); + this.emit_enum_variant_arg(2, |this| Ok(this.emit_substs(ecx, substs))) }) } } @@ -1227,9 +1281,30 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext, }) } - for &adj in tcx.adjustments.borrow().find(&id).iter() { - match *adj { - ty::AutoDerefRef(adj) => { + for &adjustment in tcx.adjustments.borrow().find(&id).iter() { + match *adjustment { + _ if ty::adjust_is_object(adjustment) => { + let method_call = MethodCall::autoobject(id); + for &method in tcx.method_map.borrow().find(&method_call).iter() { + rbml_w.tag(c::tag_table_method_map, |ebml_w| { + rbml_w.id(id); + rbml_w.tag(c::tag_table_val, |rbml_w| { + encode_method_callee(ecx, rbml_w, method_call.adjustment, method) + }) + }) + } + + for &dr in tcx.vtable_map.borrow().find(&method_call).iter() { + rbml_w.tag(c::tag_table_vtable_map, |rbml_w| { + rbml_w.id(id); + rbml_w.tag(c::tag_table_val, |ebml_w| { + encode_vtable_res_with_key(ecx, rbml_w, method_call.adjustment, dr); + }) + }) + } + } + ty::AutoDerefRef(ref adj) => { + assert!(!ty::adjust_is_object(adjustment)); for autoderef in range(0, adj.autoderefs) { let method_call = MethodCall::autoderef(id, autoderef); for &method in tcx.method_map.borrow().find(&method_call).iter() { @@ -1253,27 +1328,9 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext, } } } - ty::AutoObject(..) => { - let method_call = MethodCall::autoobject(id); - for &method in tcx.method_map.borrow().find(&method_call).iter() { - rbml_w.tag(c::tag_table_method_map, |rbml_w| { - rbml_w.id(id); - rbml_w.tag(c::tag_table_val, |rbml_w| { - encode_method_callee(ecx, rbml_w, method_call.adjustment, method) - }) - }) - } - - for &dr in tcx.vtable_map.borrow().find(&method_call).iter() { - rbml_w.tag(c::tag_table_vtable_map, |rbml_w| { - rbml_w.id(id); - rbml_w.tag(c::tag_table_val, |rbml_w| { - encode_vtable_res_with_key(ecx, rbml_w, method_call.adjustment, dr); - }) - }) - } + _ => { + assert!(!ty::adjust_is_object(adjustment)); } - _ => {} } rbml_w.tag(c::tag_table_adjustments, |rbml_w| { @@ -1321,6 +1378,9 @@ trait rbml_decoder_decoder_helpers { fn read_auto_adjustment(&mut self, xcx: &ExtendedDecodeContext) -> ty::AutoAdjustment; fn read_unboxed_closure(&mut self, xcx: &ExtendedDecodeContext) -> ty::UnboxedClosure; + fn read_auto_deref_ref(&mut self, xcx: &ExtendedDecodeContext) -> ty::AutoDerefRef; + fn read_autoref(&mut self, xcx: &ExtendedDecodeContext) -> ty::AutoRef; + fn read_unsize_kind(&mut self, xcx: &ExtendedDecodeContext) -> ty::UnsizeKind; fn convert_def_id(&mut self, xcx: &ExtendedDecodeContext, source: DefIdSource, @@ -1460,34 +1520,128 @@ impl<'a> rbml_decoder_decoder_helpers for reader::Decoder<'a> { fn read_auto_adjustment(&mut self, xcx: &ExtendedDecodeContext) -> ty::AutoAdjustment { self.read_enum("AutoAdjustment", |this| { - let variants = ["AutoAddEnv", "AutoDerefRef", "AutoObject"]; + let variants = ["AutoAddEnv", "AutoDerefRef"]; this.read_enum_variant(variants, |this, i| { Ok(match i { 0 => { let store: ty::TraitStore = this.read_enum_variant_arg(0, |this| Decodable::decode(this)).unwrap(); - ty:: AutoAddEnv(store.tr(xcx)) + ty::AutoAddEnv(store.tr(xcx)) } 1 => { let auto_deref_ref: ty::AutoDerefRef = + this.read_enum_variant_arg(0, + |this| Ok(this.read_auto_deref_ref(xcx))).unwrap(); + + ty::AutoDerefRef(auto_deref_ref) + } + _ => fail!("bad enum variant for ty::AutoAdjustment") + }) + }) + }).unwrap() + } + + fn read_auto_deref_ref(&mut self, xcx: &ExtendedDecodeContext) -> ty::AutoDerefRef { + self.read_struct("AutoDerefRef", 2, |this| { + Ok(ty::AutoDerefRef { + autoderefs: this.read_struct_field("autoderefs", 0, |this| { + Decodable::decode(this) + }).unwrap(), + autoref: this.read_struct_field("autoref", 1, |this| { + this.read_option(|this, b| { + if b { + Ok(Some(this.read_autoref(xcx))) + } else { + Ok(None) + } + }) + }).unwrap(), + }) + }).unwrap() + } + + fn read_autoref(&mut self, xcx: &ExtendedDecodeContext) -> ty::AutoRef { + self.read_enum("AutoRef", |this| { + let variants = ["AutoPtr", + "AutoUnsize", + "AutoUnsizeUniq", + "AutoUnsafe"]; + this.read_enum_variant(variants, |this, i| { + Ok(match i { + 0 => { + let r: ty::Region = 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<Box<ty::AutoRef>> = + this.read_enum_variant_arg(2, |this| this.read_option(|this, b| { + if b { + Ok(Some(box this.read_autoref(xcx))) + } else { + Ok(None) + } + })).unwrap(); + + ty::AutoPtr(r.tr(xcx), m, a) + } + 1 => { + let uk: ty::UnsizeKind = + this.read_enum_variant_arg(0, + |this| Ok(this.read_unsize_kind(xcx))).unwrap(); - ty::AutoDerefRef(auto_deref_ref.tr(xcx)) + ty::AutoUnsize(uk) } 2 => { - let store: ty::TraitStore = + let uk: ty::UnsizeKind = + this.read_enum_variant_arg(0, + |this| Ok(this.read_unsize_kind(xcx))).unwrap(); + + ty::AutoUnsizeUniq(uk) + } + 3 => { + let m: ast::Mutability = this.read_enum_variant_arg(0, |this| Decodable::decode(this)).unwrap(); - let b: ty::BuiltinBounds = + + ty::AutoUnsafe(m) + } + _ => fail!("bad enum variant for ty::AutoRef") + }) + }) + }).unwrap() + } + + fn read_unsize_kind(&mut self, xcx: &ExtendedDecodeContext) -> ty::UnsizeKind { + self.read_enum("UnsizeKind", |this| { + let variants = ["UnsizeLength", "UnsizeStruct", "UnsizeVtable"]; + 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(xcx))).unwrap(); + let idx: uint = this.read_enum_variant_arg(1, |this| Decodable::decode(this)).unwrap(); + + ty::UnsizeStruct(box uk, idx) + } + 2 => { + let b: ty::BuiltinBounds = + this.read_enum_variant_arg(0, |this| Decodable::decode(this)).unwrap(); let def_id: ast::DefId = - this.read_enum_variant_arg(2, |this| Decodable::decode(this)).unwrap(); - let substs = this.read_enum_variant_arg(3, |this| Ok(this.read_substs(xcx))) - .unwrap(); + this.read_enum_variant_arg(1, |this| Decodable::decode(this)).unwrap(); + let substs = this.read_enum_variant_arg(2, + |this| Ok(this.read_substs(xcx))).unwrap(); - ty::AutoObject(store.tr(xcx), b, def_id.tr(xcx), substs) + ty::UnsizeVtable(b, def_id.tr(xcx), substs) } - _ => fail!("bad enum variant for ty::AutoAdjustment") + _ => fail!("bad enum variant for ty::UnsizeKind") }) }) }).unwrap() diff --git a/src/librustc/middle/borrowck/mod.rs b/src/librustc/middle/borrowck/mod.rs index 9de55ccc468..230786924d7 100644 --- a/src/librustc/middle/borrowck/mod.rs +++ b/src/librustc/middle/borrowck/mod.rs @@ -428,16 +428,15 @@ impl<'a> BorrowckCtxt<'a> { adj: &ty::AutoAdjustment) -> mc::cmt { let r = match *adj { - ty::AutoAddEnv(..) | ty::AutoObject(..) => { - // no autoderefs - self.mc().cat_expr_unadjusted(expr) - } - ty::AutoDerefRef( ty::AutoDerefRef { autoderefs: autoderefs, ..}) => { self.mc().cat_expr_autoderefd(expr, autoderefs) } + ty::AutoAddEnv(..) => { + // no autoderefs + self.mc().cat_expr_unadjusted(expr) + } }; match r { diff --git a/src/librustc/middle/cfg/construct.rs b/src/librustc/middle/cfg/construct.rs index fd3074e130e..0d77b01d970 100644 --- a/src/librustc/middle/cfg/construct.rs +++ b/src/librustc/middle/cfg/construct.rs @@ -465,7 +465,6 @@ impl<'a> CFGBuilder<'a> { ast::ExprCast(e, _) | ast::ExprUnary(_, e) | ast::ExprParen(e) | - ast::ExprVstore(e, _) | ast::ExprField(e, _, _) => { self.straightline(expr, pred, [e]) } diff --git a/src/librustc/middle/check_const.rs b/src/librustc/middle/check_const.rs index 283d667f3a8..b0b2fe89c3f 100644 --- a/src/librustc/middle/check_const.rs +++ b/src/librustc/middle/check_const.rs @@ -62,7 +62,7 @@ fn check_item(v: &mut CheckCrateVisitor, it: &Item, _is_const: bool) { fn check_pat(v: &mut CheckCrateVisitor, p: &Pat, _is_const: bool) { fn is_str(e: &Expr) -> bool { match e.node { - ExprVstore(expr, ExprVstoreUniq) => { + ExprBox(_, expr) => { match expr.node { ExprLit(lit) => ast_util::lit_is_str(lit), _ => false, @@ -169,8 +169,6 @@ fn check_expr(v: &mut CheckCrateVisitor, e: &Expr, is_const: bool) { None => {} } } - ExprVstore(_, ExprVstoreMutSlice) | - ExprVstore(_, ExprVstoreSlice) | ExprVec(_) | ExprAddrOf(MutImmutable, _) | ExprParen(..) | @@ -179,13 +177,14 @@ fn check_expr(v: &mut CheckCrateVisitor, e: &Expr, is_const: bool) { ExprTup(..) | ExprRepeat(..) | ExprStruct(..) => { } - ExprAddrOf(..) => { - span_err!(v.tcx.sess, e.span, E0017, - "references in constants may only refer to immutable values"); - }, - ExprVstore(_, ExprVstoreUniq) => { - span_err!(v.tcx.sess, e.span, E0018, - "cannot allocate vectors in constant expressions"); + ExprAddrOf(_, inner) => { + match inner.node { + // Mutable slices are allowed. + ExprVec(_) => {} + _ => span_err!(v.tcx.sess, e.span, E0017, + "references in constants may only refer to immutable values"); + + } }, _ => { diff --git a/src/librustc/middle/check_static.rs b/src/librustc/middle/check_static.rs index 8985e633ad4..042a5b8f60a 100644 --- a/src/librustc/middle/check_static.rs +++ b/src/librustc/middle/check_static.rs @@ -107,21 +107,19 @@ impl<'a> Visitor<bool> for CheckStaticVisitor<'a> { match e.node { ast::ExprField(..) | ast::ExprVec(..) | - ast::ExprBlock(..) | ast::ExprTup(..) | - ast::ExprVstore(_, ast::ExprVstoreSlice) => { + ast::ExprBlock(..) | ast::ExprTup(..) => { visit::walk_expr(self, e, is_const); } - ast::ExprVstore(_, ast::ExprVstoreMutSlice) => { + ast::ExprAddrOf(ast::MutMutable, _) => { span_err!(self.tcx.sess, e.span, E0020, "static items are not allowed to have mutable slices"); - }, + }, ast::ExprUnary(ast::UnBox, _) => { span_err!(self.tcx.sess, e.span, E0021, "static items are not allowed to have managed pointers"); } ast::ExprBox(..) | - ast::ExprUnary(ast::UnUniq, _) | - ast::ExprVstore(_, ast::ExprVstoreUniq) => { + ast::ExprUnary(ast::UnUniq, _) => { span_err!(self.tcx.sess, e.span, E0022, "static items are not allowed to have custom pointers"); } diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs index b6ad584c303..03a7021b70d 100644 --- a/src/librustc/middle/const_eval.rs +++ b/src/librustc/middle/const_eval.rs @@ -206,14 +206,6 @@ impl<'a> ConstEvalVisitor<'a> { ast::ExprVec(ref es) => join_all(es.iter().map(|e| self.classify(&**e))), - ast::ExprVstore(ref e, vstore) => { - match vstore { - ast::ExprVstoreSlice => self.classify(&**e), - ast::ExprVstoreUniq | - ast::ExprVstoreMutSlice => non_const - } - } - ast::ExprStruct(_, ref fs, None) => { let cs = fs.iter().map(|f| self.classify(&*f.expr)); join_all(cs) @@ -554,8 +546,6 @@ pub fn eval_const_expr_partial<T: ty::ExprTyProvider>(tcx: &T, e: &Expr) } } ExprLit(ref lit) => Ok(lit_to_const(&**lit)), - // If we have a vstore, just keep going; it has to be a string - ExprVstore(ref e, _) => eval_const_expr_partial(tcx, &**e), ExprParen(ref e) => eval_const_expr_partial(tcx, &**e), ExprBlock(ref block) => { match block.expr { diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 84b879227ae..67ee5c5e4be 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -474,10 +474,6 @@ impl<'d,'t,TYPER:mc::Typer> ExprUseVisitor<'d,'t,TYPER> { self.walk_captures(expr) } - ast::ExprVstore(ref base, _) => { - self.consume_expr(&**base); - } - ast::ExprBox(ref place, ref base) => { self.consume_expr(&**place); self.consume_expr(&**base); @@ -672,11 +668,10 @@ impl<'d,'t,TYPER:mc::Typer> ExprUseVisitor<'d,'t,TYPER> { None => { } Some(adjustment) => { match *adjustment { - ty::AutoAddEnv(..) | - ty::AutoObject(..) => { - // Creating an object or closure consumes the - // input and stores it into the resulting rvalue. - debug!("walk_adjustment(AutoAddEnv|AutoObject)"); + ty::AutoAddEnv(..) => { + // Creating a closure consumes the input and stores it + // into the resulting rvalue. + debug!("walk_adjustment(AutoAddEnv)"); let cmt_unadjusted = return_if_err!(self.mc.cat_expr_unadjusted(expr)); self.delegate_consume(expr.id, expr.span, cmt_unadjusted); @@ -735,42 +730,39 @@ impl<'d,'t,TYPER:mc::Typer> ExprUseVisitor<'d,'t,TYPER> { fn walk_autoref(&mut self, expr: &ast::Expr, autoref: &ty::AutoRef, - autoderefs: uint) { - debug!("walk_autoref expr={} autoderefs={}", expr.repr(self.tcx()), autoderefs); + n: uint) { + debug!("walk_autoref expr={}", expr.repr(self.tcx())); - let cmt_derefd = return_if_err!( - self.mc.cat_expr_autoderefd(expr, autoderefs)); + // Match for unique trait coercions first, since we don't need the + // call to cat_expr_autoderefd. + match *autoref { + ty::AutoUnsizeUniq(ty::UnsizeVtable(..)) | + ty::AutoUnsize(ty::UnsizeVtable(..)) => { + 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); + return; + } + _ => {} + } - debug!("walk_autoref: 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) => { + ty::AutoPtr(r, m, _) => { self.delegate.borrow(expr.id, expr.span, cmt_derefd, r, ty::BorrowKind::from_mutbl(m), - AutoRef) - } - ty::AutoBorrowVec(r, m) | ty::AutoBorrowVecRef(r, m) => { - let cmt_index = self.mc.cat_index(expr, cmt_derefd, autoderefs+1); - self.delegate.borrow(expr.id, - expr.span, - cmt_index, - r, - ty::BorrowKind::from_mutbl(m), - AutoRef) - } - ty::AutoBorrowObj(r, m) => { - let cmt_deref = self.mc.cat_deref_obj(expr, cmt_derefd); - self.delegate.borrow(expr.id, - expr.span, - cmt_deref, - r, - ty::BorrowKind::from_mutbl(m), - AutoRef) + AutoRef); } - ty::AutoUnsafe(_) => {} + ty::AutoUnsizeUniq(_) | ty::AutoUnsize(_) | ty::AutoUnsafe(_) => {} } } diff --git a/src/librustc/middle/kind.rs b/src/librustc/middle/kind.rs index dbd7d6a5d6a..b96a75cba94 100644 --- a/src/librustc/middle/kind.rs +++ b/src/librustc/middle/kind.rs @@ -405,14 +405,27 @@ pub fn check_expr(cx: &mut Context, e: &Expr) { "repeated element will be copied"); } } + ExprAssign(ref lhs, _) | + ExprAssignOp(_, ref lhs, _) => { + let lhs_ty = ty::expr_ty(cx.tcx, &**lhs); + if !ty::type_is_sized(cx.tcx, lhs_ty) { + cx.tcx.sess.span_err(lhs.span, "dynamically sized type on lhs of assignment"); + } + } + ExprStruct(..) => { + let e_ty = ty::expr_ty(cx.tcx, e); + if !ty::type_is_sized(cx.tcx, e_ty) { + cx.tcx.sess.span_err(e.span, "trying to initialise a dynamically sized struct"); + } + } _ => {} } // Search for auto-adjustments to find trait coercions. match cx.tcx.adjustments.borrow().find(&e.id) { Some(adjustment) => { - match *adjustment { - ty::AutoObject(..) => { + match adjustment { + adj if ty::adjust_is_object(adj) => { let source_ty = ty::expr_ty(cx.tcx, e); let target_ty = ty::expr_ty_adjusted(cx.tcx, e); let method_call = MethodCall { @@ -425,8 +438,7 @@ pub fn check_expr(cx: &mut Context, e: &Expr) { e.span, method_call); } - ty::AutoAddEnv(..) | - ty::AutoDerefRef(..) => {} + _ => {} } } None => {} diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index 2062fa97777..38288bf3011 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -511,7 +511,7 @@ fn visit_expr(ir: &mut IrMaps, expr: &Expr) { } // otherwise, live nodes are not required: - ExprIndex(..) | ExprField(..) | ExprVstore(..) | ExprVec(..) | + ExprIndex(..) | ExprField(..) | ExprVec(..) | ExprCall(..) | ExprMethodCall(..) | ExprTup(..) | ExprBinary(..) | ExprAddrOf(..) | ExprCast(..) | ExprUnary(..) | ExprBreak(_) | @@ -1119,10 +1119,6 @@ impl<'a> Liveness<'a> { // Uninteresting cases: just propagate in rev exec order - ExprVstore(ref expr, _) => { - self.propagate_through_expr(&**expr, succ) - } - ExprVec(ref exprs) => { self.propagate_through_exprs(exprs.as_slice(), succ) } @@ -1449,8 +1445,7 @@ fn check_expr(this: &mut Liveness, expr: &Expr) { // no correctness conditions related to liveness ExprCall(..) | ExprMethodCall(..) | ExprIf(..) | ExprMatch(..) | ExprWhile(..) | ExprLoop(..) | ExprIndex(..) | ExprField(..) | - ExprVstore(..) | ExprVec(..) | ExprTup(..) | - ExprBinary(..) | + ExprVec(..) | ExprTup(..) | ExprBinary(..) | ExprCast(..) | ExprUnary(..) | ExprRet(..) | ExprBreak(..) | ExprAgain(..) | ExprLit(_) | ExprBlock(..) | ExprMac(..) | ExprAddrOf(..) | ExprStruct(..) | ExprRepeat(..) | diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index ef1e0515156..155b69d0a84 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -205,7 +205,7 @@ pub fn opt_deref_kind(t: ty::t) -> Option<deref_kind> { Some(deref_interior(InteriorField(PositionalField(0)))) } - ty::ty_vec(_, Some(_)) => { + ty::ty_vec(_, _) | ty::ty_str => { Some(deref_interior(InteriorElement(element_kind(t)))) } @@ -214,11 +214,12 @@ pub fn opt_deref_kind(t: ty::t) -> Option<deref_kind> { } pub fn deref_kind(tcx: &ty::ctxt, t: ty::t) -> deref_kind { + debug!("deref_kind {}", ty_to_str(tcx, t)); match opt_deref_kind(t) { Some(k) => k, None => { tcx.sess.bug( - format!("deref_cat() invoked on non-derefable type {}", + format!("deref_kind() invoked on non-derefable type {}", ty_to_string(tcx, t)).as_slice()); } } @@ -411,13 +412,6 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> { Some(adjustment) => { match *adjustment { - ty::AutoObject(..) => { - // Implicitly cast a concrete object to trait object. - // Result is an rvalue. - let expr_ty = if_ok!(self.expr_ty_adjusted(expr)); - Ok(self.cat_rvalue_node(expr.id(), expr.span(), expr_ty)) - } - ty::AutoAddEnv(..) => { // Convert a bare fn to a closure by adding NULL env. // Result is an rvalue. @@ -485,7 +479,7 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> { } None => { let base_cmt = if_ok!(self.cat_expr(&**base)); - Ok(self.cat_index(expr, base_cmt, 0)) + Ok(self.cat_index(expr, base_cmt)) } } } @@ -504,7 +498,7 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> { ast::ExprFnBlock(..) | ast::ExprProc(..) | ast::ExprUnboxedFn(..) | ast::ExprRet(..) | ast::ExprUnary(..) | - ast::ExprMethodCall(..) | ast::ExprCast(..) | ast::ExprVstore(..) | + ast::ExprMethodCall(..) | ast::ExprCast(..) | ast::ExprVec(..) | ast::ExprTup(..) | ast::ExprIf(..) | ast::ExprBinary(..) | ast::ExprWhile(..) | ast::ExprBlock(..) | ast::ExprLoop(..) | ast::ExprMatch(..) | @@ -703,7 +697,10 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> { -> cmt { match self.typer.temporary_scope(id) { Some(scope) => { - self.cat_rvalue(id, span, ty::ReScope(scope), expr_ty) + match ty::get(expr_ty).sty { + ty::ty_vec(_, Some(0)) => self.cat_rvalue(id, span, ty::ReStatic, expr_ty), + _ => self.cat_rvalue(id, span, ty::ReScope(scope), expr_ty) + } } None => { self.cat_rvalue(id, span, ty::ReStatic, expr_ty) @@ -751,10 +748,11 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> { implicit: bool) -> cmt { let adjustment = match self.typer.adjustments().borrow().find(&node.id()) { - Some(&ty::AutoObject(..)) => typeck::AutoObject, + Some(adj) if ty::adjust_is_object(adj) => typeck::AutoObject, _ if deref_cnt != 0 => typeck::AutoDeref(deref_cnt), _ => typeck::NoAdjustment }; + let method_call = typeck::MethodCall { expr_id: node.id(), adjustment: adjustment @@ -820,13 +818,9 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> { pub fn cat_index<N:ast_node>(&self, elt: &N, - mut base_cmt: cmt, - derefs: uint) + mut base_cmt: cmt) -> cmt { - //! Creates a cmt for an indexing operation (`[]`); this - //! indexing operation may occurs as part of an - //! AutoBorrowVec, which when converting a `~[]` to an `&[]` - //! effectively takes the address of the 0th element. + //! Creates a cmt for an indexing operation (`[]`). //! //! One subtle aspect of indexing that may not be //! immediately obvious: for anything other than a fixed-length @@ -839,20 +833,9 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> { //! cmt containing both this deref and the indexing, //! presuming that `base_cmt` is not of fixed-length type. //! - //! In the event that a deref is needed, the "deref count" - //! is taken from the parameter `derefs`. See the comment - //! on the def'n of `root_map_key` in borrowck/mod.rs - //! for more details about deref counts; the summary is - //! that `derefs` should be 0 for an explicit indexing - //! operation and N+1 for an indexing that is part of - //! an auto-adjustment, where N is the number of autoderefs - //! in that adjustment. - //! //! # Parameters //! - `elt`: the AST node being indexed //! - `base_cmt`: the cmt of `elt` - //! - `derefs`: the deref number to be used for - //! the implicit index deref, if any (see above) let method_call = typeck::MethodCall::expr(elt.id()); let method_ty = self.typer.node_method_ty(method_call); @@ -865,7 +848,7 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> { } None => { match ty::array_element_ty(base_cmt.ty) { - Some(ref mt) => mt.ty, + Some(ty) => ty, None => { self.tcx().sess.span_bug( elt.span(), @@ -876,30 +859,8 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> { } }; - return match deref_kind(self.tcx(), base_cmt.ty) { - deref_ptr(ptr) => { - // for unique ptrs, we inherit mutability from the - // owning reference. - let m = MutabilityCategory::from_pointer_kind(base_cmt.mutbl, ptr); - - // the deref is explicit in the resulting cmt - let deref_cmt = Rc::new(cmt_ { - id:elt.id(), - span:elt.span(), - cat:cat_deref(base_cmt.clone(), derefs, ptr), - mutbl:m, - ty:element_ty - }); - - interior(elt, deref_cmt, base_cmt.ty, m.inherit(), element_ty) - } - - deref_interior(_) => { - // fixed-length vectors have no deref - let m = base_cmt.mutbl.inherit(); - interior(elt, base_cmt.clone(), base_cmt.ty, m, element_ty) - } - }; + let m = base_cmt.mutbl.inherit(); + return interior(elt, base_cmt.clone(), base_cmt.ty, m, element_ty); fn interior<N: ast_node>(elt: &N, of_cmt: cmt, @@ -917,6 +878,37 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> { } } + // Takes either a vec or a reference to a vec and returns the cmt for the + // underlying vec. + fn deref_vec<N:ast_node>(&self, + elt: &N, + base_cmt: cmt) + -> cmt { + match deref_kind(self.tcx(), base_cmt.ty) { + deref_ptr(ptr) => { + // for unique ptrs, we inherit mutability from the + // owning reference. + let m = MutabilityCategory::from_pointer_kind(base_cmt.mutbl, ptr); + + // the deref is explicit in the resulting cmt + Rc::new(cmt_ { + id:elt.id(), + span:elt.span(), + cat:cat_deref(base_cmt.clone(), 0, ptr), + mutbl:m, + ty: match ty::deref(base_cmt.ty, false) { + Some(mt) => mt.ty, + None => self.tcx().sess.bug("Found non-derefable type") + } + }) + } + + deref_interior(_) => { + base_cmt + } + } + } + pub fn cat_slice_pattern(&self, vec_cmt: cmt, slice_pat: &ast::Pat) @@ -935,7 +927,7 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> { let (slice_mutbl, slice_r) = vec_slice_info(self.tcx(), slice_pat, slice_ty); - let cmt_slice = self.cat_index(slice_pat, vec_cmt, 0); + let cmt_slice = self.cat_index(slice_pat, self.deref_vec(slice_pat, vec_cmt)); return Ok((cmt_slice, slice_mutbl, slice_r)); fn vec_slice_info(tcx: &ty::ctxt, @@ -951,7 +943,7 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> { match ty::get(slice_ty).sty { ty::ty_rptr(r, ref mt) => match ty::get(mt.ty).sty { - ty::ty_vec(slice_mt, None) => (slice_mt.mutbl, r), + ty::ty_vec(_, None) => (mt.mutbl, r), _ => vec_slice_info(tcx, pat, mt.ty), }, @@ -1143,7 +1135,7 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> { } ast::PatVec(ref before, slice, ref after) => { - let elt_cmt = self.cat_index(pat, cmt, 0); + let elt_cmt = self.cat_index(pat, self.deref_vec(pat, cmt)); for before_pat in before.iter() { if_ok!(self.cat_pattern(elt_cmt.clone(), &**before_pat, |x,y,z| op(x,y,z))); diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 5f5a324857a..1a884eaea21 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -740,10 +740,6 @@ fn resolve_local(visitor: &mut RegionResolutionVisitor, visitor, &*field.expr, blk_id); } } - ast::ExprVstore(ref subexpr, _) => { - visitor.region_maps.record_rvalue_scope(subexpr.id, blk_id); - record_rvalue_scope_if_borrow_expr(visitor, &**subexpr, blk_id); - } ast::ExprVec(ref subexprs) | ast::ExprTup(ref subexprs) => { for subexpr in subexprs.iter() { diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs index d8bdeb0abf6..4a26d4f8002 100644 --- a/src/librustc/middle/trans/_match.rs +++ b/src/librustc/middle/trans/_match.rs @@ -289,8 +289,8 @@ fn trans_opt<'a>(mut bcx: &'a Block<'a>, o: &Opt) -> opt_result<'a> { return adt::trans_case(bcx, &**repr, disr_val); } range(ref l1, ref l2) => { - let (l1, _) = consts::const_expr(ccx, &**l1, true); - let (l2, _) = consts::const_expr(ccx, &**l2, true); + let (l1, _, _) = consts::const_expr(ccx, &**l1, true); + let (l2, _, _) = consts::const_expr(ccx, &**l2, true); return range_result(Result::new(bcx, l1), Result::new(bcx, l2)); } vec_len(n, vec_len_eq, _) => { @@ -692,7 +692,7 @@ fn extract_vec_elems<'a>( let vec_datum = match_datum(bcx, val, pat_id); let (base, len) = vec_datum.get_vec_base_and_len(bcx); let vec_ty = node_id_type(bcx, pat_id); - let vt = tvec::vec_types(bcx, ty::sequence_element_type(bcx.tcx(), vec_ty)); + let vt = tvec::vec_types(bcx, ty::sequence_element_type(bcx.tcx(), ty::type_content(vec_ty))); let mut elems = Vec::from_fn(elem_count, |i| { match slice { @@ -863,7 +863,7 @@ fn compare_values<'a>( match ty::get(rhs_t).sty { ty::ty_rptr(_, mt) => match ty::get(mt.ty).sty { ty::ty_str => compare_str(cx, lhs, rhs, rhs_t), - ty::ty_vec(mt, _) => match ty::get(mt.ty).sty { + ty::ty_vec(ty, _) => match ty::get(ty).sty { ty::ty_uint(ast::TyU8) => { // NOTE: cast &[u8] to &str and abuse the str_eq lang item, // which calls memcmp(). diff --git a/src/librustc/middle/trans/adt.rs b/src/librustc/middle/trans/adt.rs index 57f8f8d6692..3bcefe7ec9d 100644 --- a/src/librustc/middle/trans/adt.rs +++ b/src/librustc/middle/trans/adt.rs @@ -127,8 +127,11 @@ pub enum Repr { /// For structs, and struct-like parts of anything fancier. pub struct Struct { - pub size: u64, - pub align: u64, + // If the struct is DST, then we will not know its size. We must be careful + // never to use such a struct when a fixed size is required (e.g., stack + // allocation). + pub size: Option<u64>, + pub align: Option<u64>, pub packed: bool, pub fields: Vec<ty::t> } @@ -265,7 +268,8 @@ fn represent_type_uncached(cx: &CrateContext, t: ty::t) -> Repr { mk_struct(cx, ftys.as_slice(), false) }).collect(), dtor); } - _ => cx.sess().bug("adt::represent_type called on non-ADT type") + _ => cx.sess().bug(format!("adt::represent_type called on non-ADT type: {}", + ty_to_str(cx.tcx(), t)).as_slice()) } } @@ -284,8 +288,9 @@ pub enum PointerField { impl Case { fn is_zerolen(&self, cx: &CrateContext) -> bool { - mk_struct(cx, self.tys.as_slice(), false).size == 0 + mk_struct(cx, self.tys.as_slice(), false).size.unwrap() == 0 } + fn find_ptr(&self) -> Option<PointerField> { use back::abi::{fn_field_code, slice_elt_base, trt_field_box}; @@ -342,13 +347,22 @@ fn get_cases(tcx: &ty::ctxt, def_id: ast::DefId, substs: &subst::Substs) -> Vec< } fn mk_struct(cx: &CrateContext, tys: &[ty::t], packed: bool) -> Struct { - let lltys = tys.iter().map(|&ty| type_of::sizing_type_of(cx, ty)).collect::<Vec<_>>(); - let llty_rec = Type::struct_(cx, lltys.as_slice(), packed); - Struct { - size: machine::llsize_of_alloc(cx, llty_rec) /*bad*/as u64, - align: machine::llalign_of_min(cx, llty_rec) /*bad*/as u64, - packed: packed, - fields: Vec::from_slice(tys), + if tys.iter().all(|&ty| ty::type_is_sized(cx.tcx(), ty)) { + let lltys = tys.iter().map(|&ty| type_of::sizing_type_of(cx, ty)).collect::<Vec<_>>(); + let llty_rec = Type::struct_(cx, lltys.as_slice(), packed); + Struct { + size: Some(machine::llsize_of_alloc(cx, llty_rec) /*bad*/as u64), + align: Some(machine::llalign_of_min(cx, llty_rec) /*bad*/as u64), + packed: packed, + fields: Vec::from_slice(tys), + } + } else { + Struct { + size: None, + align: None, + packed: packed, + fields: Vec::from_slice(tys), + } } } @@ -496,9 +510,9 @@ fn generic_type_of(cx: &CrateContext, r: &Repr, name: Option<&str>, sizing: bool // of the size. // // FIXME #10604: this breaks when vector types are present. - let size = sts.iter().map(|st| st.size).max().unwrap(); - let most_aligned = sts.iter().max_by(|st| st.align).unwrap(); - let align = most_aligned.align; + let size = sts.iter().map(|st| st.size.unwrap()).max().unwrap(); + let most_aligned = sts.iter().max_by(|st| st.align.unwrap()).unwrap(); + let align = most_aligned.align.unwrap(); let discr_ty = ll_inttype(cx, ity); let discr_size = machine::llsize_of_alloc(cx, discr_ty) as u64; let align_units = (size + align - 1) / align - 1; @@ -892,12 +906,12 @@ pub fn trans_const(ccx: &CrateContext, r: &Repr, discr: Disr, } General(ity, ref cases, _) => { let case = cases.get(discr as uint); - let max_sz = cases.iter().map(|x| x.size).max().unwrap(); + let max_sz = cases.iter().map(|x| x.size.unwrap()).max().unwrap(); let lldiscr = C_integral(ll_inttype(ccx, ity), discr as u64, true); let contents = build_const_struct(ccx, case, (vec!(lldiscr)).append(vals).as_slice()); - C_struct(ccx, contents.append([padding(ccx, max_sz - case.size)]).as_slice(), + C_struct(ccx, contents.append([padding(ccx, max_sz - case.size.unwrap())]).as_slice(), false) } Univariant(ref st, _dro) => { @@ -988,9 +1002,9 @@ fn build_const_struct(ccx: &CrateContext, st: &Struct, vals: &[ValueRef]) offset += machine::llsize_of_alloc(ccx, val_ty(val)) as u64; } - assert!(offset <= st.size); - if offset != st.size { - cfields.push(padding(ccx, st.size - offset)); + assert!(offset <= st.size.unwrap()); + if offset != st.size.unwrap() { + cfields.push(padding(ccx, st.size.unwrap() - offset)); } cfields diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index 7c2f251bd16..b27afdb864b 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -195,16 +195,6 @@ pub fn decl_fn(ccx: &CrateContext, name: &str, cc: llvm::CallConv, llvm::NoReturnAttribute as uint64_t) } } - // `~` pointer return values never alias because ownership is transferred - ty::ty_uniq(t) - => match ty::get(t).sty { - ty::ty_vec(_, None) | ty::ty_str | ty::ty_trait(..) => {} - _ => unsafe { - llvm::LLVMAddReturnAttribute(llfn, - lib::llvm::NoAliasAttribute as c_uint, - lib::llvm::NoReturnAttribute as uint64_t); - } - }, _ => {} } @@ -965,14 +955,23 @@ pub fn invoke<'a>( llfn: ValueRef, llargs: Vec<ValueRef> , fn_ty: ty::t, - call_info: Option<NodeInfo>) + call_info: Option<NodeInfo>, + // FIXME(15064) is_lang_item is a horrible hack, please remove it + // at the soonest opportunity. + is_lang_item: bool) -> (ValueRef, &'a Block<'a>) { let _icx = push_ctxt("invoke_"); if bcx.unreachable.get() { return (C_null(Type::i8(bcx.ccx())), bcx); } - let attributes = get_fn_llvm_attributes(bcx.ccx(), fn_ty); + // FIXME(15064) Lang item methods may (in the reflect case) not have proper + // types, so doing an attribute lookup will fail. + let attributes = if is_lang_item { + Vec::new() + } else { + get_fn_llvm_attributes(bcx.ccx(), fn_ty) + }; match bcx.opt_node_id { None => { @@ -2311,9 +2310,7 @@ pub fn get_fn_llvm_attributes(ccx: &CrateContext, fn_ty: ty::t) match ty::get(ret_ty).sty { // `~` pointer return values never alias because ownership // is transferred - ty::ty_uniq(it) if match ty::get(it).sty { - ty::ty_str | ty::ty_vec(..) | ty::ty_trait(..) => true, _ => false - } => {} + ty::ty_uniq(it) if !ty::type_is_sized(ccx.tcx(), it) => {} ty::ty_uniq(_) => { attrs.ret(llvm::NoAliasAttribute); } @@ -2324,9 +2321,7 @@ pub fn get_fn_llvm_attributes(ccx: &CrateContext, fn_ty: ty::t) match ty::get(ret_ty).sty { // These are not really pointers but pairs, (pointer, len) ty::ty_uniq(it) | - ty::ty_rptr(_, ty::mt { ty: it, .. }) if match ty::get(it).sty { - ty::ty_str | ty::ty_vec(..) | ty::ty_trait(..) => true, _ => false - } => {} + ty::ty_rptr(_, ty::mt { ty: it, .. }) if !ty::type_is_sized(ccx.tcx(), it) => {} ty::ty_uniq(inner) | ty::ty_rptr(_, ty::mt { ty: inner, .. }) => { let llret_sz = llsize_of_real(ccx, type_of::type_of(ccx, inner)); attrs.ret(llvm::DereferenceableAttribute(llret_sz)); @@ -2593,7 +2588,7 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef { // We need the translated value here, because for enums the // LLVM type is not fully determined by the Rust type. - let (v, inlineable) = consts::const_expr(ccx, &**expr, is_local); + let (v, inlineable, _) = consts::const_expr(ccx, &**expr, is_local); ccx.const_values.borrow_mut().insert(id, v); let mut inlineable = inlineable; diff --git a/src/librustc/middle/trans/callee.rs b/src/librustc/middle/trans/callee.rs index d50b30c7545..1283cc19528 100644 --- a/src/librustc/middle/trans/callee.rs +++ b/src/librustc/middle/trans/callee.rs @@ -51,6 +51,7 @@ use middle::typeck; use middle::typeck::coherence::make_substs_for_receiver_types; use middle::typeck::MethodCall; use util::ppaux::Repr; +use util::ppaux::ty_to_string; use std::gc::Gc; use syntax::abi as synabi; @@ -853,7 +854,8 @@ pub fn trans_call_inner<'a>( llfn, llargs, callee_ty, - call_info); + call_info, + dest.is_none()); bcx = b; llresult = llret; @@ -1194,6 +1196,8 @@ pub fn trans_arg_datum<'a>( let llformal_arg_ty = type_of::type_of_explicit_arg(ccx, formal_arg_ty); debug!("casting actual type ({}) to match formal ({})", bcx.val_to_string(val), bcx.llty_str(llformal_arg_ty)); + debug!("Rust types: {}; {}", ty_to_string(bcx.tcx(), arg_datum_ty), + ty_to_string(bcx.tcx(), formal_arg_ty)); val = PointerCast(bcx, val, llformal_arg_ty); } } diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs index fefd3e32651..f0876442ff5 100644 --- a/src/librustc/middle/trans/common.rs +++ b/src/librustc/middle/trans/common.rs @@ -65,12 +65,13 @@ fn type_is_newtype_immediate(ccx: &CrateContext, ty: ty::t) -> bool { pub fn type_is_immediate(ccx: &CrateContext, ty: ty::t) -> bool { use middle::trans::machine::llsize_of_alloc; use middle::trans::type_of::sizing_type_of; + let tcx = ccx.tcx(); let simple = ty::type_is_scalar(ty) || ty::type_is_boxed(ty) || ty::type_is_unique(ty) || ty::type_is_region_ptr(ty) || type_is_newtype_immediate(ccx, ty) || ty::type_is_bot(ty) || ty::type_is_simd(tcx, ty); - if simple && !ty::type_is_trait(ty) { + if simple && !ty::type_is_fat_ptr(tcx, ty) { return true; } match ty::get(ty).sty { diff --git a/src/librustc/middle/trans/consts.rs b/src/librustc/middle/trans/consts.rs index 07f0dbaf73f..e65a10b3bb2 100644 --- a/src/librustc/middle/trans/consts.rs +++ b/src/librustc/middle/trans/consts.rs @@ -11,11 +11,9 @@ use back::abi; use llvm; -use llvm::{ConstFCmp, ConstICmp, SetLinkage, PrivateLinkage, ValueRef, Bool, True, - False}; +use llvm::{ConstFCmp, ConstICmp, SetLinkage, PrivateLinkage, ValueRef, Bool, True, False}; use llvm::{IntEQ, IntNE, IntUGT, IntUGE, IntULT, IntULE, IntSGT, IntSGE, IntSLT, IntSLE, RealOEQ, RealOGT, RealOGE, RealOLT, RealOLE, RealONE}; - use metadata::csearch; use middle::const_eval; use middle::def; @@ -98,12 +96,17 @@ pub fn const_ptrcast(cx: &CrateContext, a: ValueRef, t: Type) -> ValueRef { } } +// Helper function because we don't have tuple-swizzling. +fn first_two<R, S, T>((a, b, _): (R, S, T)) -> (R, S) { + (a, b) +} + fn const_vec(cx: &CrateContext, e: &ast::Expr, es: &[Gc<ast::Expr>], is_local: bool) -> (ValueRef, Type, bool) { let vec_ty = ty::expr_ty(cx.tcx(), e); let unit_ty = ty::sequence_element_type(cx.tcx(), vec_ty); let llunitty = type_of::type_of(cx, unit_ty); - let (vs, inlineable) = vec::unzip(es.iter().map(|e| const_expr(cx, &**e, is_local))); + let (vs, inlineable) = vec::unzip(es.iter().map(|e| first_two(const_expr(cx, &**e, is_local)))); // If the vector contains enums, an LLVM array won't work. let v = if vs.iter().any(|vi| val_ty(*vi) != llunitty) { C_struct(cx, vs.as_slice(), false) @@ -119,7 +122,8 @@ pub fn const_addr_of(cx: &CrateContext, cv: ValueRef) -> ValueRef { llvm::LLVMAddGlobal(cx.llmod, val_ty(cv).to_ref(), name) }); llvm::LLVMSetInitializer(gv, cv); - llvm::LLVMSetGlobalConstant(gv, True); + llvm::LLVMSetGlobalConstant(gv, + if mutbl == ast::MutImmutable {True} else {False}); SetLinkage(gv, PrivateLinkage); gv } @@ -131,7 +135,6 @@ fn const_deref_ptr(cx: &CrateContext, v: ValueRef) -> ValueRef { None => v }; unsafe { - assert_eq!(llvm::LLVMIsGlobalConstant(v), True); llvm::LLVMGetInitializer(v) } } @@ -146,25 +149,25 @@ fn const_deref(cx: &CrateContext, v: ValueRef, t: ty::t, explicit: bool) -> (ValueRef, ty::t) { match ty::deref(t, explicit) { Some(ref mt) => { - assert!(mt.mutbl != ast::MutMutable); - let dv = match ty::get(t).sty { + match ty::get(t).sty { ty::ty_ptr(mt) | ty::ty_rptr(_, mt) => { - match ty::get(mt.ty).sty { - ty::ty_vec(_, None) | ty::ty_str | ty::ty_trait(..) => { - cx.sess().bug("unexpected unsized type") - } - _ => const_deref_ptr(cx, v), + if ty::type_is_sized(cx.tcx(), mt.ty) { + (const_deref_ptr(cx, v), mt.ty) + } else { + // Derefing a fat pointer does not change the representation, + // just the type to ty_open. + (v, ty::mk_open(cx.tcx(), mt.ty)) } } ty::ty_enum(..) | ty::ty_struct(..) => { - const_deref_newtype(cx, v, t) + assert!(mt.mutbl != ast::MutMutable); + (const_deref_newtype(cx, v, t), mt.ty) } _ => { cx.sess().bug(format!("unexpected dereferenceable type {}", ty_to_string(cx.tcx(), t)).as_slice()) } - }; - (dv, mt.ty) + } } None => { cx.sess().bug(format!("can't dereference const of type {}", @@ -193,12 +196,12 @@ pub fn get_const_val(cx: &CrateContext, !cx.non_inlineable_statics.borrow().contains(&def_id.node)) } -pub fn const_expr(cx: &CrateContext, e: &ast::Expr, is_local: bool) -> (ValueRef, bool) { +pub fn const_expr(cx: &CrateContext, e: &ast::Expr, is_local: bool) -> (ValueRef, bool, ty::t) { let (llconst, inlineable) = const_expr_unadjusted(cx, e, is_local); let mut llconst = llconst; let mut inlineable = inlineable; let ety = ty::expr_ty(cx.tcx(), e); - let ety_adjusted = ty::expr_ty_adjusted(cx.tcx(), e); + let mut ety_adjusted = ty::expr_ty_adjusted(cx.tcx(), e); let opt_adj = cx.tcx.adjustments.borrow().find_copy(&e.id); match opt_adj { None => { } @@ -219,51 +222,64 @@ pub fn const_expr(cx: &CrateContext, e: &ast::Expr, is_local: bool) -> (ValueRef format!("unexpected static function: {:?}", store).as_slice()) } - ty::AutoObject(..) => { - cx.sess() - .span_unimpl(e.span, - "unimplemented const coercion to trait \ - object"); - } ty::AutoDerefRef(ref adj) => { let mut ty = ety; - let mut maybe_ptr = None; - for _ in range(0, adj.autoderefs) { + // Save the last autoderef in case we can avoid it. + for _ in range(0, adj.autoderefs-1) { let (dv, dt) = const_deref(cx, llconst, ty, false); - maybe_ptr = Some(llconst); llconst = dv; ty = dt; } match adj.autoref { - None => { } + None => { + let (dv, dt) = const_deref(cx, llconst, ty, false); + 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; + } Some(ref autoref) => { - // Don't copy data to do a deref+ref. - let llptr = match maybe_ptr { - Some(ptr) => ptr, - None => { - inlineable = false; - const_addr_of(cx, llconst) - } - }; match *autoref { - ty::AutoUnsafe(m) | - ty::AutoPtr(ty::ReStatic, m) => { - assert!(m != ast::MutMutable); - llconst = llptr; + ty::AutoUnsafe(_) | + ty::AutoPtr(ty::ReStatic, _, None) => { + // Don't copy data to do a deref+ref + // (i.e., skip the last auto-deref). + if adj.autoderefs == 0 { + inlineable = false; + llconst = const_addr_of(cx, llconst, ast::MutImmutable); + } } - ty::AutoBorrowVec(ty::ReStatic, m) => { - assert!(m != ast::MutMutable); - assert_eq!(abi::slice_elt_base, 0); - assert_eq!(abi::slice_elt_len, 1); + ty::AutoPtr(ty::ReStatic, _, Some(box ty::AutoUnsize(..))) => { + if adj.autoderefs > 0 { + // 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. + let (_, dt) = const_deref(cx, llconst, ty, false); + ty = dt; + } + match ty::get(ty).sty { - ty::ty_vec(_, Some(len)) => { + ty::ty_vec(unit_ty, Some(len)) => { + inlineable = false; + let llunitty = type_of::type_of(cx, unit_ty); + let llptr = const_ptrcast(cx, llconst, llunitty); + assert_eq!(abi::slice_elt_base, 0); + assert_eq!(abi::slice_elt_len, 1); llconst = C_struct(cx, [ llptr, C_uint(cx, len) ], false); } - _ => {} + _ => cx.sess().span_bug(e.span, + format!("unimplemented type in const unsize: {}", + ty_to_str(cx.tcx(), ty)).as_slice()) } } _ => { @@ -294,7 +310,7 @@ pub fn const_expr(cx: &CrateContext, e: &ast::Expr, is_local: bool) -> (ValueRef e.repr(cx.tcx()), ty_to_string(cx.tcx(), ety), csize, tsize).as_slice()); } - (llconst, inlineable) + (llconst, inlineable, ety_adjusted) } // the bool returned is whether this expression can be inlined into other crates @@ -302,7 +318,7 @@ pub fn const_expr(cx: &CrateContext, e: &ast::Expr, is_local: bool) -> (ValueRef fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr, is_local: bool) -> (ValueRef, bool) { let map_list = |exprs: &[Gc<ast::Expr>]| { - exprs.iter().map(|e| const_expr(cx, &**e, is_local)) + exprs.iter().map(|e| first_two(const_expr(cx, &**e, is_local))) .fold((Vec::new(), true), |(l, all_inlineable), (val, inlineable)| { (l.append_one(val), all_inlineable && inlineable) @@ -315,8 +331,8 @@ fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr, (consts::const_lit(cx, e, (**lit).clone()), true) } ast::ExprBinary(b, ref e1, ref e2) => { - let (te1, _) = const_expr(cx, &**e1, is_local); - let (te2, _) = const_expr(cx, &**e2, is_local); + let (te1, _, _) = const_expr(cx, &**e1, is_local); + let (te2, _, _) = const_expr(cx, &**e2, is_local); let te2 = base::cast_shift_const_rhs(b, te1, te2); @@ -397,7 +413,7 @@ fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr, }, true) }, ast::ExprUnary(u, ref e) => { - let (te, _) = const_expr(cx, &**e, is_local); + let (te, _, _) = const_expr(cx, &**e, is_local); let ty = ty::expr_ty(cx.tcx(), &**e); let is_float = ty::type_is_fp(ty); return (match u { @@ -413,9 +429,8 @@ fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr, }, true) } ast::ExprField(ref base, field, _) => { - let bt = ty::expr_ty_adjusted(cx.tcx(), &**base); + let (bv, inlineable, bt) = const_expr(cx, &**base, is_local); let brepr = adt::represent_type(cx, bt); - let (bv, inlineable) = const_expr(cx, &**base, is_local); expr::with_field_tys(cx.tcx(), bt, None, |discr, field_tys| { let ix = ty::field_idx_strict(cx.tcx(), field.node.name, field_tys); (adt::const_get_field(cx, &*brepr, bv, discr, ix), inlineable) @@ -423,8 +438,7 @@ fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr, } ast::ExprIndex(ref base, ref index) => { - let bt = ty::expr_ty_adjusted(cx.tcx(), &**base); - let (bv, inlineable) = const_expr(cx, &**base, is_local); + let (bv, inlineable, bt) = const_expr(cx, &**base, is_local); let iv = match const_eval::eval_const_expr(cx.tcx(), &**index) { const_eval::const_int(i) => i as u64, const_eval::const_uint(u) => u, @@ -433,16 +447,29 @@ fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr, }; let (arr, len) = match ty::get(bt).sty { ty::ty_vec(_, Some(u)) => (bv, C_uint(cx, u)), - ty::ty_rptr(_, mt) => match ty::get(mt.ty).sty { + ty::ty_open(ty) => match ty::get(ty).sty { ty::ty_vec(_, None) | ty::ty_str => { let e1 = const_get_elt(cx, bv, [0]); (const_deref_ptr(cx, e1), const_get_elt(cx, bv, [1])) }, _ => cx.sess().span_bug(base.span, - "index-expr base must be a vector or string type") + format!("index-expr base must be a vector \ + or string type, found {}", + ty_to_str(cx.tcx(), bt)).as_slice()) + }, + ty::ty_rptr(_, mt) => match ty::get(mt.ty).sty { + ty::ty_vec(_, Some(u)) => { + (const_deref_ptr(cx, bv), C_uint(cx, u)) + }, + _ => cx.sess().span_bug(base.span, + format!("index-expr base must be a vector \ + or string type, found {}", + ty_to_str(cx.tcx(), bt)).as_slice()) }, _ => cx.sess().span_bug(base.span, - "index-expr base must be a vector or string type") + format!("index-expr base must be a vector \ + or string type, found {}", + ty_to_str(cx.tcx(), bt)).as_slice()) }; let len = llvm::LLVMConstIntGetZExtValue(len) as u64; @@ -467,10 +494,9 @@ fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr, ast::ExprCast(ref base, _) => { let ety = ty::expr_ty(cx.tcx(), e); let llty = type_of::type_of(cx, ety); - let basety = ty::expr_ty(cx.tcx(), &**base); - let (v, inlineable) = const_expr(cx, &**base, is_local); - return (match (expr::cast_type_kind(basety), - expr::cast_type_kind(ety)) { + let (v, inlineable, basety) = const_expr(cx, &**base, is_local); + return (match (expr::cast_type_kind(cx.tcx(), basety), + expr::cast_type_kind(cx.tcx(), ety)) { (expr::cast_integral, expr::cast_integral) => { let s = ty::type_is_signed(basety) as Bool; @@ -494,7 +520,7 @@ fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr, let repr = adt::represent_type(cx, basety); let discr = adt::const_get_discrim(cx, &*repr, v); let iv = C_integral(cx.int_type, discr, false); - let ety_cast = expr::cast_type_kind(ety); + let ety_cast = expr::cast_type_kind(cx.tcx(), ety); match ety_cast { expr::cast_integral => { let s = ty::type_is_signed(ety) as Bool; @@ -516,9 +542,9 @@ fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr, } }, inlineable) } - ast::ExprAddrOf(ast::MutImmutable, ref sub) => { - let (e, _) = const_expr(cx, &**sub, is_local); - (const_addr_of(cx, e), false) + ast::ExprAddrOf(mutbl, ref sub) => { + let (e, _, _) = const_expr(cx, &**sub, is_local); + (const_addr_of(cx, e, mutbl), false) } ast::ExprTup(ref es) => { let ety = ty::expr_ty(cx.tcx(), e); @@ -540,10 +566,10 @@ fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr, let (cs, inlineable) = vec::unzip(field_tys.iter().enumerate() .map(|(ix, &field_ty)| { match fs.iter().find(|f| field_ty.ident.name == f.ident.node.name) { - Some(ref f) => const_expr(cx, &*f.expr, is_local), + Some(ref f) => first_two(const_expr(cx, &*f.expr, is_local)), None => { match base_val { - Some((bv, inlineable)) => { + Some((bv, inlineable, _)) => { (adt::const_get_field(cx, &*repr, bv, discr, ix), inlineable) } @@ -563,34 +589,6 @@ fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr, is_local); (v, inlineable) } - ast::ExprVstore(ref sub, store @ ast::ExprVstoreSlice) | - ast::ExprVstore(ref sub, store @ ast::ExprVstoreMutSlice) => { - match sub.node { - ast::ExprLit(ref lit) => { - match lit.node { - ast::LitStr(..) => { const_expr(cx, &**sub, is_local) } - _ => { cx.sess().span_bug(e.span, "bad const-slice lit") } - } - } - ast::ExprVec(ref es) => { - let (cv, llunitty, _) = const_vec(cx, - e, - es.as_slice(), - is_local); - let llty = val_ty(cv); - let gv = "const".with_c_str(|name| { - llvm::LLVMAddGlobal(cx.llmod, llty.to_ref(), name) - }); - llvm::LLVMSetInitializer(gv, cv); - llvm::LLVMSetGlobalConstant(gv, - if store == ast::ExprVstoreMutSlice { False } else { True }); - SetLinkage(gv, PrivateLinkage); - let p = const_ptrcast(cx, gv, llunitty); - (C_struct(cx, [p, C_uint(cx, es.len())], false), false) - } - _ => cx.sess().span_bug(e.span, "bad const-slice expr") - } - } ast::ExprRepeat(ref elem, ref count) => { let vec_ty = ty::expr_ty(cx.tcx(), e); let unit_ty = ty::sequence_element_type(cx.tcx(), vec_ty); @@ -669,10 +667,10 @@ fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr, _ => cx.sess().span_bug(e.span, "expected a struct or variant def") } } - ast::ExprParen(ref e) => { const_expr(cx, &**e, is_local) } + ast::ExprParen(ref e) => first_two(const_expr(cx, &**e, is_local)), ast::ExprBlock(ref block) => { match block.expr { - Some(ref expr) => const_expr(cx, &**expr, is_local), + Some(ref expr) => first_two(const_expr(cx, &**expr, is_local)), None => (C_nil(cx), true) } } diff --git a/src/librustc/middle/trans/datum.rs b/src/librustc/middle/trans/datum.rs index f69a8af9c08..b7803d404b5 100644 --- a/src/librustc/middle/trans/datum.rs +++ b/src/librustc/middle/trans/datum.rs @@ -450,6 +450,8 @@ impl Datum<Expr> { name: &str, expr_id: ast::NodeId) -> DatumBlock<'a, Lvalue> { + assert!(ty::lltype_is_sized(bcx.tcx(), self.ty), + "Trying to convert unsized value to lval"); self.match_kind( |l| DatumBlock::new(bcx, l), |r| { @@ -504,12 +506,28 @@ impl Datum<Lvalue> { self.val } - pub fn get_element(&self, - ty: ty::t, - gep: |ValueRef| -> ValueRef) - -> Datum<Lvalue> { + // Extracts a component of a compound data structure (e.g., a field from a + // struct). Note that if self is an opened, unsized type then the returned + // datum may also be unsized _without the size information_. It is the + // callers responsibility to package the result in some way to make a valid + // datum in that case (e.g., by making a fat pointer or opened pair). + pub fn get_element<'a>(&self, + bcx: &'a Block<'a>, + ty: ty::t, + gep: |ValueRef| -> ValueRef) + -> Datum<Lvalue> { + let val = match ty::get(self.ty).sty { + _ if ty::type_is_sized(bcx.tcx(), self.ty) => gep(self.val), + ty::ty_open(_) => { + let base = Load(bcx, expr::get_dataptr(bcx, self.val)); + gep(base) + } + _ => bcx.tcx().sess.bug( + format!("Unexpected unsized type in get_element: {}", + bcx.ty_to_str(self.ty)).as_slice()) + }; Datum { - val: gep(self.val), + val: val, kind: Lvalue, ty: ty, } diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs index db674b4028f..31b31224464 100644 --- a/src/librustc/middle/trans/debuginfo.rs +++ b/src/librustc/middle/trans/debuginfo.rs @@ -402,7 +402,7 @@ impl TypeMap { let inner_type_id = self.get_unique_type_id_as_string(inner_type_id); unique_type_id.push_str(inner_type_id.as_slice()); }, - ty::ty_vec(ty::mt { ty: inner_type, .. }, optional_length) => { + ty::ty_vec(inner_type, optional_length) => { match optional_length { Some(len) => { unique_type_id.push_str(format!("[{}]", len).as_slice()); @@ -595,18 +595,6 @@ impl TypeMap { UniqueTypeId(interner_key) } - fn get_unique_type_id_of_heap_vec_box(&mut self, - cx: &CrateContext, - element_type: ty::t) - -> UniqueTypeId { - let element_type_id = self.get_unique_type_id_of_type(cx, element_type); - let heap_vec_box_type_id = format!("{{HEAP_VEC_BOX<{}>}}", - self.get_unique_type_id_as_string(element_type_id) - .as_slice()); - let interner_key = self.unique_id_interner.intern(Rc::new(heap_vec_box_type_id)); - UniqueTypeId(interner_key) - } - fn get_unique_type_id_of_gc_box(&mut self, cx: &CrateContext, element_type: ty::t) @@ -2811,26 +2799,13 @@ fn subroutine_type_metadata(cx: &CrateContext, } fn trait_pointer_metadata(cx: &CrateContext, - // trait_pointer_type must be the type of the fat - // pointer to the concrete trait object - trait_pointer_type: ty::t, + trait_object_type: ty::t, unique_type_id: UniqueTypeId) -> DIType { // The implementation provided here is a stub. It makes sure that the trait // type is assigned the correct name, size, namespace, and source location. // But it does not describe the trait's methods. - let trait_object_type = match ty::get(trait_pointer_type).sty { - ty::ty_uniq(pointee_type) => pointee_type, - ty::ty_rptr(_, ty::mt { ty, .. }) => ty, - _ => { - let pp_type_name = ppaux::ty_to_string(cx.tcx(), trait_pointer_type); - cx.sess().bug(format!("debuginfo: Unexpected trait-pointer type in \ - trait_pointer_metadata(): {}", - pp_type_name.as_slice()).as_slice()); - } - }; - let def_id = match ty::get(trait_object_type).sty { ty::ty_trait(box ty::TyTrait { def_id, .. }) => def_id, _ => { @@ -2842,11 +2817,11 @@ fn trait_pointer_metadata(cx: &CrateContext, }; let trait_pointer_type_name = - compute_debuginfo_type_name(cx, trait_pointer_type, false); + compute_debuginfo_type_name(cx, trait_object_type, false); let (containing_scope, _) = get_namespace_and_span_for_item(cx, def_id); - let trait_pointer_llvm_type = type_of::type_of(cx, trait_pointer_type); + let trait_llvm_type = type_of::type_of(cx, trait_object_type); composite_type_metadata(cx, trait_pointer_llvm_type, @@ -2914,56 +2889,32 @@ fn type_metadata(cx: &CrateContext, ty::ty_box(pointee_type) => { at_box_metadata(cx, t, pointee_type, unique_type_id) } - ty::ty_vec(ref mt, Some(len)) => { - fixed_vec_metadata(cx, unique_type_id, mt.ty, len, usage_site_span) + ty::ty_vec(typ, Some(len)) => { + fixed_vec_metadata(cx, unique_type_id, typ, len, usage_site_span) } - ty::ty_uniq(pointee_type) => { - match ty::get(pointee_type).sty { - ty::ty_vec(ref mt, None) => { - let vec_metadata = vec_slice_metadata(cx, t, mt.ty, usage_site_span); - pointer_type_metadata(cx, t, vec_metadata) - } - ty::ty_str => { - let i8_t = ty::mk_i8(); - let vec_metadata = vec_slice_metadata(cx, t, i8_t, usage_site_span); - pointer_type_metadata(cx, t, vec_metadata) - } - ty::ty_trait(..) => { - MetadataCreationResult::new( + // FIXME Can we do better than this for unsized vec/str fields? + ty::ty_vec(typ, None) => fixed_vec_metadata(cx, unique_type_id, typ, 0, usage_site_span), + ty::ty_str => fixed_vec_metadata(cx, unique_type_id, ty::mk_i8(), 0, usage_site_span), + ty::ty_trait(..) => { + MetadataCreationResult::new( trait_pointer_metadata(cx, t, unique_type_id), - false) - } - _ => { - let pointee_metadata = type_metadata(cx, - pointee_type, - usage_site_span); - match debug_context(cx).type_map - .borrow() - .find_metadata_for_unique_id(unique_type_id) { - Some(metadata) => return metadata, - None => { /* proceed normally */ } - }; - - MetadataCreationResult::new(pointer_type_metadata(cx, t, pointee_metadata), - false) - } - } + false) } - ty::ty_ptr(ref mt) | ty::ty_rptr(_, ref mt) => { - match ty::get(mt.ty).sty { - ty::ty_vec(ref mt, None) => { - vec_slice_metadata(cx, t, mt.ty, unique_type_id, usage_site_span) + ty::ty_uniq(ty) | ty::ty_ptr(ty::mt{ty, ..}) | ty::ty_rptr(_, ty::mt{ty, ..}) => { + match ty::get(ty).sty { + ty::ty_vec(typ, None) => { + vec_slice_metadata(cx, t, typ, unique_type_id, usage_site_span) } ty::ty_str => { vec_slice_metadata(cx, t, ty::mk_u8(), unique_type_id, usage_site_span) } ty::ty_trait(..) => { MetadataCreationResult::new( - trait_pointer_metadata(cx, t, unique_type_id), + trait_pointer_metadata(cx, ty, unique_type_id), false) } _ => { - let pointee = type_metadata(cx, mt.ty, usage_site_span); + let pointee_metadata = type_metadata(cx, ty, usage_site_span); match debug_context(cx).type_map .borrow() @@ -2972,7 +2923,8 @@ fn type_metadata(cx: &CrateContext, None => { /* proceed normally */ } }; - MetadataCreationResult::new(pointer_type_metadata(cx, t, pointee), false) + MetadataCreationResult::new(pointer_type_metadata(cx, t, pointee_metadata), + false) } } } @@ -3471,7 +3423,6 @@ fn populate_scope_map(cx: &CrateContext, ast::ExprAgain(_) | ast::ExprPath(_) => {} - ast::ExprVstore(ref sub_exp, _) | ast::ExprCast(ref sub_exp, _) | ast::ExprAddrOf(_, ref sub_exp) | ast::ExprField(ref sub_exp, _, _) | diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index ead90dbe36b..657cd72c255 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -40,6 +40,7 @@ use metadata::csearch; use middle::def; use middle::lang_items::MallocFnLangItem; use middle::mem_categorization::Typer; +use middle::subst; use middle::trans::_match; use middle::trans::adt; use middle::trans::asm; @@ -62,8 +63,8 @@ use middle::trans::inline; use middle::trans::tvec; use middle::trans::type_of; use middle::ty::struct_fields; -use middle::ty::{AutoBorrowObj, AutoDerefRef, AutoAddEnv, AutoObject, AutoUnsafe}; -use middle::ty::{AutoPtr, AutoBorrowVec, AutoBorrowVecRef}; +use middle::ty::{AutoDerefRef, AutoAddEnv, AutoUnsafe}; +use middle::ty::{AutoPtr}; use middle::ty; use middle::typeck; use middle::typeck::MethodCall; @@ -160,6 +161,14 @@ pub fn trans<'a>(bcx: &'a Block<'a>, return DatumBlock::new(bcx, datum); } +pub fn get_len(bcx: &Block, fat_ptr: ValueRef) -> ValueRef { + GEPi(bcx, fat_ptr, [0u, abi::slice_elt_len]) +} + +pub fn get_dataptr(bcx: &Block, fat_ptr: ValueRef) -> ValueRef { + GEPi(bcx, fat_ptr, [0u, abi::slice_elt_base]) +} + fn apply_adjustments<'a>(bcx: &'a Block<'a>, expr: &ast::Expr, datum: Datum<Expr>) @@ -184,71 +193,243 @@ fn apply_adjustments<'a>(bcx: &'a Block<'a>, datum = unpack_datum!(bcx, add_env(bcx, expr, datum)); } AutoDerefRef(ref adj) => { - if adj.autoderefs > 0 { + // 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). + let autoderefs = match adj.autoref { + Some(ty::AutoUnsizeUniq(..)) => adj.autoderefs - 1, + _ => adj.autoderefs + }; + + if autoderefs > 0 { datum = unpack_datum!( - bcx, deref_multiple(bcx, expr, datum, adj.autoderefs)); + bcx, deref_multiple(bcx, expr, datum, autoderefs)); } - datum = match adj.autoref { - None => { - datum - } - Some(AutoUnsafe(..)) | // region + unsafe ptrs have same repr - Some(AutoPtr(..)) => { - unpack_datum!(bcx, auto_ref(bcx, datum, expr)) - } - Some(AutoBorrowVec(..)) => { - unpack_datum!(bcx, auto_slice(bcx, expr, datum)) + match adj.autoref { + Some(ref a) => { + datum = unpack_datum!(bcx, apply_autoref(a, + bcx, + expr, + datum)); } - Some(AutoBorrowVecRef(..)) => { - unpack_datum!(bcx, auto_slice_and_ref(bcx, expr, datum)) - } - Some(AutoBorrowObj(..)) => { - unpack_datum!(bcx, auto_borrow_obj(bcx, expr, datum)) - } - }; - } - AutoObject(..) => { - let adjusted_ty = ty::expr_ty_adjusted(bcx.tcx(), expr); - let scratch = rvalue_scratch_datum(bcx, adjusted_ty, "__adjust"); - bcx = meth::trans_trait_cast( - bcx, datum, expr.id, SaveIn(scratch.val)); - datum = scratch.to_expr_datum(); + _ => {} + } } } debug!("after adjustments, datum={}", datum.to_string(bcx.ccx())); return DatumBlock {bcx: bcx, datum: datum}; - fn auto_slice<'a>( - bcx: &'a Block<'a>, - expr: &ast::Expr, - datum: Datum<Expr>) - -> DatumBlock<'a, Expr> { - // This is not the most efficient thing possible; since slices - // are two words it'd be better if this were compiled in - // 'dest' mode, but I can't find a nice way to structure the - // code and keep it DRY that accommodates that use case at the - // moment. + fn apply_autoref<'a>(autoref: &ty::AutoRef, + bcx: &'a Block<'a>, + expr: &ast::Expr, + datum: Datum<Expr>) + -> DatumBlock<'a, Expr> { + let mut bcx = bcx; + let mut datum = datum; + + let datum = match autoref { + &AutoUnsafe(..) => { + debug!(" AutoUnsafe"); + unpack_datum!(bcx, ref_ptr(bcx, expr, datum)) + } + &AutoPtr(_, _, ref a) => { + debug!(" AutoPtr"); + match a { + &Some(box ref a) => datum = unpack_datum!(bcx, + apply_autoref(a, bcx, expr, datum)), + _ => {} + } + unpack_datum!(bcx, ref_ptr(bcx, expr, datum)) + } + &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) + } + + fn ref_ptr<'a>(bcx: &'a Block<'a>, + expr: &ast::Expr, + datum: Datum<Expr>) + -> DatumBlock<'a, Expr> { + if !ty::type_is_sized(bcx.tcx(), datum.ty) { + debug!("Taking address of unsized type {}", + bcx.ty_to_str(datum.ty)); + ref_fat_ptr(bcx, expr, datum) + } else { + debug!("Taking address of sized type {}", + bcx.ty_to_str(datum.ty)); + auto_ref(bcx, datum, expr) + } + } + + // Retrieve the information we are losing (making dynamic) in an unsizing + // adjustment. + fn unsized_info<'a>(bcx: &'a Block<'a>, + kind: &ty::UnsizeKind, + id: ast::NodeId, + sized_ty: ty::t) -> ValueRef { + match kind { + &ty::UnsizeLength(len) => C_uint(bcx.ccx(), len), + &ty::UnsizeStruct(box ref k, tp_index) => match ty::get(sized_ty).sty { + ty::ty_struct(_, ref substs) => { + let ty_substs = substs.types.get_vec(subst::TypeSpace); + let sized_ty = ty_substs.get(tp_index); + unsized_info(bcx, k, id, *sized_ty) + } + _ => bcx.sess().bug(format!("UnsizeStruct with bad sty: {}", + bcx.ty_to_str(sized_ty)).as_slice()) + }, + &ty::UnsizeVtable(..) => + PointerCast(bcx, + meth::vtable_ptr(bcx, id, sized_ty), + Type::vtable_ptr(bcx.ccx())) + } + } + + fn unsize_expr<'a>(bcx: &'a Block<'a>, + expr: &ast::Expr, + datum: Datum<Expr>, + k: &ty::UnsizeKind) + -> DatumBlock<'a, Expr> { + let tcx = bcx.tcx(); + let datum_ty = datum.ty; + let unsized_ty = ty::unsize_ty(tcx, datum_ty, k, expr.span); + let dest_ty = ty::mk_open(tcx, unsized_ty); + // Closures for extracting and manipulating the data and payload parts of + // the fat pointer. + let base = match k { + &ty::UnsizeStruct(..) => + |bcx, val| PointerCast(bcx, + val, + type_of::type_of(bcx.ccx(), unsized_ty).ptr_to()), + &ty::UnsizeLength(..) => + |bcx, val| GEPi(bcx, val, [0u, 0u]), + &ty::UnsizeVtable(..) => + |_bcx, val| PointerCast(bcx, val, Type::i8p(bcx.ccx())) + }; + let info = |bcx, _val| unsized_info(bcx, k, expr.id, datum_ty); + into_fat_ptr(bcx, expr, datum, dest_ty, base, info) + } + + fn ref_fat_ptr<'a>(bcx: &'a Block<'a>, + expr: &ast::Expr, + datum: Datum<Expr>) + -> DatumBlock<'a, Expr> { + let tcx = bcx.tcx(); + let dest_ty = ty::close_type(tcx, datum.ty); + let base = |bcx, val| Load(bcx, get_dataptr(bcx, val)); + let len = |bcx, val| Load(bcx, get_len(bcx, val)); + into_fat_ptr(bcx, expr, datum, dest_ty, base, len) + } + + fn into_fat_ptr<'a>(bcx: &'a Block<'a>, + expr: &ast::Expr, + datum: Datum<Expr>, + dest_ty: ty::t, + base: |&'a Block<'a>, ValueRef| -> ValueRef, + info: |&'a Block<'a>, ValueRef| -> ValueRef) + -> DatumBlock<'a, Expr> { + let mut bcx = bcx; + + // Arrange cleanup + let lval = unpack_datum!(bcx, + datum.to_lvalue_datum(bcx, "into_fat_ptr", expr.id)); + let base = base(bcx, lval.val); + let info = info(bcx, lval.val); + + let scratch = rvalue_scratch_datum(bcx, dest_ty, "__fat_ptr"); + Store(bcx, base, get_dataptr(bcx, scratch.val)); + Store(bcx, info, get_len(bcx, scratch.val)); + + DatumBlock::new(bcx, scratch.to_expr_datum()) + } + + fn unsize_unique_vec<'a>(bcx: &'a Block<'a>, + expr: &ast::Expr, + datum: Datum<Expr>, + len: uint) + -> DatumBlock<'a, Expr> { let mut bcx = bcx; let tcx = bcx.tcx(); - let unit_ty = ty::sequence_element_type(tcx, datum.ty); - // Arrange cleanup, if not already done. This is needed in - // case we are auto-slicing an owned vector or some such. - let datum = unpack_datum!( - bcx, datum.to_lvalue_datum(bcx, "auto_slice", expr.id)); + let datum_ty = datum.ty; + // Arrange cleanup + let lval = unpack_datum!(bcx, + datum.to_lvalue_datum(bcx, "unsize_unique_vec", expr.id)); + + 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"); + + if len == 0 { + Store(bcx, + C_null(type_of::type_of(bcx.ccx(), unit_ty).ptr_to()), + get_dataptr(bcx, scratch.val)); + } else { + // Box<[(), ..n]> will not allocate, but ~[()] expects an + // allocation of n bytes, so we must allocate here (yuck). + let llty = type_of::type_of(bcx.ccx(), unit_ty); + if llsize_of_alloc(bcx.ccx(), llty) == 0 { + let ptr_unit_ty = type_of::type_of(bcx.ccx(), unit_ty).ptr_to(); + let align = C_uint(bcx.ccx(), 8); + let alloc_result = malloc_raw_dyn(bcx, ptr_unit_ty, vec_ty, ll_len, align); + bcx = alloc_result.bcx; + let base = get_dataptr(bcx, scratch.val); + Store(bcx, alloc_result.val, base); + } else { + let base = get_dataptr(bcx, scratch.val); + let base = PointerCast(bcx, + base, + type_of::type_of(bcx.ccx(), datum_ty).ptr_to()); + bcx = lval.store_to(bcx, base); + } + } + + Store(bcx, ll_len, get_len(bcx, scratch.val)); + DatumBlock::new(bcx, scratch.to_expr_datum()) + } + + fn unsize_unique_expr<'a>(bcx: &'a Block<'a>, + expr: &ast::Expr, + datum: Datum<Expr>, + k: &ty::UnsizeKind) + -> DatumBlock<'a, Expr> { + let mut bcx = bcx; + let tcx = bcx.tcx(); + + let datum_ty = datum.ty; + let unboxed_ty = match ty::get(datum_ty).sty { + ty::ty_uniq(t) => t, + _ => bcx.sess().bug(format!("Expected ty_uniq, found {}", + bcx.ty_to_str(datum_ty)).as_slice()) + }; + let result_ty = ty::mk_uniq(tcx, ty::unsize_ty(tcx, unboxed_ty, k, expr.span)); + + let lval = unpack_datum!(bcx, + datum.to_lvalue_datum(bcx, "unsize_unique_expr", expr.id)); - let (base, len) = datum.get_vec_base_and_len(bcx); + let scratch = rvalue_scratch_datum(bcx, result_ty, "__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 = lval.store_to(bcx, base); - // this type may have a different region/mutability than the - // real one, but it will have the same runtime representation - let slice_ty = ty::mk_slice(tcx, ty::ReStatic, - ty::mt { ty: unit_ty, mutbl: ast::MutImmutable }); + let info = unsized_info(bcx, k, expr.id, unboxed_ty); + Store(bcx, info, get_len(bcx, scratch.val)); - let scratch = rvalue_scratch_datum(bcx, slice_ty, "__adjust"); - Store(bcx, base, GEPi(bcx, scratch.val, [0u, abi::slice_elt_base])); - Store(bcx, len, GEPi(bcx, scratch.val, [0u, abi::slice_elt_len])); DatumBlock::new(bcx, scratch.to_expr_datum()) } @@ -267,32 +448,6 @@ fn apply_adjustments<'a>(bcx: &'a Block<'a>, let def = ty::resolve_expr(bcx.tcx(), expr); closure::make_closure_from_bare_fn(bcx, closure_ty, def, fn_ptr) } - - fn auto_slice_and_ref<'a>( - bcx: &'a Block<'a>, - expr: &ast::Expr, - datum: Datum<Expr>) - -> DatumBlock<'a, Expr> { - let DatumBlock { bcx, datum } = auto_slice(bcx, expr, datum); - auto_ref(bcx, datum, expr) - } - - fn auto_borrow_obj<'a>(mut bcx: &'a Block<'a>, - expr: &ast::Expr, - source_datum: Datum<Expr>) - -> DatumBlock<'a, Expr> { - let tcx = bcx.tcx(); - let target_obj_ty = expr_ty_adjusted(bcx, expr); - debug!("auto_borrow_obj(target={})", target_obj_ty.repr(tcx)); - - // Arrange cleanup, if not already done. This is needed in - // case we are auto-borrowing a Box<Trait> to &Trait - let datum = unpack_datum!( - bcx, source_datum.to_lvalue_datum(bcx, "autoborrowobj", expr.id)); - let mut datum = datum.to_expr_datum(); - datum.ty = target_obj_ty; - DatumBlock::new(bcx, datum) - } } pub fn trans_to_lvalue<'a>(bcx: &'a Block<'a>, @@ -398,20 +553,25 @@ fn trans_datum_unadjusted<'a>(bcx: &'a Block<'a>, ast::ExprIndex(base, idx) => { trans_index(bcx, expr.span, &**base, &**idx, MethodCall::expr(expr.id)) } - ast::ExprVstore(ref contents, ast::ExprVstoreUniq) => { - fcx.push_ast_cleanup_scope(contents.id); - let datum = unpack_datum!( - bcx, tvec::trans_uniq_vstore(bcx, expr, &**contents)); - bcx = fcx.pop_and_trans_ast_cleanup_scope(bcx, contents.id); - DatumBlock::new(bcx, datum) - } ast::ExprBox(_, ref contents) => { // Special case for `Box<T>` and `Gc<T>` let box_ty = expr_ty(bcx, expr); let contents_ty = expr_ty(bcx, &**contents); match ty::get(box_ty).sty { ty::ty_uniq(..) => { - trans_uniq_expr(bcx, box_ty, &**contents, contents_ty) + match contents.node { + ast::ExprRepeat(..) | ast::ExprVec(..) => { + // Special case for owned vectors. + fcx.push_ast_cleanup_scope(contents.id); + let datum = unpack_datum!( + bcx, tvec::trans_uniq_vec(bcx, expr, &**contents)); + bcx = fcx.pop_and_trans_ast_cleanup_scope(bcx, contents.id); + DatumBlock::new(bcx, datum) + } + _ => { + trans_uniq_expr(bcx, box_ty, &**contents, contents_ty) + } + } } ty::ty_box(..) => { trans_managed_expr(bcx, box_ty, &**contents, contents_ty) @@ -419,6 +579,7 @@ fn trans_datum_unadjusted<'a>(bcx: &'a Block<'a>, _ => bcx.sess().span_bug(expr.span, "expected unique or managed box") } + } ast::ExprLit(ref lit) => trans_immediate_lit(bcx, expr, (**lit).clone()), ast::ExprBinary(op, ref lhs, ref rhs) => { @@ -428,7 +589,19 @@ fn trans_datum_unadjusted<'a>(bcx: &'a Block<'a>, trans_unary(bcx, expr, op, &**x) } ast::ExprAddrOf(_, ref x) => { - trans_addr_of(bcx, expr, &**x) + match x.node { + ast::ExprRepeat(..) | ast::ExprVec(..) => { + // Special case for slices. + fcx.push_ast_cleanup_scope(x.id); + let datum = unpack_datum!( + bcx, tvec::trans_slice_vec(bcx, expr, &**x)); + bcx = fcx.pop_and_trans_ast_cleanup_scope(bcx, x.id); + DatumBlock::new(bcx, datum) + } + _ => { + trans_addr_of(bcx, expr, &**x) + } + } } ast::ExprCast(ref val, _) => { // Datum output mode means this is a scalar cast: @@ -454,14 +627,28 @@ fn trans_rec_field<'a>(bcx: &'a Block<'a>, let _icx = push_ctxt("trans_rec_field"); let base_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, base, "field")); - let repr = adt::represent_type(bcx.ccx(), base_datum.ty); - with_field_tys(bcx.tcx(), base_datum.ty, None, |discr, field_tys| { - let ix = ty::field_idx_strict(bcx.tcx(), field.name, field_tys); - let d = base_datum.get_element( - field_tys[ix].mt.ty, - |srcval| adt::trans_field_ptr(bcx, &*repr, srcval, discr, ix)); + let bare_ty = ty::unopen_type(base_datum.ty); + let repr = adt::represent_type(bcx.ccx(), bare_ty); + with_field_tys(bcx.tcx(), bare_ty, None, |discr, field_tys| { + let ix = ty::field_idx_strict(bcx.tcx(), field.name, field_tys); + let d = base_datum.get_element( + bcx, + field_tys[ix].mt.ty, + |srcval| adt::trans_field_ptr(bcx, &*repr, srcval, discr, ix)); + + if ty::type_is_sized(bcx.tcx(), d.ty) { DatumBlock { datum: d.to_expr_datum(), bcx: bcx } - }) + } else { + debug!("nrc: {}", bcx.ty_to_str(d.ty)) + let scratch = rvalue_scratch_datum(bcx, ty::mk_open(bcx.tcx(), d.ty), ""); + Store(bcx, d.val, get_dataptr(bcx, scratch.val)); + let info = Load(bcx, get_len(bcx, base_datum.val)); + Store(bcx, info, get_len(bcx, scratch.val)); + + DatumBlock::new(bcx, scratch.to_expr_datum()) + + } + }) } fn trans_index<'a>(bcx: &'a Block<'a>, @@ -727,7 +914,6 @@ fn trans_rvalue_dps_unadjusted<'a>(bcx: &'a Block<'a>, let _icx = push_ctxt("trans_rvalue_dps_unadjusted"); let mut bcx = bcx; let tcx = bcx.tcx(); - let fcx = bcx.fcx; match expr.node { ast::ExprParen(ref e) => { @@ -772,14 +958,8 @@ fn trans_rvalue_dps_unadjusted<'a>(bcx: &'a Block<'a>, } } } - ast::ExprVstore(ref contents, ast::ExprVstoreSlice) | - ast::ExprVstore(ref contents, ast::ExprVstoreMutSlice) => { - fcx.push_ast_cleanup_scope(contents.id); - bcx = tvec::trans_slice_vstore(bcx, expr, &**contents, dest); - fcx.pop_and_trans_ast_cleanup_scope(bcx, contents.id) - } ast::ExprVec(..) | ast::ExprRepeat(..) => { - tvec::trans_fixed_vstore(bcx, expr, expr, dest) + tvec::trans_fixed_vstore(bcx, expr, dest) } ast::ExprFnBlock(_, ref decl, ref body) | ast::ExprProc(ref decl, ref body) => { @@ -1168,6 +1348,21 @@ pub fn trans_adt<'a>(mut bcx: &'a Block<'a>, fcx.schedule_drop_mem(scope, dest, e_ty); } + for base in optbase.iter() { + // FIXME #6573: is it sound to use the destination's repr on the base? + // And, would it ever be reasonable to be here with discr != 0? + let base_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, &*base.expr, "base")); + for &(i, t) in base.fields.iter() { + let datum = base_datum.get_element( + bcx, + t, + |srcval| adt::trans_field_ptr(bcx, repr, srcval, discr, i)); + assert!(ty::type_is_sized(bcx.tcx(), datum.ty)); + let dest = adt::trans_field_ptr(bcx, repr, addr, discr, i); + bcx = datum.store_to(bcx, dest); + } + } + adt::trans_set_discr(bcx, &*repr, addr, discr); fcx.pop_custom_cleanup_scope(custom_cleanup_scope); @@ -1301,8 +1496,28 @@ fn trans_addr_of<'a>(bcx: &'a Block<'a>, let _icx = push_ctxt("trans_addr_of"); let mut bcx = bcx; let sub_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, subexpr, "addr_of")); - let ty = expr_ty(bcx, expr); - return immediate_rvalue_bcx(bcx, sub_datum.val, ty).to_expr_datumblock(); + match ty::get(sub_datum.ty).sty { + ty::ty_open(_) => { + // Opened DST value, close to a fat pointer + debug!("Closing fat pointer {}", bcx.ty_to_str(sub_datum.ty)); + + let scratch = rvalue_scratch_datum(bcx, + ty::close_type(bcx.tcx(), sub_datum.ty), + "fat_addr_of"); + let base = Load(bcx, get_dataptr(bcx, sub_datum.val)); + Store(bcx, base, get_dataptr(bcx, scratch.val)); + + let len = Load(bcx, get_len(bcx, sub_datum.val)); + Store(bcx, len, get_len(bcx, scratch.val)); + + DatumBlock::new(bcx, scratch.to_expr_datum()) + } + _ => { + // Sized value, ref to a thin pointer + let ty = expr_ty(bcx, expr); + immediate_rvalue_bcx(bcx, sub_datum.val, ty).to_expr_datumblock() + } + } } // Important to get types for both lhs and rhs, because one might be _|_ @@ -1590,15 +1805,18 @@ pub enum cast_kind { cast_other, } -pub fn cast_type_kind(t: ty::t) -> cast_kind { +pub fn cast_type_kind(tcx: &ty::ctxt, t: ty::t) -> cast_kind { match ty::get(t).sty { ty::ty_char => cast_integral, ty::ty_float(..) => cast_float, ty::ty_ptr(..) => cast_pointer, - ty::ty_rptr(_, mt) => match ty::get(mt.ty).sty{ - ty::ty_vec(_, None) | ty::ty_str | ty::ty_trait(..) => cast_other, - _ => cast_pointer, - }, + ty::ty_rptr(_, mt) => { + if ty::type_is_sized(tcx, mt.ty) { + cast_pointer + } else { + cast_other + } + } ty::ty_bare_fn(..) => cast_pointer, ty::ty_int(..) => cast_integral, ty::ty_uint(..) => cast_integral, @@ -1618,8 +1836,8 @@ fn trans_imm_cast<'a>(bcx: &'a Block<'a>, let t_in = expr_ty(bcx, expr); let t_out = node_id_type(bcx, id); - let k_in = cast_type_kind(t_in); - let k_out = cast_type_kind(t_out); + let k_in = cast_type_kind(bcx.tcx(), t_in); + let k_out = cast_type_kind(bcx.tcx(), t_out); let s_in = k_in == cast_integral && ty::type_is_signed(t_in); let ll_t_in = type_of::arg_type_of(ccx, t_in); let ll_t_out = type_of::arg_type_of(ccx, t_out); @@ -1807,10 +2025,14 @@ fn deref_once<'a>(bcx: &'a Block<'a>, let r = match ty::get(datum.ty).sty { ty::ty_uniq(content_ty) => { - match ty::get(content_ty).sty { - ty::ty_vec(_, None) | ty::ty_str | ty::ty_trait(..) - => bcx.tcx().sess.span_bug(expr.span, "unexpected unsized box"), - _ => deref_owned_pointer(bcx, expr, datum, content_ty), + if ty::type_is_sized(bcx.tcx(), content_ty) { + deref_owned_pointer(bcx, expr, datum, content_ty) + } else { + // A fat pointer and an opened DST value have the same represenation + // just different types. + DatumBlock::new(bcx, Datum::new(datum.val, + ty::mk_open(bcx.tcx(), content_ty), + datum.kind)) } } @@ -1825,21 +2047,21 @@ fn deref_once<'a>(bcx: &'a Block<'a>, ty::ty_ptr(ty::mt { ty: content_ty, .. }) | ty::ty_rptr(_, ty::mt { ty: content_ty, .. }) => { - match ty::get(content_ty).sty { - ty::ty_vec(_, None) | ty::ty_str | ty::ty_trait(..) - => bcx.tcx().sess.span_bug(expr.span, "unexpected unsized reference"), - _ => { - assert!(!ty::type_needs_drop(bcx.tcx(), datum.ty)); - - let ptr = datum.to_llscalarish(bcx); - - // Always generate an lvalue datum, even if datum.mode is - // an rvalue. This is because datum.mode is only an - // rvalue for non-owning pointers like &T or *T, in which - // case cleanup *is* scheduled elsewhere, by the true - // owner (or, in the case of *T, by the user). - DatumBlock::new(bcx, Datum::new(ptr, content_ty, LvalueExpr)) - } + if ty::type_is_sized(bcx.tcx(), content_ty) { + let ptr = datum.to_llscalarish(bcx); + + // Always generate an lvalue datum, even if datum.mode is + // an rvalue. This is because datum.mode is only an + // rvalue for non-owning pointers like &T or *T, in which + // case cleanup *is* scheduled elsewhere, by the true + // owner (or, in the case of *T, by the user). + DatumBlock::new(bcx, Datum::new(ptr, content_ty, LvalueExpr)) + } else { + // A fat pointer and an opened DST value have the same represenation + // just different types. + DatumBlock::new(bcx, Datum::new(datum.val, + ty::mk_open(bcx.tcx(), content_ty), + datum.kind)) } } diff --git a/src/librustc/middle/trans/glue.rs b/src/librustc/middle/trans/glue.rs index 8faf27d1aa4..2994378f91c 100644 --- a/src/librustc/middle/trans/glue.rs +++ b/src/librustc/middle/trans/glue.rs @@ -98,18 +98,14 @@ pub fn get_drop_glue_type(ccx: &CrateContext, t: ty::t) -> ty::t { ty::ty_box(typ) if !ty::type_needs_drop(tcx, typ) => ty::mk_box(tcx, ty::mk_i8()), - ty::ty_uniq(typ) if !ty::type_needs_drop(tcx, typ) => { - match ty::get(typ).sty { - ty::ty_vec(_, None) | ty::ty_str | ty::ty_trait(..) => t, - _ => { - let llty = sizing_type_of(ccx, typ); - // `Box<ZeroSizeType>` does not allocate. - if llsize_of_alloc(ccx, llty) == 0 { - ty::mk_i8() - } else { - ty::mk_uniq(tcx, ty::mk_i8()) - } - } + ty::ty_uniq(typ) if !ty::type_needs_drop(tcx, typ) + && ty::type_is_sized(tcx, typ) => { + let llty = sizing_type_of(ccx, typ); + // `Box<ZeroSizeType>` does not allocate. + if llsize_of_alloc(ccx, llty) == 0 { + ty::mk_i8() + } else { + ty::mk_uniq(tcx, ty::mk_i8()) } } _ => t @@ -276,8 +272,8 @@ fn make_drop_glue<'a>(bcx: &'a Block<'a>, v0: ValueRef, t: ty::t) -> &'a Block<' } ty::ty_uniq(content_ty) => { match ty::get(content_ty).sty { - ty::ty_vec(mt, None) => { - tvec::make_drop_glue_unboxed(bcx, v0, mt.ty) + ty::ty_vec(ty, None) => { + tvec::make_drop_glue_unboxed(bcx, v0, ty) } ty::ty_str => { let unit_ty = ty::sequence_element_type(bcx.tcx(), t); @@ -297,7 +293,13 @@ fn make_drop_glue<'a>(bcx: &'a Block<'a>, v0: ValueRef, t: ty::t) -> &'a Block<' }) } _ => { - let llbox = Load(bcx, v0); + let llval = if ty::type_is_sized(bcx.tcx(), content_ty) { + v0 + } else { + // The Box is a fat pointer + GEPi(bcx, v0, [0, abi::trt_field_box]) + }; + let llbox = Load(bcx, llval); let not_null = IsNotNull(bcx, llbox); with_cond(bcx, not_null, |bcx| { let bcx = drop_ty(bcx, llbox, content_ty); diff --git a/src/librustc/middle/trans/meth.rs b/src/librustc/middle/trans/meth.rs index a9a308fc16d..3dc09040419 100644 --- a/src/librustc/middle/trans/meth.rs +++ b/src/librustc/middle/trans/meth.rs @@ -666,6 +666,26 @@ fn emit_vtable_methods(bcx: &Block, }).collect() } +pub fn vtable_ptr<'a>(bcx: &'a Block<'a>, + id: ast::NodeId, + self_ty: ty::t) -> ValueRef { + let ccx = bcx.ccx(); + let origins = { + let vtable_map = ccx.tcx.vtable_map.borrow(); + // This trait cast might be because of implicit coercion + let adjs = ccx.tcx.adjustments.borrow(); + let adjust = adjs.find(&id); + let method_call = if adjust.is_some() && ty::adjust_is_object(adjust.unwrap()) { + MethodCall::autoobject(id) + } else { + MethodCall::expr(id) + }; + let vres = vtable_map.get(&method_call).get_self().unwrap(); + resolve_param_vtables_under_param_substs(ccx.tcx(), bcx.fcx.param_substs, vres) + }; + get_vtable(bcx, self_ty, origins) +} + pub fn trans_trait_cast<'a>(bcx: &'a Block<'a>, datum: Datum<Expr>, id: ast::NodeId, @@ -688,27 +708,16 @@ pub fn trans_trait_cast<'a>(bcx: &'a Block<'a>, SaveIn(dest) => dest }; - let ccx = bcx.ccx(); let v_ty = datum.ty; - let llbox_ty = type_of(bcx.ccx(), datum.ty); + let llbox_ty = type_of(bcx.ccx(), v_ty); // Store the pointer into the first half of pair. - let mut llboxdest = GEPi(bcx, lldest, [0u, abi::trt_field_box]); - llboxdest = PointerCast(bcx, llboxdest, llbox_ty.ptr_to()); + let llboxdest = GEPi(bcx, lldest, [0u, abi::trt_field_box]); + let llboxdest = PointerCast(bcx, llboxdest, llbox_ty.ptr_to()); bcx = datum.store_to(bcx, llboxdest); // Store the vtable into the second half of pair. - let origins = { - let vtable_map = ccx.tcx.vtable_map.borrow(); - // This trait cast might be because of implicit coercion - let method_call = match ccx.tcx.adjustments.borrow().find(&id) { - Some(&ty::AutoObject(..)) => MethodCall::autoobject(id), - _ => MethodCall::expr(id) - }; - let vres = vtable_map.get(&method_call).get_self().unwrap(); - resolve_param_vtables_under_param_substs(ccx.tcx(), bcx.fcx.param_substs, vres) - }; - let vtable = get_vtable(bcx, v_ty, origins); + let vtable = vtable_ptr(bcx, id, v_ty); let llvtabledest = GEPi(bcx, lldest, [0u, abi::trt_field_vtable]); let llvtabledest = PointerCast(bcx, llvtabledest, val_ty(vtable).ptr_to()); Store(bcx, vtable, llvtabledest); diff --git a/src/librustc/middle/trans/reflect.rs b/src/librustc/middle/trans/reflect.rs index fcc1b827876..7b6d3430ae0 100644 --- a/src/librustc/middle/trans/reflect.rs +++ b/src/librustc/middle/trans/reflect.rs @@ -94,6 +94,7 @@ impl<'a, 'b> Reflector<'a, 'b> { ty::MethodTraitItem(ref method) => (*method).clone(), }; let mth_ty = ty::mk_bare_fn(tcx, method.fty.clone()); + debug!("Emit call visit method: visit_{}: {}", ty_name, ty_to_str(tcx, mth_ty)); let v = self.visitor_val; debug!("passing {} args:", args.len()); let mut bcx = self.bcx; @@ -149,13 +150,21 @@ impl<'a, 'b> Reflector<'a, 'b> { ty::ty_float(ast::TyF32) => self.leaf("f32"), ty::ty_float(ast::TyF64) => self.leaf("f64"), + ty::ty_open(_) | ty::ty_str | ty::ty_vec(_, None) | ty::ty_trait(..) => { + // Unfortunately we can't do anything here because at runtime we + // pass around the value by pointer (*u8). But unsized pointers are + // fat and so we can't just cast them to *u8 and back. So we have + // to work with the pointer directly (see ty_rptr/ty_uniq). See + // ty_struct for where this causes issues. + fail!("Can't reflect unsized type") + } + // Should rename to vec_*. - ty::ty_vec(ref mt, Some(sz)) => { - let extra = (vec!(self.c_uint(sz))).append(self.c_size_and_align(t).as_slice()); - let extra = extra.append(self.c_mt(mt).as_slice()); + ty::ty_vec(ty, Some(sz)) => { + let mut extra = (vec!(self.c_uint(sz))).append(self.c_size_and_align(t).as_slice()); + extra.push(self.c_tydesc(ty)); self.visit("evec_fixed", extra.as_slice()) } - ty::ty_vec(..) | ty::ty_str | ty::ty_trait(..) => fail!("unexpected unsized type"), // Should remove mt from box and uniq. ty::ty_box(typ) => { let extra = self.c_mt(&ty::mt { @@ -170,12 +179,6 @@ impl<'a, 'b> Reflector<'a, 'b> { } ty::ty_uniq(typ) => { match ty::get(typ).sty { - ty::ty_vec(ref mt, None) => { - let extra = Vec::new(); - let extra = extra.append(self.c_mt(mt).as_slice()); - self.visit("evec_uniq", extra.as_slice()) - } - ty::ty_str => self.visit("estr_uniq", &[]), ty::ty_trait(..) => { let extra = [ self.c_slice(token::intern_and_get_ident( @@ -183,6 +186,12 @@ impl<'a, 'b> Reflector<'a, 'b> { ]; self.visit("trait", extra); } + // FIXME(15049) allow reflection of Box<[T]>. You'll need to + // restore visit_evec_uniq. + ty::ty_vec(_, None) => { + fail!("Box<[T]> theoretically doesn't exist, so don't try to reflect it") + } + ty::ty_str => fail!("Can't reflect Box<str> which shouldn't be used anyway"), _ => { let extra = self.c_mt(&ty::mt { ty: typ, @@ -194,9 +203,8 @@ impl<'a, 'b> Reflector<'a, 'b> { } ty::ty_rptr(_, ref mt) => { match ty::get(mt.ty).sty { - ty::ty_vec(ref mt, None) => { - let extra = Vec::new(); - let extra = extra.append(self.c_mt(mt).as_slice()); + ty::ty_vec(ty, None) => { + let extra = self.c_mt(&ty::mt{ty: ty, mutbl: mt.mutbl}); self.visit("evec_slice", extra.as_slice()) } ty::ty_str => self.visit("estr_slice", &[]), @@ -266,21 +274,34 @@ impl<'a, 'b> Reflector<'a, 'b> { special_idents::unnamed_field.name; } + // This and the type_is_sized check on individual field types are + // because we cannot reflect unsized types (see note above). We + // just pretend the unsized field does not exist and print nothing. + // This is sub-optimal. + let len = if ty::type_is_sized(tcx, t) { + fields.len() + } else { + assert!(fields.len() > 0); + fields.len() - 1 + }; + let extra = (vec!( self.c_slice( token::intern_and_get_ident(ty_to_string(tcx, t).as_slice())), self.c_bool(named_fields), - self.c_uint(fields.len()) + self.c_uint(len) )).append(self.c_size_and_align(t).as_slice()); self.bracketed("class", extra.as_slice(), |this| { for (i, field) in fields.iter().enumerate() { - let extra = (vec!( - this.c_uint(i), - this.c_slice(token::get_ident(field.ident)), - this.c_bool(named_fields) - )).append(this.c_mt(&field.mt).as_slice()); - this.visit("class_field", extra.as_slice()); + if ty::type_is_sized(tcx, field.mt.ty) { + let extra = (vec!( + this.c_uint(i), + this.c_slice(token::get_ident(field.ident)), + this.c_bool(named_fields) + )).append(this.c_mt(&field.mt).as_slice()); + this.visit("class_field", extra.as_slice()); + } } }) } diff --git a/src/librustc/middle/trans/tvec.rs b/src/librustc/middle/trans/tvec.rs index 7b8537b15c5..0ec18977139 100644 --- a/src/librustc/middle/trans/tvec.rs +++ b/src/librustc/middle/trans/tvec.rs @@ -35,12 +35,12 @@ use syntax::parse::token::InternedString; fn get_len(bcx: &Block, vptr: ValueRef) -> ValueRef { let _icx = push_ctxt("tvec::get_lenl"); - Load(bcx, GEPi(bcx, vptr, [0u, abi::slice_elt_len])) + Load(bcx, expr::get_len(bcx, vptr)) } fn get_dataptr(bcx: &Block, vptr: ValueRef) -> ValueRef { let _icx = push_ctxt("tvec::get_dataptr"); - Load(bcx, GEPi(bcx, vptr, [0u, abi::slice_elt_base])) + Load(bcx, expr::get_dataptr(bcx, vptr)) } pub fn pointer_add_byte(bcx: &Block, ptr: ValueRef, bytes: ValueRef) -> ValueRef { @@ -68,7 +68,10 @@ pub fn make_drop_glue_unboxed<'a>( bcx }; - glue::trans_exchange_free(bcx, dataptr, 0, 8) + let not_null = IsNotNull(bcx, dataptr); + with_cond(bcx, not_null, |bcx| { + glue::trans_exchange_free(bcx, dataptr, 0, 8) + }) }) } @@ -92,8 +95,7 @@ impl VecTypes { pub fn trans_fixed_vstore<'a>( bcx: &'a Block<'a>, - vstore_expr: &ast::Expr, - content_expr: &ast::Expr, + expr: &ast::Expr, dest: expr::Dest) -> &'a Block<'a> { //! @@ -103,49 +105,53 @@ pub fn trans_fixed_vstore<'a>( // to store the array of the suitable size, so all we have to do is // generate the content. - debug!("trans_fixed_vstore(vstore_expr={}, dest={:?})", - bcx.expr_to_string(vstore_expr), dest.to_string(bcx.ccx())); + debug!("trans_fixed_vstore(expr={}, dest={:?})", + bcx.expr_to_string(expr), dest.to_string(bcx.ccx())); - let vt = vec_types_from_expr(bcx, vstore_expr); + let vt = vec_types_from_expr(bcx, expr); return match dest { - Ignore => write_content(bcx, &vt, vstore_expr, content_expr, dest), + Ignore => write_content(bcx, &vt, expr, expr, dest), SaveIn(lldest) => { // lldest will have type *[T x N], but we want the type *T, // so use GEP to convert: let lldest = GEPi(bcx, lldest, [0, 0]); - write_content(bcx, &vt, vstore_expr, content_expr, SaveIn(lldest)) + write_content(bcx, &vt, expr, expr, SaveIn(lldest)) } }; } -pub fn trans_slice_vstore<'a>(bcx: &'a Block<'a>, - vstore_expr: &ast::Expr, - content_expr: &ast::Expr, - dest: expr::Dest) - -> &'a Block<'a> { +pub fn trans_slice_vec<'a>(bcx: &'a Block<'a>, + slice_expr: &ast::Expr, + content_expr: &ast::Expr) + -> DatumBlock<'a, Expr> { /*! * &[...] allocates memory on the stack and writes the values into it, - * returning a slice (pair of ptr, len). &"..." is similar except that - * the memory can be statically allocated. + * returning the vector (the caller must make the reference). "..." is + * similar except that the memory can be statically allocated and we return + * a reference (strings are always by-ref). */ let fcx = bcx.fcx; let ccx = fcx.ccx; let mut bcx = bcx; - debug!("trans_slice_vstore(vstore_expr={}, dest={})", - bcx.expr_to_string(vstore_expr), dest.to_string(ccx)); + debug!("trans_slice_vec(slice_expr={})", + bcx.expr_to_string(slice_expr)); + + let vec_ty = node_id_type(bcx, slice_expr.id); - // Handle the &"..." case: + // Handle the "..." case (returns a slice since strings are always unsized): match content_expr.node { ast::ExprLit(lit) => { match lit.node { ast::LitStr(ref s, _) => { - return trans_lit_str(bcx, - content_expr, - s.clone(), - dest) + let scratch = rvalue_scratch_datum(bcx, vec_ty, ""); + bcx = trans_lit_str(bcx, + content_expr, + s.clone(), + SaveIn(scratch.val)); + return DatumBlock::new(bcx, scratch.to_expr_datum()); } _ => {} } @@ -154,11 +160,16 @@ pub fn trans_slice_vstore<'a>(bcx: &'a Block<'a>, } // Handle the &[...] case: - let vt = vec_types_from_expr(bcx, vstore_expr); + let vt = vec_types_from_expr(bcx, content_expr); let count = elements_required(bcx, content_expr); debug!(" vt={}, count={:?}", vt.to_str(ccx), count); let llcount = C_uint(ccx, count); + let fixed_ty = ty::mk_vec(bcx.tcx(), + vt.unit_ty, + Some(count)); + let llfixed_ty = type_of::type_of(bcx.ccx(), fixed_ty).ptr_to(); + let llfixed = if count == 0 { // Just create a zero-sized alloca to preserve // the non-null invariant of the inner slice ptr @@ -168,33 +179,19 @@ pub fn trans_slice_vstore<'a>(bcx: &'a Block<'a>, let llfixed = base::arrayalloca(bcx, vt.llunit_ty, llcount); // Arrange for the backing array to be cleaned up. - let fixed_ty = ty::mk_vec(bcx.tcx(), - ty::mt {ty: vt.unit_ty, - mutbl: ast::MutMutable}, - Some(count)); - let llfixed_ty = type_of::type_of(bcx.ccx(), fixed_ty).ptr_to(); let llfixed_casted = BitCast(bcx, llfixed, llfixed_ty); let cleanup_scope = cleanup::temporary_scope(bcx.tcx(), content_expr.id); fcx.schedule_lifetime_end(cleanup_scope, llfixed_casted); fcx.schedule_drop_mem(cleanup_scope, llfixed_casted, fixed_ty); // Generate the content into the backing array. - bcx = write_content(bcx, &vt, vstore_expr, + bcx = write_content(bcx, &vt, slice_expr, content_expr, SaveIn(llfixed)); - llfixed + llfixed_casted }; - // Finally, create the slice pair itself. - match dest { - Ignore => {} - SaveIn(lldest) => { - Store(bcx, llfixed, GEPi(bcx, lldest, [0u, abi::slice_elt_base])); - Store(bcx, llcount, GEPi(bcx, lldest, [0u, abi::slice_elt_len])); - } - } - - return bcx; + immediate_rvalue_bcx(bcx, llfixed, vec_ty).to_expr_datumblock() } pub fn trans_lit_str<'a>( @@ -229,24 +226,23 @@ pub fn trans_lit_str<'a>( } } -pub fn trans_uniq_vstore<'a>(bcx: &'a Block<'a>, - vstore_expr: &ast::Expr, - content_expr: &ast::Expr) - -> DatumBlock<'a, Expr> { +pub fn trans_uniq_vec<'a>(bcx: &'a Block<'a>, + uniq_expr: &ast::Expr, + content_expr: &ast::Expr) + -> DatumBlock<'a, Expr> { /*! * ~[...] and "...".to_string() allocate boxes in the exchange heap and write * the array elements into them. */ - debug!("trans_uniq_vstore(vstore_expr={})", bcx.expr_to_string(vstore_expr)); + debug!("trans_uniq_vec(vstore_expr={})", bcx.expr_to_string(uniq_expr)); let fcx = bcx.fcx; let ccx = fcx.ccx; - let vt = vec_types_from_expr(bcx, vstore_expr); + let vt = vec_types_from_expr(bcx, content_expr); let count = elements_required(bcx, content_expr); debug!(" vt={}, count={:?}", vt.to_str(ccx), count); - let llcount = C_uint(ccx, count); - let vec_ty = node_id_type(bcx, vstore_expr.id); + let vec_ty = node_id_type(bcx, uniq_expr.id); let unit_sz = nonzero_llsize_of(ccx, type_of::type_of(ccx, vt.unit_ty)); let fill = Mul(bcx, C_uint(ccx, count), unit_sz); @@ -274,15 +270,19 @@ pub fn trans_uniq_vstore<'a>(bcx: &'a Block<'a>, debug!(" alloc_uniq_vec() returned dataptr={}, len={}", bcx.val_to_str(dataptr), count); - let bcx = write_content(bcx, &vt, vstore_expr, + let bcx = write_content(bcx, &vt, uniq_expr, content_expr, SaveIn(dataptr)); fcx.pop_custom_cleanup_scope(temp_scope); - let scratch = rvalue_scratch_datum(bcx, vec_ty, ""); - Store(bcx, dataptr, GEPi(bcx, scratch.val, [0u, abi::slice_elt_base])); - Store(bcx, llcount, GEPi(bcx, scratch.val, [0u, abi::slice_elt_len])); - DatumBlock(bcx, scratch.to_expr_datum()) + if ty::type_is_sized(bcx.tcx(), vec_ty) { + immediate_rvalue_bcx(bcx, dataptr, vec_ty).to_expr_datumblock() + } else { + let scratch = rvalue_scratch_datum(bcx, vec_ty, ""); + Store(bcx, dataptr, GEPi(bcx, scratch.val, [0u, abi::slice_elt_base])); + Store(bcx, llcount, GEPi(bcx, scratch.val, [0u, abi::slice_elt_len])); + DatumBlock::new(bcx, scratch.to_expr_datum()) + } } pub fn write_content<'a>( @@ -439,11 +439,19 @@ pub fn get_fixed_base_and_len(bcx: &Block, let ccx = bcx.ccx(); - let base = GEPi(bcx, llval, [0u, abi::slice_elt_base]); + let base = expr::get_dataptr(bcx, llval); let len = C_uint(ccx, vec_length); (base, len) } +fn get_slice_base_and_len(bcx: &Block, + llval: ValueRef) + -> (ValueRef, ValueRef) { + let base = Load(bcx, GEPi(bcx, llval, [0u, abi::slice_elt_base])); + let len = Load(bcx, GEPi(bcx, llval, [0u, abi::slice_elt_len])); + (base, len) +} + pub fn get_base_and_len(bcx: &Block, llval: ValueRef, vec_ty: ty::t) @@ -459,15 +467,18 @@ pub fn get_base_and_len(bcx: &Block, let ccx = bcx.ccx(); match ty::get(vec_ty).sty { - ty::ty_vec(_, Some(n)) => { - let base = GEPi(bcx, llval, [0u, 0u]); - (base, C_uint(ccx, n)) - } + ty::ty_vec(_, Some(n)) => get_fixed_base_and_len(bcx, llval, n), + ty::ty_open(ty) => match ty::get(ty).sty { + ty::ty_vec(_, None) | ty::ty_str => get_slice_base_and_len(bcx, llval), + _ => ccx.sess().bug("unexpected type in get_base_and_len") + }, + + // Only used for pattern matching. ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ty, ..}) => match ty::get(ty).sty { - ty::ty_vec(_, None) | ty::ty_str => { - let base = Load(bcx, GEPi(bcx, llval, [0u, abi::slice_elt_base])); - let len = Load(bcx, GEPi(bcx, llval, [0u, abi::slice_elt_len])); - (base, len) + ty::ty_vec(_, None) | ty::ty_str => get_slice_base_and_len(bcx, llval), + ty::ty_vec(_, Some(n)) => { + let base = GEPi(bcx, Load(bcx, llval), [0u, 0u]); + (base, C_uint(ccx, n)) } _ => ccx.sess().bug("unexpected type in get_base_and_len"), }, diff --git a/src/librustc/middle/trans/type_.rs b/src/librustc/middle/trans/type_.rs index 99850fb9386..017d61137e4 100644 --- a/src/librustc/middle/trans/type_.rs +++ b/src/librustc/middle/trans/type_.rs @@ -231,9 +231,16 @@ impl Type { ], false) } + pub fn vtable_ptr(ccx: &CrateContext) -> Type { + Type::glue_fn(ccx, Type::i8p(ccx)).ptr_to().ptr_to() + } + pub fn opaque_trait(ccx: &CrateContext) -> Type { - let vtable = Type::glue_fn(ccx, Type::i8p(ccx)).ptr_to().ptr_to(); - Type::struct_(ccx, [vtable, Type::i8p(ccx)], false) + Type::struct_(ccx, [Type::opaque_trait_data(ccx).ptr_to(), Type::vtable_ptr(ccx)], false) + } + + pub fn opaque_trait_data(ccx: &CrateContext) -> Type { + Type::i8(ccx) } pub fn kind(&self) -> TypeKind { diff --git a/src/librustc/middle/trans/type_of.rs b/src/librustc/middle/trans/type_of.rs index bc17824ca32..9608672928d 100644 --- a/src/librustc/middle/trans/type_of.rs +++ b/src/librustc/middle/trans/type_of.rs @@ -15,6 +15,7 @@ use middle::trans::adt; use middle::trans::common::*; use middle::trans::foreign; use middle::ty; +use util::ppaux; use util::ppaux::Repr; use middle::trans::type_::Type; @@ -160,6 +161,11 @@ pub fn sizing_type_of(cx: &CrateContext, t: ty::t) -> Type { } let llsizingty = match ty::get(t).sty { + _ if !ty::lltype_is_sized(cx.tcx(), t) => { + cx.sess().bug(format!("trying to take the sizing type of {}, an unsized type", + ppaux::ty_to_str(cx.tcx(), t)).as_slice()) + } + ty::ty_nil | ty::ty_bot => Type::nil(cx), ty::ty_bool => Type::bool(cx), ty::ty_char => Type::char(cx), @@ -170,20 +176,18 @@ pub fn sizing_type_of(cx: &CrateContext, t: ty::t) -> Type { ty::ty_box(..) | ty::ty_ptr(..) => Type::i8p(cx), ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ty, ..}) => { - match ty::get(ty).sty { - ty::ty_vec(_, None) | ty::ty_str => { - Type::struct_(cx, [Type::i8p(cx), Type::i8p(cx)], false) - } - ty::ty_trait(..) => Type::opaque_trait(cx), - _ => Type::i8p(cx), + if ty::type_is_sized(cx.tcx(), ty) { + Type::i8p(cx) + } else { + Type::struct_(cx, [Type::i8p(cx), Type::i8p(cx)], false) } } ty::ty_bare_fn(..) => Type::i8p(cx), ty::ty_closure(..) => Type::struct_(cx, [Type::i8p(cx), Type::i8p(cx)], false), - ty::ty_vec(mt, Some(size)) => { - Type::array(&sizing_type_of(cx, mt.ty), size as u64) + ty::ty_vec(ty, Some(size)) => { + Type::array(&sizing_type_of(cx, ty), size as u64) } ty::ty_tup(..) | ty::ty_enum(..) | ty::ty_unboxed_closure(..) => { @@ -202,11 +206,15 @@ pub fn sizing_type_of(cx: &CrateContext, t: ty::t) -> Type { } } - ty::ty_infer(..) | ty::ty_param(..) | - ty::ty_err(..) | ty::ty_vec(_, None) | ty::ty_str | ty::ty_trait(..) => { - cx.sess().bug(format!("fictitious type {:?} in sizing_type_of()", - ty::get(t).sty).as_slice()) + ty::ty_open(_) => { + Type::struct_(cx, [Type::i8p(cx), Type::i8p(cx)], false) + } + + ty::ty_infer(..) | ty::ty_param(..) | ty::ty_err(..) => { + cx.sess().bug(format!("fictitious type {} in sizing_type_of()", + ppaux::ty_to_str(cx.tcx(), t)).as_slice()) } + ty::ty_vec(_, None) | ty::ty_trait(..) | ty::ty_str => fail!("unreachable") }; cx.llsizingtypes.borrow_mut().insert(t, llsizingty); @@ -223,13 +231,22 @@ pub fn arg_type_of(cx: &CrateContext, t: ty::t) -> Type { // NB: If you update this, be sure to update `sizing_type_of()` as well. pub fn type_of(cx: &CrateContext, t: ty::t) -> Type { + fn type_of_unsize_info(cx: &CrateContext, t: ty::t) -> Type { + match ty::get(ty::unsized_part_of_type(cx.tcx(), t)).sty { + ty::ty_str | ty::ty_vec(..) => Type::uint_from_ty(cx, ast::TyU), + ty::ty_trait(_) => Type::vtable_ptr(cx), + _ => fail!("Unexpected type returned from unsized_part_of_type : {}", + t.repr(cx.tcx())) + } + } + // Check the cache. match cx.lltypes.borrow().find(&t) { Some(&llty) => return llty, None => () } - debug!("type_of {} {:?}", t.repr(cx.tcx()), t); + debug!("type_of {} {:?}", t.repr(cx.tcx()), ty::get(t).sty); // Replace any typedef'd types with their equivalent non-typedef // type. This ensures that all LLVM nominal types that contain @@ -281,24 +298,33 @@ pub fn type_of(cx: &CrateContext, t: ty::t) -> Type { ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ty, ..}) => { match ty::get(ty).sty { - ty::ty_vec(mt, None) => { - let p_ty = type_of(cx, mt.ty).ptr_to(); - let u_ty = Type::uint_from_ty(cx, ast::TyU); - Type::struct_(cx, [p_ty, u_ty], false) - } ty::ty_str => { - // This means we get a nicer name in the output + // This means we get a nicer name in the output (str is always + // unsized). cx.tn.find_type("str_slice").unwrap() } ty::ty_trait(..) => Type::opaque_trait(cx), + _ if !ty::type_is_sized(cx.tcx(), ty) => { + let p_ty = type_of(cx, ty).ptr_to(); + Type::struct_(cx, [p_ty, type_of_unsize_info(cx, ty)], false) + } _ => type_of(cx, ty).ptr_to(), } } - ty::ty_vec(ref mt, Some(n)) => { - Type::array(&type_of(cx, mt.ty), n as u64) + ty::ty_vec(ty, Some(n)) => { + Type::array(&type_of(cx, ty), n as u64) + } + ty::ty_vec(ty, None) => { + type_of(cx, ty) } + ty::ty_trait(..) => { + Type::opaque_trait_data(cx) + } + + ty::ty_str => Type::i8(cx), + ty::ty_bare_fn(_) => { type_of_fn_from_ty(cx, t).ptr_to() } @@ -326,12 +352,27 @@ pub fn type_of(cx: &CrateContext, t: ty::t) -> Type { } } - ty::ty_vec(_, None) => cx.sess().bug("type_of with unsized ty_vec"), - ty::ty_str => cx.sess().bug("type_of with unsized (bare) ty_str"), - ty::ty_trait(..) => cx.sess().bug("type_of with unsized ty_trait"), + ty::ty_open(t) => match ty::get(t).sty { + ty::ty_struct(..) => { + let p_ty = type_of(cx, t).ptr_to(); + Type::struct_(cx, [p_ty, type_of_unsize_info(cx, t)], false) + } + ty::ty_vec(ty, None) => { + let p_ty = type_of(cx, ty).ptr_to(); + Type::struct_(cx, [p_ty, type_of_unsize_info(cx, t)], false) + } + ty::ty_str => { + let p_ty = Type::i8p(cx); + Type::struct_(cx, [p_ty, type_of_unsize_info(cx, t)], false) + } + ty::ty_trait(..) => Type::opaque_trait(cx), + _ => cx.sess().bug(format!("ty_open with sized type: {}", + ppaux::ty_to_str(cx.tcx(), t)).as_slice()) + }, + ty::ty_infer(..) => cx.sess().bug("type_of with ty_infer"), ty::ty_param(..) => cx.sess().bug("type_of with ty_param"), - ty::ty_err(..) => cx.sess().bug("type_of with ty_err") + ty::ty_err(..) => cx.sess().bug("type_of with ty_err"), }; debug!("--> mapped t={} {:?} to llty={}", diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index c00c462afae..486ed714574 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -263,37 +263,141 @@ pub enum Variance { #[deriving(Clone)] pub enum AutoAdjustment { AutoAddEnv(ty::TraitStore), - AutoDerefRef(AutoDerefRef), - AutoObject(ty::TraitStore, - ty::BuiltinBounds, - ast::DefId, /* Trait ID */ - subst::Substs /* Trait substitutions */) + AutoDerefRef(AutoDerefRef) } -#[deriving(Clone, Decodable, Encodable)] +#[deriving(Clone, PartialEq)] +pub enum UnsizeKind { + // [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<UnsizeKind>, uint), + UnsizeVtable(ty::BuiltinBounds, + ast::DefId, /* Trait ID */ + subst::Substs /* Trait substitutions */) +} + +#[deriving(Clone)] pub struct AutoDerefRef { pub autoderefs: uint, pub autoref: Option<AutoRef> } -#[deriving(Clone, Decodable, Encodable, PartialEq, Show)] +#[deriving(Clone, PartialEq)] pub enum AutoRef { /// Convert from T to &T - AutoPtr(Region, ast::Mutability), + /// The third field allows us to wrap other AutoRef adjustments. + AutoPtr(Region, ast::Mutability, Option<Box<AutoRef>>), - /// Convert from ~[]/&[] to &[] or str - AutoBorrowVec(Region, ast::Mutability), + /// Convert [T, ..n] to [T] (or similar, depending on the kind) + AutoUnsize(UnsizeKind), - /// Convert from ~[]/&[] to &&[] or str - AutoBorrowVecRef(Region, ast::Mutability), + /// 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), /// Convert from T to *T + /// Value to thin pointer AutoUnsafe(ast::Mutability), +} + +// Ugly little helper function. The 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<Region>) { + fn unsize_kind_region(k: &UnsizeKind) -> (bool, bool, Option<Region>) { + match k { + &UnsizeVtable(..) => (true, false, None), + &UnsizeStruct(box ref k, _) => unsize_kind_region(k), + _ => (false, false, None) + } + } + + match autoref { + &AutoUnsize(ref k) => unsize_kind_region(k), + &AutoUnsizeUniq(ref k) => match k { + &UnsizeVtable(..) => (true, true, None), + _ => (false, false, 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)) + } + } + _ => (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<Region> { + match adj { + &AutoDerefRef(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 { + &AutoDerefRef(AutoDerefRef{autoref: Some(ref autoref), ..}) => { + let (b, _, _) = autoref_object_region(autoref); + b + } + _ => false + } +} + +// 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(cx: &ctxt, adj: &AutoAdjustment) -> Option<t> { + fn type_of_autoref(cx: &ctxt, autoref: &AutoRef) -> Option<t> { + match autoref { + &AutoUnsize(ref k) => match k { + &UnsizeVtable(bounds, def_id, ref substs) => { + Some(mk_trait(cx, def_id, substs.clone(), bounds)) + } + _ => None + }, + &AutoUnsizeUniq(ref k) => match k { + &UnsizeVtable(bounds, def_id, ref substs) => { + Some(mk_uniq(cx, mk_trait(cx, def_id, substs.clone(), bounds))) + } + _ => None + }, + &AutoPtr(r, m, Some(box ref autoref)) => { + match type_of_autoref(cx, autoref) { + Some(t) => Some(mk_rptr(cx, r, mt {mutbl: m, ty: t})), + None => None + } + } + _ => None + } + } - /// Convert from Box<Trait>/&Trait to &Trait - AutoBorrowObj(Region, ast::Mutability), + match adj { + &AutoDerefRef(AutoDerefRef{autoref: Some(ref autoref), ..}) => { + type_of_autoref(cx, autoref) + } + _ => None + } } + + /// A restriction that certain types must be the same size. The use of /// `transmute` gives rise to these restrictions. pub struct TransmuteRestriction { @@ -802,7 +906,7 @@ pub enum sty { ty_box(t), ty_uniq(t), ty_str, - ty_vec(mt, Option<uint>), // Second field is length. + ty_vec(t, Option<uint>), // Second field is length. ty_ptr(mt), ty_rptr(Region, mt), ty_bare_fn(BareFnTy), @@ -813,6 +917,12 @@ pub enum sty { ty_tup(Vec<t>), ty_param(ParamTy), // type parameter + ty_open(t), // A deref'ed fat pointer, i.e., a dynamically sized value + // and its size. Only ever used in trans. It is not necessary + // earlier since we don't need to distinguish a DST with its + // size (e.g., in a deref) vs a DST with the size elsewhere ( + // e.g., in a field). + ty_infer(InferTy), // something used only during inference/typeck ty_err, // Also only used during inference/typeck, to represent // the type of an erroneous expression (helps cut down @@ -1377,10 +1487,10 @@ pub fn mk_t(cx: &ctxt, st: sty) -> t { &ty_trait(box ty::TyTrait { ref substs, .. }) => { flags |= sflags(substs); } - &ty_box(tt) | &ty_uniq(tt) => { + &ty_box(tt) | &ty_uniq(tt) | &ty_vec(tt, _) | &ty_open(tt) => { flags |= get(tt).flags } - &ty_ptr(ref m) | &ty_vec(ref m, _) => { + &ty_ptr(ref m) => { flags |= get(m.ty).flags; } &ty_rptr(r, ref m) => { @@ -1558,14 +1668,14 @@ pub fn mk_nil_ptr(cx: &ctxt) -> t { mk_ptr(cx, mt {ty: mk_nil(), mutbl: ast::MutImmutable}) } -pub fn mk_vec(cx: &ctxt, tm: mt, sz: Option<uint>) -> t { - mk_t(cx, ty_vec(tm, sz)) +pub fn mk_vec(cx: &ctxt, t: t, sz: Option<uint>) -> t { + mk_t(cx, ty_vec(t, sz)) } pub fn mk_slice(cx: &ctxt, r: Region, tm: mt) -> t { mk_rptr(cx, r, mt { - ty: mk_vec(cx, tm, None), + ty: mk_vec(cx, tm.ty, None), mutbl: tm.mutbl }) } @@ -1643,6 +1753,8 @@ pub fn mk_param_from_def(cx: &ctxt, def: &TypeParameterDef) -> t { mk_param(cx, def.space, def.index, def.def_id) } +pub fn mk_open(cx: &ctxt, t: t) -> t { mk_t(cx, ty_open(t)) } + pub fn walk_ty(ty: t, f: |t|) { maybe_walk_ty(ty, |t| { f(t); true }); } @@ -1653,10 +1765,9 @@ pub fn maybe_walk_ty(ty: t, f: |t| -> bool) { } match get(ty).sty { ty_nil | ty_bot | ty_bool | ty_char | ty_int(_) | ty_uint(_) | ty_float(_) | - ty_str | ty_infer(_) | ty_param(_) | ty_unboxed_closure(..) | - ty_err => {} - ty_box(ty) | ty_uniq(ty) => maybe_walk_ty(ty, f), - ty_ptr(ref tm) | ty_rptr(_, ref tm) | ty_vec(ref tm, _) => { + ty_str | ty_infer(_) | ty_param(_) | ty_unboxed_closure(_) | ty_err => {} + ty_box(ty) | ty_uniq(ty) | ty_vec(ty, _) | ty_open(ty) => maybe_walk_ty(ty, f), + ty_ptr(ref tm) | ty_rptr(_, ref tm) => { maybe_walk_ty(tm.ty, f); } ty_enum(_, ref substs) | ty_struct(_, ref substs) | @@ -1775,14 +1886,11 @@ pub fn type_is_simd(cx: &ctxt, ty: t) -> bool { pub fn sequence_element_type(cx: &ctxt, ty: t) -> t { match get(ty).sty { - ty_vec(mt, _) => mt.ty, - ty_ptr(mt{ty: t, ..}) | ty_rptr(_, mt{ty: t, ..}) | - ty_box(t) | ty_uniq(t) => match get(t).sty { - ty_vec(mt, None) => mt.ty, - ty_str => mk_mach_uint(ast::TyU8), - _ => cx.sess.bug("sequence_element_type called on non-sequence value"), - }, - _ => cx.sess.bug("sequence_element_type called on non-sequence value"), + ty_vec(ty, _) => ty, + ty_str => mk_mach_uint(ast::TyU8), + ty_open(ty) => sequence_element_type(cx, ty), + _ => cx.sess.bug(format!("sequence_element_type called on non-sequence value: {}", + ty_to_string(cx, ty)).as_slice()), } } @@ -1815,11 +1923,7 @@ pub fn type_is_boxed(ty: t) -> bool { pub fn type_is_region_ptr(ty: t) -> bool { match get(ty).sty { - ty_rptr(_, mt) => match get(mt.ty).sty { - // DST pointers should not be treated like regular pointers. - ty_vec(_, None) | ty_str | ty_trait(..) => false, - _ => true - }, + ty_rptr(..) => true, _ => false } } @@ -1841,6 +1945,13 @@ pub fn type_is_unique(ty: t) -> bool { } } +pub fn type_is_fat_ptr(cx: &ctxt, ty: t) -> bool { + match get(ty).sty { + ty_rptr(_, mt{ty, ..}) | ty_uniq(ty) if !type_is_sized(cx, ty) => true, + _ => false, + } +} + /* A scalar type is one that denotes an atomic datum, with no sub-components. (A ty_ptr is scalar because it represents a non-managed pointer, so its @@ -2232,7 +2343,7 @@ pub fn type_contents(cx: &ctxt, ty: t) -> TypeContents { // Scalar and unique types are sendable, and durable ty_nil | ty_bot | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) | - ty_bare_fn(_) | ty::ty_char | ty_str => { + ty_bare_fn(_) | ty::ty_char => { TC::None } @@ -2267,10 +2378,15 @@ pub fn type_contents(cx: &ctxt, ty: t) -> TypeContents { } } - ty_vec(mt, _) => { - tc_mt(cx, mt, cache) + ty_vec(t, Some(_)) => { + tc_ty(cx, t, cache) } + ty_vec(t, None) => { + tc_ty(cx, t, cache) | TC::Nonsized + } + ty_str => TC::Nonsized, + ty_struct(did, ref substs) => { let flds = struct_fields(cx, did, substs); let mut res = @@ -2370,7 +2486,7 @@ pub fn type_contents(cx: &ctxt, ty: t) -> TypeContents { kind_bounds_to_contents(cx, tp_def.bounds.builtin_bounds, tp_def.bounds.trait_bounds.as_slice()) - } + } ty_infer(_) => { // This occurs during coherence, but shouldn't occur at other @@ -2378,6 +2494,12 @@ pub fn type_contents(cx: &ctxt, ty: t) -> TypeContents { TC::All } + ty_open(t) => { + let result = tc_ty(cx, t, cache); + assert!(!result.is_sized(cx)) + result.unsafe_pointer() | TC::Nonsized + } + ty_err => { cx.sess.bug("asked to compute contents of error type"); } @@ -2539,7 +2661,7 @@ pub fn is_instantiable(cx: &ctxt, r_ty: t) -> bool { // normal vectors, since they don't necessarily have the // possibility to have length zero. ty_vec(_, Some(0)) => false, // don't need no contents - ty_vec(mt, Some(_)) => type_requires(cx, seen, r_ty, mt.ty), + ty_vec(ty, Some(_)) => type_requires(cx, seen, r_ty, ty), ty_nil | ty_bot | @@ -2557,7 +2679,7 @@ pub fn is_instantiable(cx: &ctxt, r_ty: t) -> bool { ty_vec(_, None) => { false } - ty_box(typ) | ty_uniq(typ) => { + ty_box(typ) | ty_uniq(typ) | ty_open(typ) => { type_requires(cx, seen, r_ty, typ) } ty_rptr(_, ref mt) => { @@ -2680,8 +2802,8 @@ pub fn is_type_representable(cx: &ctxt, sp: Span, ty: t) -> Representability { } // Fixed-length vectors. // FIXME(#11924) Behavior undecided for zero-length vectors. - ty_vec(mt, Some(_)) => { - type_structurally_recursive(cx, sp, seen, mt.ty) + ty_vec(ty, Some(_)) => { + type_structurally_recursive(cx, sp, seen, ty) } // Push struct and enum def-ids onto `seen` before recursing. @@ -2800,11 +2922,40 @@ pub fn type_is_machine(ty: t) -> bool { } // Is the type's representation size known at compile time? -#[allow(dead_code)] // leaving in for DST -pub fn type_is_sized(cx: &ctxt, ty: ty::t) -> bool { +pub fn type_is_sized(cx: &ctxt, ty: t) -> bool { type_contents(cx, ty).is_sized(cx) } +pub fn lltype_is_sized(cx: &ctxt, ty: t) -> bool { + match get(ty).sty { + ty_open(_) => true, + _ => type_contents(cx, ty).is_sized(cx) + } +} + +// Return the smallest part of t which is unsized. Fails if t 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(cx: &ctxt, ty: t) -> t { + match get(ty).sty { + ty_str | ty_trait(..) | ty_vec(..) => ty, + ty_struct(_, ref substs) => { + // Exactly one of the type parameters must be unsized. + for tp in substs.types.get_vec(subst::TypeSpace).iter() { + if !type_is_sized(cx, *tp) { + return unsized_part_of_type(cx, *tp); + } + } + fail!("Unsized struct type with no unsized type params?"); + } + _ => { + assert!(type_is_sized(cx, ty), + "unsized_part_of_type failed even though ty is unsized"); + fail!("called unsized_part_of_type with sized ty"); + } + } +} + // Whether a type is enum like, that is an enum type with only nullary // constructors pub fn type_is_c_like_enum(cx: &ctxt, ty: t) -> bool { @@ -2827,33 +2978,47 @@ pub fn type_is_c_like_enum(cx: &ctxt, ty: t) -> bool { // Some types---notably unsafe ptrs---can only be dereferenced explicitly. pub fn deref(t: t, explicit: bool) -> Option<mt> { match get(t).sty { - ty_box(typ) | ty_uniq(typ) => match get(typ).sty { - // Don't deref ~[] etc., might need to generalise this to all DST. - ty_vec(_, None) | ty_str | ty_trait(..) => None, - _ => Some(mt { - ty: typ, + ty_box(ty) | ty_uniq(ty) => { + Some(mt { + ty: ty, mutbl: ast::MutImmutable, - }), - }, - ty_rptr(_, mt) => match get(mt.ty).sty { - // Don't deref &[], might need to generalise this to all DST. - ty_vec(_, None) | ty_str | ty_trait(..) => None, - _ => Some(mt), + }) }, + ty_rptr(_, mt) => Some(mt), ty_ptr(mt) if explicit => Some(mt), _ => None } } -// Returns the type of t[i] -pub fn index(t: t) -> Option<mt> { +pub fn close_type(cx: &ctxt, t: t) -> t { match get(t).sty { - ty_vec(mt, Some(_)) => Some(mt), - ty_ptr(mt{ty: t, ..}) | ty_rptr(_, mt{ty: t, ..}) | - ty_box(t) | ty_uniq(t) => match get(t).sty { - ty_vec(mt, None) => Some(mt), - _ => None, - }, + ty_open(t) => mk_rptr(cx, ReStatic, mt {ty: t, mutbl:ast::MutImmutable}), + _ => cx.sess.bug(format!("Trying to close a non-open type {}", + ty_to_str(cx, t)).as_slice()) + } +} + +pub fn type_content(t: t) -> t { + match get(t).sty { + ty_box(ty) | ty_uniq(ty) => ty, + ty_rptr(_, mt) |ty_ptr(mt) => mt.ty, + _ => t + } + +} + +// Extract the unsized type in an open type (or just return t if it is not open). +pub fn unopen_type(t: t) -> t { + match get(t).sty { + ty_open(t) => t, + _ => t + } +} + +// Returns the type of t[i] +pub fn index(ty: t) -> Option<t> { + match get(ty).sty { + ty_vec(t, _) => Some(t), _ => None } } @@ -2861,15 +3026,10 @@ pub fn index(t: t) -> Option<mt> { // Returns the type of elements contained within an 'array-like' type. // This is exactly the same as the above, except it supports strings, // which can't actually be indexed. -pub fn array_element_ty(t: t) -> Option<mt> { - match get(t).sty { - ty_vec(mt, Some(_)) => Some(mt), - ty_ptr(mt{ty: t, ..}) | ty_rptr(_, mt{ty: t, ..}) | - ty_box(t) | ty_uniq(t) => match get(t).sty { - ty_vec(mt, None) => Some(mt), - ty_str => Some(mt {ty: mk_u8(), mutbl: ast::MutImmutable}), - _ => None, - }, +pub fn array_element_ty(t: t) -> Option<t> { + match get(ty).sty { + ty_vec(t, _) => Some(t), + ty_str => Some(ty: mk_u8()), _ => None } } @@ -3152,56 +3312,7 @@ pub fn adjust_ty(cx: &ctxt, match adj.autoref { None => adjusted_ty, - Some(ref autoref) => { - match *autoref { - AutoPtr(r, m) => { - mk_rptr(cx, r, mt { - ty: adjusted_ty, - mutbl: m - }) - } - - AutoBorrowVec(r, m) => { - borrow_vec(cx, span, r, m, adjusted_ty) - } - - AutoBorrowVecRef(r, m) => { - adjusted_ty = borrow_vec(cx, - span, - r, - m, - adjusted_ty); - mk_rptr(cx, r, mt { - ty: adjusted_ty, - mutbl: ast::MutImmutable - }) - } - - AutoUnsafe(m) => { - mk_ptr(cx, mt {ty: adjusted_ty, mutbl: m}) - } - - AutoBorrowObj(r, m) => { - borrow_obj(cx, span, r, m, adjusted_ty) - } - } - } - } - } - - AutoObject(store, bounds, def_id, ref substs) => { - - let tr = mk_trait(cx, def_id, substs.clone(), bounds); - match store { - UniqTraitStore => { - mk_uniq(cx, tr) - } - RegionTraitStore(r, m) => { - mk_rptr(cx, r, mt { - ty: tr, - mutbl: m - }) - } + Some(ref autoref) => adjust_for_autoref(cx, span, adjusted_ty, autoref) } } } @@ -3209,57 +3320,64 @@ pub fn adjust_ty(cx: &ctxt, None => unadjusted_ty }; - fn borrow_vec(cx: &ctxt, - span: Span, - r: Region, - m: ast::Mutability, - ty: ty::t) -> ty::t { - match get(ty).sty { - ty_uniq(t) | ty_ptr(mt{ty: t, ..}) | - ty_rptr(_, mt{ty: t, ..}) => match get(t).sty { - ty::ty_vec(mt, None) => ty::mk_slice(cx, r, ty::mt {ty: mt.ty, mutbl: m}), - ty::ty_str => ty::mk_str_slice(cx, r, m), - _ => { - cx.sess.span_bug( - span, - format!("borrow-vec associated with bad sty: {:?}", - get(ty).sty).as_slice()); - } - }, - ty_vec(mt, Some(_)) => ty::mk_slice(cx, r, ty::mt {ty: mt.ty, mutbl: m}), + fn adjust_for_autoref(cx: &ctxt, + span: Span, + ty: ty::t, + autoref: &AutoRef) -> ty::t{ + match *autoref { + AutoPtr(r, m, ref a) => { + let adjusted_ty = match a { + &Some(box ref a) => adjust_for_autoref(cx, span, ty, a), + &None => ty + }; + mk_rptr(cx, r, mt { + ty: adjusted_ty, + mutbl: m + }) + } - ref s => { - cx.sess.span_bug( - span, - format!("borrow-vec associated with bad sty: {:?}", - s).as_slice()); + AutoUnsafe(m) => { + mk_ptr(cx, mt {ty: ty, mutbl: m}) } + + AutoUnsize(ref k) => unsize_ty(cx, ty, k, span), + AutoUnsizeUniq(ref k) => ty::mk_uniq(cx, unsize_ty(cx, ty, k, span)), } } +} - fn borrow_obj(cx: &ctxt, span: Span, r: Region, - m: ast::Mutability, ty: ty::t) -> ty::t { - match get(ty).sty { - ty_uniq(t) | ty_rptr(_, mt{ty: t, ..}) => match get(t).sty { - ty_trait(box ty::TyTrait {def_id, ref substs, bounds, .. }) => { - mk_rptr(cx, r, mt { - ty: ty::mk_trait(cx, def_id, substs.clone(), bounds), - mutbl: m - }) - } - _ => { - cx.sess.span_bug( - span, - format!("borrow-trait-obj associated with bad sty: {:?}", - get(ty).sty).as_slice()); - } - }, - ref s => { - cx.sess.span_bug( - span, - format!("borrow-trait-obj associated with bad sty: {:?}", - s).as_slice()); +// Take a sized type and a sizing adjustment and produce an unsized version of +// the type. +pub fn unsize_ty(cx: &ctxt, + ty: ty::t, + kind: &UnsizeKind, + span: Span) + -> ty::t { + match kind { + &UnsizeLength(len) => match get(ty).sty { + ty_vec(t, Some(n)) => { + assert!(len == n); + mk_vec(cx, t, None) + } + _ => cx.sess.span_bug(span, + format!("UnsizeLength with bad sty: {}", + ty_to_str(cx, ty)).as_slice()) + }, + &UnsizeStruct(box ref k, tp_index) => match get(ty).sty { + ty_struct(did, ref substs) => { + let ty_substs = substs.types.get_vec(subst::TypeSpace); + let old_ty = ty_substs.get(tp_index); + let new_ty = unsize_ty(cx, *old_ty, k, span); + let mut unsized_substs = substs.clone(); + *unsized_substs.types.get_mut_vec(subst::TypeSpace).get_mut(tp_index) = new_ty; + mk_struct(cx, did, unsized_substs) } + _ => cx.sess.span_bug(span, + format!("UnsizeStruct with bad sty: {}", + ty_to_str(cx, ty)).as_slice()) + }, + &UnsizeVtable(bounds, def_id, ref substs) => { + mk_trait(cx, def_id, substs.clone(), bounds) } } } @@ -3267,11 +3385,11 @@ pub fn adjust_ty(cx: &ctxt, impl AutoRef { pub fn map_region(&self, f: |Region| -> Region) -> AutoRef { match *self { - ty::AutoPtr(r, m) => ty::AutoPtr(f(r), m), - ty::AutoBorrowVec(r, m) => ty::AutoBorrowVec(f(r), m), - ty::AutoBorrowVecRef(r, m) => ty::AutoBorrowVecRef(f(r), m), + ty::AutoPtr(r, m, None) => ty::AutoPtr(f(r), m, None), + ty::AutoPtr(r, m, Some(ref a)) => ty::AutoPtr(f(r), m, Some(box a.map_region(f))), + ty::AutoUnsize(ref k) => ty::AutoUnsize(k.clone()), + ty::AutoUnsizeUniq(ref k) => ty::AutoUnsizeUniq(k.clone()), ty::AutoUnsafe(m) => ty::AutoUnsafe(m), - ty::AutoBorrowObj(r, m) => ty::AutoBorrowObj(f(r), m), } } } @@ -3422,8 +3540,6 @@ pub fn expr_kind(tcx: &ctxt, expr: &ast::Expr) -> ExprKind { ast::ExprUnboxedFn(..) | ast::ExprBlock(..) | ast::ExprRepeat(..) | - ast::ExprVstore(_, ast::ExprVstoreSlice) | - ast::ExprVstore(_, ast::ExprVstoreMutSlice) | ast::ExprVec(..) => { RvalueDpsExpr } @@ -3473,8 +3589,7 @@ pub fn expr_kind(tcx: &ctxt, expr: &ast::Expr) -> ExprKind { ast::ExprLit(_) | // Note: LitStr is carved out above ast::ExprUnary(..) | ast::ExprAddrOf(..) | - ast::ExprBinary(..) | - ast::ExprVstore(_, ast::ExprVstoreUniq) => { + ast::ExprBinary(..) => { RvalueDatumExpr } @@ -3579,6 +3694,7 @@ pub fn ty_sort_string(cx: &ctxt, t: t) -> String { } } ty_err => "type error".to_string(), + ty_open(_) => "opened DST".to_string(), } } @@ -4940,15 +5056,12 @@ pub fn hash_crate_independent(tcx: &ctxt, t: t, svh: &Svh) -> u64 { ty_uniq(_) => { byte!(10); } - ty_vec(m, Some(n)) => { + ty_vec(_, Some(n)) => { byte!(11); - mt(&mut state, m); n.hash(&mut state); - 1u8.hash(&mut state); } - ty_vec(m, None) => { + ty_vec(_, None) => { byte!(11); - mt(&mut state, m); 0u8.hash(&mut state); } ty_ptr(m) => { @@ -4997,6 +5110,7 @@ pub fn hash_crate_independent(tcx: &ctxt, t: t, svh: &Svh) -> u64 { hash!(p.idx); did(&mut state, p.def_id); } + ty_open(_) => byte!(22), ty_infer(_) => unreachable!(), ty_err => byte!(23), ty_unboxed_closure(d, r) => { diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs index 9f475bfd9d5..b246b5ce7a9 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -360,8 +360,11 @@ pub fn super_fold_sty<T:TypeFolder>(this: &mut T, ty::ty_ptr(ref tm) => { ty::ty_ptr(tm.fold_with(this)) } - ty::ty_vec(ref tm, sz) => { - ty::ty_vec(tm.fold_with(this), sz) + ty::ty_vec(typ, sz) => { + ty::ty_vec(typ.fold_with(this), sz) + } + ty::ty_open(typ) => { + ty::ty_open(typ.fold_with(this)) } ty::ty_enum(tid, ref substs) => { ty::ty_enum(tid, substs.fold_with(this)) @@ -420,11 +423,13 @@ pub fn super_fold_autoref<T:TypeFolder>(this: &mut T, -> ty::AutoRef { match *autoref { - ty::AutoPtr(r, m) => ty::AutoPtr(r.fold_with(this), m), - ty::AutoBorrowVec(r, m) => ty::AutoBorrowVec(r.fold_with(this), m), - ty::AutoBorrowVecRef(r, m) => ty::AutoBorrowVecRef(r.fold_with(this), m), + 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.clone()))) + } ty::AutoUnsafe(m) => ty::AutoUnsafe(m), - ty::AutoBorrowObj(r, m) => ty::AutoBorrowObj(r.fold_with(this), m), + ty::AutoUnsize(ref k) => ty::AutoUnsize(k.clone()), + ty::AutoUnsizeUniq(ref k) => ty::AutoUnsizeUniq(k.clone()), } } diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs index 129a039a267..08e78b35e4d 100644 --- a/src/librustc/middle/typeck/astconv.rs +++ b/src/librustc/middle/typeck/astconv.rs @@ -398,10 +398,7 @@ pub fn ast_ty_to_prim_ty(tcx: &ty::ctxt, ast_ty: &ast::Ty) -> Option<ty::t> { Some(ty::mk_mach_float(ft)) } ast::TyStr => { - span_err!(tcx.sess, ast_ty.span, E0037, - "bare `str` is not a type"); - // return /something/ so they can at least get more errors - Some(ty::mk_uniq(tcx, ty::mk_str(tcx))) + Some(ty::mk_str(tcx)) } } } @@ -462,21 +459,7 @@ pub fn ast_ty_to_builtin_ty<AC:AstConv, rscope, &mt, Uniq, - |typ| { - match ty::get(typ).sty { - ty::ty_str => { - span_err!(this.tcx().sess, path.span, E0111, - "`Box<str>` is not a type"); - ty::mk_err() - } - ty::ty_vec(_, None) => { - span_err!(this.tcx().sess, path.span, E0112, - "`Box<[T]>` is not a type"); - ty::mk_err() - } - _ => ty::mk_uniq(this.tcx(), typ), - } - })) + |typ| ty::mk_uniq(this.tcx(), typ))); } span_err!(this.tcx().sess, path.span, E0113, "not enough type parameters supplied to `Box<T>`"); @@ -537,12 +520,6 @@ enum PointerTy { Uniq } -fn ast_ty_to_mt<AC:AstConv, RS:RegionScope>(this: &AC, - rscope: &RS, - ty: &ast::Ty) -> ty::mt { - ty::mt {ty: ast_ty_to_ty(this, rscope, ty), mutbl: ast::MutImmutable} -} - pub fn trait_ref_for_unboxed_function<AC:AstConv, RS:RegionScope>( this: &AC, @@ -601,11 +578,8 @@ fn mk_pointer<AC:AstConv, match a_seq_ty.ty.node { ast::TyVec(ref ty) => { - let mut mt = ast_ty_to_mt(this, rscope, &**ty); - if a_seq_ty.mutbl == ast::MutMutable { - mt.mutbl = ast::MutMutable; - } - return constr(ty::mk_vec(tcx, mt, None)); + let ty = ast_ty_to_ty(this, rscope, &**ty); + return constr(ty::mk_vec(tcx, ty, None)); } ast::TyUnboxedFn(ref unboxed_function) => { let ty::TraitRef { @@ -662,37 +636,33 @@ fn mk_pointer<AC:AstConv, Some(&def::DefTrait(trait_def_id)) => { let result = ast_path_to_trait_ref( this, rscope, trait_def_id, None, path); - let trait_store = match ptr_ty { - Uniq => ty::UniqTraitStore, - RPtr(r) => { - ty::RegionTraitStore(r, a_seq_ty.mutbl) - } - _ => { - tcx.sess.span_err( - path.span, - "~trait or &trait are the only supported \ - forms of casting-to-trait"); - return ty::mk_err(); - } + let static_region = match ptr_ty { + RPtr(r) if r == ty::ReStatic => true, + _ => false }; let bounds = conv_builtin_bounds(this.tcx(), path.span, bounds, - trait_store); + static_region); let tr = ty::mk_trait(tcx, result.def_id, result.substs.clone(), bounds); - // We could just match on ptr_ty, but we need to pass a trait - // store to conv_builtin_bounds, so mathc twice for now. - return match trait_store { - ty::UniqTraitStore => { + return match ptr_ty { + Uniq => { return ty::mk_uniq(tcx, tr); } - ty::RegionTraitStore(r, m) => { - return ty::mk_rptr(tcx, r, ty::mt{mutbl: m, ty: tr}); + RPtr(r) => { + return ty::mk_rptr(tcx, r, ty::mt{mutbl: a_seq_ty.mutbl, ty: tr}); } - } + _ => { + tcx.sess.span_err( + path.span, + "~trait or &trait are the only supported \ + forms of casting-to-trait"); + return ty::mk_err(); + } + }; } _ => {} } @@ -738,10 +708,7 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>( |ty| ty::mk_uniq(tcx, ty)) } ast::TyVec(ty) => { - tcx.sess.span_err(ast_ty.span, "bare `[]` is not a type"); - // return /something/ so they can at least get more errors - let vec_ty = ty::mk_vec(tcx, ast_ty_to_mt(this, rscope, &*ty), None); - ty::mk_uniq(tcx, vec_ty) + ty::mk_vec(tcx, ast_ty_to_ty(this, rscope, &*ty), None) } ast::TyPtr(ref mt) => { ty::mk_ptr(tcx, ty::mt { @@ -777,15 +744,14 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>( let bound_region = opt_ast_region_to_region(this, rscope, ast_ty.span, region); - let store = ty::RegionTraitStore(bound_region, ast::MutMutable); - // Use corresponding trait store to figure out default bounds // if none were specified. let bounds = conv_builtin_bounds(this.tcx(), ast_ty.span, &f.bounds, - store); + bound_region == ty::ReStatic); + let store = ty::RegionTraitStore(bound_region, ast::MutMutable); let fn_decl = ty_of_closure(this, ast_ty.id, f.fn_style, @@ -803,7 +769,7 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>( let bounds = conv_builtin_bounds(this.tcx(), ast_ty.span, &f.bounds, - ty::UniqTraitStore); + false); let fn_decl = ty_of_closure(this, ast_ty.id, @@ -841,15 +807,17 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>( _ => { }, } match a_def { - def::DefTrait(_) => { - let path_str = path_to_string(path); - tcx.sess.span_err( - ast_ty.span, - format!("reference to trait `{name}` where a \ - type is expected; try `Box<{name}>` or \ - `&{name}`", - name=path_str).as_slice()); - ty::mk_err() + def::DefTrait(trait_def_id) => { + let result = ast_path_to_trait_ref( + this, rscope, trait_def_id, None, path); + let bounds = conv_builtin_bounds(this.tcx(), + path.span, + bounds, + false); + ty::mk_trait(tcx, + result.def_id, + result.substs.clone(), + bounds) } def::DefTy(did) | def::DefStruct(did) => { ast_path_to_ty(this, rscope, did, path).ty @@ -887,10 +855,10 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>( Ok(ref r) => { match *r { const_eval::const_int(i) => - ty::mk_vec(tcx, ast_ty_to_mt(this, rscope, &*ty), + ty::mk_vec(tcx, ast_ty_to_ty(this, rscope, &*ty), Some(i as uint)), const_eval::const_uint(i) => - ty::mk_vec(tcx, ast_ty_to_mt(this, rscope, &*ty), + ty::mk_vec(tcx, ast_ty_to_ty(this, rscope, &*ty), Some(i as uint)), _ => { tcx.sess.span_fatal( @@ -1211,7 +1179,7 @@ pub fn ty_of_closure<AC:AstConv>( fn conv_builtin_bounds(tcx: &ty::ctxt, span: Span, ast_bounds: &Option<OwnedSlice<ast::TyParamBound>>, - store: ty::TraitStore) + static_region: bool) -> ty::BuiltinBounds { //! Converts a list of bounds from the AST into a `BuiltinBounds` //! struct. Reports an error if any of the bounds that appear @@ -1224,8 +1192,8 @@ fn conv_builtin_bounds(tcx: &ty::ctxt, //! override this with an empty bounds list, e.g. "Box<fn:()>" or //! "Box<Trait:>". - match (ast_bounds, store) { - (&Some(ref bound_vec), _) => { + match ast_bounds { + &Some(ref bound_vec) => { let mut builtin_bounds = ty::empty_builtin_bounds(); for ast_bound in bound_vec.iter() { match *ast_bound { @@ -1265,12 +1233,10 @@ fn conv_builtin_bounds(tcx: &ty::ctxt, builtin_bounds }, // &'static Trait is sugar for &'static Trait:'static. - (&None, ty::RegionTraitStore(ty::ReStatic, _)) => { + &None if static_region => { let mut set = ty::empty_builtin_bounds(); set.add(ty::BoundStatic); set } - // No bounds are automatically applied for &'r Trait or ~Trait - (&None, ty::RegionTraitStore(..)) | - (&None, ty::UniqTraitStore) => ty::empty_builtin_bounds(), + &None => ty::empty_builtin_bounds(), } } diff --git a/src/librustc/middle/typeck/check/_match.rs b/src/librustc/middle/typeck/check/_match.rs index 18f4607a83c..77e5fbae6ee 100644 --- a/src/librustc/middle/typeck/check/_match.rs +++ b/src/librustc/middle/typeck/check/_match.rs @@ -658,10 +658,10 @@ pub fn check_pat(pcx: &pat_ctxt, pat: &ast::Pat, expected: ty::t) { let (elt_type, region_var, mutbl, fixed) = match *structure_of(fcx, pat.span, expected) { - ty::ty_vec(mt, Some(fixed)) => - (mt.ty, default_region_var, ast::MutImmutable, Some(fixed)), + ty::ty_vec(ty, Some(fixed)) => + (ty, default_region_var, ast::MutImmutable, Some(fixed)), ty::ty_uniq(t) => match ty::get(t).sty { - ty::ty_vec(mt, None) => { + ty::ty_vec(ty, None) => { fcx.type_error_message(pat.span, |_| { "unique vector patterns are no \ @@ -669,7 +669,7 @@ pub fn check_pat(pcx: &pat_ctxt, pat: &ast::Pat, expected: ty::t) { }, expected, None); - (mt.ty, default_region_var, ast::MutImmutable, None) + (ty, default_region_var, ast::MutImmutable, None) } _ => { check_err("a vector pattern".to_string()); @@ -677,7 +677,7 @@ pub fn check_pat(pcx: &pat_ctxt, pat: &ast::Pat, expected: ty::t) { } }, ty::ty_rptr(r, mt) => match ty::get(mt.ty).sty { - ty::ty_vec(mt, None) => (mt.ty, r, mt.mutbl, None), + ty::ty_vec(ty, None) => (ty, r, mt.mutbl, None), _ => { check_err("a vector pattern".to_string()); return; diff --git a/src/librustc/middle/typeck/check/demand.rs b/src/librustc/middle/typeck/check/demand.rs index 2359f9d72d2..1b10b30b335 100644 --- a/src/librustc/middle/typeck/check/demand.rs +++ b/src/librustc/middle/typeck/check/demand.rs @@ -77,3 +77,17 @@ pub fn coerce(fcx: &FnCtxt, sp: Span, expected: ty::t, expr: &ast::Expr) { } } } + +pub fn coerce_with_fn(fcx: &FnCtxt, + sp: Span, + expected: ty::t, + expr: &ast::Expr, + handle_err: |Span, ty::t, ty::t, &ty::type_err|) { + let expr_ty = fcx.expr_ty(expr); + match fcx.mk_assignty(expr, expr_ty, expected) { + result::Ok(()) => { /* ok */ } + result::Err(ref err) => { + handle_err(sp, expected, expr_ty, err); + } + } +} diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs index 245bbe396fd..f3b829e60ca 100644 --- a/src/librustc/middle/typeck/check/method.rs +++ b/src/librustc/middle/typeck/check/method.rs @@ -356,23 +356,14 @@ impl<'a> LookupContext<'a> { let span = self.self_expr.map_or(self.span, |e| e.span); let self_expr_id = self.self_expr.map(|e| e.id); - let (self_ty, autoderefs, result) = + let (_, _, result) = check::autoderef( self.fcx, span, self_ty, self_expr_id, PreferMutLvalue, |self_ty, autoderefs| self.search_step(self_ty, autoderefs)); match result { Some(Some(result)) => Some(result), - _ => { - if self.is_overloaded_deref() { - // If we are searching for an overloaded deref, no - // need to try coercing a `~[T]` to an `&[T]` and - // searching for an overloaded deref on *that*. - None - } else { - self.search_for_autosliced_method(self_ty, autoderefs) - } - } + _ => None } } @@ -408,6 +399,16 @@ impl<'a> LookupContext<'a> { } } + // If we are searching for an overloaded deref, no + // need to try coercing a `~[T]` to an `&[T]` and + // searching for an overloaded deref on *that*. + if !self.is_overloaded_deref() { + match self.search_for_autofatptrd_method(self_ty, autoderefs) { + Some(result) => return Some(Some(result)), + None => {} + } + } + // Don't autoderef if we aren't supposed to. if self.autoderef_receiver == DontAutoderefReceiver { Some(None) @@ -441,13 +442,10 @@ impl<'a> LookupContext<'a> { let span = self.self_expr.map_or(self.span, |e| e.span); check::autoderef(self.fcx, span, self_ty, None, PreferMutLvalue, |self_ty, _| { match get(self_ty).sty { - ty_uniq(ty) | ty_rptr(_, mt {ty, ..}) => match get(ty).sty{ - ty_trait(box TyTrait { def_id, ref substs, .. }) => { - self.push_inherent_candidates_from_object(def_id, substs); - self.push_inherent_impl_candidates_for_type(def_id); - } - _ => {} - }, + ty_trait(box TyTrait { def_id, ref substs, .. }) => { + self.push_inherent_candidates_from_object(def_id, substs); + self.push_inherent_impl_candidates_for_type(def_id); + } ty_enum(did, _) | ty_struct(did, _) | ty_unboxed_closure(did, _) => { @@ -830,23 +828,22 @@ impl<'a> LookupContext<'a> { self_ty: ty::t, autoderefs: uint) -> Option<MethodCallee> { - let (self_ty, auto_deref_ref) = - self.consider_reborrow(self_ty, autoderefs); - // Hacky. For overloaded derefs, there may be an adjustment // added to the expression from the outside context, so we do not store // an explicit adjustment, but rather we hardwire the single deref // that occurs in trans and mem_categorization. - let adjustment = match self.self_expr { - Some(expr) => Some((expr.id, ty::AutoDerefRef(auto_deref_ref))), - None => return None - }; + if self.self_expr.is_none() { + return None; + } + + let (self_ty, auto_deref_ref) = self.consider_reborrow(self_ty, autoderefs); + let adjustment = Some((self.self_expr.unwrap().id, ty::AutoDerefRef(auto_deref_ref))); match self.search_for_method(self_ty) { None => None, Some(method) => { debug!("(searching for autoderef'd method) writing \ - adjustment {:?} for {}", adjustment, self.ty_to_string( self_ty)); + adjustment {:?} for {}", adjustment, self.ty_to_string(self_ty)); match adjustment { Some((self_expr_id, adj)) => { self.fcx.write_adjustment(self_expr_id, adj); @@ -890,16 +887,10 @@ impl<'a> LookupContext<'a> { ty::ty_rptr(_, self_mt) => { let region = self.infcx().next_region_var(infer::Autoref(self.span)); - let (extra_derefs, auto) = match ty::get(self_mt.ty).sty { - ty::ty_vec(_, None) => (0, ty::AutoBorrowVec(region, self_mt.mutbl)), - ty::ty_str => (0, ty::AutoBorrowVec(region, self_mt.mutbl)), - ty::ty_trait(..) => (0, ty::AutoBorrowObj(region, self_mt.mutbl)), - _ => (1, ty::AutoPtr(region, self_mt.mutbl)), - }; (ty::mk_rptr(tcx, region, self_mt), ty::AutoDerefRef { - autoderefs: autoderefs + extra_derefs, - autoref: Some(auto)}) + autoderefs: autoderefs + 1, + autoref: Some(ty::AutoPtr(region, self_mt.mutbl, None))}) } _ => { (self_ty, @@ -920,15 +911,18 @@ impl<'a> LookupContext<'a> { } } - fn auto_slice_vec(&self, mt: ty::mt, autoderefs: uint) -> Option<MethodCallee> { + // Takes an [T] - an unwrapped DST pointer (either ~ or &) + // [T] to &[T] or &&[T] (note that we started with a &[T] or ~[T] which has + // been implicitly derefed). + fn auto_slice_vec(&self, ty: ty::t, autoderefs: uint) -> Option<MethodCallee> { let tcx = self.tcx(); - debug!("auto_slice_vec {}", ppaux::ty_to_string(tcx, mt.ty)); + debug!("auto_slice_vec {}", ppaux::ty_to_string(tcx, ty)); // First try to borrow to a slice let entry = self.search_for_some_kind_of_autorefd_method( - AutoBorrowVec, autoderefs, [MutImmutable, MutMutable], + |r, m| AutoPtr(r, m, None), autoderefs, [MutImmutable, MutMutable], |m,r| ty::mk_slice(tcx, r, - ty::mt {ty:mt.ty, mutbl:m})); + ty::mt {ty:ty, mutbl:m})); if entry.is_some() { return entry; @@ -936,10 +930,11 @@ impl<'a> LookupContext<'a> { // Then try to borrow to a slice *and* borrow a pointer. self.search_for_some_kind_of_autorefd_method( - AutoBorrowVecRef, autoderefs, [MutImmutable, MutMutable], - |m,r| { + |r, m| AutoPtr(r, ast::MutImmutable, Some( box AutoPtr(r, m, None))), + autoderefs, [MutImmutable, MutMutable], + |m, r| { let slice_ty = ty::mk_slice(tcx, r, - ty::mt {ty:mt.ty, mutbl:m}); + ty::mt {ty:ty, mutbl:m}); // NB: we do not try to autoref to a mutable // pointer. That would be creating a pointer // to a temporary pointer (the borrowed @@ -949,22 +944,59 @@ impl<'a> LookupContext<'a> { }) } + // [T, ..len] -> [T] or &[T] or &&[T] + fn auto_unsize_vec(&self, ty: ty::t, autoderefs: uint, len: uint) -> Option<MethodCallee> { + let tcx = self.tcx(); + debug!("auto_unsize_vec {}", ppaux::ty_to_str(tcx, ty)); + + // First try to borrow to an unsized vec. + let entry = self.search_for_some_kind_of_autorefd_method( + |_r, _m| AutoUnsize(ty::UnsizeLength(len)), + autoderefs, [MutImmutable, MutMutable], + |_m, _r| ty::mk_vec(tcx, ty, None)); + + if entry.is_some() { + return entry; + } + + // Then try to borrow to a slice. + let entry = self.search_for_some_kind_of_autorefd_method( + |r, m| AutoPtr(r, m, Some(box AutoUnsize(ty::UnsizeLength(len)))), + autoderefs, [MutImmutable, MutMutable], + |m, r| ty::mk_slice(tcx, r, ty::mt {ty:ty, mutbl:m})); + + if entry.is_some() { + return entry; + } + + // Then try to borrow to a slice *and* borrow a pointer. + self.search_for_some_kind_of_autorefd_method( + |r, m| AutoPtr(r, m, + Some(box AutoPtr(r, m, + Some(box AutoUnsize(ty::UnsizeLength(len)))))), + autoderefs, [MutImmutable, MutMutable], + |m, r| { + let slice_ty = ty::mk_slice(tcx, r, ty::mt {ty:ty, mutbl:m}); + ty::mk_rptr(tcx, r, ty::mt {ty:slice_ty, mutbl:MutImmutable}) + }) + } fn auto_slice_str(&self, autoderefs: uint) -> Option<MethodCallee> { let tcx = self.tcx(); debug!("auto_slice_str"); let entry = self.search_for_some_kind_of_autorefd_method( - AutoBorrowVec, autoderefs, [MutImmutable], - |_m,r| ty::mk_str_slice(tcx, r, MutImmutable)); + |r, m| AutoPtr(r, m, None), autoderefs, [MutImmutable], + |_m, r| ty::mk_str_slice(tcx, r, MutImmutable)); if entry.is_some() { return entry; } self.search_for_some_kind_of_autorefd_method( - AutoBorrowVecRef, autoderefs, [MutImmutable], - |m,r| { + |r, m| AutoPtr(r, ast::MutImmutable, Some( box AutoPtr(r, m, None))), + autoderefs, [MutImmutable], + |m, r| { let slice_ty = ty::mk_str_slice(tcx, r, m); ty::mk_rptr(tcx, r, ty::mt {ty:slice_ty, mutbl:m}) }) @@ -972,6 +1004,7 @@ impl<'a> LookupContext<'a> { // Coerce Box/&Trait instances to &Trait. fn auto_slice_trait(&self, ty: ty::t, autoderefs: uint) -> Option<MethodCallee> { + debug!("auto_slice_trait"); match ty::get(ty).sty { ty_trait(box ty::TyTrait { def_id: trt_did, @@ -980,7 +1013,8 @@ impl<'a> LookupContext<'a> { .. }) => { let tcx = self.tcx(); self.search_for_some_kind_of_autorefd_method( - AutoBorrowObj, autoderefs, [MutImmutable, MutMutable], + |r, m| AutoPtr(r, m, None), + autoderefs, [MutImmutable, MutMutable], |m, r| { let tr = ty::mk_trait(tcx, trt_did, trt_substs.clone(), b); ty::mk_rptr(tcx, r, ty::mt{ ty: tr, mutbl: m }) @@ -990,31 +1024,24 @@ impl<'a> LookupContext<'a> { } } - fn search_for_autosliced_method(&self, - self_ty: ty::t, - autoderefs: uint) - -> Option<MethodCallee> { + fn search_for_autofatptrd_method(&self, + self_ty: ty::t, + autoderefs: uint) + -> Option<MethodCallee> { /*! * Searches for a candidate by converting things like * `~[]` to `&[]`. */ - debug!("search_for_autosliced_method {}", ppaux::ty_to_string(self.tcx(), self_ty)); + let tcx = self.tcx(); + debug!("search_for_autofatptrd_method {}", ppaux::ty_to_string(tcx, self_ty)); let sty = ty::get(self_ty).sty.clone(); match sty { - ty_rptr(_, mt) => match ty::get(mt.ty).sty { - ty_vec(mt, None) => self.auto_slice_vec(mt, autoderefs), - ty_trait(..) => self.auto_slice_trait(mt.ty, autoderefs), - _ => None - }, - ty_uniq(t) => match ty::get(t).sty { - ty_vec(mt, None) => self.auto_slice_vec(mt, autoderefs), - ty_str => self.auto_slice_str(autoderefs), - ty_trait(..) => self.auto_slice_trait(t, autoderefs), - _ => None - }, - ty_vec(mt, Some(_)) => self.auto_slice_vec(mt, autoderefs), + ty_vec(ty, Some(len)) => self.auto_unsize_vec(ty, autoderefs, len), + ty_vec(ty, None) => self.auto_slice_vec(ty, autoderefs), + ty_str => self.auto_slice_str(autoderefs), + ty_trait(..) => self.auto_slice_trait(self_ty, autoderefs), ty_closure(..) => { // This case should probably be handled similarly to @@ -1042,10 +1069,10 @@ impl<'a> LookupContext<'a> { ty_param(..) | ty_nil | ty_bot | ty_bool | ty_char | ty_int(..) | ty_uint(..) | ty_float(..) | ty_enum(..) | ty_ptr(..) | ty_struct(..) | - ty_unboxed_closure(..) | ty_tup(..) | + ty_unboxed_closure(..) | ty_tup(..) | ty_open(..) | ty_str | ty_vec(..) | ty_trait(..) | ty_closure(..) => { self.search_for_some_kind_of_autorefd_method( - AutoPtr, autoderefs, [MutImmutable, MutMutable], + |r, m| AutoPtr(r, m, None), autoderefs, [MutImmutable, MutMutable], |m,r| ty::mk_rptr(tcx, r, ty::mt {ty:self_ty, mutbl:m})) } @@ -1073,8 +1100,8 @@ impl<'a> LookupContext<'a> { Some(expr) => Some(expr.id), None => { assert_eq!(autoderefs, 0); - assert_eq!(kind(ty::ReEmpty, ast::MutImmutable), - ty::AutoPtr(ty::ReEmpty, ast::MutImmutable)); + assert!(kind(ty::ReEmpty, ast::MutImmutable) == + ty::AutoPtr(ty::ReEmpty, ast::MutImmutable, None)); None } }; @@ -1303,7 +1330,7 @@ impl<'a> LookupContext<'a> { match self.fcx.mk_subty(false, infer::Misc(span), rcvr_ty, transformed_self_ty) { Ok(_) => {} - Err(_) => { + Err(e) => { self.bug(format!( "{} was a subtype of {} but now is not?", self.ty_to_string(rcvr_ty), @@ -1442,17 +1469,15 @@ impl<'a> LookupContext<'a> { match ty::get(rcvr_ty).sty { ty::ty_rptr(_, mt) => { match ty::get(mt.ty).sty { - ty::ty_vec(_, None) | ty::ty_str => false, ty::ty_trait(box ty::TyTrait { def_id: self_did, .. }) => { mutability_matches(mt.mutbl, m) && rcvr_matches_object(self_did, candidate) } _ => mutability_matches(mt.mutbl, m) && - rcvr_matches_ty(self.fcx, mt.ty, candidate), + rcvr_matches_ty(self.fcx, mt.ty, candidate) } } - _ => false } } @@ -1462,7 +1487,6 @@ impl<'a> LookupContext<'a> { match ty::get(rcvr_ty).sty { ty::ty_uniq(typ) => { match ty::get(typ).sty { - ty::ty_vec(_, None) | ty::ty_str => false, ty::ty_trait(box ty::TyTrait { def_id: self_did, .. }) => { rcvr_matches_object(self_did, candidate) } diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index 02115590c7e..6d3e001a00b 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -560,21 +560,6 @@ fn check_fn<'a>(ccx: &'a CrateCtxt<'a>, check_block_with_expected(&fcx, body, ExpectHasType(ret_ty)); - // We unify the tail expr's type with the - // function result type, if there is a tail expr. - match body.expr { - Some(ref tail_expr) => { - // Special case: we print a special error if there appears - // to be do-block/for-loop confusion - demand::suptype_with_fn(&fcx, tail_expr.span, false, - fcx.ret_ty, fcx.expr_ty(&**tail_expr), - |sp, e, a, s| { - fcx.report_mismatched_return_types(sp, e, a, s); - }); - } - None => {} - } - for (input, arg) in decl.inputs.iter().zip(arg_tys.iter()) { fcx.write_ty(input.id, *arg); } @@ -2436,8 +2421,20 @@ fn check_expr_with_unifier(fcx: &FnCtxt, // The tightest thing we can say is "must unify with // else branch". Note that in the case of a "has type" // constraint, this limitation does not hold. - let expected = expected.only_has_type(); + // If the expected type is just a type variable, then don't use + // an expected type. Otherwise, we might write parts of the type + // when checking the 'then' block which are incompatible with the + // 'else' branch. + let expected = match expected.only_has_type() { + ExpectHasType(ety) => { + match infer::resolve_type(fcx.infcx(), ety, force_tvar) { + Ok(rty) if !ty::type_is_ty_var(rty) => ExpectHasType(rty), + _ => NoExpectation + } + } + None => None + }; check_block_with_expected(fcx, then_blk, expected); let then_ty = fcx.node_ty(then_blk.id); check_expr_with_expectation(fcx, &**else_expr, expected); @@ -3090,76 +3087,6 @@ fn check_expr_with_unifier(fcx: &FnCtxt, let tcx = fcx.ccx.tcx; let id = expr.id; match expr.node { - ast::ExprVstore(ev, vst) => { - let (check, t) = check_fn_for_vec_elements_expected(fcx, expected); - let typ = match ev.node { - ast::ExprVec(ref args) => { - let mutability = match vst { - ast::ExprVstoreMutSlice => ast::MutMutable, - _ => ast::MutImmutable, - }; - let mut any_error = false; - let mut any_bot = false; - for e in args.iter() { - check(fcx, &**e, t); - let arg_t = fcx.expr_ty(&**e); - if ty::type_is_error(arg_t) { - any_error = true; - } - else if ty::type_is_bot(arg_t) { - any_bot = true; - } - } - if any_error { - ty::mk_err() - } else if any_bot { - ty::mk_bot() - } else { - ast_expr_vstore_to_ty(fcx, &*ev, vst, || - ty::mt{ ty: ty::mk_vec(tcx, - ty::mt {ty: t, mutbl: mutability}, - None), - mutbl: mutability }) - } - } - ast::ExprRepeat(ref element, ref count_expr) => { - check_expr_with_hint(fcx, &**count_expr, ty::mk_uint()); - let _ = ty::eval_repeat_count(fcx, &**count_expr); - let mutability = match vst { - ast::ExprVstoreMutSlice => ast::MutMutable, - _ => ast::MutImmutable, - }; - check(fcx, &**element, t); - let arg_t = fcx.expr_ty(&**element); - if ty::type_is_error(arg_t) { - ty::mk_err() - } else if ty::type_is_bot(arg_t) { - ty::mk_bot() - } else { - ast_expr_vstore_to_ty(fcx, &*ev, vst, || - ty::mt{ ty: ty::mk_vec(tcx, - ty::mt {ty: t, mutbl: mutability}, - None), - mutbl: mutability}) - } - } - ast::ExprLit(_) => { - if vst == ast::ExprVstoreSlice { - span_err!(tcx.sess, expr.span, E0064, - "`&\"string\"` has been removed; use `\"string\"` instead"); - } else { - span_err!(tcx.sess, expr.span, E0065, - "`box \"string\"` has been removed; use \ - `\"string\".to_string()` instead"); - } - ty::mk_err() - } - _ => tcx.sess.span_bug(expr.span, "vstore modifier on non-sequence"), - }; - fcx.write_ty(ev.id, typ); - fcx.write_ty(id, typ); - } - ast::ExprBox(ref place, ref subexpr) => { check_expr(fcx, &**place); check_expr(fcx, &**subexpr); @@ -3337,22 +3264,6 @@ fn check_expr_with_unifier(fcx: &FnCtxt, hint, lvalue_pref); - // Note: at this point, we cannot say what the best lifetime - // is to use for resulting pointer. We want to use the - // shortest lifetime possible so as to avoid spurious borrowck - // errors. Moreover, the longest lifetime will depend on the - // precise details of the value whose address is being taken - // (and how long it is valid), which we don't know yet until type - // inference is complete. - // - // Therefore, here we simply generate a region variable. The - // region inferencer will then select the ultimate value. - // Finally, borrowck is charged with guaranteeing that the - // value whose address was taken can actually be made to live - // as long as it needs to live. - let region = fcx.infcx().next_region_var( - infer::AddrOfRegion(expr.span)); - let tm = ty::mt { ty: fcx.expr_ty(&**oprnd), mutbl: mutbl }; let oprnd_t = if ty::type_is_error(tm.ty) { ty::mk_err() @@ -3360,7 +3271,31 @@ fn check_expr_with_unifier(fcx: &FnCtxt, ty::mk_bot() } else { - ty::mk_rptr(tcx, region, tm) + // Note: at this point, we cannot say what the best lifetime + // is to use for resulting pointer. We want to use the + // shortest lifetime possible so as to avoid spurious borrowck + // errors. Moreover, the longest lifetime will depend on the + // precise details of the value whose address is being taken + // (and how long it is valid), which we don't know yet until type + // inference is complete. + // + // Therefore, here we simply generate a region variable. The + // region inferencer will then select the ultimate value. + // Finally, borrowck is charged with guaranteeing that the + // value whose address was taken can actually be made to live + // as long as it needs to live. + match oprnd.node { + // String literals are already, implicitly converted to slices. + //ast::ExprLit(lit) if ast_util::lit_is_str(lit) => fcx.expr_ty(oprnd), + // Empty slices live in static memory. + ast::ExprVec(ref elements) if elements.len() == 0 => { + ty::mk_rptr(tcx, ty::ReStatic, tm) + } + _ => { + let region = fcx.infcx().next_region_var(infer::AddrOfRegion(expr.span)); + ty::mk_rptr(tcx, region, tm) + } + } }; fcx.write_ty(id, oprnd_t); } @@ -3393,7 +3328,8 @@ fn check_expr_with_unifier(fcx: &FnCtxt, } }, Some(ref e) => { - check_expr_has_type(fcx, &**e, ret_ty); + //check_expr_has_type(fcx, e, ret_ty); + check_expr_coercable_to_type(fcx, &**e, ret_ty); } } fcx.write_bot(id); @@ -3547,29 +3483,60 @@ fn check_expr_with_unifier(fcx: &FnCtxt, check_cast(fcx, &**e, &**t, id, expr.span); } ast::ExprVec(ref args) => { - let (check, t) = check_fn_for_vec_elements_expected(fcx, expected); - for e in args.iter() { - check(fcx, &**e, t); - } - let typ = ty::mk_vec(tcx, ty::mt {ty: t, mutbl: ast::MutImmutable}, - Some(args.len())); + let uty = unpack_expected( + fcx, expected, + |sty| match *sty { + ty::ty_vec(ty, _) => Some(ty), + _ => None + }); + + let typ = match uty { + Some(uty) => { + for e in args.iter() { + check_expr_coercable_to_type(fcx, &**e, uty); + } + uty + } + None => { + let t: ty::t = fcx.infcx().next_ty_var(); + for e in args.iter() { + check_expr_has_type(fcx, &**e, t); + } + t + } + }; + let typ = ty::mk_vec(tcx, typ, Some(args.len())); fcx.write_ty(id, typ); } ast::ExprRepeat(ref element, ref count_expr) => { check_expr_has_type(fcx, &**count_expr, ty::mk_uint()); let count = ty::eval_repeat_count(fcx, &**count_expr); - let (check, t) = check_fn_for_vec_elements_expected(fcx, expected); - check(fcx, &**element, t); - let element_ty = fcx.expr_ty(&**element); + + let uty = unpack_expected( + fcx, expected, + |sty| match *sty { + ty::ty_vec(ty, _) => Some(ty), + _ => None + }); + + let (element_ty, t) = match uty { + Some(uty) => { + check_expr_coercable_to_type(fcx, &**element, uty); + (uty, uty) + } + None => { + let t: ty::t = fcx.infcx().next_ty_var(); + check_expr_has_type(fcx, &**element, t); + (fcx.expr_ty(&**element), t) + } + }; + if ty::type_is_error(element_ty) { fcx.write_error(id); - } - else if ty::type_is_bot(element_ty) { + } else if ty::type_is_bot(element_ty) { fcx.write_bot(id); - } - else { - let t = ty::mk_vec(tcx, ty::mt {ty: t, mutbl: ast::MutImmutable}, - Some(count)); + } else { + let t = ty::mk_vec(tcx, t, Some(count)); fcx.write_ty(id, t); } } @@ -3589,8 +3556,16 @@ fn check_expr_with_unifier(fcx: &FnCtxt, Some(ref fs) if i < fs.len() => ExpectHasType(*fs.get(i)), _ => NoExpectation }; - check_expr_with_expectation(fcx, &**e, opt_hint); - let t = fcx.expr_ty(&**e); + let t = match opt_hint { + ExpectHasType(ety) => { + check_expr_coercable_to_type(fcx, &**e, ety); + ety + } + _ => { + check_expr_with_expectation(fcx, &**e, opt_hint); + fcx.expr_ty(&**e) + } + }; err_field = err_field || ty::type_is_error(t); bot_field = bot_field || ty::type_is_bot(t); t @@ -3702,9 +3677,9 @@ fn check_expr_with_unifier(fcx: &FnCtxt, autoderef(fcx, expr.span, raw_base_t, Some(base.id), lvalue_pref, |base_t, _| ty::index(base_t)); match field_ty { - Some(mt) => { + Some(ty) => { check_expr_has_type(fcx, &**idx, ty::mk_uint()); - fcx.write_ty(id, mt.ty); + fcx.write_ty(id, ty); fcx.write_autoderef_adjustment(base.id, autoderefs); } None => { @@ -3985,15 +3960,23 @@ fn check_block_with_expected(fcx: &FnCtxt, e.span, "unreachable expression".to_string()); } - check_expr_with_expectation(fcx, &*e, expected); - let ety = fcx.expr_ty(&*e); - fcx.write_ty(blk.id, ety); - if any_err { - fcx.write_error(blk.id); - } - else if any_bot { - fcx.write_bot(blk.id); - } + let ety = match expected { + ExpectHasType(ety) => { + check_expr_coercable_to_type(fcx, &*e, ety); + ety + } + _ => { + check_expr_with_expectation(fcx, &*e, expected); + fcx.expr_ty(e) + } + }; + + fcx.write_ty(blk.id, ety); + if any_err { + fcx.write_error(blk.id); + } else if any_bot { + fcx.write_bot(blk.id); + } } }; }); @@ -4040,9 +4023,8 @@ pub fn check_const_with_ty(fcx: &FnCtxt, // emit a error. GatherLocalsVisitor { fcx: fcx }.visit_expr(e, ()); - check_expr(fcx, e); - let cty = fcx.expr_ty(e); - demand::suptype(fcx, e.span, declty, cty); + check_expr_with_hint(fcx, e, declty); + demand::coerce(fcx, e.span, declty, e); regionck::regionck_expr(fcx, e); writeback::resolve_type_vars_in_expr(fcx, e); } @@ -4132,6 +4114,7 @@ pub fn check_simd(tcx: &ty::ctxt, sp: Span, id: ast::NodeId) { } } + pub fn check_enum_variants_sized(ccx: &CrateCtxt, vs: &[ast::P<ast::Variant>]) { for &v in vs.iter() { @@ -4747,39 +4730,39 @@ pub fn type_is_uint(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool { return ty::type_is_uint(typ_s); } -pub fn ast_expr_vstore_to_ty(fcx: &FnCtxt, - e: &ast::Expr, - v: ast::ExprVstore, - mk_inner: || -> ty::mt) - -> ty::t { - match v { - ast::ExprVstoreUniq => ty::mk_uniq(fcx.ccx.tcx, mk_inner().ty), - ast::ExprVstoreSlice | ast::ExprVstoreMutSlice => { - match e.node { - ast::ExprLit(..) => { - // string literals and *empty slices* live in static memory - ty::mk_rptr(fcx.ccx.tcx, ty::ReStatic, mk_inner()) - } - ast::ExprVec(ref elements) if elements.len() == 0 => { - // string literals and *empty slices* live in static memory - ty::mk_rptr(fcx.ccx.tcx, ty::ReStatic, mk_inner()) - } - ast::ExprRepeat(..) | - ast::ExprVec(..) => { - // vector literals are temporaries on the stack - match fcx.tcx().region_maps.temporary_scope(e.id) { - Some(scope) => ty::mk_rptr(fcx.ccx.tcx, ty::ReScope(scope), mk_inner()), - None => ty::mk_rptr(fcx.ccx.tcx, ty::ReStatic, mk_inner()), - } - } - _ => { - fcx.ccx.tcx.sess.span_bug(e.span, - "vstore with unexpected \ - contents") - } - } - } - } +pub fn type_is_scalar(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool { + let typ_s = structurally_resolved_type(fcx, sp, typ); + return ty::type_is_scalar(typ_s); +} + +pub fn type_is_char(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool { + let typ_s = structurally_resolved_type(fcx, sp, typ); + return ty::type_is_char(typ_s); +} + +pub fn type_is_bare_fn(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool { + let typ_s = structurally_resolved_type(fcx, sp, typ); + return ty::type_is_bare_fn(typ_s); +} + +pub fn type_is_floating_point(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool { + let typ_s = structurally_resolved_type(fcx, sp, typ); + return ty::type_is_floating_point(typ_s); +} + +pub fn type_is_unsafe_ptr(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool { + let typ_s = structurally_resolved_type(fcx, sp, typ); + return ty::type_is_unsafe_ptr(typ_s); +} + +pub fn type_is_region_ptr(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool { + let typ_s = structurally_resolved_type(fcx, sp, typ); + return ty::type_is_region_ptr(typ_s); +} + +pub fn type_is_c_like_enum(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool { + let typ_s = structurally_resolved_type(fcx, sp, typ); + return ty::type_is_c_like_enum(fcx.ccx.tcx, typ_s); } // Returns true if b contains a break that can exit from b diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs index 3813dd79642..4f77c89e86c 100644 --- a/src/librustc/middle/typeck/check/regionck.rs +++ b/src/librustc/middle/typeck/check/regionck.rs @@ -413,40 +413,43 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) { for &adjustment in rcx.fcx.inh.adjustments.borrow().find(&expr.id).iter() { debug!("adjustment={:?}", adjustment); match *adjustment { - ty::AutoDerefRef(ty::AutoDerefRef {autoderefs, autoref: opt_autoref}) => { + ty::AutoDerefRef(ty::AutoDerefRef {autoderefs, autoref: ref opt_autoref}) => { let expr_ty = rcx.resolve_node_type(expr.id); constrain_autoderefs(rcx, expr, autoderefs, expr_ty); - for autoref in opt_autoref.iter() { - link_autoref(rcx, expr, autoderefs, autoref); - - // Require that the resulting region encompasses - // the current node. - // - // FIXME(#6268) remove to support nested method calls - constrain_regions_in_type_of_node( - rcx, expr.id, ty::ReScope(expr.id), - infer::AutoBorrow(expr.span)); + match ty::adjusted_object_region(adjustment) { + Some(trait_region) => { + // Determine if we are casting `expr` to a trait + // instance. If so, we have to be sure that the type of + // the source obeys the trait's region bound. + // + // Note: there is a subtle point here concerning type + // parameters. It is possible that the type of `source` + // contains type parameters, which in turn may contain + // regions that are not visible to us (only the caller + // knows about them). The kind checker is ultimately + // responsible for guaranteeing region safety in that + // particular case. There is an extensive comment on the + // function check_cast_for_escaping_regions() in kind.rs + // explaining how it goes about doing that. + + constrain_regions_in_type(rcx, trait_region, + infer::RelateObjectBound(expr.span), expr_ty); + } + None => { + for autoref in opt_autoref.iter() { + link_autoref(rcx, expr, autoderefs, autoref); + + // Require that the resulting region encompasses + // the current node. + // + // FIXME(#6268) remove to support nested method calls + constrain_regions_in_type_of_node( + rcx, expr.id, ty::ReScope(expr.id), + infer::AutoBorrow(expr.span)); + } + } } } - ty::AutoObject(ty::RegionTraitStore(trait_region, _), _, _, _) => { - // Determine if we are casting `expr` to a trait - // instance. If so, we have to be sure that the type of - // the source obeys the trait's region bound. - // - // Note: there is a subtle point here concerning type - // parameters. It is possible that the type of `source` - // contains type parameters, which in turn may contain - // regions that are not visible to us (only the caller - // knows about them). The kind checker is ultimately - // responsible for guaranteeing region safety in that - // particular case. There is an extensive comment on the - // function check_cast_for_escaping_regions() in kind.rs - // explaining how it goes about doing that. - - let source_ty = rcx.resolve_node_type(expr.id); - constrain_regions_in_type(rcx, trait_region, - infer::RelateObjectBound(expr.span), source_ty); - } _ => {} } } @@ -1176,24 +1179,12 @@ fn link_autoref(rcx: &Rcx, debug!("expr_cmt={}", expr_cmt.repr(rcx.tcx())); match *autoref { - ty::AutoPtr(r, m) => { - link_region(rcx, expr.span, r, - ty::BorrowKind::from_mutbl(m), expr_cmt); - } - - ty::AutoBorrowVec(r, m) | ty::AutoBorrowVecRef(r, m) => { - let cmt_index = mc.cat_index(expr, expr_cmt, autoderefs+1); - link_region(rcx, expr.span, r, - ty::BorrowKind::from_mutbl(m), cmt_index); - } - - ty::AutoBorrowObj(r, m) => { - let cmt_deref = mc.cat_deref_obj(expr, expr_cmt); + ty::AutoPtr(r, m, _) => { link_region(rcx, expr.span, r, - ty::BorrowKind::from_mutbl(m), cmt_deref); + ty::BorrowKind::from_mutbl(m), expr_cmt); } - ty::AutoUnsafe(_) => {} + ty::AutoUnsafe(_) | ty::AutoUnsizeUniq(_) | ty::AutoUnsize(_) => {} } } diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs index bc53ed58f6f..5b14ee62b0a 100644 --- a/src/librustc/middle/typeck/check/vtable.rs +++ b/src/librustc/middle/typeck/check/vtable.rs @@ -10,7 +10,7 @@ use middle::ty; -use middle::ty::{AutoAddEnv, AutoDerefRef, AutoObject, ParamTy}; +use middle::ty::{AutoDerefRef, ParamTy}; use middle::ty_fold::TypeFolder; use middle::typeck::astconv::AstConv; use middle::typeck::check::{FnCtxt, impl_self_ty}; @@ -388,7 +388,6 @@ fn search_for_vtable(vcx: &VtableContext, trait_ref: Rc<ty::TraitRef>, is_early: bool) -> Option<vtable_origin> { - debug!("nrc - search_for_vtable"); let tcx = vcx.tcx(); // First, check to see whether this is a call to the `call` method of an @@ -630,14 +629,8 @@ pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) { let _indent = indenter(); let cx = fcx.ccx; - let resolve_object_cast = |src: &ast::Expr, target_ty: ty::t, key: MethodCall| { - // Look up vtables for the type we're casting to, - // passing in the source and target type. The source - // must be a pointer type suitable to the object sigil, - // e.g.: `&x as &Trait` or `box x as Box<Trait>` - // Bounds of type's contents are not checked here, but in kind.rs. - let src_ty = structurally_resolved_type(fcx, ex.span, - fcx.expr_ty(src)); + let check_object_cast = |src_ty: ty::t, target_ty: ty::t| { + // Check that a cast is of correct types. match (&ty::get(target_ty).sty, &ty::get(src_ty).sty) { (&ty::ty_rptr(_, ty::mt{ty, mutbl}), &ty::ty_rptr(_, mt)) if !mutability_allowed(mt.mutbl, mutbl) => { @@ -648,74 +641,14 @@ pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) { _ => {} } } - - (&ty::ty_uniq(ty), &ty::ty_uniq(..) ) | - (&ty::ty_rptr(_, ty::mt{ty, ..}), &ty::ty_rptr(..)) => { - match ty::get(ty).sty { - ty::ty_trait(box ty::TyTrait { - def_id: target_def_id, substs: ref target_substs, .. - }) => { - debug!("nrc correct path"); - let typ = match &ty::get(src_ty).sty { - &ty::ty_uniq(typ) => typ, - &ty::ty_rptr(_, mt) => mt.ty, - _ => fail!("shouldn't get here"), - }; - - let vcx = fcx.vtable_context(); - - // Take the type parameters from the object - // type, but set the Self type (which is - // unknown, for the object type) to be the type - // we are casting from. - let mut target_types = target_substs.types.clone(); - assert!(target_types.get_self().is_none()); - target_types.push(subst::SelfSpace, typ); - - let target_trait_ref = Rc::new(ty::TraitRef { - def_id: target_def_id, - substs: subst::Substs { - regions: target_substs.regions.clone(), - types: target_types - } - }); - - let param_bounds = ty::ParamBounds { - builtin_bounds: ty::empty_builtin_bounds(), - trait_bounds: vec!(target_trait_ref) - }; - let vtables = - lookup_vtables_for_param(&vcx, - ex.span, - None, - ¶m_bounds, - typ, - is_early); - - if !is_early { - let mut r = VecPerParamSpace::empty(); - r.push(subst::SelfSpace, vtables); - insert_vtables(fcx, key, r); - } - - // Now, if this is &trait, we need to link the - // regions. - match (&ty::get(src_ty).sty, &ty::get(target_ty).sty) { - (&ty::ty_rptr(ra, _), &ty::ty_rptr(rb, _)) => { - debug!("nrc - make subr"); - infer::mk_subr(fcx.infcx(), - false, - infer::RelateObjectBound(ex.span), - rb, - ra); - } - _ => {} - } - } - _ => {} - } + (&ty::ty_uniq(..), &ty::ty_uniq(..) ) => {} + (&ty::ty_rptr(r_t, _), &ty::ty_rptr(r_s, _)) => { + infer::mk_subr(fcx.infcx(), + false, + infer::RelateObjectBound(ex.span), + r_t, + r_s); } - (&ty::ty_uniq(ty), _) => { match ty::get(ty).sty { ty::ty_trait(..) => { @@ -737,7 +670,55 @@ pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) { _ => {} } } + _ => {} + } + }; + let resolve_object_cast = |src_ty: ty::t, target_ty: ty::t, key: MethodCall| { + // Look up vtables for the type we're casting to, + // passing in the source and target type. The source + // must be a pointer type suitable to the object sigil, + // e.g.: `&x as &Trait` or `box x as Box<Trait>` + // Bounds of type's contents are not checked here, but in kind.rs. + match ty::get(target_ty).sty { + ty::ty_trait(box ty::TyTrait { + def_id: target_def_id, substs: ref target_substs, .. + }) => { + let vcx = fcx.vtable_context(); + + // Take the type parameters from the object + // type, but set the Self type (which is + // unknown, for the object type) to be the type + // we are casting from. + let mut target_types = target_substs.types.clone(); + assert!(target_types.get_self().is_none()); + target_types.push(subst::SelfSpace, src_ty); + + let target_trait_ref = Rc::new(ty::TraitRef { + def_id: target_def_id, + substs: subst::Substs { + regions: target_substs.regions.clone(), + types: target_types + } + }); + + let param_bounds = ty::ParamBounds { + builtin_bounds: ty::empty_builtin_bounds(), + trait_bounds: vec!(target_trait_ref) + }; + let vtables = + lookup_vtables_for_param(&vcx, + ex.span, + None, + ¶m_bounds, + src_ty, + is_early); + if !is_early { + let mut r = VecPerParamSpace::empty(); + r.push(subst::SelfSpace, vtables); + insert_vtables(fcx, key, r); + } + } _ => {} } }; @@ -792,8 +773,16 @@ pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) { ast::ExprCast(ref src, _) => { debug!("vtable resolution on expr {}", ex.repr(fcx.tcx())); let target_ty = fcx.expr_ty(ex); - let key = MethodCall::expr(ex.id); - resolve_object_cast(&**src, target_ty, key); + let src_ty = structurally_resolved_type(fcx, ex.span, + fcx.expr_ty(&**src)); + check_object_cast(src_ty, target_ty); + match (ty::deref(src_ty, false), ty::deref(target_ty, false)) { + (Some(s), Some(t)) => { + let key = MethodCall::expr(ex.id); + resolve_object_cast(s.ty, t.ty, key) + } + _ => {} + } } _ => () } @@ -802,7 +791,26 @@ pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) { match fcx.inh.adjustments.borrow().find(&ex.id) { Some(adjustment) => { match *adjustment { - AutoDerefRef(adj) => { + _ if ty::adjust_is_object(adjustment) => { + let src_ty = structurally_resolved_type(fcx, ex.span, + fcx.expr_ty(ex)); + match ty::type_of_adjust(fcx.tcx(), adjustment) { + Some(target_ty) => { + check_object_cast(src_ty, target_ty) + } + None => {} + } + + match trait_cast_types(fcx, adjustment, src_ty, ex.span) { + Some((s, t)) => { + let key = MethodCall::autoobject(ex.id); + resolve_object_cast(s, t, key) + } + None => fail!("Couldn't extract types from adjustment") + } + } + AutoDerefRef(ref adj) => { + assert!(!ty::adjust_is_object(adjustment)); for autoderef in range(0, adj.autoderefs) { let method_call = MethodCall::autoderef(ex.id, autoderef); match fcx.inh.method_map.borrow().find(&method_call) { @@ -823,37 +831,83 @@ pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) { } } } - AutoObject(store, - bounds, - def_id, - ref substs) => { - debug!("doing trait adjustment for expr {} {} \ - (early? {})", - ex.id, - ex.repr(fcx.tcx()), - is_early); - - let trait_ty = ty::mk_trait(cx.tcx, - def_id, - substs.clone(), - bounds); - let object_ty = match store { - ty::UniqTraitStore => ty::mk_uniq(cx.tcx, trait_ty), - ty::RegionTraitStore(r, m) => { - ty::mk_rptr(cx.tcx, r, ty::mt {ty: trait_ty, mutbl: m}) - } - }; - - let key = MethodCall::autoobject(ex.id); - resolve_object_cast(ex, object_ty, key); + _ => { + assert!(!ty::adjust_is_object(adjustment)); } - AutoAddEnv(..) => {} } } None => {} } } +// When we coerce (possibly implicitly) from a concrete type to a trait type, this +// function returns the concrete type and trait. This might happen arbitrarily +// deep in the adjustment. This function will fail if the adjustment does not +// match the source type. +// This function will always return types if ty::adjust_is_object is true for the +// adjustment +fn trait_cast_types(fcx: &FnCtxt, + adj: &ty::AutoAdjustment, + src_ty: ty::t, + sp: Span) + -> Option<(ty::t, ty::t)> { + fn trait_cast_types_autoref(fcx: &FnCtxt, + autoref: &ty::AutoRef, + src_ty: ty::t, + sp: Span) + -> Option<(ty::t, ty::t)> { + fn trait_cast_types_unsize(fcx: &FnCtxt, + k: &ty::UnsizeKind, + src_ty: ty::t, + sp: Span) + -> Option<(ty::t, ty::t)> { + match k { + &ty::UnsizeVtable(bounds, def_id, ref substs) => { + Some((src_ty, ty::mk_trait(fcx.tcx(), def_id, substs.clone(), bounds))) + } + &ty::UnsizeStruct(box ref k, tp_index) => match ty::get(src_ty).sty { + ty::ty_struct(_, ref substs) => { + let ty_substs = substs.types.get_vec(subst::TypeSpace); + let field_ty = *ty_substs.get(tp_index); + let field_ty = structurally_resolved_type(fcx, sp, field_ty); + trait_cast_types_unsize(fcx, k, field_ty, sp) + } + _ => fail!("Failed to find a ty_struct to correspond with \ + UnsizeStruct whilst walking adjustment. Found {}", + ppaux::ty_to_str(fcx.tcx(), src_ty)) + }, + _ => None + } + } + + match autoref { + &ty::AutoUnsize(ref k) => trait_cast_types_unsize(fcx, k, src_ty, sp), + &ty::AutoUnsizeUniq(ref k) => match k { + &ty::UnsizeVtable(bounds, def_id, ref substs) => { + Some((src_ty, ty::mk_trait(fcx.tcx(), def_id, substs.clone(), bounds))) + } + _ => None + }, + &ty::AutoPtr(_, _, Some(box ref autoref)) => { + trait_cast_types_autoref(fcx, autoref, src_ty, sp) + } + _ => None + } + } + + match adj { + &ty::AutoDerefRef(AutoDerefRef{autoref: Some(ref autoref), autoderefs}) => { + let mut derefed_type = src_ty; + for _ in range(0, autoderefs) { + derefed_type = ty::deref(derefed_type, false).unwrap().ty; + derefed_type = structurally_resolved_type(fcx, sp, derefed_type) + } + trait_cast_types_autoref(fcx, autoref, derefed_type, sp) + } + _ => None + } +} + pub fn resolve_impl(tcx: &ty::ctxt, impl_item: &ast::Item, impl_generics: &ty::Generics, diff --git a/src/librustc/middle/typeck/check/writeback.rs b/src/librustc/middle/typeck/check/writeback.rs index 892a62249ac..7951c8dfc19 100644 --- a/src/librustc/middle/typeck/check/writeback.rs +++ b/src/librustc/middle/typeck/check/writeback.rs @@ -259,6 +259,7 @@ impl<'cx> WritebackCx<'cx> { } Some(adjustment) => { + let adj_object = ty::adjust_is_object(&adjustment); let resolved_adjustment = match adjustment { ty::AutoAddEnv(store) => { // FIXME(eddyb) #2190 Allow only statically resolved @@ -286,24 +287,17 @@ impl<'cx> WritebackCx<'cx> { self.visit_vtable_map_entry(reason, method_call); } + if adj_object { + let method_call = MethodCall::autoobject(id); + self.visit_method_map_entry(reason, method_call); + self.visit_vtable_map_entry(reason, method_call); + } + ty::AutoDerefRef(ty::AutoDerefRef { autoderefs: adj.autoderefs, autoref: self.resolve(&adj.autoref, reason), }) } - - ty::AutoObject(trait_store, bb, def_id, substs) => { - let method_call = MethodCall::autoobject(id); - self.visit_method_map_entry(reason, method_call); - self.visit_vtable_map_entry(reason, method_call); - - ty::AutoObject( - self.resolve(&trait_store, reason), - self.resolve(&bb, reason), - def_id, - self.resolve(&substs, reason) - ) - } }; debug!("Adjustments for node {}: {:?}", id, resolved_adjustment); self.tcx().adjustments.borrow_mut().insert( diff --git a/src/librustc/middle/typeck/coherence.rs b/src/librustc/middle/typeck/coherence.rs index 3dee787b6c9..a6fa9d84600 100644 --- a/src/librustc/middle/typeck/coherence.rs +++ b/src/librustc/middle/typeck/coherence.rs @@ -23,7 +23,7 @@ use middle::ty::get; use middle::ty::{ImplContainer, ImplOrTraitItemId, MethodTraitItemId}; use middle::ty::{lookup_item_type}; use middle::ty::{t, ty_bool, ty_char, ty_bot, ty_box, ty_enum, ty_err}; -use middle::ty::{ty_str, ty_vec, ty_float, ty_infer, ty_int, ty_nil}; +use middle::ty::{ty_str, ty_vec, ty_float, ty_infer, ty_int, ty_nil, ty_open}; use middle::ty::{ty_param, Polytype, ty_ptr}; use middle::ty::{ty_rptr, ty_struct, ty_trait, ty_tup}; use middle::ty::{ty_uint, ty_unboxed_closure, ty_uniq, ty_bare_fn}; @@ -86,7 +86,7 @@ fn get_base_type(inference_context: &InferCtxt, ty_nil | ty_bot | ty_bool | ty_char | ty_int(..) | ty_uint(..) | ty_float(..) | ty_str(..) | ty_vec(..) | ty_bare_fn(..) | ty_closure(..) | ty_tup(..) | - ty_infer(..) | ty_param(..) | ty_err | + ty_infer(..) | ty_param(..) | ty_err | ty_open(..) | ty_box(_) | ty_uniq(_) | ty_ptr(_) | ty_rptr(_, _) => { debug!("(getting base type) no base type; found {:?}", get(original_type).sty); @@ -166,6 +166,9 @@ fn get_base_type_def_id(inference_context: &InferCtxt, enum, struct, or trait"); } }, + ty_trait(box ty::TyTrait { def_id, .. }) => { + Some(def_id) + } _ => { fail!("get_base_type() returned a type that wasn't an \ enum, struct, or trait"); diff --git a/src/librustc/middle/typeck/infer/coercion.rs b/src/librustc/middle/typeck/infer/coercion.rs index 03890250f77..6d0b34e89d6 100644 --- a/src/librustc/middle/typeck/infer/coercion.rs +++ b/src/librustc/middle/typeck/infer/coercion.rs @@ -65,7 +65,7 @@ we may want to adjust precisely when coercions occur. */ use middle::subst; -use middle::ty::{AutoPtr, AutoBorrowVec, AutoBorrowObj, AutoDerefRef}; +use middle::ty::{AutoPtr, AutoDerefRef, AutoUnsize}; use middle::ty::{mt}; use middle::ty; use middle::typeck::infer::{CoerceResult, resolve_type, Coercion}; @@ -73,6 +73,7 @@ use middle::typeck::infer::combine::{CombineFields, Combine}; use middle::typeck::infer::sub::Sub; use middle::typeck::infer::resolve::try_resolve_tvar_shallow; use util::common::indenter; +use util::ppaux; use util::ppaux::Repr; use syntax::abi; @@ -94,38 +95,51 @@ impl<'f> Coerce<'f> { b.repr(self.get_ref().infcx.tcx)); let _indent = indenter(); + // Special case: if the subtype is a sized array literal (`[T, ..n]`), + // then it would get auto-borrowed to `&[T, ..n]` and then DST-ified + // to `&[T]`. Doing it all at once makes the target code a bit more + // efficient and spares us from having to handle multiple coercions. + match ty::get(b).sty { + ty::ty_rptr(_, mt_b) => { + match ty::get(mt_b.ty).sty { + ty::ty_vec(_, None) => { + let unsize_and_ref = self.unpack_actual_value(a, |sty_a| { + self.coerce_unsized_with_borrow(a, sty_a, b, mt_b.mutbl) + }); + if unsize_and_ref.is_ok() { + return unsize_and_ref; + } + } + _ => {} + } + } + _ => {} + } + + // Consider coercing the subtype to a DST + let unsize = self.unpack_actual_value(a, |sty_a| { + self.coerce_unsized(a, sty_a, b) + }); + if unsize.is_ok() { + return unsize; + } + // Examine the supertype and consider auto-borrowing. // // Note: does not attempt to resolve type variables we encounter. // See above for details. match ty::get(b).sty { - ty::ty_rptr(r_b, mt_b) => { + ty::ty_rptr(_, mt_b) => { match ty::get(mt_b.ty).sty { - ty::ty_vec(mt_b, None) => { - return self.unpack_actual_value(a, |sty_a| { - self.coerce_borrowed_vector(a, sty_a, b, mt_b.mutbl) - }); - } - ty::ty_vec(_, _) => {}, ty::ty_str => { return self.unpack_actual_value(a, |sty_a| { - self.coerce_borrowed_string(a, sty_a, b) + self.coerce_borrowed_pointer(a, sty_a, b, ast::MutImmutable) }); } - ty::ty_trait(box ty::TyTrait { def_id, ref substs, bounds }) => { + ty::ty_trait(..) => { let result = self.unpack_actual_value(a, |sty_a| { - match *sty_a { - ty::ty_rptr(_, mt_a) => match ty::get(mt_a.ty).sty { - ty::ty_trait(..) => { - self.coerce_borrowed_object(a, sty_a, b, mt_b.mutbl) - } - _ => self.coerce_object(a, sty_a, b, def_id, substs, - ty::RegionTraitStore(r_b, mt_b.mutbl), - bounds) - }, - _ => self.coerce_borrowed_object(a, sty_a, b, mt_b.mutbl) - } + self.coerce_borrowed_object(a, sty_a, b, mt_b.mutbl) }); match result { @@ -136,37 +150,12 @@ impl<'f> Coerce<'f> { _ => { return self.unpack_actual_value(a, |sty_a| { - self.coerce_borrowed_pointer(a, sty_a, b, mt_b) + self.coerce_borrowed_pointer(a, sty_a, b, mt_b.mutbl) }); } }; } - ty::ty_uniq(t_b) => { - match ty::get(t_b).sty { - ty::ty_trait(box ty::TyTrait { def_id, ref substs, bounds }) => { - let result = self.unpack_actual_value(a, |sty_a| { - match *sty_a { - ty::ty_uniq(t_a) => match ty::get(t_a).sty { - ty::ty_trait(..) => { - Err(ty::terr_mismatch) - } - _ => self.coerce_object(a, sty_a, b, def_id, substs, - ty::UniqTraitStore, bounds) - }, - _ => Err(ty::terr_mismatch) - } - }); - - match result { - Ok(t) => return Ok(t), - Err(..) => {} - } - } - _ => {} - } - } - ty::ty_closure(box ty::ClosureTy { store: ty::RegionTraitStore(..), .. @@ -221,20 +210,21 @@ impl<'f> Coerce<'f> { self.get_ref().infcx.tcx.sess.span_bug( self.get_ref().trace.origin.span(), format!("failed to resolve even without \ - any force options: {:?}", e).as_slice()); + any force options: {:?}", e).as_slice()); } } } + // ~T -> &T or &mut T -> &T (including where T = [U] or str) pub fn coerce_borrowed_pointer(&self, a: ty::t, sty_a: &ty::sty, b: ty::t, - mt_b: ty::mt) + mutbl_b: ast::Mutability) -> CoerceResult { - debug!("coerce_borrowed_pointer(a={}, sty_a={:?}, b={}, mt_b={:?})", + debug!("coerce_borrowed_pointer(a={}, sty_a={:?}, b={})", a.repr(self.get_ref().infcx.tcx), sty_a, - b.repr(self.get_ref().infcx.tcx), mt_b); + b.repr(self.get_ref().infcx.tcx)); // If we have a parameter of type `&M T_a` and the value // provided is `expr`, we will be adding an implicit borrow, @@ -256,64 +246,182 @@ impl<'f> Coerce<'f> { let a_borrowed = ty::mk_rptr(self.get_ref().infcx.tcx, r_borrow, - mt {ty: inner_ty, mutbl: mt_b.mutbl}); + mt {ty: inner_ty, mutbl: mutbl_b}); if_ok!(sub.tys(a_borrowed, b)); + Ok(Some(AutoDerefRef(AutoDerefRef { autoderefs: 1, - autoref: Some(AutoPtr(r_borrow, mt_b.mutbl)) + autoref: Some(AutoPtr(r_borrow, mutbl_b, None)) }))) } - pub fn coerce_borrowed_string(&self, + // [T, ..n] -> &[T] or &mut [T] + fn coerce_unsized_with_borrow(&self, a: ty::t, sty_a: &ty::sty, - b: ty::t) + b: ty::t, + mutbl_b: ast::Mutability) -> CoerceResult { - debug!("coerce_borrowed_string(a={}, sty_a={:?}, b={})", + debug!("coerce_unsized_with_borrow(a={}, sty_a={:?}, b={})", a.repr(self.get_ref().infcx.tcx), sty_a, b.repr(self.get_ref().infcx.tcx)); match *sty_a { - ty::ty_uniq(_) => return Err(ty::terr_mismatch), - _ => return self.subtype(a, b), + ty::ty_vec(t_a, Some(len)) => { + let sub = Sub(self.get_ref().clone()); + let coercion = Coercion(self.get_ref().trace.clone()); + let r_borrow = self.get_ref().infcx.next_region_var(coercion); + let unsized_ty = ty::mk_slice(self.get_ref().infcx.tcx, r_borrow, + mt {ty: t_a, mutbl: mutbl_b}); + if_ok!(self.get_ref().infcx.try(|| sub.tys(unsized_ty, b))); + Ok(Some(AutoDerefRef(AutoDerefRef { + autoderefs: 0, + autoref: Some(ty::AutoPtr(r_borrow, + mutbl_b, + Some(box AutoUnsize(ty::UnsizeLength(len))))) + }))) + } + _ => Err(ty::terr_mismatch) } } - pub fn coerce_borrowed_vector(&self, - a: ty::t, - sty_a: &ty::sty, - b: ty::t, - mutbl_b: ast::Mutability) - -> CoerceResult { - debug!("coerce_borrowed_vector(a={}, sty_a={:?}, b={})", + // &[T, ..n] or &mut [T, ..n] -> &[T] + // or &mut [T, ..n] -> &mut [T] + // or &Concrete -> &Trait, etc. + fn coerce_unsized(&self, + a: ty::t, + sty_a: &ty::sty, + b: ty::t) + -> CoerceResult { + debug!("coerce_unsized(a={}, sty_a={:?}, b={})", a.repr(self.get_ref().infcx.tcx), sty_a, b.repr(self.get_ref().infcx.tcx)); + // 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. + let sub = Sub(self.get_ref().clone()); - let coercion = Coercion(self.get_ref().trace.clone()); - let r_borrow = self.get_ref().infcx.next_region_var(coercion); - let ty_inner = match *sty_a { - ty::ty_uniq(_) => return Err(ty::terr_mismatch), - ty::ty_ptr(ty::mt{ty: t, ..}) | - ty::ty_rptr(_, ty::mt{ty: t, ..}) => match ty::get(t).sty { - ty::ty_vec(mt, None) => mt.ty, - _ => { - return self.subtype(a, b); - } - }, - ty::ty_vec(mt, _) => mt.ty, - _ => { - return self.subtype(a, b); + + let sty_b = &ty::get(b).sty; + match (sty_a, sty_b) { + (&ty::ty_uniq(t_a), &ty::ty_rptr(_, mt_b)) => Err(ty::terr_mismatch), + (&ty::ty_rptr(_, ty::mt{ty: t_a, ..}), &ty::ty_rptr(_, mt_b)) => { + self.unpack_actual_value(t_a, |sty_a| { + match self.unsize_ty(sty_a, mt_b.ty) { + Some((ty, kind)) => { + let coercion = Coercion(self.get_ref().trace.clone()); + let r_borrow = self.get_ref().infcx.next_region_var(coercion); + let ty = ty::mk_rptr(self.get_ref().infcx.tcx, + r_borrow, + ty::mt{ty: ty, mutbl: mt_b.mutbl}); + if_ok!(self.get_ref().infcx.try(|| sub.tys(ty, b))); + debug!("Success, coerced with AutoDerefRef(1, \ + AutoPtr(AutoUnsize({:?})))", kind); + Ok(Some(AutoDerefRef(AutoDerefRef { + autoderefs: 1, + autoref: Some(ty::AutoPtr(r_borrow, mt_b.mutbl, + Some(box AutoUnsize(kind)))) + }))) + } + _ => Err(ty::terr_mismatch) + } + }) } - }; + (&ty::ty_uniq(t_a), &ty::ty_uniq(t_b)) => { + self.unpack_actual_value(t_a, |sty_a| { + match self.unsize_ty(sty_a, t_b) { + Some((ty, kind)) => { + let ty = ty::mk_uniq(self.get_ref().infcx.tcx, ty); + if_ok!(self.get_ref().infcx.try(|| sub.tys(ty, b))); + debug!("Success, coerced with AutoDerefRef(1, \ + AutoUnsizeUniq({:?}))", kind); + Ok(Some(AutoDerefRef(AutoDerefRef { + autoderefs: 1, + autoref: Some(ty::AutoUnsizeUniq(kind)) + }))) + } + _ => Err(ty::terr_mismatch) + } + }) + } + _ => Err(ty::terr_mismatch) + } + } - let a_borrowed = ty::mk_slice(self.get_ref().infcx.tcx, r_borrow, - mt {ty: ty_inner, mutbl: mutbl_b}); - if_ok!(sub.tys(a_borrowed, b)); - Ok(Some(AutoDerefRef(AutoDerefRef { - autoderefs: 0, - autoref: Some(AutoBorrowVec(r_borrow, mutbl_b)) - }))) + // 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, + sty_a: &ty::sty, + ty_b: ty::t) + -> Option<(ty::t, ty::UnsizeKind)> { + debug!("unsize_ty(sty_a={:?}", sty_a); + + let tcx = self.get_ref().infcx.tcx; + + self.unpack_actual_value(ty_b, |sty_b| + match (sty_a, sty_b) { + (&ty::ty_vec(t_a, Some(len)), _) => { + let ty = ty::mk_vec(tcx, t_a, None); + Some((ty, ty::UnsizeLength(len))) + } + (&ty::ty_trait(..), &ty::ty_trait(..)) => None, + (_, &ty::ty_trait(box ty::TyTrait { def_id, ref substs, bounds })) => { + let ty = ty::mk_trait(tcx, + def_id, + substs.clone(), + bounds); + Some((ty, ty::UnsizeVtable(bounds, + def_id, + substs.clone()))) + } + (&ty::ty_struct(did_a, ref substs_a), &ty::ty_struct(did_b, ref 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_vec(subst::TypeSpace); + let ty_substs_b = substs_b.types.get_vec(subst::TypeSpace); + assert!(ty_substs_a.len() == ty_substs_b.len()); + + let sub = Sub(self.get_ref().clone()); + + let mut result = None; + let mut tps = ty_substs_a.iter().zip(ty_substs_b.iter()).enumerate(); + for (i, (tp_a, tp_b)) in tps { + if self.get_ref().infcx.try(|| sub.tys(*tp_a, *tp_b)).is_ok() { + continue; + } + match self.unpack_actual_value(*tp_a, |tp| self.unsize_ty(tp, *tp_b)) { + Some((new_tp, k)) => { + // Check that the whole types match. + let mut new_substs = substs_a.clone(); + *new_substs.types.get_mut_vec(subst::TypeSpace).get_mut(i) = new_tp; + let ty = ty::mk_struct(tcx, did_a, new_substs); + if self.get_ref().infcx.try(|| sub.tys(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 + } + ) } fn coerce_borrowed_object(&self, @@ -331,7 +439,8 @@ impl<'f> Coerce<'f> { let r_a = self.get_ref().infcx.next_region_var(coercion); let a_borrowed = match *sty_a { - ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ty, ..}) => match ty::get(ty).sty { + ty::ty_uniq(ty) => return Err(ty::terr_mismatch), + ty::ty_rptr(_, ty::mt{ty, ..}) => match ty::get(ty).sty { ty::ty_trait(box ty::TyTrait { def_id, ref substs, @@ -352,8 +461,8 @@ impl<'f> Coerce<'f> { if_ok!(self.subtype(a_borrowed, b)); Ok(Some(AutoDerefRef(AutoDerefRef { - autoderefs: 0, - autoref: Some(AutoBorrowObj(r_a, b_mutbl)) + autoderefs: 1, + autoref: Some(AutoPtr(r_a, b_mutbl, None)) }))) } @@ -438,21 +547,4 @@ impl<'f> Coerce<'f> { autoref: Some(ty::AutoUnsafe(mt_b.mutbl)) }))) } - - pub fn coerce_object(&self, - a: ty::t, - sty_a: &ty::sty, - b: ty::t, - trait_def_id: ast::DefId, - trait_substs: &subst::Substs, - trait_store: ty::TraitStore, - bounds: ty::BuiltinBounds) -> CoerceResult { - - debug!("coerce_object(a={}, sty_a={:?}, b={})", - a.repr(self.get_ref().infcx.tcx), sty_a, - b.repr(self.get_ref().infcx.tcx)); - - Ok(Some(ty::AutoObject(trait_store, bounds, - trait_def_id, trait_substs.clone()))) - } } diff --git a/src/librustc/middle/typeck/infer/combine.rs b/src/librustc/middle/typeck/infer/combine.rs index d99d55d4d87..a57dec90455 100644 --- a/src/librustc/middle/typeck/infer/combine.rs +++ b/src/librustc/middle/typeck/infer/combine.rs @@ -529,10 +529,10 @@ pub fn super_tys<C:Combine>(this: &C, a: ty::t, b: ty::t) -> cres<ty::t> { check_ptr_to_unsized(this, a, b, a_mt.ty, b_mt.ty, ty::mk_rptr(tcx, r, mt)) } - (&ty::ty_vec(ref a_mt, sz_a), &ty::ty_vec(ref b_mt, sz_b)) => { - this.mts(a_mt, b_mt).and_then(|mt| { + (&ty::ty_vec(a_t, sz_a), &ty::ty_vec(b_t, sz_b)) => { + this.tys(a_t, b_t).and_then(|t| { if sz_a == sz_b { - Ok(ty::mk_vec(tcx, mt, sz_a)) + Ok(ty::mk_vec(tcx, t, sz_a)) } else { Err(ty::terr_sorts(expected_found(this, a, b))) } diff --git a/src/librustc/middle/typeck/infer/error_reporting.rs b/src/librustc/middle/typeck/infer/error_reporting.rs index 5b9b37ab844..920fa23f31d 100644 --- a/src/librustc/middle/typeck/infer/error_reporting.rs +++ b/src/librustc/middle/typeck/infer/error_reporting.rs @@ -1411,8 +1411,8 @@ impl<'a> ErrorReportingHelpers for InferCtxt<'a> { infer::AutoBorrow(span) => { self.tcx.sess.span_note( span, - "...so that automatically reference is valid \ - at the time of borrow"); + "...so that reference is valid \ + at the time of implicit borrow"); } infer::BindingTypeIsNotValidAtDecl(span) => { self.tcx.sess.span_note( diff --git a/src/librustc/middle/typeck/infer/sub.rs b/src/librustc/middle/typeck/infer/sub.rs index 44c147bfe7f..a54afb1102f 100644 --- a/src/librustc/middle/typeck/infer/sub.rs +++ b/src/librustc/middle/typeck/infer/sub.rs @@ -129,10 +129,23 @@ impl<'f> Combine for Sub<'f> { if_ok!(self.get_ref().var_sub_var(a_id, b_id)); Ok(a) } + // The vec/str check here and below is so that we don't unify + // T with [T], this is necessary so we reflect subtyping of references + // (&T does not unify with &[T]) where that in turn is to reflect + // the historical non-typedness of [T]. + (&ty::ty_infer(TyVar(_)), &ty::ty_str) | + (&ty::ty_infer(TyVar(_)), &ty::ty_vec(_, None)) => { + Err(ty::terr_sorts(expected_found(self, a, b))) + } (&ty::ty_infer(TyVar(a_id)), _) => { if_ok!(self.get_ref().var_sub_t(a_id, b)); Ok(a) } + + (&ty::ty_str, &ty::ty_infer(TyVar(_))) | + (&ty::ty_vec(_, None), &ty::ty_infer(TyVar(_))) => { + Err(ty::terr_sorts(expected_found(self, a, b))) + } (_, &ty::ty_infer(TyVar(b_id))) => { if_ok!(self.get_ref().t_sub_var(a, b_id)); Ok(a) diff --git a/src/librustc/middle/typeck/variance.rs b/src/librustc/middle/typeck/variance.rs index 97c11b92059..e6227b9c128 100644 --- a/src/librustc/middle/typeck/variance.rs +++ b/src/librustc/middle/typeck/variance.rs @@ -741,11 +741,7 @@ impl<'a> ConstraintContext<'a> { self.add_constraints_from_mt(mt, variance); } - ty::ty_vec(ref mt, _) => { - self.add_constraints_from_mt(mt, variance); - } - - ty::ty_uniq(typ) | ty::ty_box(typ) => { + ty::ty_uniq(typ) | ty::ty_box(typ) | ty::ty_vec(typ, _) | ty::ty_open(typ) => { self.add_constraints_from_ty(typ, variance); } diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index e0e9f0e6910..4f68d42de96 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -19,7 +19,7 @@ use middle::ty::{ReSkolemized, ReVar}; use middle::ty::{mt, t, ParamTy}; use middle::ty::{ty_bool, ty_char, ty_bot, ty_box, ty_struct, ty_enum}; use middle::ty::{ty_err, ty_str, ty_vec, ty_float, ty_bare_fn, ty_closure}; -use middle::ty::{ty_nil, ty_param, ty_ptr, ty_rptr, ty_tup}; +use middle::ty::{ty_nil, ty_param, ty_ptr, ty_rptr, ty_tup, ty_open}; use middle::ty::{ty_unboxed_closure}; use middle::ty::{ty_uniq, ty_trait, ty_int, ty_uint, ty_infer}; use middle::ty; @@ -370,6 +370,7 @@ pub fn ty_to_string(cx: &ctxt, typ: t) -> String { buf.push_str(mt_to_string(cx, tm).as_slice()); buf } + ty_open(typ) => format!("opened<{}>", ty_to_str(cx, typ)), ty_tup(ref elems) => { let strs: Vec<String> = elems.iter().map(|elem| ty_to_string(cx, *elem)).collect(); format!("({})", strs.connect(",")) @@ -407,7 +408,7 @@ pub fn ty_to_string(cx: &ctxt, typ: t) -> String { let trait_def = ty::lookup_trait_def(cx, did); let ty = parameterized(cx, base.as_slice(), substs, &trait_def.generics); - let bound_sep = if bounds.is_empty() { "" } else { ":" }; + let bound_sep = if bounds.is_empty() { "" } else { "+" }; let bound_str = bounds.repr(cx); format!("{}{}{}", ty, @@ -416,12 +417,12 @@ pub fn ty_to_string(cx: &ctxt, typ: t) -> String { } ty_str => "str".to_string(), ty_unboxed_closure(..) => "closure".to_string(), - ty_vec(ref mt, sz) => { + ty_vec(t, sz) => { match sz { Some(n) => { - format!("[{}, .. {}]", mt_to_string(cx, mt), n) + format!("[{}, .. {}]", ty_to_string(cx, t), n) } - None => format!("[{}]", ty_to_string(cx, mt.ty)), + None => format!("[{}]", ty_to_string(cx, t)), } } } diff --git a/src/librustc_back/abi.rs b/src/librustc_back/abi.rs index 015331b8be0..e859a5d21d7 100644 --- a/src/librustc_back/abi.rs +++ b/src/librustc_back/abi.rs @@ -20,8 +20,8 @@ pub static fn_field_box: uint = 1u; // The two fields of a trait object/trait instance: vtable and box. // The vtable contains the type descriptor as first element. -pub static trt_field_vtable: uint = 0u; -pub static trt_field_box: uint = 1u; +pub static trt_field_box: uint = 0u; +pub static trt_field_vtable: uint = 1u; pub static slice_elt_base: uint = 0u; pub static slice_elt_len: uint = 1u; diff --git a/src/librustc_back/svh.rs b/src/librustc_back/svh.rs index 29668795ed7..6af19d948e0 100644 --- a/src/librustc_back/svh.rs +++ b/src/librustc_back/svh.rs @@ -225,7 +225,6 @@ mod svh_visitor { SawExprBreak(Option<token::InternedString>), SawExprAgain(Option<token::InternedString>), - SawExprVstore, SawExprBox, SawExprVec, SawExprCall, @@ -257,7 +256,6 @@ mod svh_visitor { fn saw_expr<'a>(node: &'a Expr_) -> SawExprComponent<'a> { match *node { - ExprVstore(..) => SawExprVstore, ExprBox(..) => SawExprBox, ExprVec(..) => SawExprVec, ExprCall(..) => SawExprCall, diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 68e1529fb17..dc2c0d1d083 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1250,8 +1250,8 @@ impl Clean<Type> for ty::t { }); lang_struct(box_did, t, "Box", Unique) } - ty::ty_vec(mt, None) => Vector(box mt.ty.clean()), - ty::ty_vec(mt, Some(i)) => FixedVector(box mt.ty.clean(), + ty::ty_vec(ty, None) => Vector(box ty.clean()), + ty::ty_vec(ty, Some(i)) => FixedVector(box ty.clean(), format!("{}", i)), ty::ty_ptr(mt) => RawPointer(mt.mutbl.clean(), box mt.ty.clean()), ty::ty_rptr(r, mt) => BorrowedRef { @@ -1315,6 +1315,7 @@ impl Clean<Type> for ty::t { ty::ty_unboxed_closure(..) => Primitive(Unit), // FIXME(pcwalton) ty::ty_infer(..) => fail!("ty_infer"), + ty::ty_open(..) => fail!("ty_open"), ty::ty_err => fail!("ty_err"), } } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index be62b1cc36f..6415ee85f57 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -259,7 +259,8 @@ pub fn run(mut krate: clean::Crate, external_html: &ExternalHtml, dst: Path) -> // Crawl the crate attributes looking for attributes which control how we're // going to emit HTML - match krate.module.as_ref().map(|m| m.doc_list().unwrap_or(&[])) { + let default: &[_] = &[]; + match krate.module.as_ref().map(|m| m.doc_list().unwrap_or(default)) { Some(attrs) => { for attr in attrs.iter() { match *attr { diff --git a/src/librustuv/homing.rs b/src/librustuv/homing.rs index 91614763ce5..55d9811ccad 100644 --- a/src/librustuv/homing.rs +++ b/src/librustuv/homing.rs @@ -72,13 +72,15 @@ impl Clone for HomeHandle { } pub fn local_id() -> uint { + use std::raw::TraitObject; + let mut io = match LocalIo::borrow() { Some(io) => io, None => return 0, }; let io = io.get(); unsafe { - let (_vtable, ptr): (uint, uint) = mem::transmute(io); - return ptr; + let obj: TraitObject = mem::transmute(io); + return mem::transmute(obj.data); } } diff --git a/src/librustuv/lib.rs b/src/librustuv/lib.rs index dd80ab3ee78..6e948992979 100644 --- a/src/librustuv/lib.rs +++ b/src/librustuv/lib.rs @@ -462,13 +462,14 @@ pub fn slice_to_uv_buf(v: &[u8]) -> Buf { // This function is full of lies! #[cfg(test)] fn local_loop() -> &'static mut uvio::UvIoFactory { + use std::raw::TraitObject; unsafe { mem::transmute({ let mut task = Local::borrow(None::<Task>); let mut io = task.local_io().unwrap(); - let (_vtable, uvio): (uint, &'static mut uvio::UvIoFactory) = + let obj: TraitObject = mem::transmute(io.get()); - uvio + obj.data }) } } diff --git a/src/libstd/path/posix.rs b/src/libstd/path/posix.rs index 0a7817c3e00..06eab31d7bf 100644 --- a/src/libstd/path/posix.rs +++ b/src/libstd/path/posix.rs @@ -464,6 +464,7 @@ static dot_dot_static: &'static [u8] = b".."; mod tests { use prelude::*; use super::*; + use mem; use str; use str::StrSlice; @@ -621,8 +622,10 @@ mod tests { macro_rules! t( (s: $path:expr, $op:ident, $exp:expr) => ( { - let path = Path::new($path); - assert!(path.$op() == ($exp).as_bytes()); + unsafe { + let path = Path::new($path); + assert!(path.$op() == mem::transmute(($exp).as_bytes())); + } } ); (s: $path:expr, $op:ident, $exp:expr, opt) => ( @@ -634,9 +637,11 @@ mod tests { ); (v: $path:expr, $op:ident, $exp:expr) => ( { - let arg = $path; - let path = Path::new(arg); - assert!(path.$op() == $exp); + unsafe { + let arg = $path; + let path = Path::new(arg); + assert!(path.$op() == mem::transmute($exp)); + } } ); ) @@ -684,8 +689,9 @@ mod tests { t!(v: b"hi/there.txt", extension, Some(b"txt")); t!(v: b"hi/there\x80.txt", extension, Some(b"txt")); t!(v: b"hi/there.t\x80xt", extension, Some(b"t\x80xt")); - t!(v: b"hi/there", extension, None); - t!(v: b"hi/there\x80", extension, None); + let no: Option<&'static [u8]> = None; + t!(v: b"hi/there", extension, no); + t!(v: b"hi/there\x80", extension, no); t!(s: "hi/there.txt", extension, Some("txt"), opt); t!(s: "hi/there", extension, None, opt); t!(s: "there.txt", extension, Some("txt"), opt); @@ -974,57 +980,62 @@ mod tests { macro_rules! t( (s: $path:expr, $filename:expr, $dirname:expr, $filestem:expr, $ext:expr) => ( { - let path = $path; - let filename = $filename; - assert!(path.filename_str() == filename, - "{}.filename_str(): Expected `{:?}`, found {:?}", - path.as_str().unwrap(), filename, path.filename_str()); - let dirname = $dirname; - assert!(path.dirname_str() == dirname, - "`{}`.dirname_str(): Expected `{:?}`, found `{:?}`", - path.as_str().unwrap(), dirname, path.dirname_str()); - let filestem = $filestem; - assert!(path.filestem_str() == filestem, - "`{}`.filestem_str(): Expected `{:?}`, found `{:?}`", - path.as_str().unwrap(), filestem, path.filestem_str()); - let ext = $ext; - assert!(path.extension_str() == ext, - "`{}`.extension_str(): Expected `{:?}`, found `{:?}`", - path.as_str().unwrap(), ext, path.extension_str()); + unsafe { + let path = $path; + let filename = $filename; + assert!(path.filename_str() == filename, + "{}.filename_str(): Expected `{:?}`, found {:?}", + path.as_str().unwrap(), filename, path.filename_str()); + let dirname = $dirname; + assert!(path.dirname_str() == dirname, + "`{}`.dirname_str(): Expected `{:?}`, found `{:?}`", + path.as_str().unwrap(), dirname, path.dirname_str()); + let filestem = $filestem; + assert!(path.filestem_str() == filestem, + "`{}`.filestem_str(): Expected `{:?}`, found `{:?}`", + path.as_str().unwrap(), filestem, path.filestem_str()); + let ext = $ext; + assert!(path.extension_str() == mem::transmute(ext), + "`{}`.extension_str(): Expected `{:?}`, found `{:?}`", + path.as_str().unwrap(), ext, path.extension_str()); + } } ); (v: $path:expr, $filename:expr, $dirname:expr, $filestem:expr, $ext:expr) => ( { - let path = $path; - assert!(path.filename() == $filename); - assert!(path.dirname() == $dirname); - assert!(path.filestem() == $filestem); - assert!(path.extension() == $ext); + unsafe { + let path = $path; + assert!(path.filename() == mem::transmute($filename)); + assert!(path.dirname() == mem::transmute($dirname)); + assert!(path.filestem() == mem::transmute($filestem)); + assert!(path.extension() == mem::transmute($ext)); + } } ) ) - t!(v: Path::new(b"a/b/c"), Some(b"c"), b"a/b", Some(b"c"), None); - t!(v: Path::new(b"a/b/\xFF"), Some(b"\xFF"), b"a/b", Some(b"\xFF"), None); + let no: Option<&'static str> = None; + t!(v: Path::new(b"a/b/c"), Some(b"c"), b"a/b", Some(b"c"), no); + t!(v: Path::new(b"a/b/\xFF"), Some(b"\xFF"), b"a/b", Some(b"\xFF"), no); t!(v: Path::new(b"hi/there.\xFF"), Some(b"there.\xFF"), b"hi", Some(b"there"), Some(b"\xFF")); - t!(s: Path::new("a/b/c"), Some("c"), Some("a/b"), Some("c"), None); - t!(s: Path::new("."), None, Some("."), None, None); - t!(s: Path::new("/"), None, Some("/"), None, None); - t!(s: Path::new(".."), None, Some(".."), None, None); - t!(s: Path::new("../.."), None, Some("../.."), None, None); + t!(s: Path::new("a/b/c"), Some("c"), Some("a/b"), Some("c"), no); + t!(s: Path::new("."), None, Some("."), None, no); + t!(s: Path::new("/"), None, Some("/"), None, no); + t!(s: Path::new(".."), None, Some(".."), None, no); + t!(s: Path::new("../.."), None, Some("../.."), None, no); t!(s: Path::new("hi/there.txt"), Some("there.txt"), Some("hi"), Some("there"), Some("txt")); - t!(s: Path::new("hi/there"), Some("there"), Some("hi"), Some("there"), None); + t!(s: Path::new("hi/there"), Some("there"), Some("hi"), Some("there"), no); t!(s: Path::new("hi/there."), Some("there."), Some("hi"), Some("there"), Some("")); - t!(s: Path::new("hi/.there"), Some(".there"), Some("hi"), Some(".there"), None); + t!(s: Path::new("hi/.there"), Some(".there"), Some("hi"), Some(".there"), no); t!(s: Path::new("hi/..there"), Some("..there"), Some("hi"), Some("."), Some("there")); - t!(s: Path::new(b"a/b/\xFF"), None, Some("a/b"), None, None); + t!(s: Path::new(b"a/b/\xFF"), None, Some("a/b"), None, no); t!(s: Path::new(b"a/b/\xFF.txt"), None, Some("a/b"), None, Some("txt")); - t!(s: Path::new(b"a/b/c.\x80"), None, Some("a/b"), Some("c"), None); - t!(s: Path::new(b"\xFF/b"), Some("b"), None, Some("b"), None); + t!(s: Path::new(b"a/b/c.\x80"), None, Some("a/b"), Some("c"), no); + t!(s: Path::new(b"\xFF/b"), Some("b"), None, Some("b"), no); } #[test] diff --git a/src/libstd/path/windows.rs b/src/libstd/path/windows.rs index dd87e214c2c..d9864cfaa61 100644 --- a/src/libstd/path/windows.rs +++ b/src/libstd/path/windows.rs @@ -1141,6 +1141,7 @@ fn prefix_len(p: Option<PathPrefix>) -> uint { #[cfg(test)] mod tests { + use mem; use prelude::*; use super::*; use super::parse_prefix; @@ -1383,9 +1384,11 @@ mod tests { macro_rules! t( (s: $path:expr, $op:ident, $exp:expr) => ( { - let path = $path; - let path = Path::new(path); - assert!(path.$op() == Some($exp)); + unsafe { + let path = $path; + let path = Path::new(path); + assert!(path.$op() == Some(mem::transmute($exp))); + } } ); (s: $path:expr, $op:ident, $exp:expr, opt) => ( @@ -1398,9 +1401,11 @@ mod tests { ); (v: $path:expr, $op:ident, $exp:expr) => ( { - let path = $path; - let path = Path::new(path); - assert!(path.$op() == $exp); + unsafe { + let path = $path; + let path = Path::new(path); + assert!(path.$op() == mem::transmute($exp)); + } } ) ) @@ -1485,7 +1490,8 @@ mod tests { // filestem is based on filename, so we don't need the full set of prefix tests t!(v: b"hi\\there.txt", extension, Some(b"txt")); - t!(v: b"hi\\there", extension, None); + let no: Option<&'static [u8]> = None; + t!(v: b"hi\\there", extension, no); t!(s: "hi\\there.txt", extension_str, Some("txt"), opt); t!(s: "hi\\there", extension_str, None, opt); t!(s: "there.txt", extension_str, Some("txt"), opt); @@ -1892,48 +1898,53 @@ mod tests { macro_rules! t( (s: $path:expr, $filename:expr, $dirname:expr, $filestem:expr, $ext:expr) => ( { - let path = $path; - let filename = $filename; - assert!(path.filename_str() == filename, - "`{}`.filename_str(): Expected `{:?}`, found `{:?}`", - path.as_str().unwrap(), filename, path.filename_str()); - let dirname = $dirname; - assert!(path.dirname_str() == dirname, - "`{}`.dirname_str(): Expected `{:?}`, found `{:?}`", - path.as_str().unwrap(), dirname, path.dirname_str()); - let filestem = $filestem; - assert!(path.filestem_str() == filestem, - "`{}`.filestem_str(): Expected `{:?}`, found `{:?}`", - path.as_str().unwrap(), filestem, path.filestem_str()); - let ext = $ext; - assert!(path.extension_str() == ext, - "`{}`.extension_str(): Expected `{:?}`, found `{:?}`", - path.as_str().unwrap(), ext, path.extension_str()); + unsafe { + let path = $path; + let filename = $filename; + assert!(path.filename_str() == filename, + "`{}`.filename_str(): Expected `{:?}`, found `{:?}`", + path.as_str().unwrap(), filename, path.filename_str()); + let dirname = $dirname; + assert!(path.dirname_str() == dirname, + "`{}`.dirname_str(): Expected `{:?}`, found `{:?}`", + path.as_str().unwrap(), dirname, path.dirname_str()); + let filestem = $filestem; + assert!(path.filestem_str() == filestem, + "`{}`.filestem_str(): Expected `{:?}`, found `{:?}`", + path.as_str().unwrap(), filestem, path.filestem_str()); + let ext = $ext; + assert!(path.extension_str() == mem::transmute(ext), + "`{}`.extension_str(): Expected `{:?}`, found `{:?}`", + path.as_str().unwrap(), ext, path.extension_str()); + } } ); (v: $path:expr, $filename:expr, $dirname:expr, $filestem:expr, $ext:expr) => ( { - let path = $path; - assert!(path.filename() == $filename); - assert!(path.dirname() == $dirname); - assert!(path.filestem() == $filestem); - assert!(path.extension() == $ext); + unsafe { + let path = $path; + assert!(path.filename() == mem::transmute($filename)); + assert!(path.dirname() == mem::transmute($dirname)); + assert!(path.filestem() == mem::transmute($filestem)); + assert!(path.extension() == mem::transmute($ext)); + } } ) ) - t!(v: Path::new(b"a\\b\\c"), Some(b"c"), b"a\\b", Some(b"c"), None); - t!(s: Path::new("a\\b\\c"), Some("c"), Some("a\\b"), Some("c"), None); - t!(s: Path::new("."), None, Some("."), None, None); - t!(s: Path::new("\\"), None, Some("\\"), None, None); - t!(s: Path::new(".."), None, Some(".."), None, None); - t!(s: Path::new("..\\.."), None, Some("..\\.."), None, None); + let no: Option<&'static str> = None; + t!(v: Path::new(b"a\\b\\c"), Some(b"c"), b"a\\b", Some(b"c"), no); + t!(s: Path::new("a\\b\\c"), Some("c"), Some("a\\b"), Some("c"), no); + t!(s: Path::new("."), None, Some("."), None, no); + t!(s: Path::new("\\"), None, Some("\\"), None, no); + t!(s: Path::new(".."), None, Some(".."), None, no); + t!(s: Path::new("..\\.."), None, Some("..\\.."), None, no); t!(s: Path::new("hi\\there.txt"), Some("there.txt"), Some("hi"), Some("there"), Some("txt")); - t!(s: Path::new("hi\\there"), Some("there"), Some("hi"), Some("there"), None); + t!(s: Path::new("hi\\there"), Some("there"), Some("hi"), Some("there"), no); t!(s: Path::new("hi\\there."), Some("there."), Some("hi"), Some("there"), Some("")); - t!(s: Path::new("hi\\.there"), Some(".there"), Some("hi"), Some(".there"), None); + t!(s: Path::new("hi\\.there"), Some(".there"), Some("hi"), Some(".there"), no); t!(s: Path::new("hi\\..there"), Some("..there"), Some("hi"), Some("."), Some("there")); diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 42d9430d732..7d5787092a5 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -395,16 +395,6 @@ pub enum Mutability { } #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] -pub enum ExprVstore { - /// ~[1, 2, 3, 4] - ExprVstoreUniq, - /// &[1, 2, 3, 4] - ExprVstoreSlice, - /// &mut [1, 2, 3, 4] - ExprVstoreMutSlice, -} - -#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] pub enum BinOp { BiAdd, BiSub, @@ -522,7 +512,6 @@ pub struct Expr { #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] pub enum Expr_ { - ExprVstore(Gc<Expr>, ExprVstore), /// First expr is the place; second expr is the value. ExprBox(Gc<Expr>, Gc<Expr>), ExprVec(Vec<Gc<Expr>>), diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index f7eddca4b7a..909f8f1e78c 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -143,12 +143,10 @@ pub trait AstBuilder { fn expr_u8(&self, sp: Span, u: u8) -> Gc<ast::Expr>; fn expr_bool(&self, sp: Span, value: bool) -> Gc<ast::Expr>; - fn expr_vstore(&self, sp: Span, expr: Gc<ast::Expr>, vst: ast::ExprVstore) -> Gc<ast::Expr>; fn expr_vec(&self, sp: Span, exprs: Vec<Gc<ast::Expr>> ) -> Gc<ast::Expr>; fn expr_vec_ng(&self, sp: Span) -> Gc<ast::Expr>; fn expr_vec_slice(&self, sp: Span, exprs: Vec<Gc<ast::Expr>> ) -> Gc<ast::Expr>; fn expr_str(&self, sp: Span, s: InternedString) -> Gc<ast::Expr>; - fn expr_str_uniq(&self, sp: Span, s: InternedString) -> Gc<ast::Expr>; fn expr_some(&self, sp: Span, expr: Gc<ast::Expr>) -> Gc<ast::Expr>; fn expr_none(&self, sp: Span) -> Gc<ast::Expr>; @@ -654,9 +652,6 @@ impl<'a> AstBuilder for ExtCtxt<'a> { self.expr_lit(sp, ast::LitBool(value)) } - fn expr_vstore(&self, sp: Span, expr: Gc<ast::Expr>, vst: ast::ExprVstore) -> Gc<ast::Expr> { - self.expr(sp, ast::ExprVstore(expr, vst)) - } fn expr_vec(&self, sp: Span, exprs: Vec<Gc<ast::Expr>> ) -> Gc<ast::Expr> { self.expr(sp, ast::ExprVec(exprs)) } @@ -669,15 +664,11 @@ impl<'a> AstBuilder for ExtCtxt<'a> { Vec::new()) } fn expr_vec_slice(&self, sp: Span, exprs: Vec<Gc<ast::Expr>> ) -> Gc<ast::Expr> { - self.expr_vstore(sp, self.expr_vec(sp, exprs), ast::ExprVstoreSlice) + self.expr_addr_of(sp, self.expr_vec(sp, exprs)) } fn expr_str(&self, sp: Span, s: InternedString) -> Gc<ast::Expr> { self.expr_lit(sp, ast::LitStr(s, ast::CookedStr)) } - fn expr_str_uniq(&self, sp: Span, s: InternedString) -> Gc<ast::Expr> { - self.expr_vstore(sp, self.expr_str(sp, s), ast::ExprVstoreUniq) - } - fn expr_cast(&self, sp: Span, expr: Gc<ast::Expr>, ty: P<ast::Ty>) -> Gc<ast::Expr> { self.expr(sp, ast::ExprCast(expr, ty)) diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index fb96b4b83d7..4a0787aeb9e 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -1088,9 +1088,6 @@ pub fn noop_fold_pat<T: Folder>(p: Gc<Pat>, folder: &mut T) -> Gc<Pat> { pub fn noop_fold_expr<T: Folder>(e: Gc<Expr>, folder: &mut T) -> Gc<Expr> { let id = folder.new_id(e.id); let node = match e.node { - ExprVstore(e, v) => { - ExprVstore(folder.fold_expr(e), v) - } ExprBox(p, e) => { ExprBox(folder.fold_expr(p), folder.fold_expr(e)) } diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 17a27a5a39e..585b98925cc 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -1137,7 +1137,8 @@ mod test { let item = parse_item_from_source_str(name.clone(), source, Vec::new(), &sess).unwrap(); let docs = item.attrs.iter().filter(|a| a.name().get() == "doc") .map(|a| a.value_str().unwrap().get().to_string()).collect::<Vec<_>>(); - assert_eq!(docs.as_slice(), &["/// doc comment".to_string(), "/// line 2".to_string()]); + let b: &[_] = &["/// doc comment".to_string(), "/// line 2".to_string()]; + assert_eq!(docs.as_slice(), b); let source = "/** doc comment\r\n * with CRLF */\r\nfn foo() {}".to_string(); let item = parse_item_from_source_str(name, source, Vec::new(), &sess).unwrap(); diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 2409912abe4..00513f7f67c 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -27,9 +27,8 @@ use ast::{ExprField, ExprFnBlock, ExprIf, ExprIndex}; use ast::{ExprLit, ExprLoop, ExprMac}; use ast::{ExprMethodCall, ExprParen, ExprPath, ExprProc}; use ast::{ExprRepeat, ExprRet, ExprStruct, ExprTup, ExprUnary, ExprUnboxedFn}; -use ast::{ExprVec, ExprVstore, ExprVstoreSlice}; -use ast::{ExprVstoreMutSlice, ExprWhile, ExprForLoop, Field, FnDecl}; -use ast::{ExprVstoreUniq, Once, Many}; +use ast::{ExprVec, ExprWhile, ExprForLoop, Field, FnDecl}; +use ast::{Once, Many}; use ast::{FnUnboxedClosureKind, FnMutUnboxedClosureKind}; use ast::{FnOnceUnboxedClosureKind}; use ast::{ForeignItem, ForeignItemStatic, ForeignItemFn, ForeignMod}; @@ -1428,13 +1427,16 @@ impl<'a> Parser<'a> { } else if self.token == token::TILDE { // OWNED POINTER self.bump(); - let last_span = self.last_span; + let span = self.last_span; match self.token { - token::LBRACKET => - self.obsolete(last_span, ObsoleteOwnedVector), - _ => self.obsolete(last_span, ObsoleteOwnedType), - }; - TyUniq(self.parse_ty(true)) + token::IDENT(ref ident, _) + if "str" == token::get_ident(*ident).get() => { + // This is OK (for now). + } + token::LBRACKET => {} // Also OK. + _ => self.obsolete(span, ObsoleteOwnedType) + } + TyUniq(self.parse_ty(false)) } else if self.token == token::BINOP(token::STAR) { // STAR POINTER (bare pointer?) self.bump(); @@ -2549,16 +2551,7 @@ impl<'a> Parser<'a> { let m = self.parse_mutability(); let e = self.parse_prefix_expr(); hi = e.span.hi; - // HACK: turn &[...] into a &-vec - ex = match e.node { - ExprVec(..) if m == MutImmutable => { - ExprVstore(e, ExprVstoreSlice) - } - ExprVec(..) if m == MutMutable => { - ExprVstore(e, ExprVstoreMutSlice) - } - _ => ExprAddrOf(m, e) - }; + ex = ExprAddrOf(m, e); } token::AT => { self.bump(); @@ -2570,25 +2563,18 @@ impl<'a> Parser<'a> { } token::TILDE => { self.bump(); + let span = self.last_span; + match self.token { + token::LIT_STR(_) => { + // This is OK (for now). + } + token::LBRACKET => {} // Also OK. + _ => self.obsolete(span, ObsoleteOwnedExpr) + } let e = self.parse_prefix_expr(); hi = e.span.hi; - // HACK: turn ~[...] into a ~-vec - let last_span = self.last_span; - ex = match e.node { - ExprVec(..) | ExprRepeat(..) => { - self.obsolete(last_span, ObsoleteOwnedVector); - ExprVstore(e, ExprVstoreUniq) - } - ExprLit(lit) if lit_is_str(lit) => { - self.obsolete(last_span, ObsoleteOwnedExpr); - ExprVstore(e, ExprVstoreUniq) - } - _ => { - self.obsolete(last_span, ObsoleteOwnedExpr); - self.mk_unary(UnUniq, e) - } - }; + ex = self.mk_unary(UnUniq, e); } token::IDENT(_, _) => { if self.is_keyword(keywords::Box) { @@ -2607,24 +2593,10 @@ impl<'a> Parser<'a> { } } - // Otherwise, we use the unique pointer default. - let subexpression = self.parse_prefix_expr(); - hi = subexpression.span.hi; - // HACK: turn `box [...]` into a boxed-vec - ex = match subexpression.node { - ExprVec(..) | ExprRepeat(..) => { - let last_span = self.last_span; - self.obsolete(last_span, ObsoleteOwnedVector); - ExprVstore(subexpression, ExprVstoreUniq) - } - ExprLit(lit) if lit_is_str(lit) => { - ExprVstore(subexpression, ExprVstoreUniq) - } - _ => self.mk_unary(UnUniq, subexpression) - }; - } else { - return self.parse_dot_or_call_expr() - } + // Otherwise, we use the unique pointer default. + let subexpression = self.parse_prefix_expr(); + hi = subexpression.span.hi; + ex = self.mk_unary(UnUniq, subexpression); } _ => return self.parse_dot_or_call_expr() } diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 6fe44078447..d5b6c5652a0 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -159,6 +159,7 @@ impl<'a> State<'a> { } pub fn to_string(f: |&mut State| -> IoResult<()>) -> String { + use std::raw::TraitObject; let mut s = rust_printer(box MemWriter::new()); f(&mut s).unwrap(); eof(&mut s.s).unwrap(); @@ -166,7 +167,8 @@ pub fn to_string(f: |&mut State| -> IoResult<()>) -> String { // FIXME(pcwalton): A nasty function to extract the string from an `io::Writer` // that we "know" to be a `MemWriter` that works around the lack of checked // downcasts. - let (_, wr): (uint, Box<MemWriter>) = mem::transmute_copy(&s.s.out); + let obj: TraitObject = mem::transmute_copy(&s.s.out); + let wr: Box<MemWriter> = mem::transmute(obj.data); let result = String::from_utf8(Vec::from_slice(wr.get_ref().as_slice())).unwrap(); mem::forget(wr); @@ -1321,16 +1323,6 @@ impl<'a> State<'a> { } } - pub fn print_expr_vstore(&mut self, t: ast::ExprVstore) -> IoResult<()> { - match t { - ast::ExprVstoreUniq => word(&mut self.s, "box "), - ast::ExprVstoreSlice => word(&mut self.s, "&"), - ast::ExprVstoreMutSlice => { - try!(word(&mut self.s, "&")); - word(&mut self.s, "mut") - } - } - } fn print_call_post(&mut self, args: &[Gc<ast::Expr>]) -> IoResult<()> { try!(self.popen()); @@ -1355,10 +1347,6 @@ impl<'a> State<'a> { try!(self.ibox(indent_unit)); try!(self.ann.pre(self, NodeExpr(expr))); match expr.node { - ast::ExprVstore(ref e, v) => { - try!(self.print_expr_vstore(v)); - try!(self.print_expr(&**e)); - }, ast::ExprBox(ref p, ref e) => { try!(word(&mut self.s, "box")); try!(word(&mut self.s, "(")); diff --git a/src/libsyntax/util/small_vector.rs b/src/libsyntax/util/small_vector.rs index 43367611ab2..517c5e5bf47 100644 --- a/src/libsyntax/util/small_vector.rs +++ b/src/libsyntax/util/small_vector.rs @@ -64,7 +64,10 @@ impl<T> SmallVector<T> { pub fn as_slice<'a>(&'a self) -> &'a [T] { match self.repr { - Zero => &[], + Zero => { + let result: &[T] = &[]; + result + } One(ref v) => slice::ref_slice(v), Many(ref vs) => vs.as_slice() } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 9e371143311..6c6f59f0df6 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -729,9 +729,6 @@ pub fn walk_mac<E, V: Visitor<E>>(_: &mut V, _: &Mac, _: E) { pub fn walk_expr<E: Clone, V: Visitor<E>>(visitor: &mut V, expression: &Expr, env: E) { match expression.node { - ExprVstore(ref subexpression, _) => { - visitor.visit_expr(&**subexpression, env.clone()) - } ExprBox(ref place, ref subexpression) => { visitor.visit_expr(&**place, env.clone()); visitor.visit_expr(&**subexpression, env.clone()) diff --git a/src/test/compile-fail/const-cast-different-types.rs b/src/test/compile-fail/const-cast-different-types.rs index f7d5ddb3145..4f53694ebd6 100644 --- a/src/test/compile-fail/const-cast-different-types.rs +++ b/src/test/compile-fail/const-cast-different-types.rs @@ -9,8 +9,8 @@ // except according to those terms. static a: &'static str = "foo"; -static b: *const u8 = a as *const u8; //~ ERROR non-scalar cast -static c: *const u8 = &a as *const u8; //~ ERROR mismatched types +static b: *const u8 = a as *const u8; //~ ERROR mismatched types: expected `*u8` but found `&'static str` +static c: *const u8 = &a as *const u8; //~ ERROR mismatched types: expected `*u8` but found `&&'static str` fn main() { } diff --git a/src/test/compile-fail/dst-bad-assign-2.rs b/src/test/compile-fail/dst-bad-assign-2.rs new file mode 100644 index 00000000000..282cf57df26 --- /dev/null +++ b/src/test/compile-fail/dst-bad-assign-2.rs @@ -0,0 +1,46 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Forbid assignment into a dynamically sized type. + +struct Fat<type T> { + f1: int, + f2: &'static str, + ptr: T +} + +#[deriving(PartialEq,Eq)] +struct Bar; + +#[deriving(PartialEq,Eq)] +struct Bar1 { + f: int +} + +trait ToBar { + fn to_bar(&self) -> Bar; + fn to_val(&self) -> int; +} + +impl ToBar for Bar1 { + fn to_bar(&self) -> Bar { + Bar + } + fn to_val(&self) -> int { + self.f + } +} + +pub fn main() { + // Assignment. + let f5: &mut Fat<ToBar> = &mut Fat { f1: 5, f2: "some str", ptr: Bar1 {f :42} }; + let z: Box<ToBar> = box Bar1 {f: 36}; + f5.ptr = *z; //~ ERROR dynamically sized type on lhs of assignment +} diff --git a/src/test/compile-fail/dst-bad-assign.rs b/src/test/compile-fail/dst-bad-assign.rs new file mode 100644 index 00000000000..e069eb01ae1 --- /dev/null +++ b/src/test/compile-fail/dst-bad-assign.rs @@ -0,0 +1,46 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Forbid assignment into a dynamically sized type. + +struct Fat<type T> { + f1: int, + f2: &'static str, + ptr: T +} + +#[deriving(PartialEq,Eq)] +struct Bar; + +#[deriving(PartialEq,Eq)] +struct Bar1 { + f: int +} + +trait ToBar { + fn to_bar(&self) -> Bar; + fn to_val(&self) -> int; +} + +impl ToBar for Bar1 { + fn to_bar(&self) -> Bar { + Bar + } + fn to_val(&self) -> int { + self.f + } +} + +pub fn main() { + // Assignment. + let f5: &mut Fat<ToBar> = &mut Fat { f1: 5, f2: "some str", ptr: Bar1 {f :42} }; + let z: Box<ToBar> = box Bar1 {f: 36}; + f5.ptr = Bar1 {f: 36}; //~ ERROR mismatched types: expected `ToBar` but found `Bar1` +} diff --git a/src/test/compile-fail/dst-bad-coerce1.rs b/src/test/compile-fail/dst-bad-coerce1.rs new file mode 100644 index 00000000000..a7dc4e123af --- /dev/null +++ b/src/test/compile-fail/dst-bad-coerce1.rs @@ -0,0 +1,32 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Attempt to change the type as well as unsizing. + +struct Fat<type T> { + ptr: T +} + +struct Foo; +trait Bar {} + +pub fn main() { + // With a vec of ints. + let f1 = Fat { ptr: [1, 2, 3] }; + let f2: &Fat<[int, ..3]> = &f1; + let f3: &Fat<[uint]> = f2; + //~^ ERROR mismatched types: expected `&Fat<[uint]>` but found `&Fat<[int, .. 3]>` + + // With a trait. + let f1 = Fat { ptr: Foo }; + let f2: &Fat<Foo> = &f1; + let f3: &Fat<Bar> = f2; + //~^ ERROR failed to find an implementation of trait Bar for Foo +} diff --git a/src/test/compile-fail/dst-bad-coerce2.rs b/src/test/compile-fail/dst-bad-coerce2.rs new file mode 100644 index 00000000000..d4ce59b7261 --- /dev/null +++ b/src/test/compile-fail/dst-bad-coerce2.rs @@ -0,0 +1,31 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Attempt to change the mutability as well as unsizing. + +struct Fat<type T> { + ptr: T +} + +struct Foo; +trait Bar {} +impl Bar for Foo {} + +pub fn main() { + // With a vec of ints. + let f1 = Fat { ptr: [1, 2, 3] }; + let f2: &Fat<[int, ..3]> = &f1; + let f3: &mut Fat<[int]> = f2; //~ ERROR cannot borrow immutable dereference + + // With a trait. + let f1 = Fat { ptr: Foo }; + let f2: &Fat<Foo> = &f1; + let f3: &mut Fat<Bar> = f2; //~ ERROR cannot borrow immutable dereference +} diff --git a/src/test/compile-fail/dst-bad-coerce3.rs b/src/test/compile-fail/dst-bad-coerce3.rs new file mode 100644 index 00000000000..bd7c46060a5 --- /dev/null +++ b/src/test/compile-fail/dst-bad-coerce3.rs @@ -0,0 +1,35 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Attempt to extend the lifetime as well as unsizing. + +struct Fat<type T> { + ptr: T +} + +struct Foo; +trait Bar {} +impl Bar for Foo {} + +fn baz<'a>() { + // With a vec of ints. + let f1 = Fat { ptr: [1, 2, 3] }; + let f2: &Fat<[int, ..3]> = &f1; //~ ERROR `f1` does not live long enough + let f3: &'a Fat<[int]> = f2; + + // With a trait. + let f1 = Fat { ptr: Foo }; + let f2: &Fat<Foo> = &f1; //~ ERROR `f1` does not live long enough + let f3: &'a Fat<Bar> = f2; +} + +pub fn main() { + baz(); +} diff --git a/src/test/compile-fail/dst-bad-coerce4.rs b/src/test/compile-fail/dst-bad-coerce4.rs new file mode 100644 index 00000000000..0916fa08a39 --- /dev/null +++ b/src/test/compile-fail/dst-bad-coerce4.rs @@ -0,0 +1,22 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Attempt to coerce from unsized to sized. + +struct Fat<type T> { + ptr: T +} + +pub fn main() { + // With a vec of ints. + let f1: &Fat<[int]> = &Fat { ptr: [1, 2, 3] }; + let f2: &Fat<[int, ..3]> = f1; + //~^ ERROR mismatched types: expected `&Fat<[int, .. 3]>` but found `&Fat<[int]>` +} diff --git a/src/test/compile-fail/dst-bad-deep.rs b/src/test/compile-fail/dst-bad-deep.rs new file mode 100644 index 00000000000..b18e7dad4ac --- /dev/null +++ b/src/test/compile-fail/dst-bad-deep.rs @@ -0,0 +1,25 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Try to initialise a DST struct where the lost information is deeply nested. +// This is an error because it requires an unsized rvalue. This is a problem +// because it would require stack allocation of an unsized temporary (*g in the +// test). + +struct Fat<type T> { + ptr: T +} + +pub fn main() { + let f: Fat<[int, ..3]> = Fat { ptr: [5i, 6, 7] }; + let g: &Fat<[int]> = &f; + let h: &Fat<Fat<[int]>> = &Fat { ptr: *g }; + //~^ ERROR trying to initialise a dynamically sized struct +} diff --git a/src/test/compile-fail/issue-10291.rs b/src/test/compile-fail/issue-10291.rs index 71b98bb5f5a..8ae20dfde91 100644 --- a/src/test/compile-fail/issue-10291.rs +++ b/src/test/compile-fail/issue-10291.rs @@ -8,11 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn test<'x>(x: &'x int) { //~ NOTE the lifetime 'x as defined +fn test<'x>(x: &'x int) { drop::< <'z>|&'z int| -> &'z int>(|z| { - //~^ ERROR mismatched types - //~^^ ERROR cannot infer an appropriate lifetime x + //~^ ERROR cannot infer an appropriate lifetime }); } diff --git a/src/test/compile-fail/issue-13446.rs b/src/test/compile-fail/issue-13446.rs index 0bb6ded0012..162324b7c59 100644 --- a/src/test/compile-fail/issue-13446.rs +++ b/src/test/compile-fail/issue-13446.rs @@ -11,7 +11,9 @@ // Used to cause ICE -static VEC: [u32, ..256] = vec!(); //~ ERROR mismatched types +// error-pattern: mismatched types + +static VEC: [u32, ..256] = vec!(); fn main() {} diff --git a/src/test/compile-fail/issue-4523.rs b/src/test/compile-fail/issue-4523.rs index 026327a358a..5063a78e383 100644 --- a/src/test/compile-fail/issue-4523.rs +++ b/src/test/compile-fail/issue-4523.rs @@ -10,8 +10,8 @@ fn foopy() {} -static f: ||: 'static = foopy; //~ ERROR found extern fn +static f: ||: 'static = foopy; fn main () { - f(); + f(); //~ ERROR closure invocation in a static location } diff --git a/src/test/compile-fail/issue-4972.rs b/src/test/compile-fail/issue-4972.rs index d684d1b376b..f7199a92d27 100644 --- a/src/test/compile-fail/issue-4972.rs +++ b/src/test/compile-fail/issue-4972.rs @@ -17,7 +17,7 @@ pub enum TraitWrapper { fn get_tw_map(tw: &TraitWrapper) -> &MyTrait { match *tw { - A(box ref map) => map, //~ ERROR cannot be dereferenced + A(box ref map) => map, //~ ERROR mismatched types: expected `Box<MyTrait>` but found a box } } diff --git a/src/test/compile-fail/issue-5883.rs b/src/test/compile-fail/issue-5883.rs index 831e165ad0e..3703d4f39ac 100644 --- a/src/test/compile-fail/issue-5883.rs +++ b/src/test/compile-fail/issue-5883.rs @@ -11,15 +11,14 @@ trait A {} struct Struct { - r: A //~ ERROR reference to trait `A` where a type is expected; try `Box<A>` or `&A` + r: A } fn new_struct(r: A) -> Struct { - //~^ ERROR reference to trait `A` where a type is expected; try `Box<A>` or `&A` + //~^ ERROR variable `r` has dynamically sized type `A` Struct { r: r } } trait Curve {} enum E {X(Curve)} -//~^ ERROR reference to trait `Curve` where a type is expected; try `Box<Curve>` or `&Curve` fn main() {} diff --git a/src/test/compile-fail/issue-7013.rs b/src/test/compile-fail/issue-7013.rs index ea332c1e252..efd8e75d3d6 100644 --- a/src/test/compile-fail/issue-7013.rs +++ b/src/test/compile-fail/issue-7013.rs @@ -32,7 +32,7 @@ struct A { fn main() { let a = A {v: box B{v: None} as Box<Foo+Send>}; - //~^ ERROR cannot pack type `Box<B>`, which does not fulfill `Send` + //~^ ERROR cannot pack type `Box<B>` as a trait bounded by Send because the type does not fulfil let v = Rc::new(RefCell::new(a)); let w = v.clone(); let b = &*v; diff --git a/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param.rs b/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param.rs index ef5a45fcf70..481fb3dee73 100644 --- a/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param.rs +++ b/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param.rs @@ -36,14 +36,14 @@ fn foo4<'a, 'b>(x: &'a Foo) -> (&'b int, &'a int, &'b int) { struct Bar<'x, 'y, 'z> { bar: &'y int, baz: int } fn bar1<'a>(x: &Bar) -> (&'a int, &'a int, &'a int) { //~^ NOTE: consider using an explicit lifetime parameter as shown: fn bar1<'b, 'c, 'a>(x: &'a Bar<'b, 'a, 'c>) -> (&'a int, &'a int, &'a int) - (x.bar, &x.baz, &x.baz) //~ ERROR: mismatched types + (x.bar, &x.baz, &x.baz) //~ ERROR: cannot infer //~^ ERROR: cannot infer //~^^ ERROR: cannot infer } fn bar2<'a, 'b, 'c>(x: &Bar<'a, 'b, 'c>) -> (&'a int, &'a int, &'a int) { //~^ NOTE: consider using an explicit lifetime parameter as shown: fn bar2<'a, 'c>(x: &'a Bar<'a, 'a, 'c>) -> (&'a int, &'a int, &'a int) - (x.bar, &x.baz, &x.baz) //~ ERROR: mismatched types + (x.bar, &x.baz, &x.baz) //~ ERROR: cannot infer //~^ ERROR: cannot infer //~^^ ERROR: cannot infer } @@ -53,21 +53,19 @@ struct Dog<'y> { dog: &'y int } fn cat2<'x, 'y>(x: Cat<'x, Dog<'y>>) -> &'x int { //~^ NOTE: consider using an explicit lifetime parameter as shown: fn cat2<'x>(x: Cat<'x, Dog<'x>>) -> &'x int - x.t.dog //~ ERROR: mismatched types + x.t.dog //~ ERROR: cannot infer } struct Baz<'x> { bar: &'x int } - impl<'a> Baz<'a> { fn baz2<'b>(&self, x: &int) -> (&'b int, &'b int) { // The lifetime that gets assigned to `x` seems somewhat random. // I have disabled this test for the time being. --pcwalton (self.bar, x) //~ ERROR: cannot infer - //~^ ERROR: mismatched types - //~^^ ERROR: mismatched types + //~^ ERROR: cannot infer } } diff --git a/src/test/compile-fail/lub-if.rs b/src/test/compile-fail/lub-if.rs index 82938d63ce5..5440219e55e 100644 --- a/src/test/compile-fail/lub-if.rs +++ b/src/test/compile-fail/lub-if.rs @@ -31,18 +31,18 @@ pub fn opt_str1<'a>(maybestr: &'a Option<String>) -> &'a str { } pub fn opt_str2<'a>(maybestr: &'a Option<String>) -> &'static str { - if maybestr.is_none() { //~ ERROR mismatched types + if maybestr.is_none() { "(none)" } else { let s: &'a str = maybestr.get_ref().as_slice(); - s + s //~ ERROR cannot infer an appropriate lifetime for automatic coercion due to conflicting } } pub fn opt_str3<'a>(maybestr: &'a Option<String>) -> &'static str { - if maybestr.is_some() { //~ ERROR mismatched types + if maybestr.is_some() { let s: &'a str = maybestr.get_ref().as_slice(); - s + s //~ ERROR cannot infer an appropriate lifetime for automatic coercion due to conflicting } else { "(none)" } diff --git a/src/test/compile-fail/lub-match.rs b/src/test/compile-fail/lub-match.rs index 98bea422fb5..febe5f45d96 100644 --- a/src/test/compile-fail/lub-match.rs +++ b/src/test/compile-fail/lub-match.rs @@ -33,7 +33,7 @@ pub fn opt_str1<'a>(maybestr: &'a Option<String>) -> &'a str { } pub fn opt_str2<'a>(maybestr: &'a Option<String>) -> &'static str { - match *maybestr { //~ ERROR mismatched types + match *maybestr { //~ ERROR cannot infer an appropriate lifetime for automatic coercion due to None => "(none)", Some(ref s) => { let s: &'a str = s.as_slice(); @@ -43,7 +43,7 @@ pub fn opt_str2<'a>(maybestr: &'a Option<String>) -> &'static str { } pub fn opt_str3<'a>(maybestr: &'a Option<String>) -> &'static str { - match *maybestr { //~ ERROR mismatched types + match *maybestr { //~ ERROR cannot infer an appropriate lifetime for automatic coercion due to Some(ref s) => { let s: &'a str = s.as_slice(); s diff --git a/src/test/compile-fail/regions-early-bound-error-method.rs b/src/test/compile-fail/regions-early-bound-error-method.rs index 9c8f8f8c30c..0cb88b924f8 100644 --- a/src/test/compile-fail/regions-early-bound-error-method.rs +++ b/src/test/compile-fail/regions-early-bound-error-method.rs @@ -27,7 +27,7 @@ impl<'a> GetRef<'a> for Box<'a> { impl<'a> Box<'a> { fn or<'b,G:GetRef<'b>>(&self, g2: G) -> &'a int { - g2.get() //~ ERROR lifetime mismatch + g2.get() //~ ERROR cannot infer an appropriate lifetime for automatic coercion due to } } diff --git a/src/test/compile-fail/regions-early-bound-error.rs b/src/test/compile-fail/regions-early-bound-error.rs index 9cff4849cbe..25016c104ad 100644 --- a/src/test/compile-fail/regions-early-bound-error.rs +++ b/src/test/compile-fail/regions-early-bound-error.rs @@ -26,7 +26,7 @@ impl<'a,T:Clone> GetRef<'a,T> for Box<'a,T> { } fn get<'a,'b,G:GetRef<'a, int>>(g1: G, b: &'b int) -> &'b int { - g1.get() //~ ERROR lifetime mismatch + g1.get() //~ ERROR cannot infer an appropriate lifetime for automatic coercion due to } fn main() { diff --git a/src/test/compile-fail/regions-glb-free-free.rs b/src/test/compile-fail/regions-glb-free-free.rs index 1d8c4cec655..0eb47da16b6 100644 --- a/src/test/compile-fail/regions-glb-free-free.rs +++ b/src/test/compile-fail/regions-glb-free-free.rs @@ -22,9 +22,9 @@ mod argparse { impl<'a> Flag<'a> { pub fn set_desc(self, s: &str) -> Flag<'a> { - Flag { //~ ERROR cannot infer + Flag { name: self.name, - desc: s, + desc: s, //~ ERROR cannot infer an appropriate lifetime for automatic coercion due t max_count: self.max_count, value: self.value } diff --git a/src/test/compile-fail/regions-nested-fns.rs b/src/test/compile-fail/regions-nested-fns.rs index c66e5616b84..7dc57d37e24 100644 --- a/src/test/compile-fail/regions-nested-fns.rs +++ b/src/test/compile-fail/regions-nested-fns.rs @@ -21,8 +21,7 @@ fn nested<'x>(x: &'x int) { }); ignore::< <'z>|&'z int| -> &'z int>(|z| { - if false { return x; } //~ ERROR mismatched types - //~^ ERROR cannot infer + if false { return x; } //~ ERROR cannot infer an appropriate lifetime for automatic if false { return ay; } return z; }); diff --git a/src/test/compile-fail/regions-ret-borrowed-1.rs b/src/test/compile-fail/regions-ret-borrowed-1.rs index 068ecb7118f..df46b2aaac0 100644 --- a/src/test/compile-fail/regions-ret-borrowed-1.rs +++ b/src/test/compile-fail/regions-ret-borrowed-1.rs @@ -17,7 +17,7 @@ fn with<R>(f: <'a>|x: &'a int| -> R) -> R { } fn return_it<'a>() -> &'a int { - with(|o| o) //~ ERROR mismatched types + with(|o| o) //~^ ERROR lifetime of return value does not outlive the function call //~^^ ERROR cannot infer } diff --git a/src/test/compile-fail/regions-ret-borrowed.rs b/src/test/compile-fail/regions-ret-borrowed.rs index f9983bcf801..507a48fb741 100644 --- a/src/test/compile-fail/regions-ret-borrowed.rs +++ b/src/test/compile-fail/regions-ret-borrowed.rs @@ -20,7 +20,7 @@ fn with<R>(f: |x: &int| -> R) -> R { } fn return_it<'a>() -> &'a int { - with(|o| o) //~ ERROR mismatched types + with(|o| o) //~^ ERROR lifetime of return value does not outlive the function call //~^^ ERROR cannot infer } diff --git a/src/test/compile-fail/regions-return-stack-allocated-vec.rs b/src/test/compile-fail/regions-return-stack-allocated-vec.rs index b5f4fcadf89..3c5423c44d0 100644 --- a/src/test/compile-fail/regions-return-stack-allocated-vec.rs +++ b/src/test/compile-fail/regions-return-stack-allocated-vec.rs @@ -11,7 +11,7 @@ // Test that we cannot return a stack allocated slice fn function(x: int) -> &'static [int] { - &[x] //~ ERROR mismatched types + &[x] //~ ERROR borrowed value does not live long enough } fn main() { diff --git a/src/test/compile-fail/trait-bounds-not-on-bare-trait.rs b/src/test/compile-fail/trait-bounds-not-on-bare-trait.rs index f0f388a5a07..78b4ab817bf 100644 --- a/src/test/compile-fail/trait-bounds-not-on-bare-trait.rs +++ b/src/test/compile-fail/trait-bounds-not-on-bare-trait.rs @@ -14,7 +14,7 @@ trait Foo { // This should emit the less confusing error, not the more confusing one. fn foo(_x: Foo + Send) { - //~^ERROR reference to trait `Foo` where a type is expected; try `Box<Foo>` or `&Foo` + //~^ERROR variable `_x` has dynamically sized type `Foo+Send` } fn main() { } diff --git a/src/test/run-make/graphviz-flowgraph/f15.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f15.dot-expected.dot index bc47d9aff81..978cca56b56 100644 --- a/src/test/run-make/graphviz-flowgraph/f15.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f15.dot-expected.dot @@ -6,37 +6,37 @@ digraph block { N4[label="expr 151i"]; N5[label="local mut y"]; N6[label="(dummy_node)"]; - N7[label="expr \'outer:\l loop {\l \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\" }\l if y >= 2i { break ; \"unreachable\" }\l y -= 3i;\l }\l y -= 4i;\l x -= 5i;\l }\l"]; + N7[label="expr \'outer:\l loop {\l \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { break ; \"unreachable\"; }\l y -= 3i;\l }\l y -= 4i;\l x -= 5i;\l }\l"]; N8[label="(dummy_node)"]; - N9[label="expr \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\" }\l if y >= 2i { break ; \"unreachable\" }\l y -= 3i;\l }\l"]; + N9[label="expr \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { break ; \"unreachable\"; }\l y -= 3i;\l }\l"]; N10[label="expr x"]; N11[label="expr 1i"]; N12[label="expr x == 1i"]; N13[label="expr break \'outer"]; N14[label="(dummy_node)"]; N15[label="expr \"unreachable\""]; - N16[label="block { break \'outer ; \"unreachable\" }"]; - N17[label="expr if x == 1i { break \'outer ; \"unreachable\" }"]; + N16[label="block { break \'outer ; \"unreachable\"; }"]; + N17[label="expr if x == 1i { break \'outer ; \"unreachable\"; }"]; N18[label="expr y"]; N19[label="expr 2i"]; N20[label="expr y >= 2i"]; N21[label="expr break"]; N22[label="(dummy_node)"]; N23[label="expr \"unreachable\""]; - N24[label="block { break ; \"unreachable\" }"]; - N25[label="expr if y >= 2i { break ; \"unreachable\" }"]; + N24[label="block { break ; \"unreachable\"; }"]; + N25[label="expr if y >= 2i { break ; \"unreachable\"; }"]; N26[label="expr 3i"]; N27[label="expr y"]; N28[label="expr y -= 3i"]; - N29[label="block {\l if x == 1i { break \'outer ; \"unreachable\" }\l if y >= 2i { break ; \"unreachable\" }\l y -= 3i;\l}\l"]; + N29[label="block {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { break ; \"unreachable\"; }\l y -= 3i;\l}\l"]; N30[label="expr 4i"]; N31[label="expr y"]; N32[label="expr y -= 4i"]; N33[label="expr 5i"]; N34[label="expr x"]; N35[label="expr x -= 5i"]; - N36[label="block {\l \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\" }\l if y >= 2i { break ; \"unreachable\" }\l y -= 3i;\l }\l y -= 4i;\l x -= 5i;\l}\l"]; - N37[label="block {\l let mut x = 15i;\l let mut y = 151i;\l \'outer:\l loop {\l \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\" }\l if y >= 2i { break ; \"unreachable\" }\l y -= 3i;\l }\l y -= 4i;\l x -= 5i;\l }\l}\l"]; + N36[label="block {\l \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { break ; \"unreachable\"; }\l y -= 3i;\l }\l y -= 4i;\l x -= 5i;\l}\l"]; + N37[label="block {\l let mut x = 15i;\l let mut y = 151i;\l \'outer:\l loop {\l \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { break ; \"unreachable\"; }\l y -= 3i;\l }\l y -= 4i;\l x -= 5i;\l }\l}\l"]; N0 -> N2; N2 -> N3; N3 -> N4; @@ -47,7 +47,7 @@ digraph block { N10 -> N11; N11 -> N12; N12 -> N13; - N13 -> N7[label="exiting scope_0 expr break \'outer,\lexiting scope_1 stmt break \'outer ;,\lexiting scope_2 block { break \'outer ; \"unreachable\" },\lexiting scope_3 expr if x == 1i { break \'outer ; \"unreachable\" },\lexiting scope_4 stmt if x == 1i { break \'outer ; \"unreachable\" },\lexiting scope_5 block {\l if x == 1i { break \'outer ; \"unreachable\" }\l if y >= 2i { break ; \"unreachable\" }\l y -= 3i;\l}\l,\lexiting scope_6 expr \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\" }\l if y >= 2i { break ; \"unreachable\" }\l y -= 3i;\l }\l,\lexiting scope_7 stmt \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\" }\l if y >= 2i { break ; \"unreachable\" }\l y -= 3i;\l }\l,\lexiting scope_8 block {\l \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\" }\l if y >= 2i { break ; \"unreachable\" }\l y -= 3i;\l }\l y -= 4i;\l x -= 5i;\l}\l"]; + N13 -> N7[label="exiting scope_0 expr break \'outer,\lexiting scope_1 stmt break \'outer ;,\lexiting scope_2 block { break \'outer ; \"unreachable\"; },\lexiting scope_3 expr if x == 1i { break \'outer ; \"unreachable\"; },\lexiting scope_4 stmt if x == 1i { break \'outer ; \"unreachable\"; },\lexiting scope_5 block {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { break ; \"unreachable\"; }\l y -= 3;\l}\l,\lexiting scope_6 expr \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { break ; \"unreachable\"; }\l y -= 3;\l }\l,\lexiting scope_7 stmt \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { break ; \"unreachable\"; }\l y -= 3;\l }\l,\lexiting scope_8 block {\l \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { break ; \"unreachable\"; }\l y -= 3;\l }\l y -= 4;\l x -= 5;\l}\l"]; N14 -> N15; N15 -> N16; N12 -> N17; @@ -56,7 +56,7 @@ digraph block { N18 -> N19; N19 -> N20; N20 -> N21; - N21 -> N9[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\" },\lexiting scope_3 expr if y >= 2i { break ; \"unreachable\" },\lexiting scope_4 stmt if y >= 2i { break ; \"unreachable\" },\lexiting scope_5 block {\l if x == 1i { break \'outer ; \"unreachable\" }\l if y >= 2i { break ; \"unreachable\" }\l y -= 3i;\l}\l"]; + N21 -> N9[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if y >= 2i { break ; \"unreachable\"; },\lexiting scope_4 stmt if y >= 2i { break ; \"unreachable\"; },\lexiting scope_5 block {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { break ; \"unreachable\"; }\l y -= 3i;\l}\l"]; N22 -> N23; N23 -> N24; N20 -> N25; diff --git a/src/test/run-make/graphviz-flowgraph/f15.rs b/src/test/run-make/graphviz-flowgraph/f15.rs index e5ca1de3f2d..62233dcb7d8 100644 --- a/src/test/run-make/graphviz-flowgraph/f15.rs +++ b/src/test/run-make/graphviz-flowgraph/f15.rs @@ -16,11 +16,11 @@ pub fn expr_break_label_15() { 'inner: loop { if x == 1i { break 'outer; - "unreachable" + "unreachable"; } if y >= 2i { break; - "unreachable" + "unreachable"; } y -= 3i; } diff --git a/src/test/run-make/graphviz-flowgraph/f16.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f16.dot-expected.dot index 9c60e19f8b0..963c4b43531 100644 --- a/src/test/run-make/graphviz-flowgraph/f16.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f16.dot-expected.dot @@ -6,38 +6,38 @@ digraph block { N4[label="expr 16i"]; N5[label="local mut y"]; N6[label="(dummy_node)"]; - N7[label="expr \'outer:\l loop {\l \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\" }\l if y >= 1i { break ; \"unreachable\" }\l y -= 1i;\l }\l y -= 1i;\l x -= 1i;\l }\l"]; + N7[label="expr \'outer:\l loop {\l \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 1i { break ; \"unreachable\"; }\l y -= 1i;\l }\l y -= 1i;\l x -= 1i;\l }\l"]; N8[label="(dummy_node)"]; - N9[label="expr \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\" }\l if y >= 1i { break ; \"unreachable\" }\l y -= 1i;\l }\l"]; + N9[label="expr \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 1i { break ; \"unreachable\"; }\l y -= 1i;\l }\l"]; N10[label="expr x"]; N11[label="expr 1i"]; N12[label="expr x == 1i"]; N13[label="expr continue \'outer"]; N14[label="(dummy_node)"]; N15[label="expr \"unreachable\""]; - N16[label="block { continue \'outer ; \"unreachable\" }"]; - N17[label="expr if x == 1i { continue \'outer ; \"unreachable\" }"]; + N16[label="block { continue \'outer ; \"unreachable\"; }"]; + N17[label="expr if x == 1i { continue \'outer ; \"unreachable\"; }"]; N18[label="expr y"]; N19[label="expr 1i"]; N20[label="expr y >= 1i"]; N21[label="expr break"]; N22[label="(dummy_node)"]; N23[label="expr \"unreachable\""]; - N24[label="block { break ; \"unreachable\" }"]; - N25[label="expr if y >= 1i { break ; \"unreachable\" }"]; + N24[label="block { break ; \"unreachable\"; }"]; + N25[label="expr if y >= 1i { break ; \"unreachable\"; }"]; N26[label="expr 1i"]; N27[label="expr y"]; N28[label="expr y -= 1i"]; - N29[label="block {\l if x == 1i { continue \'outer ; \"unreachable\" }\l if y >= 1i { break ; \"unreachable\" }\l y -= 1i;\l}\l"]; - N30[label="expr 1i"]; + N29[label="block {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 1i { break ; \"unreachable\"; }\l y -= 1i;\l}\l"]; + N30[label="expr 1"]; N31[label="expr y"]; N32[label="expr y -= 1i"]; N33[label="expr 1i"]; N34[label="expr x"]; N35[label="expr x -= 1i"]; - N36[label="block {\l \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\" }\l if y >= 1i { break ; \"unreachable\" }\l y -= 1i;\l }\l y -= 1i;\l x -= 1i;\l}\l"]; + N36[label="block {\l \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 1i { break ; \"unreachable\"; }\l y -= 1i;\l }\l y -= 1i;\l x -= 1i;\l}\l"]; N37[label="expr \"unreachable\""]; - N38[label="block {\l let mut x = 16i;\l let mut y = 16i;\l \'outer:\l loop {\l \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\" }\l if y >= 1i { break ; \"unreachable\" }\l y -= 1i;\l }\l y -= 1i;\l x -= 1i;\l }\l \"unreachable\";\l}\l"]; + N38[label="block {\l let mut x = 16i;\l let mut y = 16i;\l \'outer:\l loop {\l \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 1i { break ; \"unreachable\"; }\l y -= 1i;\l }\l y -= 1i;\l x -= 1i;\l }\l \"unreachable\";\l}\l"]; N0 -> N2; N2 -> N3; N3 -> N4; @@ -48,7 +48,7 @@ digraph block { N10 -> N11; N11 -> N12; N12 -> N13; - N13 -> N6[label="exiting scope_0 expr continue \'outer,\lexiting scope_1 stmt continue \'outer ;,\lexiting scope_2 block { continue \'outer ; \"unreachable\" },\lexiting scope_3 expr if x == 1i { continue \'outer ; \"unreachable\" },\lexiting scope_4 stmt if x == 1i { continue \'outer ; \"unreachable\" },\lexiting scope_5 block {\l if x == 1i { continue \'outer ; \"unreachable\" }\l if y >= 1i { break ; \"unreachable\" }\l y -= 1i;\l}\l,\lexiting scope_6 expr \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\" }\l if y >= 1i { break ; \"unreachable\" }\l y -= 1i;\l }\l,\lexiting scope_7 stmt \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\" }\l if y >= 1i { break ; \"unreachable\" }\l y -= 1i;\l }\l,\lexiting scope_8 block {\l \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\" }\l if y >= 1i { break ; \"unreachable\" }\l y -= 1i;\l }\l y -= 1i;\l x -= 1i;\l}\l"]; + N13 -> N6[label="exiting scope_0 expr continue \'outer,\lexiting scope_1 stmt continue \'outer ;,\lexiting scope_2 block { continue \'outer ; \"unreachable\"; },\lexiting scope_3 expr if x == 1i { continue \'outer ; \"unreachable\"; },\lexiting scope_4 stmt if x == 1i { continue \'outer ; \"unreachable\"; },\lexiting scope_5 block {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 1i { break ; \"unreachable\"; }\l y -= 1i;\l}\l,\lexiting scope_6 expr \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 1i { break ; \"unreachable\"; }\l y -= 1i;\l }\l,\lexiting scope_7 stmt \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 1i { break ; \"unreachable\"; }\l y -= 1i;\l }\l,\lexiting scope_8 block {\l \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 1i { break ; \"unreachable\"; }\l y -= 1i;\l }\l y -= 1i;\l x -= 1i;\l}\l"]; N14 -> N15; N15 -> N16; N12 -> N17; @@ -57,7 +57,7 @@ digraph block { N18 -> N19; N19 -> N20; N20 -> N21; - N21 -> N9[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\" },\lexiting scope_3 expr if y >= 1i { break ; \"unreachable\" },\lexiting scope_4 stmt if y >= 1i { break ; \"unreachable\" },\lexiting scope_5 block {\l if x == 1i { continue \'outer ; \"unreachable\" }\l if y >= 1i { break ; \"unreachable\" }\l y -= 1i;\l}\l"]; + N21 -> N9[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if y >= 1i { break ; \"unreachable\"; },\lexiting scope_4 stmt if y >= 1i { break ; \"unreachable\"; },\lexiting scope_5 block {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 1i { break ; \"unreachable\"; }\l y -= 1i;\l}\l"]; N22 -> N23; N23 -> N24; N20 -> N25; diff --git a/src/test/run-make/graphviz-flowgraph/f16.rs b/src/test/run-make/graphviz-flowgraph/f16.rs index 78de99d28fc..2683d8bd06b 100644 --- a/src/test/run-make/graphviz-flowgraph/f16.rs +++ b/src/test/run-make/graphviz-flowgraph/f16.rs @@ -16,11 +16,11 @@ pub fn expr_continue_label_16() { 'inner: loop { if x == 1i { continue 'outer; - "unreachable" + "unreachable"; } if y >= 1i { break; - "unreachable" + "unreachable"; } y -= 1i; } diff --git a/src/test/run-pass/check-static-slice.rs b/src/test/run-pass/check-static-slice.rs new file mode 100644 index 00000000000..17957dbcc13 --- /dev/null +++ b/src/test/run-pass/check-static-slice.rs @@ -0,0 +1,40 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Check that the various ways of getting to a reference to a vec (both sized +// and unsized) work properly. + +static aa: [int, ..3] = [1, 2, 3]; +static ab: &'static [int, ..3] = &aa; +static ac: &'static [int] = ab; +static ad: &'static [int] = &aa; +static ae: &'static [int, ..3] = &[1, 2, 3]; +static af: &'static [int] = &[1, 2, 3]; + +static ca: int = aa[0]; +static cb: int = ab[1]; +static cc: int = ac[2]; +static cd: int = ad[0]; +static ce: int = ae[1]; +static cf: int = af[2]; + +fn main () { + let b: &[int] = &[1, 2, 3]; + assert!(ac == b); + assert!(ad == b); + assert!(af == b); + + assert!(ca == 1); + assert!(cb == 2); + assert!(cc == 3); + assert!(cd == 1); + assert!(ce == 2); + assert!(cf == 3); +} diff --git a/src/test/run-pass/const-enum-vec-index.rs b/src/test/run-pass/const-enum-vec-index.rs index 4c81eaae1d8..5be21696bd1 100644 --- a/src/test/run-pass/const-enum-vec-index.rs +++ b/src/test/run-pass/const-enum-vec-index.rs @@ -12,6 +12,9 @@ enum E { V1(int), V0 } static C: &'static [E] = &[V0, V1(0xDEADBEE)]; static C0: E = C[0]; static C1: E = C[1]; +static D: &'static [E, ..2] = &[V0, V1(0xDEADBEE)]; +static D0: E = C[0]; +static D1: E = C[1]; pub fn main() { match C0 { @@ -22,4 +25,13 @@ pub fn main() { V1(n) => assert!(n == 0xDEADBEE), _ => fail!() } + + match D0 { + V0 => (), + _ => fail!() + } + match D1 { + V1(n) => assert!(n == 0xDEADBEE), + _ => fail!() + } } diff --git a/src/test/run-pass/dst-struct-reflect.rs b/src/test/run-pass/dst-struct-reflect.rs new file mode 100644 index 00000000000..297880a8b53 --- /dev/null +++ b/src/test/run-pass/dst-struct-reflect.rs @@ -0,0 +1,59 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that structs with unsized fields work with {:?} reflection. + +extern crate debug; + +struct Fat<type T> { + f1: int, + f2: &'static str, + ptr: T +} + +// x is a fat pointer +fn reflect(x: &Fat<[int]>, cmp: &str) { + // Don't test this result because reflecting unsized fields is undefined for now. + let _s = format!("{:?}", x); + let s = format!("{:?}", &x.ptr); + assert!(s == cmp.to_string()) + + println!("{:?}", x); + println!("{:?}", &x.ptr); +} + +fn reflect_0(x: &Fat<[int]>) { + let _s = format!("{:?}", x.ptr[0]); + println!("{:?}", x.ptr[0]); +} + +pub fn main() { + // With a vec of ints. + let f1 = Fat { f1: 5, f2: "some str", ptr: [1, 2, 3] }; + reflect(&f1, "&[1, 2, 3]"); + reflect_0(&f1); + let f2 = &f1; + reflect(f2, "&[1, 2, 3]"); + reflect_0(f2); + let f3: &Fat<[int]> = f2; + reflect(f3, "&[1, 2, 3]"); + reflect_0(f3); + let f4: &Fat<[int]> = &f1; + reflect(f4, "&[1, 2, 3]"); + reflect_0(f4); + let f5: &Fat<[int]> = &Fat { f1: 5, f2: "some str", ptr: [1, 2, 3] }; + reflect(f5, "&[1, 2, 3]"); + reflect_0(f5); + + // Zero size vec. + let f5: &Fat<[int]> = &Fat { f1: 5, f2: "some str", ptr: [] }; + reflect(f5, "&[]"); +} + diff --git a/src/test/run-pass/dst-struct-sole.rs b/src/test/run-pass/dst-struct-sole.rs new file mode 100644 index 00000000000..3f01d013cee --- /dev/null +++ b/src/test/run-pass/dst-struct-sole.rs @@ -0,0 +1,84 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// As dst-struct.rs, but the unsized field is the only field in the struct. + +struct Fat<type T> { + ptr: T +} + +// x is a fat pointer +fn foo(x: &Fat<[int]>) { + let y = &x.ptr; + assert!(x.ptr.len() == 3); + assert!(y[0] == 1); + assert!(x.ptr[1] == 2); +} + +fn foo2<T:ToBar>(x: &Fat<[T]>) { + let y = &x.ptr; + let bar = Bar; + assert!(x.ptr.len() == 3); + assert!(y[0].to_bar() == bar); + assert!(x.ptr[1].to_bar() == bar); +} + +#[deriving(PartialEq,Eq)] +struct Bar; + +trait ToBar { + fn to_bar(&self) -> Bar; +} + +impl ToBar for Bar { + fn to_bar(&self) -> Bar { + *self + } +} + +pub fn main() { + // With a vec of ints. + let f1 = Fat { ptr: [1, 2, 3] }; + foo(&f1); + let f2 = &f1; + foo(f2); + let f3: &Fat<[int]> = f2; + foo(f3); + let f4: &Fat<[int]> = &f1; + foo(f4); + let f5: &Fat<[int]> = &Fat { ptr: [1, 2, 3] }; + foo(f5); + + // With a vec of Bars. + let bar = Bar; + let f1 = Fat { ptr: [bar, bar, bar] }; + foo2(&f1); + let f2 = &f1; + foo2(f2); + let f3: &Fat<[Bar]> = f2; + foo2(f3); + let f4: &Fat<[Bar]> = &f1; + foo2(f4); + let f5: &Fat<[Bar]> = &Fat { ptr: [bar, bar, bar] }; + foo2(f5); + + // Assignment. + let f5: &mut Fat<[int]> = &mut Fat { ptr: [1, 2, 3] }; + f5.ptr[1] = 34; + assert!(f5.ptr[0] == 1); + assert!(f5.ptr[1] == 34); + assert!(f5.ptr[2] == 3); + + // Zero size vec. + let f5: &Fat<[int]> = &Fat { ptr: [] }; + assert!(f5.ptr.len() == 0); + let f5: &Fat<[Bar]> = &Fat { ptr: [] }; + assert!(f5.ptr.len() == 0); +} diff --git a/src/test/run-pass/dst-struct.rs b/src/test/run-pass/dst-struct.rs new file mode 100644 index 00000000000..ae1f854ccab --- /dev/null +++ b/src/test/run-pass/dst-struct.rs @@ -0,0 +1,127 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct Fat<type T> { + f1: int, + f2: &'static str, + ptr: T +} + +// x is a fat pointer +fn foo(x: &Fat<[int]>) { + let y = &x.ptr; + assert!(x.ptr.len() == 3); + assert!(y[0] == 1); + assert!(x.ptr[1] == 2); + assert!(x.f1 == 5); + assert!(x.f2 == "some str"); +} + +fn foo2<T:ToBar>(x: &Fat<[T]>) { + let y = &x.ptr; + let bar = Bar; + assert!(x.ptr.len() == 3); + assert!(y[0].to_bar() == bar); + assert!(x.ptr[1].to_bar() == bar); + assert!(x.f1 == 5); + assert!(x.f2 == "some str"); +} + +fn foo3(x: &Fat<Fat<[int]>>) { + let y = &x.ptr.ptr; + assert!(x.f1 == 5); + assert!(x.f2 == "some str"); + assert!(x.ptr.f1 == 8); + assert!(x.ptr.f2 == "deep str"); + assert!(x.ptr.ptr.len() == 3); + assert!(y[0] == 1); + assert!(x.ptr.ptr[1] == 2); +} + + +#[deriving(PartialEq,Eq)] +struct Bar; + +trait ToBar { + fn to_bar(&self) -> Bar; +} + +impl ToBar for Bar { + fn to_bar(&self) -> Bar { + *self + } +} + +pub fn main() { + // With a vec of ints. + let f1 = Fat { f1: 5, f2: "some str", ptr: [1, 2, 3] }; + foo(&f1); + let f2 = &f1; + foo(f2); + let f3: &Fat<[int]> = f2; + foo(f3); + let f4: &Fat<[int]> = &f1; + foo(f4); + let f5: &Fat<[int]> = &Fat { f1: 5, f2: "some str", ptr: [1, 2, 3] }; + foo(f5); + + // With a vec of Bars. + let bar = Bar; + let f1 = Fat { f1: 5, f2: "some str", ptr: [bar, bar, bar] }; + foo2(&f1); + let f2 = &f1; + foo2(f2); + let f3: &Fat<[Bar]> = f2; + foo2(f3); + let f4: &Fat<[Bar]> = &f1; + foo2(f4); + let f5: &Fat<[Bar]> = &Fat { f1: 5, f2: "some str", ptr: [bar, bar, bar] }; + foo2(f5); + + // Assignment. + let f5: &mut Fat<[int]> = &mut Fat { f1: 5, f2: "some str", ptr: [1, 2, 3] }; + f5.ptr[1] = 34; + assert!(f5.ptr[0] == 1); + assert!(f5.ptr[1] == 34); + assert!(f5.ptr[2] == 3); + + // Zero size vec. + let f5: &Fat<[int]> = &Fat { f1: 5, f2: "some str", ptr: [] }; + assert!(f5.ptr.len() == 0); + let f5: &Fat<[Bar]> = &Fat { f1: 5, f2: "some str", ptr: [] }; + assert!(f5.ptr.len() == 0); + + // Deeply nested. + let f1 = Fat { f1: 5, f2: "some str", ptr: Fat { f1: 8, f2: "deep str", ptr: [1, 2, 3]} }; + foo3(&f1); + let f2 = &f1; + foo3(f2); + let f3: &Fat<Fat<[int]>> = f2; + foo3(f3); + let f4: &Fat<Fat<[int]>> = &f1; + foo3(f4); + let f5: &Fat<Fat<[int]>> = + &Fat { f1: 5, f2: "some str", ptr: Fat { f1: 8, f2: "deep str", ptr: [1, 2, 3]} }; + foo3(f5); + + // Box. + let f1 = box [1i, 2, 3]; + assert!((*f1)[1] == 2); + let f2: Box<[int]> = f1; + assert!((*f2)[1] == 2); + + // Nested Box. + let f1 : Box<Fat<[int, ..3]>> = box Fat { f1: 5, f2: "some str", ptr: [1, 2, 3] }; + foo(&*f1); + let f2 : Box<Fat<[int]>> = f1; + foo(&*f2); + let f3 : Box<Fat<[int]>> = box Fat { f1: 5, f2: "some str", ptr: [1, 2, 3] }; + foo(&*f3); +} diff --git a/src/test/run-pass/dst-trait.rs b/src/test/run-pass/dst-trait.rs new file mode 100644 index 00000000000..7429136716c --- /dev/null +++ b/src/test/run-pass/dst-trait.rs @@ -0,0 +1,111 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct Fat<type T> { + f1: int, + f2: &'static str, + ptr: T +} + +#[deriving(PartialEq,Eq)] +struct Bar; + +#[deriving(PartialEq,Eq)] +struct Bar1 { + f: int +} + +trait ToBar { + fn to_bar(&self) -> Bar; + fn to_val(&self) -> int; +} + +impl ToBar for Bar { + fn to_bar(&self) -> Bar { + *self + } + fn to_val(&self) -> int { + 0 + } +} +impl ToBar for Bar1 { + fn to_bar(&self) -> Bar { + Bar + } + fn to_val(&self) -> int { + self.f + } +} + +// x is a fat pointer +fn foo(x: &Fat<ToBar>) { + assert!(x.f1 == 5); + assert!(x.f2 == "some str"); + assert!(x.ptr.to_bar() == Bar); + assert!(x.ptr.to_val() == 42); + + let y = &x.ptr; + assert!(y.to_bar() == Bar); + assert!(y.to_val() == 42); +} + +fn bar(x: &ToBar) { + assert!(x.to_bar() == Bar); + assert!(x.to_val() == 42); +} + +fn baz(x: &Fat<Fat<ToBar>>) { + assert!(x.f1 == 5); + assert!(x.f2 == "some str"); + assert!(x.ptr.f1 == 8); + assert!(x.ptr.f2 == "deep str"); + assert!(x.ptr.ptr.to_bar() == Bar); + assert!(x.ptr.ptr.to_val() == 42); + + let y = &x.ptr.ptr; + assert!(y.to_bar() == Bar); + assert!(y.to_val() == 42); + +} + +pub fn main() { + let f1 = Fat { f1: 5, f2: "some str", ptr: Bar1 {f :42} }; + foo(&f1); + let f2 = &f1; + foo(f2); + let f3: &Fat<ToBar> = f2; + foo(f3); + let f4: &Fat<ToBar> = &f1; + foo(f4); + let f5: &Fat<ToBar> = &Fat { f1: 5, f2: "some str", ptr: Bar1 {f :42} }; + foo(f5); + + // Zero size object. + let f6: &Fat<ToBar> = &Fat { f1: 5, f2: "some str", ptr: Bar }; + assert!(f6.ptr.to_bar() == Bar); + + // &* + let f7: Box<ToBar> = box Bar1 {f :42}; + bar(&*f7); + + // Deep nesting + let f1 = + Fat { f1: 5, f2: "some str", ptr: Fat { f1: 8, f2: "deep str", ptr: Bar1 {f :42}} }; + baz(&f1); + let f2 = &f1; + baz(f2); + let f3: &Fat<Fat<ToBar>> = f2; + baz(f3); + let f4: &Fat<Fat<ToBar>> = &f1; + baz(f4); + let f5: &Fat<Fat<ToBar>> = + &Fat { f1: 5, f2: "some str", ptr: Fat { f1: 8, f2: "deep str", ptr: Bar1 {f :42}} }; + baz(f5); +} diff --git a/src/test/run-pass/evec-slice.rs b/src/test/run-pass/evec-slice.rs index 9c5995b7ba0..4a112f145c3 100644 --- a/src/test/run-pass/evec-slice.rs +++ b/src/test/run-pass/evec-slice.rs @@ -14,7 +14,7 @@ extern crate debug; pub fn main() { let x : &[int] = &[1,2,3,4,5]; - let mut z = &[1,2,3,4,5]; + let mut z : &[int] = &[1,2,3,4,5]; z = x; assert_eq!(z[0], 1); assert_eq!(z[4], 5); diff --git a/src/test/run-pass/gc-vec.rs b/src/test/run-pass/gc-vec.rs new file mode 100644 index 00000000000..d2f43aacd66 --- /dev/null +++ b/src/test/run-pass/gc-vec.rs @@ -0,0 +1,22 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::gc::{GC}; + +fn main() { + // A fixed-size array allocated in a garbage-collected box + let x = box(GC) [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + assert_eq!(x[0], 1); + assert_eq!(x[6], 7); + assert_eq!(x[9], 10); + + let y = x; + assert!(*y == [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); +} diff --git a/src/test/run-pass/issue-7012.rs b/src/test/run-pass/issue-7012.rs index 4e74a7a1ecf..96db28f4a10 100644 --- a/src/test/run-pass/issue-7012.rs +++ b/src/test/run-pass/issue-7012.rs @@ -22,6 +22,7 @@ static test1: signature<'static> = signature { }; pub fn main() { - let test = &[0x243f6a88u32,0x85a308d3u32,0x13198a2eu32,0x03707344u32,0xa4093822u32,0x299f31d0u32]; + let test: &[u32] = &[0x243f6a88u32,0x85a308d3u32,0x13198a2eu32, + 0x03707344u32,0xa4093822u32,0x299f31d0u32]; println!("{}",test==test1.pattern); } diff --git a/src/test/run-pass/issue-9259.rs b/src/test/run-pass/issue-9259.rs index 35f51efe135..2818b824969 100644 --- a/src/test/run-pass/issue-9259.rs +++ b/src/test/run-pass/issue-9259.rs @@ -14,7 +14,7 @@ struct A<'a> { } pub fn main() { - let b = &["foo".to_string()]; + let b: &[String] = &["foo".to_string()]; let a = A { a: &["test".to_string()], b: Some(b), diff --git a/src/test/run-pass/overloaded-deref-count.rs b/src/test/run-pass/overloaded-deref-count.rs index 0b5406b8f67..2d546639939 100644 --- a/src/test/run-pass/overloaded-deref-count.rs +++ b/src/test/run-pass/overloaded-deref-count.rs @@ -81,5 +81,6 @@ pub fn main() { // Check the final states. assert_eq!(*n, 2); - assert_eq!((*v).as_slice(), &[1, 2]); + let expected: &[_] = &[1, 2]; + assert_eq!((*v).as_slice(), expected); } diff --git a/src/test/run-pass/reflect-visit-type.rs b/src/test/run-pass/reflect-visit-type.rs index 596e56b424a..f599a2b7ad5 100644 --- a/src/test/run-pass/reflect-visit-type.rs +++ b/src/test/run-pass/reflect-visit-type.rs @@ -61,6 +61,8 @@ impl TyVisitor for MyVisitor { fn visit_char(&mut self) -> bool { true } fn visit_estr_slice(&mut self) -> bool { true } + // NOTE: remove after snapshot + #[cfg(stage0)] fn visit_estr_fixed(&mut self, _sz: uint, _sz2: uint, _align: uint) -> bool { true } @@ -72,7 +74,7 @@ impl TyVisitor for MyVisitor { fn visit_evec_slice(&mut self, _mtbl: uint, _inner: *const TyDesc) -> bool { true } fn visit_evec_fixed(&mut self, _n: uint, _sz: uint, _align: uint, - _mtbl: uint, _inner: *const TyDesc) -> bool { true } + _inner: *const TyDesc) -> bool { true } fn visit_enter_rec(&mut self, _n_fields: uint, _sz: uint, _align: uint) -> bool { true } diff --git a/src/test/run-pass/smallest-hello-world.rs b/src/test/run-pass/smallest-hello-world.rs index 4f1a3817fab..52e71186537 100644 --- a/src/test/run-pass/smallest-hello-world.rs +++ b/src/test/run-pass/smallest-hello-world.rs @@ -22,6 +22,7 @@ extern "rust-intrinsic" { fn transmute<T, U>(t: T) -> U; } #[lang = "stack_exhausted"] extern fn stack_exhausted() {} #[lang = "eh_personality"] extern fn eh_personality() {} +#[lang = "sized"] pub trait Sized {} #[start] #[no_split_stack] diff --git a/src/test/run-pass/vec-dst.rs b/src/test/run-pass/vec-dst.rs new file mode 100644 index 00000000000..809dde38eb4 --- /dev/null +++ b/src/test/run-pass/vec-dst.rs @@ -0,0 +1,115 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +extern crate debug; + +fn reflect() { + // Tests for reflective printing. + // Also tests drop glue. + let x = [1, 2, 3, 4]; + let x2 = [(), (), ()]; + let e1: [uint, ..0] = []; + let e2: [&'static str, ..0] = []; + let e3: [(), ..0] = []; + assert!(format!("{:?}", x) == "[1u, 2u, 3u, 4u]".to_string()); + assert!(format!("{:?}", x2) == "[(), (), ()]".to_string()); + assert!(format!("{:?}", e1) == "[]".to_string()); + assert!(format!("{:?}", e2) == "[]".to_string()); + assert!(format!("{:?}", e3) == "[]".to_string()); + + let rx: &[uint, ..4] = &x; + let rx2: &[(), ..3] = &x2; + let re1: &[uint, ..0] = &e1; + let re2: &[&'static str, ..0] = &e2; + let re3: &[(), ..0] = &e3; + assert!(format!("{:?}", rx) == "&[1u, 2u, 3u, 4u]".to_string()); + assert!(format!("{:?}", rx2) == "&[(), (), ()]".to_string()); + assert!(format!("{:?}", re1) == "&[]".to_string()); + assert!(format!("{:?}", re2) == "&[]".to_string()); + assert!(format!("{:?}", re3) == "&[]".to_string()); + + let rx: &[uint] = &x; + let rx2: &[()] = &x2; + let re1: &[uint] = &e1; + let re2: &[&'static str] = &e2; + let re3: &[()] = &e3; + assert!(format!("{:?}", rx) == "&[1u, 2u, 3u, 4u]".to_string()); + assert!(format!("{:?}", rx2) == "&[(), (), ()]".to_string()); + assert!(format!("{:?}", re1) == "&[]".to_string()); + assert!(format!("{:?}", re2) == "&[]".to_string()); + assert!(format!("{:?}", re3) == "&[]".to_string()); + + // FIXME(15049) These should all work some day. + /*let rx: Box<[uint, ..4]> = box x; + let rx2: Box<[(), ..3]> = box x2; + let re1: Box<[uint, ..0]> = box e1; + let re2: Box<[&'static str, ..0]> = box e2; + let re3: Box<[(), ..0]> = box e3; + assert!(format!("{:?}", rx) == "box [1u, 2u, 3u, 4u]".to_string()); + assert!(format!("{:?}", rx2) == "box [(), (), ()]".to_string()); + assert!(format!("{:?}", re1) == "box []".to_string()); + assert!(format!("{:?}", re2) == "box []".to_string()); + assert!(format!("{:?}", re3) == "box []".to_string()); + + let x = [1, 2, 3, 4]; + let x2 = [(), (), ()]; + let e1: [uint, ..0] = []; + let e2: [&'static str, ..0] = []; + let e3: [(), ..0] = []; + let rx: Box<[uint]> = box x; + let rx2: Box<[()]> = box x2; + let re1: Box<[uint]> = box e1; + let re2: Box<[&'static str]> = box e2; + let re3: Box<[()]> = box e3; + assert!(format!("{:?}", rx) == "box [1u, 2u, 3u, 4u]".to_string()); + assert!(format!("{:?}", rx2) == "box [(), (), ()]".to_string()); + assert!(format!("{:?}", re1) == "box []".to_string()); + assert!(format!("{:?}", re2) == "box []".to_string()); + assert!(format!("{:?}", re3) == "box []".to_string());*/ +} + +fn sub_expr() { + // Test for a &[T] => &&[T] coercion in sub-expression position + // (surpisingly, this can cause errors which are not caused by either of: + // `let x = vec.mut_slice(0, 2);` + // `foo(vec.mut_slice(0, 2));` ). + let mut vec: Vec<int> = vec!(1, 2, 3, 4); + let b: &mut [int] = [1, 2]; + assert!(vec.mut_slice(0, 2) == b); +} + +fn index() { + // Tests for indexing into box/& [T, ..n] + let x: [int, ..3] = [1, 2, 3]; + let mut x: Box<[int, ..3]> = box x; + assert!(x[0] == 1); + assert!(x[1] == 2); + assert!(x[2] == 3); + x[1] = 45; + assert!(x[0] == 1); + assert!(x[1] == 45); + assert!(x[2] == 3); + + let mut x: [int, ..3] = [1, 2, 3]; + let x: &mut [int, ..3] = &mut x; + assert!(x[0] == 1); + assert!(x[1] == 2); + assert!(x[2] == 3); + x[1] = 45; + assert!(x[0] == 1); + assert!(x[1] == 45); + assert!(x[2] == 3); +} + +pub fn main() { + reflect(); + sub_expr(); + index(); +} |
