Auto merge of #24261 - nrc:coerce-refactor, r=nikomatsakis

@eddyb's preparatory work for DST coercions

r? @nikomatsakis
This commit is contained in:
bors 2015-04-14 11:16:57 +00:00
commit 47551b5745
30 changed files with 919 additions and 1561 deletions

View File

@ -70,7 +70,7 @@ use option::Option::{self, Some, None};
use marker::Sized;
use usize;
fn _assert_is_object_safe(_: &Iterator) {}
fn _assert_is_object_safe(_: &Iterator<Item=()>) {}
/// An interface for dealing with "external iterators". These types of iterators
/// can be resumed at any time as all state is stored internally as opposed to

View File

@ -601,18 +601,18 @@ impl tr for ty::UpvarCapture {
trait read_method_callee_helper<'tcx> {
fn read_method_callee<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
-> (ty::ExprAdjustment, MethodCallee<'tcx>);
-> (u32, MethodCallee<'tcx>);
}
fn encode_method_callee<'a, 'tcx>(ecx: &e::EncodeContext<'a, 'tcx>,
rbml_w: &mut Encoder,
adjustment: ty::ExprAdjustment,
autoderef: u32,
method: &MethodCallee<'tcx>) {
use serialize::Encoder;
rbml_w.emit_struct("MethodCallee", 4, |rbml_w| {
rbml_w.emit_struct_field("adjustment", 0, |rbml_w| {
adjustment.encode(rbml_w)
rbml_w.emit_struct_field("autoderef", 0, |rbml_w| {
autoderef.encode(rbml_w)
});
rbml_w.emit_struct_field("origin", 1, |rbml_w| {
Ok(rbml_w.emit_method_origin(ecx, &method.origin))
@ -628,13 +628,13 @@ fn encode_method_callee<'a, 'tcx>(ecx: &e::EncodeContext<'a, 'tcx>,
impl<'a, 'tcx> read_method_callee_helper<'tcx> for reader::Decoder<'a> {
fn read_method_callee<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>)
-> (ty::ExprAdjustment, MethodCallee<'tcx>) {
-> (u32, MethodCallee<'tcx>) {
self.read_struct("MethodCallee", 4, |this| {
let adjustment = this.read_struct_field("adjustment", 0, |this| {
let autoderef = this.read_struct_field("autoderef", 0, |this| {
Decodable::decode(this)
}).unwrap();
Ok((adjustment, MethodCallee {
Ok((autoderef, MethodCallee {
origin: this.read_struct_field("origin", 1, |this| {
Ok(this.read_method_origin(dcx))
}).unwrap(),
@ -688,7 +688,7 @@ pub trait vtable_decoder_helpers<'tcx> {
fn read_vtable_res_with_key(&mut self,
tcx: &ty::ctxt<'tcx>,
cdata: &cstore::crate_metadata)
-> (ty::ExprAdjustment, ty::vtable_res<'tcx>);
-> (u32, ty::vtable_res<'tcx>);
fn read_vtable_res(&mut self,
tcx: &ty::ctxt<'tcx>, cdata: &cstore::crate_metadata)
-> ty::vtable_res<'tcx>;
@ -713,12 +713,12 @@ impl<'tcx, 'a> vtable_decoder_helpers<'tcx> for reader::Decoder<'a> {
fn read_vtable_res_with_key(&mut self,
tcx: &ty::ctxt<'tcx>,
cdata: &cstore::crate_metadata)
-> (ty::ExprAdjustment, ty::vtable_res<'tcx>) {
-> (u32, ty::vtable_res<'tcx>) {
self.read_struct("VtableWithKey", 2, |this| {
let adjustment = this.read_struct_field("adjustment", 0, |this| {
let autoderef = this.read_struct_field("autoderef", 0, |this| {
Decodable::decode(this)
}).unwrap();
Ok((adjustment, this.read_struct_field("vtable_res", 1, |this| {
Ok((autoderef, this.read_struct_field("vtable_res", 1, |this| {
Ok(this.read_vtable_res(tcx, cdata))
}).unwrap()))
}).unwrap()
@ -845,12 +845,9 @@ trait rbml_writer_helpers<'tcx> {
fn emit_builtin_bounds(&mut self, ecx: &e::EncodeContext, bounds: &ty::BuiltinBounds);
fn emit_auto_adjustment<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>,
adj: &ty::AutoAdjustment<'tcx>);
fn emit_autoref<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>,
autoref: &ty::AutoRef<'tcx>);
fn emit_autoref<'a>(&mut self, autoref: &ty::AutoRef<'tcx>);
fn emit_auto_deref_ref<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>,
auto_deref_ref: &ty::AutoDerefRef<'tcx>);
fn emit_unsize_kind<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>,
uk: &ty::UnsizeKind<'tcx>);
}
impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> {
@ -1012,10 +1009,8 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> {
self.emit_enum("AutoAdjustment", |this| {
match *adj {
ty::AdjustReifyFnPointer(def_id) => {
this.emit_enum_variant("AdjustReifyFnPointer", 1, 2, |this| {
this.emit_enum_variant_arg(0, |this| def_id.encode(this))
})
ty::AdjustReifyFnPointer=> {
this.emit_enum_variant("AdjustReifyFnPointer", 1, 0, |_| Ok(()))
}
ty::AdjustUnsafeFnPointer => {
@ -1034,50 +1029,20 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> {
});
}
fn emit_autoref<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>,
autoref: &ty::AutoRef<'tcx>) {
fn emit_autoref<'b>(&mut self, autoref: &ty::AutoRef<'tcx>) {
use serialize::Encoder;
self.emit_enum("AutoRef", |this| {
match autoref {
&ty::AutoPtr(r, m, None) => {
this.emit_enum_variant("AutoPtr", 0, 3, |this| {
&ty::AutoPtr(r, m) => {
this.emit_enum_variant("AutoPtr", 0, 2, |this| {
this.emit_enum_variant_arg(0, |this| r.encode(this));
this.emit_enum_variant_arg(1, |this| m.encode(this));
this.emit_enum_variant_arg(2,
|this| this.emit_option(|this| this.emit_option_none()))
this.emit_enum_variant_arg(1, |this| m.encode(this))
})
}
&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, None) => {
this.emit_enum_variant("AutoUnsafe", 3, 2, |this| {
this.emit_enum_variant_arg(0, |this| m.encode(this));
this.emit_enum_variant_arg(1,
|this| this.emit_option(|this| this.emit_option_none()))
})
}
&ty::AutoUnsafe(m, Some(box ref a)) => {
this.emit_enum_variant("AutoUnsafe", 3, 2, |this| {
this.emit_enum_variant_arg(0, |this| m.encode(this));
this.emit_enum_variant_arg(1, |this| this.emit_option(
|this| this.emit_option_some(|this| Ok(this.emit_autoref(ecx, a)))))
&ty::AutoUnsafe(m) => {
this.emit_enum_variant("AutoUnsafe", 1, 1, |this| {
this.emit_enum_variant_arg(0, |this| m.encode(this))
})
}
}
@ -1090,57 +1055,28 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> {
self.emit_struct("AutoDerefRef", 2, |this| {
this.emit_struct_field("autoderefs", 0, |this| auto_deref_ref.autoderefs.encode(this));
this.emit_struct_field("autoref", 1, |this| {
this.emit_option(|this| {
match auto_deref_ref.autoref {
None => this.emit_option_none(),
Some(ref a) => this.emit_option_some(|this| Ok(this.emit_autoref(ecx, a))),
Some(ref a) => this.emit_option_some(|this| Ok(this.emit_autoref(a))),
}
})
});
this.emit_struct_field("unsize", 2, |this| {
this.emit_option(|this| {
match auto_deref_ref.unsize {
None => this.emit_option_none(),
Some(target) => this.emit_option_some(|this| {
Ok(this.emit_ty(ecx, target))
})
}
})
})
});
}
fn emit_unsize_kind<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>,
uk: &ty::UnsizeKind<'tcx>) {
use serialize::Encoder;
self.emit_enum("UnsizeKind", |this| {
match *uk {
ty::UnsizeLength(len) => {
this.emit_enum_variant("UnsizeLength", 0, 1, |this| {
this.emit_enum_variant_arg(0, |this| len.encode(this))
})
}
ty::UnsizeStruct(box ref uk, idx) => {
this.emit_enum_variant("UnsizeStruct", 1, 2, |this| {
this.emit_enum_variant_arg(0, |this| Ok(this.emit_unsize_kind(ecx, uk)));
this.emit_enum_variant_arg(1, |this| idx.encode(this))
})
}
ty::UnsizeVtable(ty::TyTrait { ref principal,
bounds: ref b },
self_ty) => {
this.emit_enum_variant("UnsizeVtable", 2, 4, |this| {
this.emit_enum_variant_arg(0, |this| {
try!(this.emit_struct_field("principal", 0, |this| {
Ok(this.emit_trait_ref(ecx, &*principal.0))
}));
this.emit_struct_field("bounds", 1, |this| {
Ok(this.emit_existential_bounds(ecx, b))
})
});
this.emit_enum_variant_arg(1, |this| Ok(this.emit_ty(ecx, self_ty)))
})
}
ty::UnsizeUpcast(target_ty) => {
this.emit_enum_variant("UnsizeUpcast", 3, 1, |this| {
this.emit_enum_variant_arg(0, |this| Ok(this.emit_ty(ecx, target_ty)))
})
}
}
});
}
}
trait write_tag_and_id {
@ -1258,7 +1194,7 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext,
if let Some(method) = tcx.method_map.borrow().get(&method_call) {
rbml_w.tag(c::tag_table_method_map, |rbml_w| {
rbml_w.id(id);
encode_method_callee(ecx, rbml_w, method_call.adjustment, method)
encode_method_callee(ecx, rbml_w, method_call.autoderef, method)
})
}
@ -1271,31 +1207,19 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext,
if let Some(adjustment) = tcx.adjustments.borrow().get(&id) {
match *adjustment {
_ if ty::adjust_is_object(adjustment) => {
let method_call = MethodCall::autoobject(id);
if let Some(method) = tcx.method_map.borrow().get(&method_call) {
rbml_w.tag(c::tag_table_method_map, |rbml_w| {
rbml_w.id(id);
encode_method_callee(ecx, rbml_w, method_call.adjustment, method)
})
}
}
ty::AdjustDerefRef(ref adj) => {
assert!(!ty::adjust_is_object(adjustment));
for autoderef in 0..adj.autoderefs {
let method_call = MethodCall::autoderef(id, autoderef);
let method_call = MethodCall::autoderef(id, autoderef as u32);
if let Some(method) = tcx.method_map.borrow().get(&method_call) {
rbml_w.tag(c::tag_table_method_map, |rbml_w| {
rbml_w.id(id);
encode_method_callee(ecx, rbml_w,
method_call.adjustment, method)
method_call.autoderef, method)
})
}
}
}
_ => {
assert!(!ty::adjust_is_object(adjustment));
}
_ => {}
}
rbml_w.tag(c::tag_table_adjustments, |rbml_w| {
@ -1367,8 +1291,6 @@ trait rbml_decoder_decoder_helpers<'tcx> {
-> ty::AutoDerefRef<'tcx>;
fn read_autoref<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
-> ty::AutoRef<'tcx>;
fn read_unsize_kind<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
-> ty::UnsizeKind<'tcx>;
fn convert_def_id(&mut self,
dcx: &DecodeContext,
source: DefIdSource,
@ -1640,18 +1562,11 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> {
fn read_auto_adjustment<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>)
-> ty::AutoAdjustment<'tcx> {
self.read_enum("AutoAdjustment", |this| {
let variants = ["AutoAddEnv", "AutoDerefRef"];
let variants = ["AdjustReifyFnPointer", "AdjustUnsafeFnPointer", "AdjustDerefRef"];
this.read_enum_variant(&variants, |this, i| {
Ok(match i {
1 => {
let def_id: ast::DefId =
this.read_def_id(dcx);
ty::AdjustReifyFnPointer(def_id)
}
2 => {
ty::AdjustUnsafeFnPointer
}
1 => ty::AdjustReifyFnPointer,
2 => ty::AdjustUnsafeFnPointer,
3 => {
let auto_deref_ref: ty::AutoDerefRef =
this.read_enum_variant_arg(0,
@ -1681,16 +1596,23 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> {
}
})
}).unwrap(),
unsize: this.read_struct_field("unsize", 2, |this| {
this.read_option(|this, b| {
if b {
Ok(Some(this.read_ty(dcx)))
} else {
Ok(None)
}
})
}).unwrap(),
})
}).unwrap()
}
fn read_autoref<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) -> ty::AutoRef<'tcx> {
fn read_autoref<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>)
-> ty::AutoRef<'tcx> {
self.read_enum("AutoRef", |this| {
let variants = ["AutoPtr",
"AutoUnsize",
"AutoUnsizeUniq",
"AutoUnsafe"];
let variants = ["AutoPtr", "AutoUnsafe"];
this.read_enum_variant(&variants, |this, i| {
Ok(match i {
0 => {
@ -1698,44 +1620,14 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> {
this.read_enum_variant_arg(0, |this| Decodable::decode(this)).unwrap();
let m: ast::Mutability =
this.read_enum_variant_arg(1, |this| Decodable::decode(this)).unwrap();
let a: Option<Box<ty::AutoRef>> =
this.read_enum_variant_arg(2, |this| this.read_option(|this, b| {
if b {
Ok(Some(box this.read_autoref(dcx)))
} else {
Ok(None)
}
})).unwrap();
ty::AutoPtr(r.tr(dcx), m, a)
ty::AutoPtr(dcx.tcx.mk_region(r.tr(dcx)), m)
}
1 => {
let uk: ty::UnsizeKind =
this.read_enum_variant_arg(0,
|this| Ok(this.read_unsize_kind(dcx))).unwrap();
ty::AutoUnsize(uk)
}
2 => {
let uk: ty::UnsizeKind =
this.read_enum_variant_arg(0,
|this| Ok(this.read_unsize_kind(dcx))).unwrap();
ty::AutoUnsizeUniq(uk)
}
3 => {
let m: ast::Mutability =
this.read_enum_variant_arg(0, |this| Decodable::decode(this)).unwrap();
let a: Option<Box<ty::AutoRef>> =
this.read_enum_variant_arg(1, |this| this.read_option(|this, b| {
if b {
Ok(Some(box this.read_autoref(dcx)))
} else {
Ok(None)
}
})).unwrap();
ty::AutoUnsafe(m, a)
ty::AutoUnsafe(m)
}
_ => panic!("bad enum variant for ty::AutoRef")
})
@ -1743,54 +1635,6 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> {
}).unwrap()
}
fn read_unsize_kind<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>)
-> ty::UnsizeKind<'tcx> {
self.read_enum("UnsizeKind", |this| {
let variants = &["UnsizeLength", "UnsizeStruct", "UnsizeVtable", "UnsizeUpcast"];
this.read_enum_variant(variants, |this, i| {
Ok(match i {
0 => {
let len: usize =
this.read_enum_variant_arg(0, |this| Decodable::decode(this)).unwrap();
ty::UnsizeLength(len)
}
1 => {
let uk: ty::UnsizeKind =
this.read_enum_variant_arg(0,
|this| Ok(this.read_unsize_kind(dcx))).unwrap();
let idx: usize =
this.read_enum_variant_arg(1, |this| Decodable::decode(this)).unwrap();
ty::UnsizeStruct(box uk, idx)
}
2 => {
let ty_trait = try!(this.read_enum_variant_arg(0, |this| {
let principal = try!(this.read_struct_field("principal", 0, |this| {
Ok(this.read_poly_trait_ref(dcx))
}));
Ok(ty::TyTrait {
principal: principal,
bounds: try!(this.read_struct_field("bounds", 1, |this| {
Ok(this.read_existential_bounds(dcx))
})),
})
}));
let self_ty =
this.read_enum_variant_arg(1, |this| Ok(this.read_ty(dcx))).unwrap();
ty::UnsizeVtable(ty_trait, self_ty)
}
3 => {
let target_ty =
this.read_enum_variant_arg(0, |this| Ok(this.read_ty(dcx))).unwrap();
ty::UnsizeUpcast(target_ty)
}
_ => panic!("bad enum variant for ty::UnsizeKind")
})
})
}).unwrap()
}
fn read_closure_kind<'b, 'c>(&mut self, _dcx: &DecodeContext<'b, 'c, 'tcx>)
-> ty::ClosureKind
{
@ -1922,10 +1766,10 @@ fn decode_side_tables(dcx: &DecodeContext,
dcx.tcx.ty_param_defs.borrow_mut().insert(id, bounds);
}
c::tag_table_method_map => {
let (adjustment, method) = val_dsr.read_method_callee(dcx);
let (autoderef, method) = val_dsr.read_method_callee(dcx);
let method_call = MethodCall {
expr_id: id,
adjustment: adjustment
autoderef: autoderef
};
dcx.tcx.method_map.borrow_mut().insert(method_call, method);
}

View File

@ -787,23 +787,19 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
// process.
fn walk_adjustment(&mut self, expr: &ast::Expr) {
let typer = self.typer;
match typer.adjustments().borrow().get(&expr.id) {
None => { }
Some(adjustment) => {
match *adjustment {
ty::AdjustReifyFnPointer(..) |
ty::AdjustUnsafeFnPointer(..) => {
// Creating a closure/fn-pointer consumes the
// input and stores it into the resulting
// rvalue.
debug!("walk_adjustment(AutoAddEnv|AdjustReifyFnPointer)");
let cmt_unadjusted =
return_if_err!(self.mc.cat_expr_unadjusted(expr));
self.delegate_consume(expr.id, expr.span, cmt_unadjusted);
}
ty::AdjustDerefRef(ref adj) => {
self.walk_autoderefref(expr, adj);
}
if let Some(adjustment) = typer.adjustments().borrow().get(&expr.id) {
match *adjustment {
ty::AdjustReifyFnPointer |
ty::AdjustUnsafeFnPointer => {
// Creating a closure/fn-pointer or unsizing consumes
// the input and stores it into the resulting rvalue.
debug!("walk_adjustment(AdjustReifyFnPointer|AdjustUnsafeFnPointer)");
let cmt_unadjusted =
return_if_err!(self.mc.cat_expr_unadjusted(expr));
self.delegate_consume(expr.id, expr.span, cmt_unadjusted);
}
ty::AdjustDerefRef(ref adj) => {
self.walk_autoderefref(expr, adj);
}
}
}
@ -818,7 +814,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
debug!("walk_autoderefs expr={} autoderefs={}", expr.repr(self.tcx()), autoderefs);
for i in 0..autoderefs {
let deref_id = ty::MethodCall::autoderef(expr.id, i);
let deref_id = ty::MethodCall::autoderef(expr.id, i as u32);
match self.typer.node_method_ty(deref_id) {
None => {}
Some(method_ty) => {
@ -852,30 +848,19 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
self.walk_autoderefs(expr, adj.autoderefs);
// Weird hacky special case: AutoUnsizeUniq, which converts
// from a ~T to a ~Trait etc, always comes in a stylized
// fashion. In particular, we want to consume the ~ pointer
// being dereferenced, not the dereferenced content (as the
// content is, at least for upcasts, unsized).
match adj.autoref {
Some(ty::AutoUnsizeUniq(_)) => {
assert!(adj.autoderefs == 1,
format!("Expected exactly 1 deref with Uniq AutoRefs, found: {}",
adj.autoderefs));
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, adj.autoderefs));
let autoref = adj.autoref.as_ref();
let cmt_derefd = return_if_err!(
self.mc.cat_expr_autoderefd(expr, adj.autoderefs));
self.walk_autoref(expr, &cmt_derefd, autoref);
let cmt_refd =
self.walk_autoref(expr, cmt_derefd, adj.autoref);
if adj.unsize.is_some() {
// Unsizing consumes the thin pointer and produces a fat one.
self.delegate_consume(expr.id, expr.span, cmt_refd);
}
}
/// Walks the autoref `opt_autoref` applied to the autoderef'd
/// `expr`. `cmt_derefd` is the mem-categorized form of `expr`
/// after all relevant autoderefs have occurred. Because AutoRefs
@ -886,79 +871,40 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
/// autoref.
fn walk_autoref(&mut self,
expr: &ast::Expr,
cmt_derefd: &mc::cmt<'tcx>,
opt_autoref: Option<&ty::AutoRef<'tcx>>)
cmt_base: mc::cmt<'tcx>,
opt_autoref: Option<ty::AutoRef<'tcx>>)
-> mc::cmt<'tcx>
{
debug!("walk_autoref(expr.id={} cmt_derefd={} opt_autoref={:?})",
expr.id,
cmt_derefd.repr(self.tcx()),
cmt_base.repr(self.tcx()),
opt_autoref);
let cmt_base_ty = cmt_base.ty;
let autoref = match opt_autoref {
Some(autoref) => autoref,
Some(ref autoref) => autoref,
None => {
// No recursive step here, this is a base case.
return cmt_derefd.clone();
// No AutoRef.
return cmt_base;
}
};
debug!("walk_autoref: expr.id={} cmt_base={}",
expr.id,
cmt_base.repr(self.tcx()));
match *autoref {
ty::AutoPtr(r, m, ref baseref) => {
let cmt_base = self.walk_autoref_recursively(expr, cmt_derefd, baseref);
debug!("walk_autoref: expr.id={} cmt_base={}",
expr.id,
cmt_base.repr(self.tcx()));
ty::AutoPtr(r, m) => {
self.delegate.borrow(expr.id,
expr.span,
cmt_base,
r,
*r,
ty::BorrowKind::from_mutbl(m),
AutoRef);
}
ty::AutoUnsize(_) => {
// Converting a `[T; N]` to `[T]` or `T` to `Trait`
// isn't really a borrow, move, etc, in and of itself.
// Also, no recursive step here, this is a base case.
// It may seem a bit odd to return the cmt_derefd
// unmodified here, but in fact I think it's the right
// thing to do. Essentially the unsize transformation
// isn't really relevant to the borrowing rules --
// it's best thought of as a kind of side-modifier to
// the autoref, adding additional data that is
// attached to the pointer that is produced, but not
// affecting the data being borrowed in any other
// way. To see what I mean, consider this example:
//
// fn foo<'a>(&'a self) -> &'a Trait { self }
//
// This is valid because the underlying `self` value
// lives for the lifetime 'a. If we were to treat the
// "unsizing" as e.g. producing an rvalue, that would
// only be valid for the temporary scope, which isn't
// enough to justify the return value, which have the
// lifetime 'a.
//
// Another option would be to add a variant for
// categorization (like downcast) that wraps
// cmt_derefd and represents the unsizing operation.
// But I don't think there is any particular use for
// this (yet). -nmatsakis
return cmt_derefd.clone();
}
ty::AutoUnsizeUniq(_) => {
// these are handled via special case above
self.tcx().sess.span_bug(expr.span, "nexpected AutoUnsizeUniq");
}
ty::AutoUnsafe(m, ref baseref) => {
let cmt_base = self.walk_autoref_recursively(expr, cmt_derefd, baseref);
ty::AutoUnsafe(m) => {
debug!("walk_autoref: expr.id={} cmt_base={}",
expr.id,
cmt_base.repr(self.tcx()));
@ -983,24 +929,12 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
let adj_ty =
ty::adjust_ty_for_autoref(self.tcx(),
expr.span,
cmt_derefd.ty,
cmt_base_ty,
opt_autoref);
self.mc.cat_rvalue_node(expr.id, expr.span, adj_ty)
}
fn walk_autoref_recursively(&mut self,
expr: &ast::Expr,
cmt_derefd: &mc::cmt<'tcx>,
autoref: &Option<Box<ty::AutoRef<'tcx>>>)
-> mc::cmt<'tcx>
{
// Shuffle from a ref to an optional box to an optional ref.
let autoref: Option<&ty::AutoRef<'tcx>> = autoref.as_ref().map(|b| &**b);
self.walk_autoref(expr, cmt_derefd, autoref)
}
// When this returns true, it means that the expression *is* a
// method-call (i.e. via the operator-overload). This true result

View File

@ -451,33 +451,23 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
Some(adjustment) => {
match *adjustment {
ty::AdjustReifyFnPointer(..) |
ty::AdjustUnsafeFnPointer(..) => {
debug!("cat_expr(AdjustReifyFnPointer): {}",
expr.repr(self.tcx()));
// Convert a bare fn to a closure by adding NULL env.
// Result is an rvalue.
let expr_ty = try!(self.expr_ty_adjusted(expr));
Ok(self.cat_rvalue_node(expr.id(), expr.span(), expr_ty))
}
ty::AdjustDerefRef(
ty::AutoDerefRef {
autoref: Some(_), ..}) => {
debug!("cat_expr(AdjustDerefRef): {}",
expr.repr(self.tcx()));
// Equivalent to &*expr or something similar.
// Result is an rvalue.
let expr_ty = try!(self.expr_ty_adjusted(expr));
Ok(self.cat_rvalue_node(expr.id(), expr.span(), expr_ty))
}
ty::AdjustDerefRef(
ty::AutoDerefRef {
autoref: None, autoderefs}) => {
autoref: None, unsize: None, autoderefs, ..}) => {
// Equivalent to *expr or something similar.
self.cat_expr_autoderefd(expr, autoderefs)
}
ty::AdjustReifyFnPointer |
ty::AdjustUnsafeFnPointer |
ty::AdjustDerefRef(_) => {
debug!("cat_expr({}): {}",
adjustment.repr(self.tcx()),
expr.repr(self.tcx()));
// Result is an rvalue.
let expr_ty = try!(self.expr_ty_adjusted(expr));
Ok(self.cat_rvalue_node(expr.id(), expr.span(), expr_ty))
}
}
}
}
@ -928,15 +918,9 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
deref_cnt: usize,
deref_context: DerefKindContext)
-> McResult<cmt<'tcx>> {
let adjustment = match self.typer.adjustments().borrow().get(&node.id()) {
Some(adj) if ty::adjust_is_object(adj) => ty::AutoObject,
_ if deref_cnt != 0 => ty::AutoDeref(deref_cnt),
_ => ty::NoAdjustment
};
let method_call = ty::MethodCall {
expr_id: node.id(),
adjustment: adjustment
autoderef: deref_cnt as u32
};
let method_ty = self.typer.node_method_ty(method_call);

View File

@ -20,7 +20,6 @@ pub use self::ClosureKind::*;
pub use self::Variance::*;
pub use self::AutoAdjustment::*;
pub use self::Representability::*;
pub use self::UnsizeKind::*;
pub use self::AutoRef::*;
pub use self::ExprKind::*;
pub use self::DtorKind::*;
@ -33,7 +32,6 @@ pub use self::ImplOrTraitItem::*;
pub use self::BoundRegion::*;
pub use self::sty::*;
pub use self::IntVarValue::*;
pub use self::ExprAdjustment::*;
pub use self::vtable_origin::*;
pub use self::MethodOrigin::*;
pub use self::CopyImplementationError::*;
@ -283,145 +281,97 @@ pub enum Variance {
Bivariant, // T<A> <: T<B> -- e.g., unused type parameter
}
#[derive(Clone, Debug)]
#[derive(Copy, Clone, Debug)]
pub enum AutoAdjustment<'tcx> {
AdjustReifyFnPointer(ast::DefId), // go from a fn-item type to a fn-pointer type
AdjustUnsafeFnPointer, // go from a safe fn pointer to an unsafe fn pointer
AdjustDerefRef(AutoDerefRef<'tcx>)
AdjustReifyFnPointer, // go from a fn-item type to a fn-pointer type
AdjustUnsafeFnPointer, // go from a safe fn pointer to an unsafe fn pointer
AdjustDerefRef(AutoDerefRef<'tcx>),
}
#[derive(Clone, PartialEq, Debug)]
pub enum UnsizeKind<'tcx> {
// [T, ..n] -> [T], the usize field is n.
UnsizeLength(usize),
// An unsize coercion applied to the tail field of a struct.
// The usize is the index of the type parameter which is unsized.
UnsizeStruct(Box<UnsizeKind<'tcx>>, usize),
UnsizeVtable(TyTrait<'tcx>, /* the self type of the trait */ Ty<'tcx>),
UnsizeUpcast(Ty<'tcx>),
}
#[derive(Clone, Debug)]
/// Represents coercing a pointer to a different kind of pointer - where 'kind'
/// here means either or both of raw vs borrowed vs unique and fat vs thin.
///
/// We transform pointers by following the following steps in order:
/// 1. Deref the pointer `self.autoderefs` times (may be 0).
/// 2. If `autoref` is `Some(_)`, then take the address and produce either a
/// `&` or `*` pointer.
/// 3. If `unsize` is `Some(_)`, then apply the unsize transformation,
/// which will do things like convert thin pointers to fat
/// pointers, or convert structs containing thin pointers to
/// structs containing fat pointers, or convert between fat
/// pointers. We don't store the details of how the transform is
/// done (in fact, we don't know that, because it might depend on
/// the precise type parameters). We just store the target
/// type. Trans figures out what has to be done at monomorphization
/// time based on the precise source/target type at hand.
///
/// To make that more concrete, here are some common scenarios:
///
/// 1. The simplest cases are where the pointer is not adjusted fat vs thin.
/// Here the pointer will be dereferenced N times (where a dereference can
/// happen to to raw or borrowed pointers or any smart pointer which implements
/// Deref, including Box<_>). The number of dereferences is given by
/// `autoderefs`. It can then be auto-referenced zero or one times, indicated
/// by `autoref`, to either a raw or borrowed pointer. In these cases unsize is
/// None.
///
/// 2. A thin-to-fat coercon involves unsizing the underlying data. We start
/// with a thin pointer, deref a number of times, unsize the underlying data,
/// then autoref. The 'unsize' phase may change a fixed length array to a
/// dynamically sized one, a concrete object to a trait object, or statically
/// sized struct to a dyncamically sized one. E.g., &[i32; 4] -> &[i32] is
/// represented by:
///
/// ```
/// AutoDerefRef {
/// autoderefs: 1, // &[i32; 4] -> [i32; 4]
/// autoref: Some(AutoPtr), // [i32] -> &[i32]
/// unsize: Some([i32]), // [i32; 4] -> [i32]
/// }
/// ```
///
/// Note that for a struct, the 'deep' unsizing of the struct is not recorded.
/// E.g., `struct Foo<T> { x: T }` we can coerce &Foo<[i32; 4]> to &Foo<[i32]>
/// The autoderef and -ref are the same as in the above example, but the type
/// stored in `unsize` is `Foo<[i32]>`, we don't store any further detail about
/// the underlying conversions from `[i32; 4]` to `[i32]`.
///
/// 3. Coercing a `Box<T>` to `Box<Trait>` is an interesting special case. In
/// that case, we have the pointer we need coming in, so there are no
/// autoderefs, and no autoref. Instead we just do the `Unsize` transformation.
/// At some point, of course, `Box` should move out of the compiler, in which
/// case this is analogous to transformating a struct. E.g., Box<[i32; 4]> ->
/// Box<[i32]> is represented by:
///
/// ```
/// AutoDerefRef {
/// autoderefs: 0,
/// autoref: None,
/// unsize: Some(Box<[i32]>),
/// }
/// ```
#[derive(Copy, Clone, Debug)]
pub struct AutoDerefRef<'tcx> {
/// Step 1. Apply a number of dereferences, producing an lvalue.
pub autoderefs: usize,
pub autoref: Option<AutoRef<'tcx>>
/// Step 2. Optionally produce a pointer/reference from the value.
pub autoref: Option<AutoRef<'tcx>>,
/// Step 3. Unsize a pointer/reference value, e.g. `&[T; n]` to
/// `&[T]`. The stored type is the target pointer type. Note that
/// the source could be a thin or fat pointer.
pub unsize: Option<Ty<'tcx>>,
}
#[derive(Clone, PartialEq, Debug)]
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum AutoRef<'tcx> {
/// Convert from T to &T
/// The third field allows us to wrap other AutoRef adjustments.
AutoPtr(Region, ast::Mutability, Option<Box<AutoRef<'tcx>>>),
/// Convert from T to &T.
AutoPtr(&'tcx Region, ast::Mutability),
/// Convert [T, ..n] to [T] (or similar, depending on the kind)
AutoUnsize(UnsizeKind<'tcx>),
/// Convert Box<[T, ..n]> to Box<[T]> or something similar in a Box.
/// With DST and Box a library type, this should be replaced by UnsizeStruct.
AutoUnsizeUniq(UnsizeKind<'tcx>),
/// Convert from T to *T
/// Value to thin pointer
/// The second field allows us to wrap other AutoRef adjustments.
AutoUnsafe(ast::Mutability, Option<Box<AutoRef<'tcx>>>),
}
// Ugly little helper function. The first bool in the returned tuple is true if
// there is an 'unsize to trait object' adjustment at the bottom of the
// adjustment. If that is surrounded by an AutoPtr, then we also return the
// region of the AutoPtr (in the third argument). The second bool is true if the
// adjustment is unique.
fn autoref_object_region(autoref: &AutoRef) -> (bool, bool, Option<Region>) {
fn unsize_kind_is_object(k: &UnsizeKind) -> bool {
match k {
&UnsizeVtable(..) => true,
&UnsizeStruct(box ref k, _) => unsize_kind_is_object(k),
_ => false
}
}
match autoref {
&AutoUnsize(ref k) => (unsize_kind_is_object(k), false, None),
&AutoUnsizeUniq(ref k) => (unsize_kind_is_object(k), true, None),
&AutoPtr(adj_r, _, Some(box ref autoref)) => {
let (b, u, r) = autoref_object_region(autoref);
if r.is_some() || u {
(b, u, r)
} else {
(b, u, Some(adj_r))
}
}
&AutoUnsafe(_, Some(box ref autoref)) => autoref_object_region(autoref),
_ => (false, false, None)
}
}
// If the adjustment introduces a borrowed reference to a trait object, then
// returns the region of the borrowed reference.
pub fn adjusted_object_region(adj: &AutoAdjustment) -> Option<Region> {
match adj {
&AdjustDerefRef(AutoDerefRef{autoref: Some(ref autoref), ..}) => {
let (b, _, r) = autoref_object_region(autoref);
if b {
r
} else {
None
}
}
_ => None
}
}
// Returns true if there is a trait cast at the bottom of the adjustment.
pub fn adjust_is_object(adj: &AutoAdjustment) -> bool {
match adj {
&AdjustDerefRef(AutoDerefRef{autoref: Some(ref autoref), ..}) => {
let (b, _, _) = autoref_object_region(autoref);
b
}
_ => false
}
}
// If possible, returns the type expected from the given adjustment. This is not
// possible if the adjustment depends on the type of the adjusted expression.
pub fn type_of_adjust<'tcx>(cx: &ctxt<'tcx>, adj: &AutoAdjustment<'tcx>) -> Option<Ty<'tcx>> {
fn type_of_autoref<'tcx>(cx: &ctxt<'tcx>, autoref: &AutoRef<'tcx>) -> Option<Ty<'tcx>> {
match autoref {
&AutoUnsize(ref k) => match k {
&UnsizeVtable(TyTrait { ref principal, ref bounds }, _) => {
Some(mk_trait(cx, principal.clone(), bounds.clone()))
}
_ => None
},
&AutoUnsizeUniq(ref k) => match k {
&UnsizeVtable(TyTrait { ref principal, ref bounds }, _) => {
Some(mk_uniq(cx, mk_trait(cx, principal.clone(), bounds.clone())))
}
_ => None
},
&AutoPtr(r, m, Some(box ref autoref)) => {
match type_of_autoref(cx, autoref) {
Some(ty) => Some(mk_rptr(cx, cx.mk_region(r), mt {mutbl: m, ty: ty})),
None => None
}
}
&AutoUnsafe(m, Some(box ref autoref)) => {
match type_of_autoref(cx, autoref) {
Some(ty) => Some(mk_ptr(cx, mt {mutbl: m, ty: ty})),
None => None
}
}
_ => None
}
}
match adj {
&AdjustDerefRef(AutoDerefRef{autoref: Some(ref autoref), ..}) => {
type_of_autoref(cx, autoref)
}
_ => None
}
/// Convert from T to *T.
/// Value to thin pointer.
AutoUnsafe(ast::Mutability),
}
#[derive(Clone, Copy, RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Debug)]
@ -509,35 +459,21 @@ pub struct MethodCallee<'tcx> {
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub struct MethodCall {
pub expr_id: ast::NodeId,
pub adjustment: ExprAdjustment
}
#[derive(Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable, Copy)]
pub enum ExprAdjustment {
NoAdjustment,
AutoDeref(usize),
AutoObject
pub autoderef: u32
}
impl MethodCall {
pub fn expr(id: ast::NodeId) -> MethodCall {
MethodCall {
expr_id: id,
adjustment: NoAdjustment
autoderef: 0
}
}
pub fn autoobject(id: ast::NodeId) -> MethodCall {
MethodCall {
expr_id: id,
adjustment: AutoObject
}
}
pub fn autoderef(expr_id: ast::NodeId, autoderef: usize) -> MethodCall {
pub fn autoderef(expr_id: ast::NodeId, autoderef: u32) -> MethodCall {
MethodCall {
expr_id: expr_id,
adjustment: AutoDeref(1 + autoderef)
autoderef: 1 + autoderef
}
}
}
@ -4581,16 +4517,15 @@ pub fn adjust_ty<'tcx, F>(cx: &ctxt<'tcx>,
return match adjustment {
Some(adjustment) => {
match *adjustment {
AdjustReifyFnPointer(_) => {
AdjustReifyFnPointer => {
match unadjusted_ty.sty {
ty::ty_bare_fn(Some(_), b) => {
ty::mk_bare_fn(cx, None, b)
}
ref b => {
_ => {
cx.sess.bug(
&format!("AdjustReifyFnPointer adjustment on non-fn-item: \
{:?}",
b));
{}", unadjusted_ty.repr(cx)));
}
}
}
@ -4612,11 +4547,11 @@ pub fn adjust_ty<'tcx, F>(cx: &ctxt<'tcx>,
if !ty::type_is_error(adjusted_ty) {
for i in 0..adj.autoderefs {
let method_call = MethodCall::autoderef(expr_id, i);
let method_call = MethodCall::autoderef(expr_id, i as u32);
match method_type(method_call) {
Some(method_ty) => {
// overloaded deref operators have all late-bound
// regions fully instantiated and coverge
// Overloaded deref operators have all late-bound
// regions fully instantiated and coverge.
let fn_ret =
ty::no_late_bound_regions(cx,
&ty_fn_ret(method_ty)).unwrap();
@ -4629,8 +4564,7 @@ pub fn adjust_ty<'tcx, F>(cx: &ctxt<'tcx>,
None => {
cx.sess.span_bug(
span,
&format!("the {}th autoderef failed: \
{}",
&format!("the {}th autoderef failed: {}",
i,
ty_to_string(cx, adjusted_ty))
);
@ -4639,7 +4573,11 @@ pub fn adjust_ty<'tcx, F>(cx: &ctxt<'tcx>,
}
}
adjust_ty_for_autoref(cx, span, adjusted_ty, adj.autoref.as_ref())
if let Some(target) = adj.unsize {
target
} else {
adjust_ty_for_autoref(cx, adjusted_ty, adj.autoref)
}
}
}
}
@ -4648,73 +4586,16 @@ pub fn adjust_ty<'tcx, F>(cx: &ctxt<'tcx>,
}
pub fn adjust_ty_for_autoref<'tcx>(cx: &ctxt<'tcx>,
span: Span,
ty: Ty<'tcx>,
autoref: Option<&AutoRef<'tcx>>)
-> Ty<'tcx>
{
autoref: Option<AutoRef<'tcx>>)
-> Ty<'tcx> {
match autoref {
None => ty,
Some(&AutoPtr(r, m, ref a)) => {
let adjusted_ty = match a {
&Some(box ref a) => adjust_ty_for_autoref(cx, span, ty, Some(a)),
&None => ty
};
mk_rptr(cx, cx.mk_region(r), mt {
ty: adjusted_ty,
mutbl: m
})
Some(AutoPtr(r, m)) => {
mk_rptr(cx, r, mt { ty: ty, mutbl: m })
}
Some(&AutoUnsafe(m, ref a)) => {
let adjusted_ty = match a {
&Some(box ref a) => adjust_ty_for_autoref(cx, span, ty, Some(a)),
&None => ty
};
mk_ptr(cx, mt {ty: adjusted_ty, mutbl: m})
}
Some(&AutoUnsize(ref k)) => unsize_ty(cx, ty, k, span),
Some(&AutoUnsizeUniq(ref k)) => ty::mk_uniq(cx, unsize_ty(cx, ty, k, span)),
}
}
// Take a sized type and a sizing adjustment and produce an unsized version of
// the type.
pub fn unsize_ty<'tcx>(cx: &ctxt<'tcx>,
ty: Ty<'tcx>,
kind: &UnsizeKind<'tcx>,
span: Span)
-> Ty<'tcx> {
match kind {
&UnsizeLength(len) => match ty.sty {
ty_vec(ty, Some(n)) => {
assert!(len == n);
mk_vec(cx, ty, None)
}
_ => cx.sess.span_bug(span,
&format!("UnsizeLength with bad sty: {:?}",
ty_to_string(cx, ty)))
},
&UnsizeStruct(box ref k, tp_index) => match ty.sty {
ty_struct(did, substs) => {
let ty_substs = substs.types.get_slice(subst::TypeSpace);
let new_ty = unsize_ty(cx, ty_substs[tp_index], k, span);
let mut unsized_substs = substs.clone();
unsized_substs.types.get_mut_slice(subst::TypeSpace)[tp_index] = new_ty;
mk_struct(cx, did, cx.mk_substs(unsized_substs))
}
_ => cx.sess.span_bug(span,
&format!("UnsizeStruct with bad sty: {:?}",
ty_to_string(cx, ty)))
},
&UnsizeVtable(TyTrait { ref principal, ref bounds }, _) => {
mk_trait(cx, principal.clone(), bounds.clone())
}
&UnsizeUpcast(target_ty) => {
target_ty
Some(AutoUnsafe(m)) => {
mk_ptr(cx, mt { ty: ty, mutbl: m })
}
}
}
@ -5971,6 +5852,47 @@ pub fn tup_fields<'tcx>(v: &[Ty<'tcx>]) -> Vec<field<'tcx>> {
}).collect()
}
/// Returns the deeply last field of nested structures, or the same type,
/// if not a structure at all. Corresponds to the only possible unsized
/// field, and its type can be used to determine unsizing strategy.
pub fn struct_tail<'tcx>(cx: &ctxt<'tcx>, mut ty: Ty<'tcx>) -> Ty<'tcx> {
while let ty_struct(def_id, substs) = ty.sty {
match struct_fields(cx, def_id, substs).last() {
Some(f) => ty = f.mt.ty,
None => break
}
}
ty
}
/// Same as applying struct_tail on `source` and `target`, but only
/// keeps going as long as the two types are instances of the same
/// structure definitions.
/// For `(Foo<Foo<T>>, Foo<Trait>)`, the result will be `(Foo<T>, Trait)`,
/// whereas struct_tail produces `T`, and `Trait`, respectively.
pub fn struct_lockstep_tails<'tcx>(cx: &ctxt<'tcx>,
source: Ty<'tcx>,
target: Ty<'tcx>)
-> (Ty<'tcx>, Ty<'tcx>) {
let (mut a, mut b) = (source, target);
while let (&ty_struct(a_did, a_substs), &ty_struct(b_did, b_substs)) = (&a.sty, &b.sty) {
if a_did != b_did {
continue;
}
if let Some(a_f) = struct_fields(cx, a_did, a_substs).last() {
if let Some(b_f) = struct_fields(cx, b_did, b_substs).last() {
a = a_f.mt.ty;
b = b_f.mt.ty;
} else {
break;
}
} else {
break;
}
}
(a, b)
}
#[derive(Copy, Clone)]
pub struct ClosureUpvar<'tcx> {
pub def: def::Def,
@ -6881,8 +6803,8 @@ pub fn with_freevars<T, F>(tcx: &ty::ctxt, fid: ast::NodeId, f: F) -> T where
impl<'tcx> AutoAdjustment<'tcx> {
pub fn is_identity(&self) -> bool {
match *self {
AdjustReifyFnPointer(..) => false,
AdjustUnsafeFnPointer(..) => false,
AdjustReifyFnPointer |
AdjustUnsafeFnPointer => false,
AdjustDerefRef(ref r) => r.is_identity(),
}
}
@ -6890,7 +6812,7 @@ impl<'tcx> AutoAdjustment<'tcx> {
impl<'tcx> AutoDerefRef<'tcx> {
pub fn is_identity(&self) -> bool {
self.autoderefs == 0 && self.autoref.is_none()
self.autoderefs == 0 && self.unsize.is_none() && self.autoref.is_none()
}
}
@ -7051,8 +6973,8 @@ impl DebruijnIndex {
impl<'tcx> Repr<'tcx> for AutoAdjustment<'tcx> {
fn repr(&self, tcx: &ctxt<'tcx>) -> String {
match *self {
AdjustReifyFnPointer(def_id) => {
format!("AdjustReifyFnPointer({})", def_id.repr(tcx))
AdjustReifyFnPointer => {
format!("AdjustReifyFnPointer")
}
AdjustUnsafeFnPointer => {
format!("AdjustUnsafeFnPointer")
@ -7064,37 +6986,21 @@ impl<'tcx> Repr<'tcx> for AutoAdjustment<'tcx> {
}
}
impl<'tcx> Repr<'tcx> for UnsizeKind<'tcx> {
fn repr(&self, tcx: &ctxt<'tcx>) -> String {
match *self {
UnsizeLength(n) => format!("UnsizeLength({})", n),
UnsizeStruct(ref k, n) => format!("UnsizeStruct({},{})", k.repr(tcx), n),
UnsizeVtable(ref a, ref b) => format!("UnsizeVtable({},{})", a.repr(tcx), b.repr(tcx)),
UnsizeUpcast(ref a) => format!("UnsizeUpcast({})", a.repr(tcx)),
}
}
}
impl<'tcx> Repr<'tcx> for AutoDerefRef<'tcx> {
fn repr(&self, tcx: &ctxt<'tcx>) -> String {
format!("AutoDerefRef({}, {})", self.autoderefs, self.autoref.repr(tcx))
format!("AutoDerefRef({}, unsize={}, {})",
self.autoderefs, self.unsize.repr(tcx), self.autoref.repr(tcx))
}
}
impl<'tcx> Repr<'tcx> for AutoRef<'tcx> {
fn repr(&self, tcx: &ctxt<'tcx>) -> String {
match *self {
AutoPtr(a, b, ref c) => {
format!("AutoPtr({},{:?},{})", a.repr(tcx), b, c.repr(tcx))
AutoPtr(a, b) => {
format!("AutoPtr({},{:?})", a.repr(tcx), b)
}
AutoUnsize(ref a) => {
format!("AutoUnsize({})", a.repr(tcx))
}
AutoUnsizeUniq(ref a) => {
format!("AutoUnsizeUniq({})", a.repr(tcx))
}
AutoUnsafe(ref a, ref b) => {
format!("AutoUnsafe({:?},{})", a, b.repr(tcx))
AutoUnsafe(ref a) => {
format!("AutoUnsafe({:?})", a)
}
}
}

View File

@ -477,24 +477,6 @@ impl<'tcx> TypeFoldable<'tcx> for ty::InstantiatedPredicates<'tcx> {
}
}
impl<'tcx> TypeFoldable<'tcx> for ty::UnsizeKind<'tcx> {
fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::UnsizeKind<'tcx> {
match *self {
ty::UnsizeLength(len) => ty::UnsizeLength(len),
ty::UnsizeStruct(box ref k, n) => ty::UnsizeStruct(box k.fold_with(folder), n),
ty::UnsizeVtable(ty::TyTrait{ref principal, ref bounds}, self_ty) => {
ty::UnsizeVtable(
ty::TyTrait {
principal: principal.fold_with(folder),
bounds: bounds.fold_with(folder),
},
self_ty.fold_with(folder))
}
ty::UnsizeUpcast(t) => ty::UnsizeUpcast(t.fold_with(folder)),
}
}
}
impl<'tcx,O> TypeFoldable<'tcx> for traits::Obligation<'tcx,O>
where O : TypeFoldable<'tcx>
{
@ -768,16 +750,11 @@ pub fn super_fold_autoref<'tcx, T: TypeFolder<'tcx>>(this: &mut T,
-> ty::AutoRef<'tcx>
{
match *autoref {
ty::AutoPtr(r, m, None) => ty::AutoPtr(this.fold_region(r), m, None),
ty::AutoPtr(r, m, Some(ref a)) => {
ty::AutoPtr(this.fold_region(r), m, Some(box super_fold_autoref(this, &**a)))
ty::AutoPtr(r, m) => {
let r = r.fold_with(this);
ty::AutoPtr(this.tcx().mk_region(r), m)
}
ty::AutoUnsafe(m, None) => ty::AutoUnsafe(m, None),
ty::AutoUnsafe(m, Some(ref a)) => {
ty::AutoUnsafe(m, Some(box super_fold_autoref(this, &**a)))
}
ty::AutoUnsize(ref k) => ty::AutoUnsize(k.fold_with(this)),
ty::AutoUnsizeUniq(ref k) => ty::AutoUnsizeUniq(k.fold_with(this)),
ty::AutoUnsafe(m) => ty::AutoUnsafe(m)
}
}

View File

@ -1405,11 +1405,11 @@ impl LintPass for UnusedAllocation {
if let Some(adjustment) = cx.tcx.adjustments.borrow().get(&e.id) {
if let ty::AdjustDerefRef(ty::AutoDerefRef { ref autoref, .. }) = *adjustment {
match autoref {
&Some(ty::AutoPtr(_, ast::MutImmutable, None)) => {
&Some(ty::AutoPtr(_, ast::MutImmutable)) => {
cx.span_lint(UNUSED_ALLOCATION, e.span,
"unnecessary allocation, use & instead");
}
&Some(ty::AutoPtr(_, ast::MutMutable, None)) => {
&Some(ty::AutoPtr(_, ast::MutMutable)) => {
cx.span_lint(UNUSED_ALLOCATION, e.span,
"unnecessary allocation, use &mut instead");
}

View File

@ -146,33 +146,6 @@ pub fn type_is_fat_ptr<'tcx>(cx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool {
}
}
// Return the smallest part of `ty` which is unsized. Fails if `ty` is sized.
// 'Smallest' here means component of the static representation of the type; not
// the size of an object at runtime.
pub fn unsized_part_of_type<'tcx>(cx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
match ty.sty {
ty::ty_str | ty::ty_trait(..) | ty::ty_vec(..) => ty,
ty::ty_struct(def_id, substs) => {
let unsized_fields: Vec<_> =
ty::struct_fields(cx, def_id, substs)
.iter()
.map(|f| f.mt.ty)
.filter(|ty| !type_is_sized(cx, *ty))
.collect();
// Exactly one of the fields must be unsized.
assert!(unsized_fields.len() == 1);
unsized_part_of_type(cx, unsized_fields[0])
}
_ => {
assert!(type_is_sized(cx, ty),
"unsized_part_of_type failed even though ty is unsized");
panic!("called unsized_part_of_type with sized ty");
}
}
}
// Some things don't need cleanups during unwinding because the
// task can free them all at once later. Currently only things
// that only contain scalars and shared boxes can avoid unwind

View File

@ -254,7 +254,7 @@ pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
&ty::expr_ty_adjusted(cx.tcx(), e));
let opt_adj = cx.tcx().adjustments.borrow().get(&e.id).cloned();
match opt_adj {
Some(ty::AdjustReifyFnPointer(_def_id)) => {
Some(ty::AdjustReifyFnPointer) => {
// FIXME(#19925) once fn item types are
// zero-sized, we'll need to do something here
}
@ -272,73 +272,56 @@ pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
}
}
let second_autoref = match adj.autoref {
None => {
let (dv, dt) = const_deref(cx, llconst, ty);
llconst = dv;
// If we derefed a fat pointer then we will have an
// open type here. So we need to update the type with
// the one returned from const_deref.
ety_adjusted = dt;
None
}
Some(ty::AutoUnsafe(_, opt_autoref)) |
Some(ty::AutoPtr(_, _, opt_autoref)) => {
if adj.autoderefs == 0 {
// Don't copy data to do a deref+ref
// (i.e., skip the last auto-deref).
llconst = addr_of(cx, llconst, "autoref");
} else {
// Seeing as we are deref'ing here and take a reference
// again to make the pointer part of the far pointer below,
// we just skip the whole thing. We still need the type
// though. This works even if we don't need to deref
// because of byref semantics. Note that this is not just
// an optimisation, it is necessary for mutable vectors to
// work properly.
ty = match ty::deref(ty, true) {
Some(mt) => mt.ty,
None => {
cx.sess().bug(&format!("unexpected dereferenceable type {}",
ty_to_string(cx.tcx(), ty)))
}
}
}
opt_autoref
}
Some(autoref) => {
cx.sess().span_bug(e.span,
&format!("unimplemented const first autoref {:?}", autoref))
}
};
match second_autoref {
None => {}
Some(box ty::AutoUnsafe(_, None)) |
Some(box ty::AutoPtr(_, _, None)) => {
if adj.autoref.is_some() {
if adj.autoderefs == 0 {
// Don't copy data to do a deref+ref
// (i.e., skip the last auto-deref).
llconst = addr_of(cx, llconst, "autoref");
ty = ty::mk_imm_rptr(cx.tcx(), cx.tcx().mk_region(ty::ReStatic), ty);
}
Some(box ty::AutoUnsize(ref k)) => {
let info =
expr::unsized_info(
cx, k, e.id, ty, param_substs,
|| const_get_elt(cx, llconst, &[abi::FAT_PTR_EXTRA as u32]));
} else {
let (dv, dt) = const_deref(cx, llconst, ty);
llconst = dv;
let unsized_ty = ty::unsize_ty(cx.tcx(), ty, k, e.span);
let ptr_ty = type_of::in_memory_type_of(cx, unsized_ty).ptr_to();
let base = ptrcast(llconst, ptr_ty);
// 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;
}
let prev_const = cx.const_unsized().borrow_mut()
.insert(base, llconst);
assert!(prev_const.is_none() || prev_const == Some(llconst));
assert_eq!(abi::FAT_PTR_ADDR, 0);
assert_eq!(abi::FAT_PTR_EXTRA, 1);
llconst = C_struct(cx, &[base, info], false);
}
Some(autoref) => {
cx.sess().span_bug(e.span,
&format!("unimplemented const second autoref {:?}", autoref))
}
if let Some(target) = adj.unsize {
let target = monomorphize::apply_param_substs(cx.tcx(),
param_substs,
&target);
let pointee_ty = ty::deref(ty, true)
.expect("consts: unsizing got non-pointer type").ty;
let (base, old_info) = if !type_is_sized(cx.tcx(), pointee_ty) {
// Normally, the source is a thin pointer and we are
// adding extra info to make a fat pointer. The exception
// is when we are upcasting an existing object fat pointer
// to use a different vtable. In that case, we want to
// load out the original data pointer so we can repackage
// it.
(const_get_elt(cx, llconst, &[abi::FAT_PTR_ADDR as u32]),
Some(const_get_elt(cx, llconst, &[abi::FAT_PTR_EXTRA as u32])))
} else {
(llconst, None)
};
let unsized_ty = ty::deref(target, true)
.expect("consts: unsizing got non-pointer target type").ty;
let ptr_ty = type_of::in_memory_type_of(cx, unsized_ty).ptr_to();
let base = ptrcast(base, ptr_ty);
let info = expr::unsized_info(cx, pointee_ty, unsized_ty,
old_info, param_substs);
let prev_const = cx.const_unsized().borrow_mut()
.insert(base, llconst);
assert!(prev_const.is_none() || prev_const == Some(llconst));
assert_eq!(abi::FAT_PTR_ADDR, 0);
assert_eq!(abi::FAT_PTR_EXTRA, 1);
llconst = C_struct(cx, &[base, info], false);
}
}
None => {}

View File

@ -72,8 +72,7 @@ use trans::monomorphize;
use trans::tvec;
use trans::type_of;
use middle::ty::{struct_fields, tup_fields};
use middle::ty::{AdjustDerefRef, AdjustReifyFnPointer, AdjustUnsafeFnPointer, AutoUnsafe};
use middle::ty::AutoPtr;
use middle::ty::{AdjustDerefRef, AdjustReifyFnPointer, AdjustUnsafeFnPointer};
use middle::ty::{self, Ty};
use middle::ty::MethodCall;
use util::common::indenter;
@ -290,72 +289,39 @@ pub fn copy_fat_ptr(bcx: Block, src_ptr: ValueRef, dst_ptr: ValueRef) {
Store(bcx, Load(bcx, get_len(bcx, src_ptr)), get_len(bcx, dst_ptr));
}
// Retrieve the information we are losing (making dynamic) in an unsizing
// adjustment.
//
// The `unadjusted_val` argument is a bit funny. It is intended
// for use in an upcast, where the new vtable for an object will
// be drived from the old one. Hence it is a pointer to the fat
// pointer.
pub fn unsized_info_bcx<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
kind: &ty::UnsizeKind<'tcx>,
id: ast::NodeId,
unadjusted_ty: Ty<'tcx>,
unadjusted_val: ValueRef, // see above (*)
param_substs: &'tcx subst::Substs<'tcx>)
-> ValueRef {
unsized_info(
bcx.ccx(),
kind,
id,
unadjusted_ty,
param_substs,
|| Load(bcx, GEPi(bcx, unadjusted_val, &[0, abi::FAT_PTR_EXTRA])))
}
// Same as `unsize_info_bcx`, but does not require a bcx -- instead it
// takes an extra closure to compute the upcast vtable.
pub fn unsized_info<'ccx, 'tcx, MK_UPCAST_VTABLE>(
ccx: &CrateContext<'ccx, 'tcx>,
kind: &ty::UnsizeKind<'tcx>,
id: ast::NodeId,
unadjusted_ty: Ty<'tcx>,
param_substs: &'tcx subst::Substs<'tcx>,
mk_upcast_vtable: MK_UPCAST_VTABLE) // see notes above
-> ValueRef
where MK_UPCAST_VTABLE: FnOnce() -> ValueRef
{
debug!("unsized_info(kind={:?}, id={}, unadjusted_ty={})",
kind, id, unadjusted_ty.repr(ccx.tcx()));
match kind {
&ty::UnsizeLength(len) => C_uint(ccx, len),
&ty::UnsizeStruct(box ref k, tp_index) => match unadjusted_ty.sty {
ty::ty_struct(_, ref substs) => {
let ty_substs = substs.types.get_slice(subst::TypeSpace);
unsized_info(ccx, k, id, ty_substs[tp_index], param_substs,
mk_upcast_vtable)
}
_ => ccx.sess().bug(&format!("UnsizeStruct with bad sty: {}",
unadjusted_ty.repr(ccx.tcx())))
},
&ty::UnsizeVtable(ty::TyTrait { ref principal, .. }, _) => {
// Note that we preserve binding levels here:
let substs = principal.0.substs.with_self_ty(unadjusted_ty).erase_regions();
let substs = ccx.tcx().mk_substs(substs);
let trait_ref = ty::Binder(Rc::new(ty::TraitRef { def_id: principal.def_id(),
substs: substs }));
let trait_ref = monomorphize::apply_param_substs(ccx.tcx(),
param_substs,
&trait_ref);
consts::ptrcast(meth::get_vtable(ccx, trait_ref, param_substs),
Type::vtable_ptr(ccx))
}
&ty::UnsizeUpcast(_) => {
/// Retrieve the information we are losing (making dynamic) in an unsizing
/// adjustment.
///
/// The `old_info` argument is a bit funny. It is intended for use
/// in an upcast, where the new vtable for an object will be drived
/// from the old one.
pub fn unsized_info<'ccx, 'tcx>(ccx: &CrateContext<'ccx, 'tcx>,
source: Ty<'tcx>,
target: Ty<'tcx>,
old_info: Option<ValueRef>,
param_substs: &'tcx subst::Substs<'tcx>)
-> ValueRef {
let (source, target) = ty::struct_lockstep_tails(ccx.tcx(), source, target);
match (&source.sty, &target.sty) {
(&ty::ty_vec(_, Some(len)), &ty::ty_vec(_, None)) => C_uint(ccx, len),
(&ty::ty_trait(_), &ty::ty_trait(_)) => {
// For now, upcasts are limited to changes in marker
// traits, and hence never actually require an actual
// change to the vtable.
mk_upcast_vtable()
old_info.expect("unsized_info: missing old info for trait upcast")
}
(_, &ty::ty_trait(box ty::TyTrait { ref principal, .. })) => {
// Note that we preserve binding levels here:
let substs = principal.0.substs.with_self_ty(source).erase_regions();
let substs = ccx.tcx().mk_substs(substs);
let trait_ref = ty::Binder(Rc::new(ty::TraitRef { def_id: principal.def_id(),
substs: substs }));
consts::ptrcast(meth::get_vtable(ccx, trait_ref, param_substs),
Type::vtable_ptr(ccx))
}
_ => ccx.sess().bug(&format!("unsized_info: invalid unsizing {} -> {}",
source.repr(ccx.tcx()),
target.repr(ccx.tcx())))
}
}
@ -379,7 +345,7 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
datum.to_string(bcx.ccx()),
adjustment);
match adjustment {
AdjustReifyFnPointer(_def_id) => {
AdjustReifyFnPointer => {
// FIXME(#19925) once fn item types are
// zero-sized, we'll need to do something here
}
@ -387,202 +353,112 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
// purely a type-level thing
}
AdjustDerefRef(ref adj) => {
let (autoderefs, use_autoref) = match adj.autoref {
// Extracting a value from a box counts as a deref, but if we are
// just converting Box<[T, ..n]> to Box<[T]> we aren't really doing
// a deref (and wouldn't if we could treat Box like a normal struct).
Some(ty::AutoUnsizeUniq(..)) => (adj.autoderefs - 1, true),
let skip_reborrows = if adj.autoderefs == 1 && adj.autoref.is_some() {
// We are a bit paranoid about adjustments and thus might have a re-
// borrow here which merely derefs and then refs again (it might have
// a different region or mutability, but we don't care here. It might
// also be just in case we need to unsize. But if there are no nested
// adjustments then it should be a no-op).
Some(ty::AutoPtr(_, _, None)) |
Some(ty::AutoUnsafe(_, None)) if adj.autoderefs == 1 => {
match datum.ty.sty {
// Don't skip a conversion from Box<T> to &T, etc.
ty::ty_rptr(..) => {
let method_call = MethodCall::autoderef(expr.id, adj.autoderefs-1);
let method = bcx.tcx().method_map.borrow().get(&method_call).is_some();
if method {
// Don't skip an overloaded deref.
(adj.autoderefs, true)
} else {
(adj.autoderefs - 1, false)
}
// a different region or mutability, but we don't care here).
match datum.ty.sty {
// Don't skip a conversion from Box<T> to &T, etc.
ty::ty_rptr(..) => {
let method_call = MethodCall::autoderef(expr.id, 0);
if bcx.tcx().method_map.borrow().contains_key(&method_call) {
// Don't skip an overloaded deref.
0
} else {
1
}
_ => (adj.autoderefs, true),
}
_ => 0
}
_ => (adj.autoderefs, true)
} else {
0
};
if autoderefs > 0 {
if adj.autoderefs > skip_reborrows {
// Schedule cleanup.
let lval = unpack_datum!(bcx, datum.to_lvalue_datum(bcx, "auto_deref", expr.id));
datum = unpack_datum!(
bcx, deref_multiple(bcx, expr, lval.to_expr_datum(), autoderefs));
datum = unpack_datum!(bcx, deref_multiple(bcx, expr,
lval.to_expr_datum(),
adj.autoderefs - skip_reborrows));
}
// (You might think there is a more elegant way to do this than a
// use_autoref bool, but then you remember that the borrow checker exists).
if let (true, &Some(ref a)) = (use_autoref, &adj.autoref) {
datum = unpack_datum!(bcx, apply_autoref(a,
bcx,
expr,
datum));
// skip_reborrows bool, but then you remember that the borrow checker exists).
if skip_reborrows == 0 && adj.autoref.is_some() {
datum = unpack_datum!(bcx, apply_autoref(bcx, expr, datum));
}
if let Some(target) = adj.unsize {
datum = unpack_datum!(bcx, unsize_pointer(bcx, datum,
bcx.monomorphize(&target)));
}
}
}
debug!("after adjustments, datum={}", datum.to_string(bcx.ccx()));
return DatumBlock::new(bcx, datum);
fn apply_autoref<'blk, 'tcx>(autoref: &ty::AutoRef<'tcx>,
bcx: Block<'blk, 'tcx>,
fn apply_autoref<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
expr: &ast::Expr,
datum: Datum<'tcx, Expr>)
-> DatumBlock<'blk, 'tcx, Expr> {
let mut bcx = bcx;
let mut datum = datum;
let datum = match autoref {
&AutoPtr(_, _, ref a) | &AutoUnsafe(_, ref a) => {
debug!(" AutoPtr");
if let &Some(box ref a) = a {
datum = unpack_datum!(bcx, apply_autoref(a, bcx, expr, datum));
}
if !type_is_sized(bcx.tcx(), datum.ty) {
// Arrange cleanup
let lval = unpack_datum!(bcx,
datum.to_lvalue_datum(bcx, "ref_fat_ptr", expr.id));
unpack_datum!(bcx, ref_fat_ptr(bcx, lval))
} else {
unpack_datum!(bcx, auto_ref(bcx, datum, expr))
}
}
&ty::AutoUnsize(ref k) => {
debug!(" AutoUnsize");
unpack_datum!(bcx, unsize_expr(bcx, expr, datum, k))
}
&ty::AutoUnsizeUniq(ty::UnsizeLength(len)) => {
debug!(" AutoUnsizeUniq(UnsizeLength)");
unpack_datum!(bcx, unsize_unique_vec(bcx, expr, datum, len))
}
&ty::AutoUnsizeUniq(ref k) => {
debug!(" AutoUnsizeUniq");
unpack_datum!(bcx, unsize_unique_expr(bcx, expr, datum, k))
}
};
DatumBlock::new(bcx, datum)
if !type_is_sized(bcx.tcx(), datum.ty) {
// Arrange cleanup
let lval = unpack_datum!(bcx,
datum.to_lvalue_datum(bcx, "ref_fat_ptr", expr.id));
ref_fat_ptr(bcx, lval)
} else {
auto_ref(bcx, datum, expr)
}
}
fn unsize_expr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
expr: &ast::Expr,
datum: Datum<'tcx, Expr>,
k: &ty::UnsizeKind<'tcx>)
-> DatumBlock<'blk, 'tcx, Expr> {
fn unsize_pointer<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
datum: Datum<'tcx, Expr>,
target: Ty<'tcx>)
-> DatumBlock<'blk, 'tcx, Expr> {
let mut bcx = bcx;
let tcx = bcx.tcx();
let datum_ty = datum.ty;
let unsized_ty = ty::unsize_ty(tcx, datum_ty, k, expr.span);
debug!("unsized_ty={}", unsized_ty.repr(bcx.tcx()));
let unsized_ty = ty::deref(target, true)
.expect("expr::unsize got non-pointer target type").ty;
debug!("unsize_lvalue(unsized_ty={})", unsized_ty.repr(bcx.tcx()));
let info = unsized_info_bcx(bcx, k, expr.id, datum_ty, datum.val, bcx.fcx.param_substs);
// We do not arrange cleanup ourselves; if we already are an
// L-value, then cleanup will have already been scheduled (and
// the `datum.to_rvalue_datum` call below will emit code to zero
// the drop flag when moving out of the L-value). If we are an
// R-value, then we do not need to schedule cleanup.
let datum = unpack_datum!(bcx, datum.to_rvalue_datum(bcx, "__unsize_ref"));
// Arrange cleanup
let lval = unpack_datum!(bcx, datum.to_lvalue_datum(bcx, "into_fat_ptr", expr.id));
// Compute the base pointer. This doesn't change the pointer value,
// but merely its type.
let ptr_ty = type_of::in_memory_type_of(bcx.ccx(), unsized_ty).ptr_to();
let base = if !type_is_sized(bcx.tcx(), lval.ty) {
let pointee_ty = ty::deref(datum.ty, true)
.expect("expr::unsize got non-pointer datum type").ty;
let (base, old_info) = if !type_is_sized(bcx.tcx(), pointee_ty) {
// Normally, the source is a thin pointer and we are
// adding extra info to make a fat pointer. The exception
// is when we are upcasting an existing object fat pointer
// to use a different vtable. In that case, we want to
// load out the original data pointer so we can repackage
// it.
Load(bcx, get_dataptr(bcx, lval.val))
(Load(bcx, get_dataptr(bcx, datum.val)),
Some(Load(bcx, get_len(bcx, datum.val))))
} else {
lval.val
(datum.val, None)
};
let info = unsized_info(bcx.ccx(), pointee_ty, unsized_ty,
old_info, bcx.fcx.param_substs);
// Compute the base pointer. This doesn't change the pointer value,
// but merely its type.
let ptr_ty = type_of::in_memory_type_of(bcx.ccx(), unsized_ty).ptr_to();
let base = PointerCast(bcx, base, ptr_ty);
let llty = type_of::type_of(bcx.ccx(), unsized_ty);
let llty = type_of::type_of(bcx.ccx(), target);
// HACK(eddyb) get around issues with lifetime intrinsics.
let scratch = alloca_no_lifetime(bcx, llty, "__fat_ptr");
Store(bcx, base, get_dataptr(bcx, scratch));
Store(bcx, info, get_len(bcx, scratch));
DatumBlock::new(bcx, Datum::new(scratch, unsized_ty, LvalueExpr))
}
fn unsize_unique_vec<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
expr: &ast::Expr,
datum: Datum<'tcx, Expr>,
len: usize)
-> DatumBlock<'blk, 'tcx, Expr> {
let mut bcx = bcx;
let tcx = bcx.tcx();
let datum_ty = datum.ty;
debug!("unsize_unique_vec expr.id={} datum_ty={} len={}",
expr.id, datum_ty.repr(tcx), len);
// We do not arrange cleanup ourselves; if we already are an
// L-value, then cleanup will have already been scheduled (and
// the `datum.store_to` call below will emit code to zero the
// drop flag when moving out of the L-value). If we are an R-value,
// then we do not need to schedule cleanup.
let ll_len = C_uint(bcx.ccx(), len);
let unit_ty = ty::sequence_element_type(tcx, ty::type_content(datum_ty));
let vec_ty = ty::mk_uniq(tcx, ty::mk_vec(tcx, unit_ty, None));
let scratch = rvalue_scratch_datum(bcx, vec_ty, "__unsize_unique");
let base = get_dataptr(bcx, scratch.val);
let base = PointerCast(bcx,
base,
type_of::type_of(bcx.ccx(), datum_ty).ptr_to());
bcx = datum.store_to(bcx, base);
Store(bcx, ll_len, get_len(bcx, scratch.val));
DatumBlock::new(bcx, scratch.to_expr_datum())
}
fn unsize_unique_expr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
expr: &ast::Expr,
datum: Datum<'tcx, Expr>,
k: &ty::UnsizeKind<'tcx>)
-> DatumBlock<'blk, 'tcx, Expr> {
let mut bcx = bcx;
let tcx = bcx.tcx();
let datum_ty = datum.ty;
let unboxed_ty = match datum_ty.sty {
ty::ty_uniq(t) => t,
_ => bcx.sess().bug(&format!("Expected ty_uniq, found {}",
bcx.ty_to_string(datum_ty)))
};
let result_ty = ty::mk_uniq(tcx, ty::unsize_ty(tcx, unboxed_ty, k, expr.span));
// We do not arrange cleanup ourselves; if we already are an
// L-value, then cleanup will have already been scheduled (and
// the `datum.store_to` call below will emit code to zero the
// drop flag when moving out of the L-value). If we are an R-value,
// then we do not need to schedule cleanup.
let scratch = rvalue_scratch_datum(bcx, result_ty, "__uniq_fat_ptr");
let llbox_ty = type_of::type_of(bcx.ccx(), datum_ty);
let base = PointerCast(bcx, get_dataptr(bcx, scratch.val), llbox_ty.ptr_to());
bcx = datum.store_to(bcx, base);
let info = unsized_info_bcx(bcx, k, expr.id, unboxed_ty, base, bcx.fcx.param_substs);
Store(bcx, info, get_len(bcx, scratch.val));
DatumBlock::new(bcx, scratch.to_expr_datum())
DatumBlock::new(bcx, Datum::new(scratch, target, RvalueExpr(Rvalue::new(ByRef))))
}
}
@ -2233,7 +2109,7 @@ fn deref_multiple<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
let mut bcx = bcx;
let mut datum = datum;
for i in 0..times {
let method_call = MethodCall::autoderef(expr.id, i);
let method_call = MethodCall::autoderef(expr.id, i as u32);
datum = unpack_datum!(bcx, deref_once(bcx, expr, datum, method_call));
}
DatumBlock { bcx: bcx, datum: datum }
@ -2265,10 +2141,11 @@ fn deref_once<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
// converts from the `Smaht<T>` pointer that we have into
// a `&T` pointer. We can then proceed down the normal
// path (below) to dereference that `&T`.
let datum = match method_call.adjustment {
let datum = if method_call.autoderef == 0 {
datum
} else {
// Always perform an AutoPtr when applying an overloaded auto-deref
ty::AutoDeref(_) => unpack_datum!(bcx, auto_ref(bcx, datum, expr)),
_ => datum
unpack_datum!(bcx, auto_ref(bcx, datum, expr))
};
let ref_ty = // invoked methods have their LB regions instantiated

View File

@ -359,14 +359,14 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) ->
cx.tn().find_type("str_slice").unwrap()
} else {
let ptr_ty = in_memory_type_of(cx, ty).ptr_to();
let unsized_part = unsized_part_of_type(cx.tcx(), ty);
let unsized_part = ty::struct_tail(cx.tcx(), ty);
let info_ty = match unsized_part.sty {
ty::ty_str | ty::ty_vec(..) => {
Type::uint_from_ty(cx, ast::TyUs)
}
ty::ty_trait(_) => Type::vtable_ptr(cx),
_ => panic!("Unexpected type returned from \
unsized_part_of_type: {} for ty={}",
struct_tail: {} for ty={}",
unsized_part.repr(cx.tcx()), ty.repr(cx.tcx()))
};
Type::struct_(cx, &[ptr_ty, info_ty], false)

View File

@ -59,6 +59,7 @@ use middle::ty::{self, RegionEscape, Ty};
use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope, ExplicitRscope,
ObjectLifetimeDefaultRscope, ShiftedRscope, BindingRscope};
use util::common::{ErrorReported, FN_OUTPUT_NAME};
use util::nodemap::FnvHashSet;
use util::ppaux::{self, Repr, UserString};
use std::iter::repeat;
@ -1011,13 +1012,58 @@ fn trait_ref_to_object_type<'tcx>(this: &AstConv<'tcx>,
projection_bounds,
bounds);
let result = ty::mk_trait(this.tcx(), trait_ref, existential_bounds);
let result = make_object_type(this, span, trait_ref, existential_bounds);
debug!("trait_ref_to_object_type: result={}",
result.repr(this.tcx()));
result
}
fn make_object_type<'tcx>(this: &AstConv<'tcx>,
span: Span,
principal: ty::PolyTraitRef<'tcx>,
bounds: ty::ExistentialBounds<'tcx>)
-> Ty<'tcx> {
let tcx = this.tcx();
let object = ty::TyTrait {
principal: principal,
bounds: bounds
};
let object_trait_ref =
object.principal_trait_ref_with_self_ty(tcx, tcx.types.err);
// ensure the super predicates and stop if we encountered an error
if this.ensure_super_predicates(span, object.principal_def_id()).is_err() {
return tcx.types.err;
}
let mut associated_types: FnvHashSet<(ast::DefId, ast::Name)> =
traits::supertraits(tcx, object_trait_ref)
.flat_map(|tr| {
let trait_def = ty::lookup_trait_def(tcx, tr.def_id());
trait_def.associated_type_names
.clone()
.into_iter()
.map(move |associated_type_name| (tr.def_id(), associated_type_name))
})
.collect();
for projection_bound in &object.bounds.projection_bounds {
let pair = (projection_bound.0.projection_ty.trait_ref.def_id,
projection_bound.0.projection_ty.item_name);
associated_types.remove(&pair);
}
for (trait_def_id, name) in associated_types {
span_err!(tcx.sess, span, E0191,
"the value of the associated type `{}` (from the trait `{}`) must be specified",
name.user_string(tcx),
ty::item_path_str(tcx, trait_def_id));
}
ty::mk_trait(tcx, object.principal, object.bounds)
}
fn report_ambiguous_associated_type(tcx: &ty::ctxt,
span: Span,
type_str: &str,
@ -1914,7 +1960,7 @@ fn conv_ty_poly_trait_ref<'tcx>(
projection_bounds,
partitioned_bounds);
ty::mk_trait(this.tcx(), main_trait_bound, bounds)
make_object_type(this, span, main_trait_bound, bounds)
}
pub fn conv_existential_bounds_from_partitioned_bounds<'tcx>(

View File

@ -125,14 +125,10 @@ fn try_overloaded_call_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
adjusted_ty.repr(fcx.tcx()),
autoderefs);
let autoderefref = ty::AutoDerefRef { autoderefs: autoderefs, autoref: None };
// If the callee is a bare function or a closure, then we're all set.
match structurally_resolved_type(fcx, callee_expr.span, adjusted_ty).sty {
ty::ty_bare_fn(..) => {
fcx.write_adjustment(callee_expr.id,
callee_expr.span,
ty::AdjustDerefRef(autoderefref));
fcx.write_autoderef_adjustment(callee_expr.id, autoderefs);
return Some(CallStep::Builtin);
}
@ -149,14 +145,14 @@ fn try_overloaded_call_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
fcx.infcx().replace_late_bound_regions_with_fresh_var(call_expr.span,
infer::FnCall,
&closure_ty.sig).0;
fcx.record_deferred_call_resolution(
def_id,
Box::new(CallResolution {call_expr: call_expr,
callee_expr: callee_expr,
adjusted_ty: adjusted_ty,
autoderefref: autoderefref,
fn_sig: fn_sig.clone(),
closure_def_id: def_id}));
fcx.record_deferred_call_resolution(def_id, Box::new(CallResolution {
call_expr: call_expr,
callee_expr: callee_expr,
adjusted_ty: adjusted_ty,
autoderefs: autoderefs,
fn_sig: fn_sig.clone(),
closure_def_id: def_id
}));
return Some(CallStep::DeferredClosure(fn_sig));
}
}
@ -176,7 +172,7 @@ fn try_overloaded_call_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
_ => {}
}
try_overloaded_call_traits(fcx, call_expr, callee_expr, adjusted_ty, autoderefref)
try_overloaded_call_traits(fcx, call_expr, callee_expr, adjusted_ty, autoderefs)
.map(|method_callee| CallStep::Overloaded(method_callee))
}
@ -184,7 +180,7 @@ fn try_overloaded_call_traits<'a,'tcx>(fcx: &FnCtxt<'a, 'tcx>,
call_expr: &ast::Expr,
callee_expr: &ast::Expr,
adjusted_ty: Ty<'tcx>,
autoderefref: ty::AutoDerefRef<'tcx>)
autoderefs: usize)
-> Option<ty::MethodCallee<'tcx>>
{
// Try the options that are least restrictive on the caller first.
@ -203,7 +199,8 @@ fn try_overloaded_call_traits<'a,'tcx>(fcx: &FnCtxt<'a, 'tcx>,
Some(&*callee_expr),
method_name,
trait_def_id,
autoderefref.clone(),
autoderefs,
false,
adjusted_ty,
None) {
None => continue,
@ -335,7 +332,7 @@ struct CallResolution<'tcx> {
call_expr: &'tcx ast::Expr,
callee_expr: &'tcx ast::Expr,
adjusted_ty: Ty<'tcx>,
autoderefref: ty::AutoDerefRef<'tcx>,
autoderefs: usize,
fn_sig: ty::FnSig<'tcx>,
closure_def_id: ast::DefId,
}
@ -343,11 +340,11 @@ struct CallResolution<'tcx> {
impl<'tcx> Repr<'tcx> for CallResolution<'tcx> {
fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
format!("CallResolution(call_expr={}, callee_expr={}, adjusted_ty={}, \
autoderefref={}, fn_sig={}, closure_def_id={})",
autoderefs={}, fn_sig={}, closure_def_id={})",
self.call_expr.repr(tcx),
self.callee_expr.repr(tcx),
self.adjusted_ty.repr(tcx),
self.autoderefref.repr(tcx),
self.autoderefs,
self.fn_sig.repr(tcx),
self.closure_def_id.repr(tcx))
}
@ -364,7 +361,7 @@ impl<'tcx> DeferredCallResolution<'tcx> for CallResolution<'tcx> {
// We may now know enough to figure out fn vs fnmut etc.
match try_overloaded_call_traits(fcx, self.call_expr, self.callee_expr,
self.adjusted_ty, self.autoderefref.clone()) {
self.adjusted_ty, self.autoderefs) {
Some(method_callee) => {
// One problem is that when we get here, we are going
// to have a newly instantiated function signature

View File

@ -61,21 +61,25 @@
//! we may want to adjust precisely when coercions occur.
use check::{autoderef, FnCtxt, NoPreference, PreferMutLvalue, UnresolvedTypeAction};
use check::vtable;
use middle::infer::{self, Coercion};
use middle::subst;
use middle::ty::{AutoPtr, AutoDerefRef, AdjustDerefRef, AutoUnsize, AutoUnsafe};
use middle::traits;
use middle::ty::{AutoDerefRef, AdjustDerefRef};
use middle::ty::{self, mt, Ty};
use middle::ty_relate::RelateResult;
use util::common::indent;
use util::ppaux;
use util::ppaux::Repr;
use std::cell::Cell;
use syntax::ast;
struct Coerce<'a, 'tcx: 'a> {
fcx: &'a FnCtxt<'a, 'tcx>,
origin: infer::TypeOrigin,
unsizing_obligation: Cell<Option<Ty<'tcx>>>
}
type CoerceResult<'tcx> = RelateResult<'tcx, Option<ty::AutoAdjustment<'tcx>>>;
@ -144,11 +148,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
self.unpack_actual_value(a, |a| {
match a.sty {
ty::ty_bare_fn(Some(a_def_id), a_f) => {
ty::ty_bare_fn(Some(_), a_f) => {
// Function items are coercible to any closure
// type; function pointers are not (that would
// require double indirection).
self.coerce_from_fn_item(a, a_def_id, a_f, b)
self.coerce_from_fn_item(a, a_f, b)
}
ty::ty_bare_fn(None, a_f) => {
// We permit coercion of fn pointers to drop the
@ -184,18 +188,16 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
match a.sty {
ty::ty_rptr(_, mt_a) => {
if !can_coerce_mutbls(mt_a.mutbl, mutbl_b) {
return Err(ty::terr_mutability);
}
try!(coerce_mutbls(mt_a.mutbl, mutbl_b));
}
_ => return self.subtype(a, b)
}
let coercion = Coercion(self.origin.span());
let r_borrow = self.fcx.infcx().next_region_var(coercion);
let autoref = Some(AutoPtr(r_borrow, mutbl_b, None));
let r_borrow = self.tcx().mk_region(r_borrow);
let autoref = Some(ty::AutoPtr(r_borrow, mutbl_b));
let lvalue_pref = match mutbl_b {
ast::MutMutable => PreferMutLvalue,
ast::MutImmutable => NoPreference
@ -229,7 +231,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
Some(_) => {
Ok(Some(AdjustDerefRef(AutoDerefRef {
autoderefs: autoderefs,
autoref: autoref
autoref: autoref,
unsize: None
})))
}
None => {
@ -257,183 +260,148 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
// we can't unify [T] with U. But to properly support DST, we need to allow
// that, at which point we will need extra checks on b here.
match (&a.sty, &b.sty) {
(&ty::ty_rptr(_, ty::mt{ty: t_a, mutbl: mutbl_a}), &ty::ty_rptr(_, mt_b)) => {
match self.unsize_ty(t_a, mt_b.ty) {
Some((ty, kind)) => {
if !can_coerce_mutbls(mutbl_a, mt_b.mutbl) {
return Err(ty::terr_mutability);
}
let (reborrow, target) = match (&a.sty, &b.sty) {
(&ty::ty_rptr(_, mt_a), &ty::ty_rptr(_, mt_b)) => {
if let Some(target) = self.unsize_ty(mt_a.ty, mt_b.ty) {
try!(coerce_mutbls(mt_a.mutbl, mt_b.mutbl));
let coercion = Coercion(self.origin.span());
let r_borrow = self.fcx.infcx().next_region_var(coercion);
let ty = ty::mk_rptr(self.tcx(),
self.tcx().mk_region(r_borrow),
ty::mt{ty: ty, mutbl: mt_b.mutbl});
try!(self.subtype(ty, b));
debug!("Success, coerced with AutoDerefRef(1, \
AutoPtr(AutoUnsize({:?})))", kind);
Ok(Some(AdjustDerefRef(AutoDerefRef {
autoderefs: 1,
autoref: Some(ty::AutoPtr(r_borrow, mt_b.mutbl,
Some(box AutoUnsize(kind))))
})))
}
_ => Err(ty::terr_mismatch)
let coercion = Coercion(self.origin.span());
let r_borrow = self.fcx.infcx().next_region_var(coercion);
let region = self.tcx().mk_region(r_borrow);
(Some(ty::AutoPtr(region, mt_b.mutbl)), target)
} else {
return Err(ty::terr_mismatch);
}
}
(&ty::ty_rptr(_, ty::mt{ty: t_a, mutbl: mutbl_a}), &ty::ty_ptr(mt_b)) => {
match self.unsize_ty(t_a, mt_b.ty) {
Some((ty, kind)) => {
if !can_coerce_mutbls(mutbl_a, mt_b.mutbl) {
return Err(ty::terr_mutability);
}
let ty = ty::mk_ptr(self.tcx(),
ty::mt{ty: ty, mutbl: mt_b.mutbl});
try!(self.subtype(ty, b));
debug!("Success, coerced with AutoDerefRef(1, \
AutoPtr(AutoUnsize({:?})))", kind);
Ok(Some(AdjustDerefRef(AutoDerefRef {
autoderefs: 1,
autoref: Some(ty::AutoUnsafe(mt_b.mutbl,
Some(box AutoUnsize(kind))))
})))
}
_ => Err(ty::terr_mismatch)
(&ty::ty_rptr(_, mt_a), &ty::ty_ptr(mt_b)) => {
if let Some(target) = self.unsize_ty(mt_a.ty, mt_b.ty) {
try!(coerce_mutbls(mt_a.mutbl, mt_b.mutbl));
(Some(ty::AutoUnsafe(mt_b.mutbl)), target)
} else {
return Err(ty::terr_mismatch);
}
}
(&ty::ty_uniq(t_a), &ty::ty_uniq(t_b)) => {
match self.unsize_ty(t_a, t_b) {
Some((ty, kind)) => {
let ty = ty::mk_uniq(self.tcx(), ty);
try!(self.subtype(ty, b));
debug!("Success, coerced with AutoDerefRef(1, \
AutoUnsizeUniq({:?}))", kind);
Ok(Some(AdjustDerefRef(AutoDerefRef {
autoderefs: 1,
autoref: Some(ty::AutoUnsizeUniq(kind))
})))
}
_ => Err(ty::terr_mismatch)
if let Some(target) = self.unsize_ty(t_a, t_b) {
(None, ty::mk_uniq(self.tcx(), target))
} else {
return Err(ty::terr_mismatch);
}
}
_ => Err(ty::terr_mismatch)
}
_ => return Err(ty::terr_mismatch)
};
let target = ty::adjust_ty_for_autoref(self.tcx(), target, reborrow);
try!(self.subtype(target, b));
let adjustment = AutoDerefRef {
autoderefs: if reborrow.is_some() { 1 } else { 0 },
autoref: reborrow,
unsize: Some(target)
};
debug!("Success, coerced with {}", adjustment.repr(self.tcx()));
Ok(Some(AdjustDerefRef(adjustment)))
}
// Takes a type and returns an unsized version along with the adjustment
// performed to unsize it.
// E.g., `[T, ..n]` -> `([T], UnsizeLength(n))`
// Takes a type and returns an unsized version.
// E.g., `[T, ..n]` -> `[T]`.
fn unsize_ty(&self,
ty_a: Ty<'tcx>,
ty_b: Ty<'tcx>)
-> Option<(Ty<'tcx>, ty::UnsizeKind<'tcx>)>
{
-> Option<Ty<'tcx>> {
let tcx = self.tcx();
self.unpack_actual_value(ty_a, |a| {
self.unpack_actual_value(ty_b, |b| {
debug!("unsize_ty(a={}, b={})", a.repr(self.tcx()), b.repr(self.tcx()));
match (&a.sty, &b.sty) {
(&ty::ty_vec(t_a, Some(len)), &ty::ty_vec(_, None)) => {
let ty = ty::mk_vec(tcx, t_a, None);
Some((ty, ty::UnsizeLength(len)))
}
(&ty::ty_trait(ref data_a), &ty::ty_trait(ref data_b)) => {
// Upcasts permit two things:
//
// 1. Dropping builtin bounds, e.g. `Foo+Send` to `Foo`
// 2. Tightening the region bound, e.g. `Foo+'a` to `Foo+'b` if `'a : 'b`
//
// Note that neither of these changes requires any
// change at runtime. Eventually this will be
// generalized.
//
// We always upcast when we can because of reason
// #2 (region bounds).
if data_a.bounds.builtin_bounds.is_superset(&data_b.bounds.builtin_bounds) {
// construct a type `a1` which is a version of
// `a` using the upcast bounds from `b`
let bounds_a1 = ty::ExistentialBounds {
// From type b
region_bound: data_b.bounds.region_bound,
builtin_bounds: data_b.bounds.builtin_bounds,
// From type a
projection_bounds: data_a.bounds.projection_bounds.clone(),
};
let ty_a1 = ty::mk_trait(tcx, data_a.principal.clone(), bounds_a1);
// relate `a1` to `b`
let result = self.fcx.infcx().commit_if_ok(|_| {
// it's ok to upcast from Foo+'a to Foo+'b so long as 'a : 'b
try!(self.outlives(infer::RelateObjectBound(self.origin.span()),
data_a.bounds.region_bound,
data_b.bounds.region_bound));
self.subtype(ty_a1, ty_b)
});
// if that was successful, we have a coercion
match result {
Ok(_) => Some((ty_b, ty::UnsizeUpcast(ty_b))),
Err(_) => None,
}
} else {
None
}
}
(_, &ty::ty_trait(ref data)) => {
Some((ty_b, ty::UnsizeVtable(ty::TyTrait {
principal: data.principal.clone(),
bounds: data.bounds.clone()
},
ty_a)))
}
(&ty::ty_struct(did_a, substs_a), &ty::ty_struct(did_b, substs_b))
if did_a == did_b => {
debug!("unsizing a struct");
// Try unsizing each type param in turn to see if we end up with ty_b.
let ty_substs_a = substs_a.types.get_slice(subst::TypeSpace);
let ty_substs_b = substs_b.types.get_slice(subst::TypeSpace);
assert!(ty_substs_a.len() == ty_substs_b.len());
let mut result = None;
let tps = ty_substs_a.iter().zip(ty_substs_b.iter()).enumerate();
for (i, (tp_a, tp_b)) in tps {
if self.subtype(*tp_a, *tp_b).is_ok() {
continue;
}
match self.unsize_ty(*tp_a, *tp_b) {
Some((new_tp, k)) => {
// Check that the whole types match.
let mut new_substs = substs_a.clone();
new_substs.types.get_mut_slice(subst::TypeSpace)[i] = new_tp;
let ty = ty::mk_struct(tcx, did_a, tcx.mk_substs(new_substs));
if self.subtype(ty, ty_b).is_err() {
debug!("Unsized type parameter '{}', but still \
could not match types {} and {}",
ppaux::ty_to_string(tcx, *tp_a),
ppaux::ty_to_string(tcx, ty),
ppaux::ty_to_string(tcx, ty_b));
// We can only unsize a single type parameter, so
// if we unsize one and it doesn't give us the
// type we want, then we won't succeed later.
break;
}
result = Some((ty, ty::UnsizeStruct(box k, i)));
break;
}
None => {}
}
}
result
}
_ => None
self.unpack_actual_value(ty_a, |a| self.unpack_actual_value(ty_b, |b| {
debug!("unsize_ty(a={}, b={})", a.repr(self.tcx()), b.repr(self.tcx()));
match (&a.sty, &b.sty) {
(&ty::ty_vec(t_a, Some(_)), &ty::ty_vec(_, None)) => {
Some(ty::mk_vec(tcx, t_a, None))
}
})
})
(&ty::ty_trait(ref data_a), &ty::ty_trait(ref data_b)) => {
// Upcasts permit two things:
//
// 1. Dropping builtin bounds, e.g. `Foo+Send` to `Foo`
// 2. Tightening the region bound, e.g. `Foo+'a` to `Foo+'b` if `'a : 'b`
//
// Note that neither of these changes requires any
// change at runtime. Eventually this will be
// generalized.
//
// We always upcast when we can because of reason
// #2 (region bounds).
if data_a.bounds.builtin_bounds.is_superset(&data_b.bounds.builtin_bounds) {
// construct a type `a1` which is a version of
// `a` using the upcast bounds from `b`
let bounds_a1 = ty::ExistentialBounds {
// From type b
region_bound: data_b.bounds.region_bound,
builtin_bounds: data_b.bounds.builtin_bounds,
// From type a
projection_bounds: data_a.bounds.projection_bounds.clone(),
};
let ty_a1 = ty::mk_trait(tcx, data_a.principal.clone(), bounds_a1);
// relate `a1` to `b`
let result = self.fcx.infcx().commit_if_ok(|_| {
// it's ok to upcast from Foo+'a to Foo+'b so long as 'a : 'b
try!(self.outlives(infer::RelateObjectBound(self.origin.span()),
data_a.bounds.region_bound,
data_b.bounds.region_bound));
self.subtype(ty_a1, ty_b)
});
// if that was successful, we have a coercion
match result {
Ok(_) => Some(ty_b),
Err(_) => None,
}
} else {
None
}
}
(_, &ty::ty_trait(_)) => {
assert!(self.unsizing_obligation.get().is_none());
self.unsizing_obligation.set(Some(a));
Some(ty_b)
}
(&ty::ty_struct(did_a, substs_a), &ty::ty_struct(did_b, substs_b))
if did_a == did_b => {
debug!("unsizing a struct");
// Try unsizing each type param in turn to see if we end up with ty_b.
let ty_substs_a = substs_a.types.get_slice(subst::TypeSpace);
let ty_substs_b = substs_b.types.get_slice(subst::TypeSpace);
assert!(ty_substs_a.len() == ty_substs_b.len());
let tps = ty_substs_a.iter().zip(ty_substs_b.iter()).enumerate();
for (i, (tp_a, tp_b)) in tps {
if self.subtype(*tp_a, *tp_b).is_ok() {
continue;
}
if let Some(new_tp) = self.unsize_ty(tp_a, tp_b) {
// Check that the whole types match.
let mut new_substs = substs_a.clone();
new_substs.types.get_mut_slice(subst::TypeSpace)[i] = new_tp;
let ty = ty::mk_struct(tcx, did_a, tcx.mk_substs(new_substs));
if self.subtype(ty, ty_b).is_err() {
debug!("Unsized type parameter '{}', but still \
could not match types {} and {}",
ppaux::ty_to_string(tcx, tp_a),
ppaux::ty_to_string(tcx, ty),
ppaux::ty_to_string(tcx, ty_b));
// We can only unsize a single type parameter, so
// if we unsize one and it doesn't give us the
// type we want, then we won't succeed later.
break;
}
return Some(ty);
}
}
None
}
_ => None
}
}))
}
fn coerce_from_fn_pointer(&self,
@ -451,29 +419,22 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
debug!("coerce_from_fn_pointer(a={}, b={})",
a.repr(self.tcx()), b.repr(self.tcx()));
match b.sty {
ty::ty_bare_fn(None, fn_ty_b) => {
match (fn_ty_a.unsafety, fn_ty_b.unsafety) {
(ast::Unsafety::Normal, ast::Unsafety::Unsafe) => {
let unsafe_a = self.tcx().safe_to_unsafe_fn_ty(fn_ty_a);
try!(self.subtype(unsafe_a, b));
Ok(Some(ty::AdjustUnsafeFnPointer))
}
_ => {
self.subtype(a, b)
}
if let ty::ty_bare_fn(None, fn_ty_b) = b.sty {
match (fn_ty_a.unsafety, fn_ty_b.unsafety) {
(ast::Unsafety::Normal, ast::Unsafety::Unsafe) => {
let unsafe_a = self.tcx().safe_to_unsafe_fn_ty(fn_ty_a);
try!(self.subtype(unsafe_a, b));
return Ok(Some(ty::AdjustUnsafeFnPointer));
}
}
_ => {
return self.subtype(a, b)
_ => {}
}
}
self.subtype(a, b)
})
}
fn coerce_from_fn_item(&self,
a: Ty<'tcx>,
fn_def_id_a: ast::DefId,
fn_ty_a: &'tcx ty::BareFnTy<'tcx>,
b: Ty<'tcx>)
-> CoerceResult<'tcx> {
@ -490,11 +451,9 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
ty::ty_bare_fn(None, _) => {
let a_fn_pointer = ty::mk_bare_fn(self.tcx(), None, fn_ty_a);
try!(self.subtype(a_fn_pointer, b));
Ok(Some(ty::AdjustReifyFnPointer(fn_def_id_a)))
}
_ => {
return self.subtype(a, b)
Ok(Some(ty::AdjustReifyFnPointer))
}
_ => self.subtype(a, b)
}
})
}
@ -518,16 +477,15 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
// Check that the types which they point at are compatible.
let a_unsafe = ty::mk_ptr(self.tcx(), ty::mt{ mutbl: mutbl_b, ty: mt_a.ty });
try!(self.subtype(a_unsafe, b));
if !can_coerce_mutbls(mt_a.mutbl, mutbl_b) {
return Err(ty::terr_mutability);
}
try!(coerce_mutbls(mt_a.mutbl, mutbl_b));
// Although references and unsafe ptrs have the same
// representation, we still register an AutoDerefRef so that
// regionck knows that the region for `a` must be valid here.
Ok(Some(AdjustDerefRef(AutoDerefRef {
autoderefs: 1,
autoref: Some(ty::AutoUnsafe(mutbl_b, None))
autoref: Some(ty::AutoUnsafe(mutbl_b)),
unsize: None
})))
}
}
@ -538,27 +496,59 @@ pub fn mk_assignty<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
b: Ty<'tcx>)
-> RelateResult<'tcx, ()> {
debug!("mk_assignty({} -> {})", a.repr(fcx.tcx()), b.repr(fcx.tcx()));
let adjustment = try!(indent(|| {
let (adjustment, unsizing_obligation) = try!(indent(|| {
fcx.infcx().commit_if_ok(|_| {
Coerce {
let coerce = Coerce {
fcx: fcx,
origin: infer::ExprAssignable(expr.span),
}.coerce(expr, a, b)
unsizing_obligation: Cell::new(None)
};
Ok((try!(coerce.coerce(expr, a, b)),
coerce.unsizing_obligation.get()))
})
}));
if let Some(AdjustDerefRef(auto)) = adjustment {
if let (Some(source), Some(target)) = (unsizing_obligation, auto.unsize) {
let target = ty::deref(target, true)
.expect("coercion: unsizing got non-pointer target type").ty;
let target = ty::struct_tail(fcx.tcx(), target);
if let ty::ty_trait(ref ty_trait) = target.sty {
vtable::check_object_safety(fcx.tcx(), ty_trait, expr.span);
// If the type is `Foo+'a`, ensures that the type
// being cast to `Foo+'a` implements `Foo`:
vtable::register_object_cast_obligations(fcx,
expr.span,
ty_trait,
source);
// If the type is `Foo+'a`, ensures that the type
// being cast to `Foo+'a` outlives `'a`:
let cause = traits::ObligationCause {
span: expr.span,
body_id: fcx.body_id,
code: traits::ObjectCastObligation(source)
};
fcx.register_region_obligation(source, ty_trait.bounds.region_bound, cause);
}
}
}
if let Some(adjustment) = adjustment {
fcx.write_adjustment(expr.id, expr.span, adjustment);
debug!("Success, coerced with {}", adjustment.repr(fcx.tcx()));
fcx.write_adjustment(expr.id, adjustment);
}
Ok(())
}
fn can_coerce_mutbls(from_mutbl: ast::Mutability,
to_mutbl: ast::Mutability)
-> bool {
fn coerce_mutbls<'tcx>(from_mutbl: ast::Mutability,
to_mutbl: ast::Mutability)
-> CoerceResult<'tcx> {
match (from_mutbl, to_mutbl) {
(ast::MutMutable, ast::MutMutable) => true,
(ast::MutImmutable, ast::MutImmutable) => true,
(ast::MutMutable, ast::MutImmutable) => true,
(ast::MutImmutable, ast::MutMutable) => false,
(ast::MutMutable, ast::MutMutable) |
(ast::MutImmutable, ast::MutImmutable) |
(ast::MutMutable, ast::MutImmutable) => Ok(None),
(ast::MutImmutable, ast::MutMutable) => Err(ty::terr_mutability)
}
}

View File

@ -24,7 +24,6 @@ use middle::infer::InferCtxt;
use syntax::ast;
use syntax::codemap::Span;
use std::rc::Rc;
use std::mem;
use std::iter::repeat;
use util::ppaux::Repr;
@ -84,7 +83,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
-> MethodCallee<'tcx>
{
// Adjust the self expression the user provided and obtain the adjusted type.
let self_ty = self.adjust_self_ty(unadjusted_self_ty, &pick.adjustment);
let self_ty = self.adjust_self_ty(unadjusted_self_ty, &pick);
// Make sure nobody calls `drop()` explicitly.
self.enforce_illegal_method_limitations(&pick);
@ -134,11 +133,23 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
fn adjust_self_ty(&mut self,
unadjusted_self_ty: Ty<'tcx>,
adjustment: &probe::PickAdjustment)
pick: &probe::Pick<'tcx>)
-> Ty<'tcx>
{
// Construct the actual adjustment and write it into the table
let auto_deref_ref = self.create_ty_adjustment(adjustment);
let (autoref, unsize) = if let Some(mutbl) = pick.autoref {
let region = self.infcx().next_region_var(infer::Autoref(self.span));
let autoref = ty::AutoPtr(self.tcx().mk_region(region), mutbl);
(Some(autoref), pick.unsize.map(|target| {
ty::adjust_ty_for_autoref(self.tcx(), target, Some(autoref))
}))
} else {
// No unsizing should be performed without autoref (at
// least during method dispach). This is because we
// currently only unsize `[T;N]` to `[T]`, and naturally
// that must occur being a reference.
assert!(pick.unsize.is_none());
(None, None)
};
// Commit the autoderefs by calling `autoderef again, but this
// time writing the results into the various tables.
@ -149,47 +160,27 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
UnresolvedTypeAction::Error,
NoPreference,
|_, n| {
if n == auto_deref_ref.autoderefs {
if n == pick.autoderefs {
Some(())
} else {
None
}
});
assert_eq!(n, auto_deref_ref.autoderefs);
assert_eq!(n, pick.autoderefs);
assert_eq!(result, Some(()));
let final_ty =
ty::adjust_ty_for_autoref(self.tcx(), self.span, autoderefd_ty,
auto_deref_ref.autoref.as_ref());
// Write out the final adjustment.
self.fcx.write_adjustment(self.self_expr.id, self.span, ty::AdjustDerefRef(auto_deref_ref));
self.fcx.write_adjustment(self.self_expr.id,
ty::AdjustDerefRef(ty::AutoDerefRef {
autoderefs: pick.autoderefs,
autoref: autoref,
unsize: unsize
}));
final_ty
}
fn create_ty_adjustment(&mut self,
adjustment: &probe::PickAdjustment)
-> ty::AutoDerefRef<'tcx>
{
match *adjustment {
probe::AutoDeref(num) => {
ty::AutoDerefRef {
autoderefs: num,
autoref: None,
}
}
probe::AutoUnsizeLength(autoderefs, len) => {
ty::AutoDerefRef {
autoderefs: autoderefs,
autoref: Some(ty::AutoUnsize(ty::UnsizeLength(len))),
}
}
probe::AutoRef(mutability, ref sub_adjustment) => {
let deref = self.create_ty_adjustment(&**sub_adjustment);
let region = self.infcx().next_region_var(infer::Autoref(self.span));
wrap_autoref(deref, |base| ty::AutoPtr(region, mutability, base))
}
if let Some(target) = unsize {
target
} else {
ty::adjust_ty_for_autoref(self.tcx(), autoderefd_ty, autoref)
}
}
@ -499,10 +490,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
.adjustments
.borrow()
.get(&expr.id) {
Some(&ty::AdjustDerefRef(ty::AutoDerefRef {
autoderefs: autoderef_count,
autoref: _
})) => autoderef_count,
Some(&ty::AdjustDerefRef(ref adj)) => adj.autoderefs,
Some(_) | None => 0,
};
@ -529,17 +517,6 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
if i != 0 {
match expr.node {
ast::ExprIndex(ref base_expr, ref index_expr) => {
let mut base_adjustment =
match self.fcx.inh.adjustments.borrow().get(&base_expr.id) {
Some(&ty::AdjustDerefRef(ref adr)) => (*adr).clone(),
None => ty::AutoDerefRef { autoderefs: 0, autoref: None },
Some(_) => {
self.tcx().sess.span_bug(
base_expr.span,
"unexpected adjustment type");
}
};
// If this is an overloaded index, the
// adjustment will include an extra layer of
// autoref because the method is an &self/&mut
@ -548,21 +525,44 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
// expects. This is annoying and horrible. We
// ought to recode this routine so it doesn't
// (ab)use the normal type checking paths.
base_adjustment.autoref = match base_adjustment.autoref {
None => { None }
Some(ty::AutoPtr(_, _, None)) => { None }
Some(ty::AutoPtr(_, _, Some(box r))) => { Some(r) }
let adj = self.fcx.inh.adjustments.borrow().get(&base_expr.id).cloned();
let (autoderefs, unsize) = match adj {
Some(ty::AdjustDerefRef(adr)) => match adr.autoref {
None => {
assert!(adr.unsize.is_none());
(adr.autoderefs, None)
}
Some(ty::AutoPtr(_, _)) => {
(adr.autoderefs, adr.unsize.map(|target| {
ty::deref(target, false)
.expect("fixup: AutoPtr is not &T").ty
}))
}
Some(_) => {
self.tcx().sess.span_bug(
base_expr.span,
&format!("unexpected adjustment autoref {}",
adr.repr(self.tcx())));
}
},
None => (0, None),
Some(_) => {
self.tcx().sess.span_bug(
base_expr.span,
"unexpected adjustment autoref");
"unexpected adjustment type");
}
};
let adjusted_base_ty =
self.fcx.adjust_expr_ty(
&**base_expr,
Some(&ty::AdjustDerefRef(base_adjustment.clone())));
let (adjusted_base_ty, unsize) = if let Some(target) = unsize {
(target, true)
} else {
(self.fcx.adjust_expr_ty(base_expr,
Some(&ty::AdjustDerefRef(ty::AutoDerefRef {
autoderefs: autoderefs,
autoref: None,
unsize: None
}))), false)
};
let index_expr_ty = self.fcx.expr_ty(&**index_expr);
let result = check::try_index_step(
@ -571,7 +571,8 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
expr,
&**base_expr,
adjusted_base_ty,
base_adjustment,
autoderefs,
unsize,
PreferMutLvalue,
index_expr_ty);
@ -658,14 +659,3 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
self.span, infer::FnCall, value).0
}
}
fn wrap_autoref<'tcx, F>(mut deref: ty::AutoDerefRef<'tcx>,
base_fn: F)
-> ty::AutoDerefRef<'tcx> where
F: FnOnce(Option<Box<ty::AutoRef<'tcx>>>) -> ty::AutoRef<'tcx>,
{
let autoref = mem::replace(&mut deref.autoref, None);
let autoref = autoref.map(|r| box r);
deref.autoref = Some(base_fn(autoref));
deref
}

View File

@ -122,8 +122,7 @@ pub fn lookup_in_trait<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
-> Option<MethodCallee<'tcx>>
{
lookup_in_trait_adjusted(fcx, span, self_expr, m_name, trait_def_id,
ty::AutoDerefRef { autoderefs: 0, autoref: None },
self_ty, opt_input_types)
0, false, self_ty, opt_input_types)
}
/// `lookup_in_trait_adjusted` is used for overloaded operators. It does a very narrow slice of
@ -140,7 +139,8 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
self_expr: Option<&ast::Expr>,
m_name: ast::Name,
trait_def_id: DefId,
autoderefref: ty::AutoDerefRef<'tcx>,
autoderefs: usize,
unsize: bool,
self_ty: Ty<'tcx>,
opt_input_types: Option<Vec<Ty<'tcx>>>)
-> Option<MethodCallee<'tcx>>
@ -241,18 +241,15 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
Some(self_expr) => {
debug!("lookup_in_trait_adjusted: inserting adjustment if needed \
(self-id={}, base adjustment={:?}, explicit_self={:?})",
self_expr.id, autoderefref, method_ty.explicit_self);
(self-id={}, autoderefs={}, unsize={}, explicit_self={:?})",
self_expr.id, autoderefs, unsize,
method_ty.explicit_self);
match method_ty.explicit_self {
ty::ByValueExplicitSelfCategory => {
// Trait method is fn(self), no transformation needed.
if !autoderefref.is_identity() {
fcx.write_adjustment(
self_expr.id,
span,
ty::AdjustDerefRef(autoderefref));
}
assert!(!unsize);
fcx.write_autoderef_adjustment(self_expr.id, autoderefs);
}
ty::ByReferenceExplicitSelfCategory(..) => {
@ -260,14 +257,15 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
// autoref. Pull the region etc out of the type of first argument.
match transformed_self_ty.sty {
ty::ty_rptr(region, ty::mt { mutbl, ty: _ }) => {
let ty::AutoDerefRef { autoderefs, autoref } = autoderefref;
let autoref = autoref.map(|r| box r);
fcx.write_adjustment(
self_expr.id,
span,
fcx.write_adjustment(self_expr.id,
ty::AdjustDerefRef(ty::AutoDerefRef {
autoderefs: autoderefs,
autoref: Some(ty::AutoPtr(*region, mutbl, autoref))
autoref: Some(ty::AutoPtr(region, mutbl)),
unsize: if unsize {
Some(transformed_self_ty)
} else {
None
}
}));
}

View File

@ -31,7 +31,6 @@ use std::rc::Rc;
use util::ppaux::Repr;
use self::CandidateKind::*;
pub use self::PickAdjustment::*;
pub use self::PickKind::*;
struct ProbeContext<'a, 'tcx:'a> {
@ -49,7 +48,8 @@ struct ProbeContext<'a, 'tcx:'a> {
struct CandidateStep<'tcx> {
self_ty: Ty<'tcx>,
adjustment: PickAdjustment,
autoderefs: usize,
unsize: bool
}
struct Candidate<'tcx> {
@ -70,8 +70,24 @@ enum CandidateKind<'tcx> {
pub struct Pick<'tcx> {
pub method_ty: Rc<ty::Method<'tcx>>,
pub adjustment: PickAdjustment,
pub kind: PickKind<'tcx>,
// Indicates that the source expression should be autoderef'd N times
//
// A = expr | *expr | **expr | ...
pub autoderefs: usize,
// Indicates that an autoref is applied after the optional autoderefs
//
// B = A | &A | &mut A
pub autoref: Option<ast::Mutability>,
// Indicates that the source expression should be "unsized" to a
// target type. This should probably eventually go away in favor
// of just coercing method receivers.
//
// C = B | unsize(B)
pub unsize: Option<Ty<'tcx>>,
}
#[derive(Clone,Debug)]
@ -85,30 +101,6 @@ pub enum PickKind<'tcx> {
pub type PickResult<'tcx> = Result<Pick<'tcx>, MethodError>;
// This is a kind of "abstracted" version of ty::AutoAdjustment. The
// difference is that it doesn't embed any regions or other
// specifics. The "confirmation" step recreates those details as
// needed.
#[derive(Clone,Debug)]
pub enum PickAdjustment {
// Indicates that the source expression should be autoderef'd N times
//
// A = expr | *expr | **expr
AutoDeref(usize),
// Indicates that the source expression should be autoderef'd N
// times and then "unsized". This should probably eventually go
// away in favor of just coercing method receivers.
//
// A = unsize(expr | *expr | **expr)
AutoUnsizeLength(/* number of autoderefs */ usize, /* length*/ usize),
// Indicates that an autoref is applied after some number of other adjustments
//
// A = &A | &mut A
AutoRef(ast::Mutability, Box<PickAdjustment>),
}
#[derive(PartialEq, Eq, Copy, Clone)]
pub enum Mode {
// An expression of the form `receiver.method_name(...)`.
@ -149,7 +141,8 @@ pub fn probe<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
} else {
vec![CandidateStep {
self_ty: self_ty,
adjustment: AutoDeref(0)
autoderefs: 0,
unsize: false
}]
};
@ -200,16 +193,21 @@ fn create_steps<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
UnresolvedTypeAction::Error,
NoPreference,
|t, d| {
let adjustment = AutoDeref(d);
steps.push(CandidateStep { self_ty: t, adjustment: adjustment });
steps.push(CandidateStep {
self_ty: t,
autoderefs: d,
unsize: false
});
None::<()> // keep iterating until we can't anymore
});
match final_ty.sty {
ty::ty_vec(elem_ty, Some(len)) => {
ty::ty_vec(elem_ty, Some(_)) => {
let slice_ty = ty::mk_vec(fcx.tcx(), elem_ty, None);
steps.push(CandidateStep {
self_ty: ty::mk_vec(fcx.tcx(), elem_ty, None),
adjustment: AutoUnsizeLength(dereferences, len),
self_ty: slice_ty,
autoderefs: dereferences,
unsize: true
});
}
ty::ty_err => return None,
@ -926,20 +924,21 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
* consuming them for their entire lifetime.
*/
let adjustment = match step.adjustment {
AutoDeref(d) => consider_reborrow(step.self_ty, d),
AutoUnsizeLength(..) | AutoRef(..) => step.adjustment.clone(),
};
return self.pick_method(step.self_ty).map(|r| self.adjust(r, adjustment.clone()));
fn consider_reborrow<'tcx>(ty: Ty<'tcx>, d: usize) -> PickAdjustment {
// Insert a `&*` or `&mut *` if this is a reference type:
match ty.sty {
ty::ty_rptr(_, ref mt) => AutoRef(mt.mutbl, box AutoDeref(d+1)),
_ => AutoDeref(d),
}
if step.unsize {
return None;
}
self.pick_method(step.self_ty).map(|r| r.map(|mut pick| {
pick.autoderefs = step.autoderefs;
// Insert a `&*` or `&mut *` if this is a reference type:
if let ty::ty_rptr(_, mt) = step.self_ty.sty {
pick.autoderefs += 1;
pick.autoref = Some(mt.mutbl);
}
pick
}))
}
fn pick_autorefd_method(&mut self,
@ -947,46 +946,28 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
-> Option<PickResult<'tcx>>
{
let tcx = self.tcx();
self.search_mutabilities(
|m| AutoRef(m, box step.adjustment.clone()),
|m,r| ty::mk_rptr(tcx, tcx.mk_region(r), ty::mt {ty:step.self_ty, mutbl:m}))
}
fn search_mutabilities<F, G>(&mut self,
mut mk_adjustment: F,
mut mk_autoref_ty: G)
-> Option<PickResult<'tcx>> where
F: FnMut(ast::Mutability) -> PickAdjustment,
G: FnMut(ast::Mutability, ty::Region) -> Ty<'tcx>,
{
// In general, during probing we erase regions. See
// `impl_self_ty()` for an explanation.
let region = ty::ReStatic;
let region = tcx.mk_region(ty::ReStatic);
// Search through mutabilities in order to find one where pick works:
[ast::MutImmutable, ast::MutMutable]
.iter()
.flat_map(|&m| {
let autoref_ty = mk_autoref_ty(m, region);
self.pick_method(autoref_ty)
.map(|r| self.adjust(r, mk_adjustment(m)))
.into_iter()
})
.nth(0)
}
fn adjust(&mut self,
result: PickResult<'tcx>,
adjustment: PickAdjustment)
-> PickResult<'tcx>
{
match result {
Err(e) => Err(e),
Ok(mut pick) => {
pick.adjustment = adjustment;
Ok(pick)
}
}
[ast::MutImmutable, ast::MutMutable].iter().filter_map(|&m| {
let autoref_ty = ty::mk_rptr(tcx, region, ty::mt {
ty: step.self_ty,
mutbl: m
});
self.pick_method(autoref_ty).map(|r| r.map(|mut pick| {
pick.autoderefs = step.autoderefs;
pick.autoref = Some(m);
pick.unsize = if step.unsize {
Some(step.self_ty)
} else {
None
};
pick
}))
}).nth(0)
}
fn pick_method(&mut self, self_ty: Ty<'tcx>) -> Option<PickResult<'tcx>> {
@ -1122,8 +1103,10 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
let method_ty = probes[0].method_ty.clone();
Some(Pick {
method_ty: method_ty,
adjustment: AutoDeref(0),
kind: TraitPick(trait_def_id, method_num)
kind: TraitPick(trait_def_id, method_num),
autoderefs: 0,
autoref: None,
unsize: None
})
}
@ -1296,7 +1279,6 @@ impl<'tcx> Candidate<'tcx> {
fn to_unadjusted_pick(&self) -> Pick<'tcx> {
Pick {
method_ty: self.method_ty.clone(),
adjustment: AutoDeref(0),
kind: match self.kind {
InherentImplCandidate(def_id, _) => {
InherentImplPick(def_id)
@ -1323,7 +1305,10 @@ impl<'tcx> Candidate<'tcx> {
ProjectionCandidate(def_id, index) => {
TraitPick(def_id, index)
}
}
},
autoderefs: 0,
autoref: None,
unsize: None
}
}
@ -1392,15 +1377,10 @@ impl<'tcx> Repr<'tcx> for CandidateKind<'tcx> {
impl<'tcx> Repr<'tcx> for CandidateStep<'tcx> {
fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
format!("CandidateStep({},{:?})",
format!("CandidateStep({}, autoderefs={}, unsize={})",
self.self_ty.repr(tcx),
self.adjustment)
}
}
impl<'tcx> Repr<'tcx> for PickAdjustment {
fn repr(&self, _tcx: &ty::ctxt) -> String {
format!("{:?}", self)
self.autoderefs,
self.unsize)
}
}
@ -1412,9 +1392,12 @@ impl<'tcx> Repr<'tcx> for PickKind<'tcx> {
impl<'tcx> Repr<'tcx> for Pick<'tcx> {
fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
format!("Pick(method_ty={}, adjustment={:?}, kind={:?})",
format!("Pick(method_ty={}, autoderefs={},
autoref={}, unsize={}, kind={:?})",
self.method_ty.repr(tcx),
self.adjustment,
self.autoderefs,
self.autoref.repr(tcx),
self.unsize.repr(tcx),
self.kind)
}
}

View File

@ -1292,21 +1292,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pub fn write_autoderef_adjustment(&self,
node_id: ast::NodeId,
span: Span,
derefs: usize) {
if derefs == 0 { return; }
self.write_adjustment(
node_id,
span,
ty::AdjustDerefRef(ty::AutoDerefRef {
autoderefs: derefs,
autoref: None })
autoref: None,
unsize: None
})
);
}
pub fn write_adjustment(&self,
node_id: ast::NodeId,
span: Span,
adj: ty::AutoAdjustment<'tcx>) {
debug!("write_adjustment(node_id={}, adj={})", node_id, adj.repr(self.tcx()));
@ -1314,13 +1312,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return;
}
// Careful: adjustments can imply trait obligations if we are
// casting from a concrete type to an object type. I think
// it'd probably be nicer to move the logic that creates the
// obligation into the code that creates the adjustment, but
// that's a bit awkward, so instead we go digging and pull the
// obligation out here.
self.register_adjustment_obligations(span, &adj);
self.inh.adjustments.borrow_mut().insert(node_id, adj);
}
@ -1383,74 +1374,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
cause)
}
fn register_adjustment_obligations(&self,
span: Span,
adj: &ty::AutoAdjustment<'tcx>) {
match *adj {
ty::AdjustReifyFnPointer(..) => { }
ty::AdjustUnsafeFnPointer => { }
ty::AdjustDerefRef(ref d_r) => {
match d_r.autoref {
Some(ref a_r) => {
self.register_autoref_obligations(span, a_r);
}
None => {}
}
}
}
}
fn register_autoref_obligations(&self,
span: Span,
autoref: &ty::AutoRef<'tcx>) {
match *autoref {
ty::AutoUnsize(ref unsize) => {
self.register_unsize_obligations(span, unsize);
}
ty::AutoPtr(_, _, None) |
ty::AutoUnsafe(_, None) => {
}
ty::AutoPtr(_, _, Some(ref a_r)) |
ty::AutoUnsafe(_, Some(ref a_r)) => {
self.register_autoref_obligations(span, &**a_r)
}
ty::AutoUnsizeUniq(ref unsize) => {
self.register_unsize_obligations(span, unsize);
}
}
}
fn register_unsize_obligations(&self,
span: Span,
unsize: &ty::UnsizeKind<'tcx>) {
debug!("register_unsize_obligations: unsize={:?}", unsize);
match *unsize {
ty::UnsizeLength(..) => {}
ty::UnsizeStruct(ref u, _) => {
self.register_unsize_obligations(span, &**u)
}
ty::UnsizeVtable(ref ty_trait, self_ty) => {
vtable::check_object_safety(self.tcx(), ty_trait, span);
// If the type is `Foo+'a`, ensures that the type
// being cast to `Foo+'a` implements `Foo`:
vtable::register_object_cast_obligations(self,
span,
ty_trait,
self_ty);
// If the type is `Foo+'a`, ensures that the type
// being cast to `Foo+'a` outlives `'a`:
let cause = traits::ObligationCause { span: span,
body_id: self.body_id,
code: traits::ObjectCastObligation(self_ty) };
self.register_region_obligation(self_ty, ty_trait.bounds.region_bound, cause);
}
ty::UnsizeUpcast(_) => { }
}
}
/// Returns the type of `def_id` with all generics replaced by by fresh type/region variables.
/// Also returns the substitution from the type parameters on `def_id` to the fresh variables.
/// Registers any trait obligations specified on `def_id` at the same time.
@ -1881,7 +1804,8 @@ pub fn autoderef<'a, 'tcx, T, F>(fcx: &FnCtxt<'a, 'tcx>,
let mt = match ty::deref(resolved_t, false) {
Some(mt) => Some(mt),
None => {
let method_call = opt_expr.map(|expr| MethodCall::autoderef(expr.id, autoderefs));
let method_call =
opt_expr.map(|expr| MethodCall::autoderef(expr.id, autoderefs as u32));
// Super subtle: it might seem as though we should
// pass `opt_expr` to `try_overloaded_deref`, so that
@ -1972,13 +1896,13 @@ fn make_overloaded_lvalue_return_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
}
}
fn autoderef_for_index<'a, 'tcx, T, F>(fcx: &FnCtxt<'a, 'tcx>,
base_expr: &ast::Expr,
base_ty: Ty<'tcx>,
lvalue_pref: LvaluePreference,
mut step: F)
-> Option<T> where
F: FnMut(Ty<'tcx>, ty::AutoDerefRef<'tcx>) -> Option<T>,
fn lookup_indexing<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
expr: &ast::Expr,
base_expr: &'tcx ast::Expr,
base_ty: Ty<'tcx>,
idx_ty: Ty<'tcx>,
lvalue_pref: LvaluePreference)
-> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)>
{
// FIXME(#18741) -- this is almost but not quite the same as the
// autoderef that normal method probing does. They could likely be
@ -1991,9 +1915,9 @@ fn autoderef_for_index<'a, 'tcx, T, F>(fcx: &FnCtxt<'a, 'tcx>,
UnresolvedTypeAction::Error,
lvalue_pref,
|adj_ty, idx| {
let autoderefref = ty::AutoDerefRef { autoderefs: idx, autoref: None };
step(adj_ty, autoderefref)
});
try_index_step(fcx, MethodCall::expr(expr.id), expr, base_expr,
adj_ty, idx, false, lvalue_pref, idx_ty)
});
if final_mt.is_some() {
return final_mt;
@ -2001,41 +1925,38 @@ fn autoderef_for_index<'a, 'tcx, T, F>(fcx: &FnCtxt<'a, 'tcx>,
// After we have fully autoderef'd, if the resulting type is [T, ..n], then
// do a final unsized coercion to yield [T].
match ty.sty {
ty::ty_vec(element_ty, Some(n)) => {
let adjusted_ty = ty::mk_vec(fcx.tcx(), element_ty, None);
let autoderefref = ty::AutoDerefRef {
autoderefs: autoderefs,
autoref: Some(ty::AutoUnsize(ty::UnsizeLength(n)))
};
step(adjusted_ty, autoderefref)
}
_ => {
None
}
if let ty::ty_vec(element_ty, Some(_)) = ty.sty {
let adjusted_ty = ty::mk_vec(fcx.tcx(), element_ty, None);
try_index_step(fcx, MethodCall::expr(expr.id), expr, base_expr,
adjusted_ty, autoderefs, true, lvalue_pref, idx_ty)
} else {
None
}
}
/// To type-check `base_expr[index_expr]`, we progressively autoderef (and otherwise adjust)
/// `base_expr`, looking for a type which either supports builtin indexing or overloaded indexing.
/// This loop implements one step in that search; the autoderef loop is implemented by
/// `autoderef_for_index`.
/// `lookup_indexing`.
fn try_index_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
method_call: MethodCall,
expr: &ast::Expr,
base_expr: &'tcx ast::Expr,
adjusted_ty: Ty<'tcx>,
adjustment: ty::AutoDerefRef<'tcx>,
autoderefs: usize,
unsize: bool,
lvalue_pref: LvaluePreference,
index_ty: Ty<'tcx>)
-> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)>
{
let tcx = fcx.tcx();
debug!("try_index_step(expr={}, base_expr.id={}, adjusted_ty={}, adjustment={:?}, index_ty={})",
debug!("try_index_step(expr={}, base_expr.id={}, adjusted_ty={}, \
autoderefs={}, unsize={}, index_ty={})",
expr.repr(tcx),
base_expr.repr(tcx),
adjusted_ty.repr(tcx),
adjustment,
autoderefs,
unsize,
index_ty.repr(tcx));
let input_ty = fcx.infcx().next_ty_var();
@ -2044,7 +1965,9 @@ fn try_index_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
match (ty::index(adjusted_ty), &index_ty.sty) {
(Some(ty), &ty::ty_uint(ast::TyUs)) | (Some(ty), &ty::ty_infer(ty::IntVar(_))) => {
debug!("try_index_step: success, using built-in indexing");
fcx.write_adjustment(base_expr.id, base_expr.span, ty::AdjustDerefRef(adjustment));
// If we had `[T; N]`, we should've caught it before unsizing to `[T]`.
assert!(!unsize);
fcx.write_autoderef_adjustment(base_expr.id, autoderefs);
return Some((tcx.types.usize, ty));
}
_ => {}
@ -2058,7 +1981,8 @@ fn try_index_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
Some(&*base_expr),
token::intern("index_mut"),
trait_did,
adjustment.clone(),
autoderefs,
unsize,
adjusted_ty,
Some(vec![input_ty]))
}
@ -2073,7 +1997,8 @@ fn try_index_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
Some(&*base_expr),
token::intern("index"),
trait_did,
adjustment.clone(),
autoderefs,
unsize,
adjusted_ty,
Some(vec![input_ty]))
}
@ -2662,7 +2587,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
match field_ty {
Some(field_ty) => {
fcx.write_ty(expr.id, field_ty);
fcx.write_autoderef_adjustment(base.id, base.span, autoderefs);
fcx.write_autoderef_adjustment(base.id, autoderefs);
return;
}
None => {}
@ -2773,7 +2698,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
match field_ty {
Some(field_ty) => {
fcx.write_ty(expr.id, field_ty);
fcx.write_autoderef_adjustment(base.id, base.span, autoderefs);
fcx.write_autoderef_adjustment(base.id, autoderefs);
return;
}
None => {}
@ -3600,26 +3525,13 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
fcx.write_ty(id, idx_t);
} else {
let base_t = structurally_resolved_type(fcx, expr.span, base_t);
let result =
autoderef_for_index(fcx, &**base, base_t, lvalue_pref, |adj_ty, adj| {
try_index_step(fcx,
MethodCall::expr(expr.id),
expr,
&**base,
adj_ty,
adj,
lvalue_pref,
idx_t)
});
match result {
match lookup_indexing(fcx, expr, base, base_t, idx_t, lvalue_pref) {
Some((index_ty, element_ty)) => {
let idx_expr_ty = fcx.expr_ty(idx);
demand::eqtype(fcx, expr.span, index_ty, idx_expr_ty);
fcx.write_ty(id, element_ty);
}
_ => {
None => {
check_expr_has_type(fcx, &**idx, fcx.tcx().types.err);
fcx.type_error_message(
expr.span,

View File

@ -313,9 +313,15 @@ fn lookup_op_method<'a, 'tcx>(fcx: &'a FnCtxt<'a, 'tcx>,
let method = match trait_did {
Some(trait_did) => {
let noop = ty::AutoDerefRef { autoderefs: 0, autoref: None };
method::lookup_in_trait_adjusted(fcx, expr.span, Some(lhs_expr), opname,
trait_did, noop, lhs_ty, Some(other_tys))
method::lookup_in_trait_adjusted(fcx,
expr.span,
Some(lhs_expr),
opname,
trait_did,
0,
false,
lhs_ty,
Some(other_tys))
}
None => None
};

View File

@ -499,10 +499,10 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
if let Some(adjustment) = rcx.fcx.inh.adjustments.borrow().get(&expr.id) {
debug!("adjustment={:?}", adjustment);
match *adjustment {
ty::AdjustDerefRef(ty::AutoDerefRef {autoderefs, autoref: ref opt_autoref}) => {
ty::AdjustDerefRef(ty::AutoDerefRef {autoderefs, ref autoref, ..}) => {
let expr_ty = rcx.resolve_node_type(expr.id);
constrain_autoderefs(rcx, expr, autoderefs, expr_ty);
if let Some(ref autoref) = *opt_autoref {
if let Some(ref autoref) = *autoref {
link_autoref(rcx, expr, autoderefs, autoref);
// Require that the resulting region encompasses
@ -872,7 +872,7 @@ fn constrain_autoderefs<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>,
let r_deref_expr = ty::ReScope(CodeExtent::from_node_id(deref_expr.id));
for i in 0..derefs {
let method_call = MethodCall::autoderef(deref_expr.id, i);
let method_call = MethodCall::autoderef(deref_expr.id, i as u32);
debug!("constrain_autoderefs: method_call={:?} (of {:?} total)", method_call, derefs);
derefd_ty = match rcx.fcx.inh.method_map.borrow().get(&method_call) {
@ -904,7 +904,7 @@ fn constrain_autoderefs<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>,
let self_cmt = ignore_err!(mc.cat_expr_autoderefd(deref_expr, i));
debug!("constrain_autoderefs: self_cmt={:?}",
self_cmt.repr(rcx.tcx()));
link_region(rcx, deref_expr.span, *r,
link_region(rcx, deref_expr.span, r,
ty::BorrowKind::from_mutbl(m), self_cmt);
}
@ -1102,7 +1102,7 @@ fn link_pattern<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>,
ast::PatVec(_, Some(ref slice_pat), _) => {
match mc.cat_slice_pattern(sub_cmt, &**slice_pat) {
Ok((slice_cmt, slice_mutbl, slice_r)) => {
link_region(rcx, sub_pat.span, slice_r,
link_region(rcx, sub_pat.span, &slice_r,
ty::BorrowKind::from_mutbl(slice_mutbl),
slice_cmt);
}
@ -1127,16 +1127,15 @@ fn link_autoref(rcx: &Rcx,
debug!("expr_cmt={}", expr_cmt.repr(rcx.tcx()));
match *autoref {
ty::AutoPtr(r, m, _) => {
link_region(rcx, expr.span, r, ty::BorrowKind::from_mutbl(m), expr_cmt);
ty::AutoPtr(r, m) => {
link_region(rcx, expr.span, r,
ty::BorrowKind::from_mutbl(m), expr_cmt);
}
ty::AutoUnsafe(m, _) => {
ty::AutoUnsafe(m) => {
let r = ty::ReScope(CodeExtent::from_node_id(expr.id));
link_region(rcx, expr.span, r, ty::BorrowKind::from_mutbl(m), expr_cmt);
link_region(rcx, expr.span, &r, ty::BorrowKind::from_mutbl(m), expr_cmt);
}
ty::AutoUnsizeUniq(_) | ty::AutoUnsize(_) => {}
}
}
@ -1151,7 +1150,7 @@ fn link_by_ref(rcx: &Rcx,
let mc = mc::MemCategorizationContext::new(rcx.fcx);
let expr_cmt = ignore_err!(mc.cat_expr(expr));
let borrow_region = ty::ReScope(callee_scope);
link_region(rcx, expr.span, borrow_region, ty::ImmBorrow, expr_cmt);
link_region(rcx, expr.span, &borrow_region, ty::ImmBorrow, expr_cmt);
}
/// Like `link_region()`, except that the region is extracted from the type of `id`, which must be
@ -1169,7 +1168,7 @@ fn link_region_from_node_type<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>,
let tcx = rcx.fcx.ccx.tcx;
debug!("rptr_ty={}", ty_to_string(tcx, rptr_ty));
let r = ty::ty_region(tcx, span, rptr_ty);
link_region(rcx, span, r, ty::BorrowKind::from_mutbl(mutbl),
link_region(rcx, span, &r, ty::BorrowKind::from_mutbl(mutbl),
cmt_borrowed);
}
}
@ -1179,7 +1178,7 @@ fn link_region_from_node_type<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>,
/// between regions, as explained in `link_reborrowed_region()`.
fn link_region<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>,
span: Span,
borrow_region: ty::Region,
borrow_region: &ty::Region,
borrow_kind: ty::BorrowKind,
borrow_cmt: mc::cmt<'tcx>) {
let mut borrow_cmt = borrow_cmt;
@ -1273,7 +1272,7 @@ fn link_region<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>,
/// recurse and process `ref_cmt` (see case 2 above).
fn link_reborrowed_region<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>,
span: Span,
borrow_region: ty::Region,
borrow_region: &ty::Region,
borrow_kind: ty::BorrowKind,
ref_cmt: mc::cmt<'tcx>,
ref_region: ty::Region,
@ -1318,7 +1317,7 @@ fn link_reborrowed_region<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>,
debug!("link_reborrowed_region: {} <= {}",
borrow_region.repr(rcx.tcx()),
ref_region.repr(rcx.tcx()));
rcx.fcx.mk_subr(cause, borrow_region, ref_region);
rcx.fcx.mk_subr(cause, *borrow_region, ref_region);
// If we end up needing to recurse and establish a region link
// with `ref_cmt`, calculate what borrow kind we will end up

View File

@ -13,9 +13,7 @@ use middle::traits::{self, ObjectSafetyViolation, MethodViolationCode};
use middle::traits::{Obligation, ObligationCause};
use middle::traits::report_fulfillment_errors;
use middle::ty::{self, Ty, AsPredicate};
use syntax::ast;
use syntax::codemap::Span;
use util::nodemap::FnvHashSet;
use util::ppaux::{Repr, UserString};
@ -133,46 +131,9 @@ pub fn register_object_cast_obligations<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
fcx.register_predicate(projection_obligation);
}
// Finally, check that there IS a projection predicate for every associated type.
check_object_type_binds_all_associated_types(fcx.tcx(),
span,
object_trait);
object_trait_ref
}
fn check_object_type_binds_all_associated_types<'tcx>(tcx: &ty::ctxt<'tcx>,
span: Span,
object_trait: &ty::TyTrait<'tcx>)
{
let object_trait_ref =
object_trait.principal_trait_ref_with_self_ty(tcx, tcx.types.err);
let mut associated_types: FnvHashSet<(ast::DefId, ast::Name)> =
traits::supertraits(tcx, object_trait_ref.clone())
.flat_map(|tr| {
let trait_def = ty::lookup_trait_def(tcx, tr.def_id());
trait_def.associated_type_names
.clone()
.into_iter()
.map(move |associated_type_name| (tr.def_id(), associated_type_name))
})
.collect();
for projection_bound in &object_trait.bounds.projection_bounds {
let pair = (projection_bound.0.projection_ty.trait_ref.def_id,
projection_bound.0.projection_ty.item_name);
associated_types.remove(&pair);
}
for (trait_def_id, name) in associated_types {
span_err!(tcx.sess, span, E0191,
"the value of the associated type `{}` (from the trait `{}`) must be specified",
name.user_string(tcx),
ty::item_path_str(tcx, trait_def_id));
}
}
pub fn select_all_fcx_obligations_and_apply_defaults(fcx: &FnCtxt) {
debug!("select_all_fcx_obligations_and_apply_defaults");

View File

@ -285,11 +285,8 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
}
Some(adjustment) => {
let adj_object = ty::adjust_is_object(&adjustment);
let resolved_adjustment = match adjustment {
ty::AdjustReifyFnPointer(def_id) => {
ty::AdjustReifyFnPointer(def_id)
}
ty::AdjustReifyFnPointer => ty::AdjustReifyFnPointer,
ty::AdjustUnsafeFnPointer => {
ty::AdjustUnsafeFnPointer
@ -297,18 +294,14 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
ty::AdjustDerefRef(adj) => {
for autoderef in 0..adj.autoderefs {
let method_call = MethodCall::autoderef(id, autoderef);
self.visit_method_map_entry(reason, method_call);
}
if adj_object {
let method_call = MethodCall::autoobject(id);
let method_call = MethodCall::autoderef(id, autoderef as u32);
self.visit_method_map_entry(reason, method_call);
}
ty::AdjustDerefRef(ty::AutoDerefRef {
autoderefs: adj.autoderefs,
autoref: self.resolve(&adj.autoref, reason),
unsize: self.resolve(&adj.unsize, reason),
})
}
};

View File

@ -34,6 +34,9 @@ fn dent<C:BoxCar>(c: C, color: C::Color) {
fn dent_object<COLOR>(c: BoxCar<Color=COLOR>) {
//~^ ERROR ambiguous associated type
//~| ERROR the value of the associated type `Color` (from the trait `Vehicle`) must be specified
//~| NOTE could derive from `Vehicle`
//~| NOTE could derive from `Box`
}
fn paint<C:BoxCar>(c: C, d: C::Color) {

View File

@ -20,7 +20,7 @@ impl Foo for X {
type Item = bool;
}
fn print_x(_: &Foo, extra: &str) {
fn print_x(_: &Foo<Item=bool>, extra: &str) {
println!("{}", extra);
}

View File

@ -1,4 +1,4 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
@ -9,7 +9,7 @@
// except according to those terms.
// Test that a partially specified trait object with unspecified associated
// type does not ICE.
// type does not type-check.
// pretty-expanded FIXME #23616
@ -20,7 +20,6 @@ trait Foo {
}
fn bar(x: &Foo) {}
// FIXME(#19482) -- `Foo` should specify `A`, but this is not
// currently enforced except at object creation
//~^ ERROR the associated type `A` (from the trait `Foo`) must be specified
pub fn main() {}

View File

@ -14,7 +14,7 @@ use std::ops::Add;
fn main() {
let x = &10 as
//~^ ERROR the value of the associated type `Output` (from the trait `core::ops::Add`) must be specified
&Add;
//~^ ERROR the type parameter `RHS` must be explicitly specified in an object type because its default value `Self` references the type `Self`
//~^^ ERROR the value of the associated type `Output` (from the trait `core::ops::Add`) must be specified
}

View File

@ -14,6 +14,7 @@ use std::ops::{Add, Sub};
type Test = Add +
//~^ ERROR the type parameter `RHS` must be explicitly specified in an object type because its default value `Self` references the type `Self`
//~^^ ERROR the value of the associated type `Output` (from the trait `core::ops::Add`) must be specified [E0191]
Sub;
//~^ ERROR only the builtin traits can be used as closure or object bounds

View File

@ -11,7 +11,8 @@
#![feature(rustc_attrs)]
#![allow(warnings)]
pub fn fail(x: Option<& (Iterator+Send)>) -> Option<&Iterator> {
pub fn fail(x: Option<&(Iterator<Item=()>+Send)>)
-> Option<&Iterator<Item=()>> {
// This call used to trigger an LLVM assertion because the return
// slot had type "Option<&Iterator>"* instead of
// "Option<&(Iterator+Send)>"* -- but this now yields a
@ -23,7 +24,8 @@ pub fn fail(x: Option<& (Iterator+Send)>) -> Option<&Iterator> {
inner(x) //~ ERROR mismatched types
}
pub fn inner(x: Option<& (Iterator+Send)>) -> Option<&(Iterator+Send)> {
pub fn inner(x: Option<&(Iterator<Item=()>+Send)>)
-> Option<&(Iterator<Item=()>+Send)> {
x
}

View File

@ -11,7 +11,7 @@
// Test that the `Fn` traits require `()` form without a feature gate.
fn bar1(x: &Fn<()>) {
fn bar1(x: &Fn<(), Output=()>) {
//~^ ERROR angle-bracket notation is not stable when used with the `Fn` family
}

View File

@ -10,7 +10,7 @@
#![ crate_name = "test" ]
#![allow(unstable)]
#![feature(box_syntax, old_io, rustc_private, core)]
#![feature(box_syntax, old_io, rustc_private, core, zero_one)]
extern crate graphviz;
// A simple rust project
@ -25,7 +25,7 @@ use std::old_io::stdio::println;
use sub::sub2 as msalias;
use sub::sub2;
use sub::sub2::nested_struct as sub_struct;
use std::num::Float;
use std::num::One;
use std::num::cast;
use std::num::{from_int,from_i8,from_i32};
@ -42,7 +42,7 @@ fn test_alias<I: Iterator>(i: Option<<I as Iterator>::Item>) {
let s = sub_struct{ field2: 45, };
// import tests
fn foo(x: &Float) {}
fn foo(x: &One) {}
let _: Option<u8> = from_i32(45);
let x = 42;