Auto merge of #24261 - nrc:coerce-refactor, r=nikomatsakis
@eddyb's preparatory work for DST coercions r? @nikomatsakis
This commit is contained in:
commit
47551b5745
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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 => {}
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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>(
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
};
|
||||
|
@ -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
|
||||
|
@ -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");
|
||||
|
||||
|
@ -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),
|
||||
})
|
||||
}
|
||||
};
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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() {}
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user