mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-04 11:04:03 +00:00
DST coercions and DST structs
[breaking-change] 1. The internal layout for traits has changed from (vtable, data) to (data, vtable). If you were relying on this in unsafe transmutes, you might get some very weird and apparently unrelated errors. You should not be doing this! Prefer not to do this at all, but if you must, you should use raw::TraitObject rather than hardcoding rustc's internal representation into your code. 2. The minimal type of reference-to-vec-literals (e.g., `&[1, 2, 3]`) is now a fixed size vec (e.g., `&[int, ..3]`) where it used to be an unsized vec (e.g., `&[int]`). If you want the unszied type, you must explicitly give the type (e.g., `let x: &[_] = &[1, 2, 3]`). Note in particular where multiple blocks must have the same type (e.g., if and else clauses, vec elements), the compiler will not coerce to the unsized type without a hint. E.g., `[&[1], &[1, 2]]` used to be a valid expression of type '[&[int]]'. It no longer type checks since the first element now has type `&[int, ..1]` and the second has type &[int, ..2]` which are incompatible. 3. The type of blocks (including functions) must be coercible to the expected type (used to be a subtype). Mostly this makes things more flexible and not less (in particular, in the case of coercing function bodies to the return type). However, in some rare cases, this is less flexible. TBH, I'm not exactly sure of the exact effects. I think the change causes us to resolve inferred type variables slightly earlier which might make us slightly more restrictive. Possibly it only affects blocks with unreachable code. E.g., `if ... { fail!(); "Hello" }` used to type check, it no longer does. The fix is to add a semicolon after the string.
This commit is contained in:
parent
37a94b80f2
commit
3e626375d8
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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) }
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -1623,7 +1623,6 @@ pub mod bytes {
|
||||
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Boilerplate traits
|
||||
//
|
||||
|
@ -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);
|
||||
|
@ -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'{']));
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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]
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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)");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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,32 +1520,21 @@ 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| Decodable::decode(this)).unwrap();
|
||||
this.read_enum_variant_arg(0,
|
||||
|this| Ok(this.read_auto_deref_ref(xcx))).unwrap();
|
||||
|
||||
ty::AutoDerefRef(auto_deref_ref.tr(xcx))
|
||||
}
|
||||
2 => {
|
||||
let store: ty::TraitStore =
|
||||
this.read_enum_variant_arg(0, |this| Decodable::decode(this)).unwrap();
|
||||
let b: ty::BuiltinBounds =
|
||||
this.read_enum_variant_arg(1, |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();
|
||||
|
||||
ty::AutoObject(store.tr(xcx), b, def_id.tr(xcx), substs)
|
||||
ty::AutoDerefRef(auto_deref_ref)
|
||||
}
|
||||
_ => fail!("bad enum variant for ty::AutoAdjustment")
|
||||
})
|
||||
@ -1493,6 +1542,111 @@ impl<'a> rbml_decoder_decoder_helpers for reader::Decoder<'a> {
|
||||
}).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::AutoUnsize(uk)
|
||||
}
|
||||
2 => {
|
||||
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();
|
||||
|
||||
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(1, |this| Decodable::decode(this)).unwrap();
|
||||
let substs = this.read_enum_variant_arg(2,
|
||||
|this| Ok(this.read_substs(xcx))).unwrap();
|
||||
|
||||
ty::UnsizeVtable(b, def_id.tr(xcx), substs)
|
||||
}
|
||||
_ => fail!("bad enum variant for ty::UnsizeKind")
|
||||
})
|
||||
})
|
||||
}).unwrap()
|
||||
}
|
||||
|
||||
fn read_unboxed_closure(&mut self, xcx: &ExtendedDecodeContext)
|
||||
-> ty::UnboxedClosure {
|
||||
let closure_type = self.read_opaque(|this, doc| {
|
||||
|
@ -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 {
|
||||
|
@ -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])
|
||||
}
|
||||
|
@ -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");
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
_ => {
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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()));
|
||||
|
||||
// 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;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
let cmt_derefd = return_if_err!(
|
||||
self.mc.cat_expr_autoderefd(expr, autoderefs));
|
||||
|
||||
debug!("walk_autoref: cmt_derefd={}", cmt_derefd.repr(self.tcx()));
|
||||
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)
|
||||
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)
|
||||
}
|
||||
ty::AutoUnsafe(_) => {}
|
||||
ty::AutoUnsizeUniq(_) | ty::AutoUnsize(_) | ty::AutoUnsafe(_) => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 => {}
|
||||
|
@ -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(..) |
|
||||
|
@ -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)));
|
||||
|
@ -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() {
|
||||
|
@ -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().
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
}
|
||||
|
@ -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,29 +2889,33 @@ 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)
|
||||
// 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)
|
||||
}
|
||||
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 => {
|
||||
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)
|
||||
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_metadata = type_metadata(cx,
|
||||
pointee_type,
|
||||
usage_site_span);
|
||||
let pointee_metadata = type_metadata(cx, ty, usage_site_span);
|
||||
|
||||
match debug_context(cx).type_map
|
||||
.borrow()
|
||||
.find_metadata_for_unique_id(unique_type_id) {
|
||||
@ -2949,33 +2928,6 @@ fn type_metadata(cx: &CrateContext,
|
||||
}
|
||||
}
|
||||
}
|
||||
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_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),
|
||||
false)
|
||||
}
|
||||
_ => {
|
||||
let pointee = type_metadata(cx, mt.ty, 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), false)
|
||||
}
|
||||
}
|
||||
}
|
||||
ty::ty_bare_fn(ref barefnty) => {
|
||||
subroutine_type_metadata(cx, unique_type_id, &barefnty.sig, usage_site_span)
|
||||
}
|
||||
@ -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, _, _) |
|
||||
|
@ -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
|
||||
match adj.autoref {
|
||||
Some(ref a) => {
|
||||
datum = unpack_datum!(bcx, apply_autoref(a,
|
||||
bcx,
|
||||
expr,
|
||||
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))
|
||||
}
|
||||
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 (base, len) = datum.get_vec_base_and_len(bcx);
|
||||
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");
|
||||
|
||||
// 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 });
|
||||
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 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);
|
||||
|
||||
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));
|
||||
if ty::type_is_sized(bcx.tcx(), content_ty) {
|
||||
let ptr = datum.to_llscalarish(bcx);
|
||||
|
||||
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))
|
||||
}
|
||||
// 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))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -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));
|
||||
|
||||
// Handle the &"..." case:
|
||||
let vec_ty = node_id_type(bcx, slice_expr.id);
|
||||
|
||||
// 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"),
|
||||
},
|
||||
|
@ -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 {
|
||||
|
@ -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,23 +298,32 @@ 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={}",
|
||||
|
@ -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),
|
||||
|
||||
/// Convert from Box<Trait>/&Trait to &Trait
|
||||
AutoBorrowObj(Region, 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
|
||||
}
|
||||
}
|
||||
|
||||
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}),
|
||||
|
||||
ref s => {
|
||||
cx.sess.span_bug(
|
||||
span,
|
||||
format!("borrow-vec associated with bad sty: {:?}",
|
||||
s).as_slice());
|
||||
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
|
||||
})
|
||||
}
|
||||
|
||||
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) => {
|
||||
|
@ -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()),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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,10 +636,24 @@ 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,
|
||||
let static_region = match ptr_ty {
|
||||
RPtr(r) if r == ty::ReStatic => true,
|
||||
_ => false
|
||||
};
|
||||
let bounds = conv_builtin_bounds(this.tcx(),
|
||||
path.span,
|
||||
bounds,
|
||||
static_region);
|
||||
let tr = ty::mk_trait(tcx,
|
||||
result.def_id,
|
||||
result.substs.clone(),
|
||||
bounds);
|
||||
return match ptr_ty {
|
||||
Uniq => {
|
||||
return ty::mk_uniq(tcx, tr);
|
||||
}
|
||||
RPtr(r) => {
|
||||
ty::RegionTraitStore(r, a_seq_ty.mutbl)
|
||||
return ty::mk_rptr(tcx, r, ty::mt{mutbl: a_seq_ty.mutbl, ty: tr});
|
||||
}
|
||||
_ => {
|
||||
tcx.sess.span_err(
|
||||
@ -675,24 +663,6 @@ fn mk_pointer<AC:AstConv,
|
||||
return ty::mk_err();
|
||||
}
|
||||
};
|
||||
let bounds = conv_builtin_bounds(this.tcx(),
|
||||
path.span,
|
||||
bounds,
|
||||
trait_store);
|
||||
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 ty::mk_uniq(tcx, tr);
|
||||
}
|
||||
ty::RegionTraitStore(r, m) => {
|
||||
return ty::mk_rptr(tcx, r, ty::mt{mutbl: m, ty: tr});
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
@ -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(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
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.
|
||||
|
||||
// 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));
|
||||
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) => {
|
||||
ty::AutoPtr(r, m, _) => {
|
||||
link_region(rcx, expr.span, r,
|
||||
ty::BorrowKind::from_mutbl(m), expr_cmt);
|
||||
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);
|
||||
link_region(rcx, expr.span, r,
|
||||
ty::BorrowKind::from_mutbl(m), cmt_deref);
|
||||
}
|
||||
|
||||
ty::AutoUnsafe(_) => {}
|
||||
ty::AutoUnsafe(_) | ty::AutoUnsizeUniq(_) | ty::AutoUnsize(_) => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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(
|
||||
|
@ -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");
|
||||
|
@ -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,
|
||||
a: ty::t,
|
||||
sty_a: &ty::sty,
|
||||
b: ty::t)
|
||||
-> CoerceResult {
|
||||
debug!("coerce_borrowed_string(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),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn coerce_borrowed_vector(&self,
|
||||
// [T, ..n] -> &[T] or &mut [T]
|
||||
fn coerce_unsized_with_borrow(&self,
|
||||
a: ty::t,
|
||||
sty_a: &ty::sty,
|
||||
b: ty::t,
|
||||
mutbl_b: ast::Mutability)
|
||||
-> CoerceResult {
|
||||
debug!("coerce_borrowed_vector(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));
|
||||
|
||||
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);
|
||||
match *sty_a {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
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))
|
||||
})))
|
||||
// &[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 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)
|
||||
}
|
||||
}
|
||||
|
||||
// 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())))
|
||||
}
|
||||
}
|
||||
|
@ -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)))
|
||||
}
|
||||
|
@ -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(
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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"),
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -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]
|
||||
|
@ -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"));
|
||||
|
||||
|
@ -394,16 +394,6 @@ pub enum Mutability {
|
||||
MutImmutable,
|
||||
}
|
||||
|
||||
#[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,
|
||||
@ -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>>),
|
||||
|
@ -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))
|
||||
|
@ -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))
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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, "("));
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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())
|
||||
|
@ -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() {
|
||||
}
|
||||
|
46
src/test/compile-fail/dst-bad-assign-2.rs
Normal file
46
src/test/compile-fail/dst-bad-assign-2.rs
Normal file
@ -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
|
||||
}
|
46
src/test/compile-fail/dst-bad-assign.rs
Normal file
46
src/test/compile-fail/dst-bad-assign.rs
Normal file
@ -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`
|
||||
}
|
32
src/test/compile-fail/dst-bad-coerce1.rs
Normal file
32
src/test/compile-fail/dst-bad-coerce1.rs
Normal file
@ -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
|
||||
}
|
31
src/test/compile-fail/dst-bad-coerce2.rs
Normal file
31
src/test/compile-fail/dst-bad-coerce2.rs
Normal file
@ -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
|
||||
}
|
35
src/test/compile-fail/dst-bad-coerce3.rs
Normal file
35
src/test/compile-fail/dst-bad-coerce3.rs
Normal file
@ -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();
|
||||
}
|
22
src/test/compile-fail/dst-bad-coerce4.rs
Normal file
22
src/test/compile-fail/dst-bad-coerce4.rs
Normal file
@ -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]>`
|
||||
}
|
25
src/test/compile-fail/dst-bad-deep.rs
Normal file
25
src/test/compile-fail/dst-bad-deep.rs
Normal file
@ -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
|
||||
}
|
@ -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
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -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() {}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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() {}
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)"
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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() {
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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;
|
||||
});
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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() {
|
||||
|
@ -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() { }
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user