From 4e8e64140ff60d1a20d7e54369db714a9fcd8b96 Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Mon, 16 Mar 2015 18:45:01 +0200 Subject: [PATCH 1/4] eddyb's refactoring of coercions/adjustments --- src/librustc/middle/astencode.rs | 274 +++--------- src/librustc/middle/expr_use_visitor.rs | 88 ++-- src/librustc/middle/mem_categorization.rs | 38 +- src/librustc/middle/ty.rs | 326 ++++----------- src/librustc/middle/ty_fold.rs | 31 +- src/librustc_lint/builtin.rs | 4 +- src/librustc_trans/trans/common.rs | 27 -- src/librustc_trans/trans/consts.rs | 115 +++-- src/librustc_trans/trans/expr.rs | 319 +++++--------- src/librustc_trans/trans/type_of.rs | 4 +- src/librustc_typeck/astconv.rs | 50 ++- src/librustc_typeck/check/callee.rs | 37 +- src/librustc_typeck/check/coercion.rs | 395 +++++++++--------- src/librustc_typeck/check/method/confirm.rs | 133 +++--- src/librustc_typeck/check/method/mod.rs | 32 +- src/librustc_typeck/check/method/probe.rs | 167 ++++---- src/librustc_typeck/check/mod.rs | 166 ++------ src/librustc_typeck/check/regionck.rs | 29 +- src/librustc_typeck/check/vtable.rs | 38 -- src/librustc_typeck/check/writeback.rs | 13 +- ...pe-projection-from-multiple-supertraits.rs | 2 + src/test/compile-fail/issue-18819.rs | 2 +- .../issue-19482.rs} | 7 +- src/test/compile-fail/retslot-cast.rs | 6 +- .../unboxed-closure-sugar-not-used-on-fn.rs | 2 +- 25 files changed, 815 insertions(+), 1490 deletions(-) rename src/test/{run-pass/issue-19121.rs => compile-fail/issue-19482.rs} (75%) diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index 998ce0cac4700..2b8540a34b15b 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -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| { - this.emit_enum_variant_arg(0, |this| r.encode(this)); - this.emit_enum_variant_arg(1, |this| m.encode(this)); - this.emit_enum_variant_arg(2, - |this| this.emit_option(|this| this.emit_option_none())) - }) - } - &ty::AutoPtr(r, m, Some(box ref a)) => { - this.emit_enum_variant("AutoPtr", 0, 3, |this| { + &ty::AutoPtr(r, m) => { + this.emit_enum_variant("AutoPtr", 0, 2, |this| { this.emit_enum_variant_arg(0, |this| r.encode(this)); - this.emit_enum_variant_arg(1, |this| m.encode(this)); - this.emit_enum_variant_arg(2, |this| this.emit_option( - |this| this.emit_option_some(|this| Ok(this.emit_autoref(ecx, a))))) - }) - } - &ty::AutoUnsize(ref uk) => { - this.emit_enum_variant("AutoUnsize", 1, 1, |this| { - this.emit_enum_variant_arg(0, |this| Ok(this.emit_unsize_kind(ecx, uk))) + this.emit_enum_variant_arg(1, |this| m.encode(this)) }) } - &ty::AutoUnsizeUniq(ref uk) => { - this.emit_enum_variant("AutoUnsizeUniq", 2, 1, |this| { - this.emit_enum_variant_arg(0, |this| Ok(this.emit_unsize_kind(ecx, uk))) - }) - } - &ty::AutoUnsafe(m, None) => { - this.emit_enum_variant("AutoUnsafe", 3, 2, |this| { - this.emit_enum_variant_arg(0, |this| m.encode(this)); - this.emit_enum_variant_arg(1, - |this| this.emit_option(|this| this.emit_option_none())) - }) - } - &ty::AutoUnsafe(m, Some(box ref a)) => { - this.emit_enum_variant("AutoUnsafe", 3, 2, |this| { - this.emit_enum_variant_arg(0, |this| m.encode(this)); - this.emit_enum_variant_arg(1, |this| this.emit_option( - |this| this.emit_option_some(|this| Ok(this.emit_autoref(ecx, a))))) + &ty::AutoUnsafe(m) => { + this.emit_enum_variant("AutoUnsafe", 1, 1, |this| { + this.emit_enum_variant_arg(0, |this| m.encode(this)) }) } } @@ -1090,55 +1055,26 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> { self.emit_struct("AutoDerefRef", 2, |this| { this.emit_struct_field("autoderefs", 0, |this| auto_deref_ref.autoderefs.encode(this)); + this.emit_struct_field("autoref", 1, |this| { this.emit_option(|this| { match auto_deref_ref.autoref { None => this.emit_option_none(), - Some(ref a) => this.emit_option_some(|this| Ok(this.emit_autoref(ecx, a))), + Some(ref a) => this.emit_option_some(|this| Ok(this.emit_autoref(a))), } }) - }) - }); - } - - fn emit_unsize_kind<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>, - uk: &ty::UnsizeKind<'tcx>) { - use serialize::Encoder; + }); - self.emit_enum("UnsizeKind", |this| { - match *uk { - ty::UnsizeLength(len) => { - this.emit_enum_variant("UnsizeLength", 0, 1, |this| { - this.emit_enum_variant_arg(0, |this| len.encode(this)) - }) - } - ty::UnsizeStruct(box ref uk, idx) => { - this.emit_enum_variant("UnsizeStruct", 1, 2, |this| { - this.emit_enum_variant_arg(0, |this| Ok(this.emit_unsize_kind(ecx, uk))); - this.emit_enum_variant_arg(1, |this| idx.encode(this)) - }) - } - ty::UnsizeVtable(ty::TyTrait { ref principal, - bounds: ref b }, - self_ty) => { - this.emit_enum_variant("UnsizeVtable", 2, 4, |this| { - this.emit_enum_variant_arg(0, |this| { - try!(this.emit_struct_field("principal", 0, |this| { - Ok(this.emit_trait_ref(ecx, &*principal.0)) - })); - this.emit_struct_field("bounds", 1, |this| { - Ok(this.emit_existential_bounds(ecx, b)) - }) - }); - this.emit_enum_variant_arg(1, |this| Ok(this.emit_ty(ecx, self_ty))) - }) - } - ty::UnsizeUpcast(target_ty) => { - this.emit_enum_variant("UnsizeUpcast", 3, 1, |this| { - this.emit_enum_variant_arg(0, |this| Ok(this.emit_ty(ecx, target_ty))) - }) - } - } + this.emit_struct_field("unsize", 2, |this| { + this.emit_option(|this| { + match auto_deref_ref.unsize { + None => this.emit_option_none(), + Some(target) => this.emit_option_some(|this| { + Ok(this.emit_ty(ecx, target)) + }) + } + }) + }) }); } } @@ -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,94 +1620,16 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { this.read_enum_variant_arg(0, |this| Decodable::decode(this)).unwrap(); let m: ast::Mutability = this.read_enum_variant_arg(1, |this| Decodable::decode(this)).unwrap(); - let a: Option> = - this.read_enum_variant_arg(2, |this| this.read_option(|this, b| { - if b { - Ok(Some(box this.read_autoref(dcx))) - } else { - Ok(None) - } - })).unwrap(); - - ty::AutoPtr(r.tr(dcx), m, a) - } - 1 => { - let uk: ty::UnsizeKind = - this.read_enum_variant_arg(0, - |this| Ok(this.read_unsize_kind(dcx))).unwrap(); - - ty::AutoUnsize(uk) - } - 2 => { - let uk: ty::UnsizeKind = - this.read_enum_variant_arg(0, - |this| Ok(this.read_unsize_kind(dcx))).unwrap(); - ty::AutoUnsizeUniq(uk) + ty::AutoPtr(dcx.tcx.mk_region(r.tr(dcx)), m) } - 3 => { + 1 => { let m: ast::Mutability = this.read_enum_variant_arg(0, |this| Decodable::decode(this)).unwrap(); - let a: Option> = - this.read_enum_variant_arg(1, |this| this.read_option(|this, b| { - if b { - Ok(Some(box this.read_autoref(dcx))) - } else { - Ok(None) - } - })).unwrap(); - - ty::AutoUnsafe(m, a) - } - _ => panic!("bad enum variant for ty::AutoRef") - }) - }) - }).unwrap() - } - - fn read_unsize_kind<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) - -> ty::UnsizeKind<'tcx> { - self.read_enum("UnsizeKind", |this| { - let variants = &["UnsizeLength", "UnsizeStruct", "UnsizeVtable", "UnsizeUpcast"]; - this.read_enum_variant(variants, |this, i| { - Ok(match i { - 0 => { - let len: 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) + ty::AutoUnsafe(m) } - 3 => { - let target_ty = - this.read_enum_variant_arg(0, |this| Ok(this.read_ty(dcx))).unwrap(); - ty::UnsizeUpcast(target_ty) - } - _ => panic!("bad enum variant for ty::UnsizeKind") + _ => panic!("bad enum variant for ty::AutoRef") }) }) }).unwrap() @@ -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); } diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 18e634a2dd630..c1c551c2be9eb 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -787,23 +787,30 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { // process. fn walk_adjustment(&mut self, expr: &ast::Expr) { let typer = self.typer; - match typer.adjustments().borrow().get(&expr.id) { - None => { } - Some(adjustment) => { - match *adjustment { - ty::AdjustReifyFnPointer(..) | - ty::AdjustUnsafeFnPointer(..) => { - // Creating a closure/fn-pointer consumes the - // input and stores it into the resulting - // rvalue. - debug!("walk_adjustment(AutoAddEnv|AdjustReifyFnPointer)"); + if let Some(adjustment) = typer.adjustments().borrow().get(&expr.id) { + match *adjustment { + ty::AdjustReifyFnPointer | + ty::AdjustUnsafeFnPointer => { + // Creating a closure/fn-pointer or unsizing consumes + // the input and stores it into the resulting rvalue. + debug!("walk_adjustment(AdjustReifyFnPointer|AdjustUnsafeFnPointer)"); + let cmt_unadjusted = + return_if_err!(self.mc.cat_expr_unadjusted(expr)); + self.delegate_consume(expr.id, expr.span, cmt_unadjusted); + } + ty::AdjustDerefRef(ref adj) => { + self.walk_autoderefs(expr, adj.autoderefs); + if let Some(ref r) = adj.autoref { + self.walk_autoref(expr, r, adj.autoderefs); + } else if adj.unsize.is_some() { + assert!(adj.autoderefs == 0, + format!("Expected no derefs with \ + unsize AutoRefs, found: {}", + adj.repr(self.tcx()))); let cmt_unadjusted = return_if_err!(self.mc.cat_expr_unadjusted(expr)); self.delegate_consume(expr.id, expr.span, cmt_unadjusted); } - ty::AdjustDerefRef(ref adj) => { - self.walk_autoderefref(expr, adj); - } } } } @@ -818,7 +825,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) => { @@ -903,59 +910,22 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { } }; - match *autoref { - ty::AutoPtr(r, m, ref baseref) => { - let cmt_base = self.walk_autoref_recursively(expr, cmt_derefd, 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())); + debug!("walk_autoref: expr.id={} cmt_base={}", + expr.id, + cmt_base.repr(self.tcx())); + match *autoref { + ty::AutoPtr(r, m) => { self.delegate.borrow(expr.id, expr.span, - cmt_base, - r, + cmt_derefd, + *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); diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 6c7dc61109fb5..003306fe558a1 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -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): {}", + autoref: None, unsize: None, autoderefs, ..}) => { + // Equivalent to *expr or something similar. + self.cat_expr_autoderefd(expr, autoderefs) + } + + ty::AdjustReifyFnPointer | + ty::AdjustUnsafeFnPointer | + ty::AdjustDerefRef(_) => { + debug!("cat_expr({}): {}", + adjustment.repr(self.tcx()), expr.repr(self.tcx())); - // Equivalent to &*expr or something similar. // Result is an rvalue. let expr_ty = try!(self.expr_ty_adjusted(expr)); Ok(self.cat_rvalue_node(expr.id(), expr.span(), expr_ty)) } - - ty::AdjustDerefRef( - ty::AutoDerefRef { - autoref: None, autoderefs}) => { - // Equivalent to *expr or something similar. - self.cat_expr_autoderefd(expr, autoderefs) - } } } } @@ -928,15 +918,9 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> { deref_cnt: usize, deref_context: DerefKindContext) -> McResult> { - let adjustment = match self.typer.adjustments().borrow().get(&node.id()) { - Some(adj) if ty::adjust_is_object(adj) => ty::AutoObject, - _ if deref_cnt != 0 => ty::AutoDeref(deref_cnt), - _ => ty::NoAdjustment - }; - let method_call = ty::MethodCall { expr_id: node.id(), - adjustment: adjustment + autoderef: deref_cnt as u32 }; let method_ty = self.typer.node_method_ty(method_call); diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 0a747ba881fd6..ccb0fa7bfdb40 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -20,7 +20,6 @@ pub use self::ClosureKind::*; pub use self::Variance::*; pub use self::AutoAdjustment::*; pub use self::Representability::*; -pub use self::UnsizeKind::*; pub use self::AutoRef::*; pub use self::ExprKind::*; pub use self::DtorKind::*; @@ -33,7 +32,6 @@ pub use self::ImplOrTraitItem::*; pub use self::BoundRegion::*; pub use self::sty::*; pub use self::IntVarValue::*; -pub use self::ExprAdjustment::*; pub use self::vtable_origin::*; pub use self::MethodOrigin::*; pub use self::CopyImplementationError::*; @@ -283,145 +281,34 @@ pub enum Variance { Bivariant, // T <: T -- e.g., unused type parameter } -#[derive(Clone, Debug)] +#[derive(Copy, Clone, Debug)] pub enum AutoAdjustment<'tcx> { - AdjustReifyFnPointer(ast::DefId), // go from a fn-item type to a fn-pointer type + AdjustReifyFnPointer, // go from a fn-item type to a fn-pointer type AdjustUnsafeFnPointer, // go from a safe fn pointer to an unsafe fn pointer - AdjustDerefRef(AutoDerefRef<'tcx>) -} - -#[derive(Clone, PartialEq, Debug)] -pub enum UnsizeKind<'tcx> { - // [T, ..n] -> [T], the 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>, usize), - UnsizeVtable(TyTrait<'tcx>, /* the self type of the trait */ Ty<'tcx>), - UnsizeUpcast(Ty<'tcx>), + AdjustDerefRef(AutoDerefRef<'tcx>), } -#[derive(Clone, Debug)] +#[derive(Copy, Clone, Debug)] pub struct AutoDerefRef<'tcx> { + /// Apply a number of dereferences, producing an lvalue. pub autoderefs: usize, - pub autoref: Option> + + /// Produce a pointer/reference from the value. + pub autoref: Option>, + + /// Unsize a pointer/reference value, e.g. &[T; n] to &[T]. + /// The stored type is the target pointer type. + pub unsize: Option>, } -#[derive(Clone, PartialEq, Debug)] +#[derive(Copy, Clone, PartialEq, Debug)] pub enum AutoRef<'tcx> { /// Convert from T to &T - /// The third field allows us to wrap other AutoRef adjustments. - AutoPtr(Region, ast::Mutability, Option>>), - - /// Convert [T, ..n] to [T] (or similar, depending on the kind) - AutoUnsize(UnsizeKind<'tcx>), - - /// Convert Box<[T, ..n]> to Box<[T]> or something similar in a Box. - /// With DST and Box a library type, this should be replaced by UnsizeStruct. - AutoUnsizeUniq(UnsizeKind<'tcx>), + AutoPtr(&'tcx Region, ast::Mutability), /// Convert from T to *T /// Value to thin pointer - /// The second field allows us to wrap other AutoRef adjustments. - AutoUnsafe(ast::Mutability, Option>>), -} - -// Ugly little helper function. The first bool in the returned tuple is true if -// there is an 'unsize to trait object' adjustment at the bottom of the -// adjustment. If that is surrounded by an AutoPtr, then we also return the -// region of the AutoPtr (in the third argument). The second bool is true if the -// adjustment is unique. -fn autoref_object_region(autoref: &AutoRef) -> (bool, bool, Option) { - fn unsize_kind_is_object(k: &UnsizeKind) -> bool { - match k { - &UnsizeVtable(..) => true, - &UnsizeStruct(box ref k, _) => unsize_kind_is_object(k), - _ => false - } - } - - match autoref { - &AutoUnsize(ref k) => (unsize_kind_is_object(k), false, None), - &AutoUnsizeUniq(ref k) => (unsize_kind_is_object(k), true, None), - &AutoPtr(adj_r, _, Some(box ref autoref)) => { - let (b, u, r) = autoref_object_region(autoref); - if r.is_some() || u { - (b, u, r) - } else { - (b, u, Some(adj_r)) - } - } - &AutoUnsafe(_, Some(box ref autoref)) => autoref_object_region(autoref), - _ => (false, false, None) - } -} - -// If the adjustment introduces a borrowed reference to a trait object, then -// returns the region of the borrowed reference. -pub fn adjusted_object_region(adj: &AutoAdjustment) -> Option { - match adj { - &AdjustDerefRef(AutoDerefRef{autoref: Some(ref autoref), ..}) => { - let (b, _, r) = autoref_object_region(autoref); - if b { - r - } else { - None - } - } - _ => None - } -} - -// Returns true if there is a trait cast at the bottom of the adjustment. -pub fn adjust_is_object(adj: &AutoAdjustment) -> bool { - match adj { - &AdjustDerefRef(AutoDerefRef{autoref: Some(ref autoref), ..}) => { - let (b, _, _) = autoref_object_region(autoref); - b - } - _ => false - } -} - -// If possible, returns the type expected from the given adjustment. This is not -// possible if the adjustment depends on the type of the adjusted expression. -pub fn type_of_adjust<'tcx>(cx: &ctxt<'tcx>, adj: &AutoAdjustment<'tcx>) -> Option> { - fn type_of_autoref<'tcx>(cx: &ctxt<'tcx>, autoref: &AutoRef<'tcx>) -> Option> { - match autoref { - &AutoUnsize(ref k) => match k { - &UnsizeVtable(TyTrait { ref principal, ref bounds }, _) => { - Some(mk_trait(cx, principal.clone(), bounds.clone())) - } - _ => None - }, - &AutoUnsizeUniq(ref k) => match k { - &UnsizeVtable(TyTrait { ref principal, ref bounds }, _) => { - Some(mk_uniq(cx, mk_trait(cx, principal.clone(), bounds.clone()))) - } - _ => None - }, - &AutoPtr(r, m, Some(box ref autoref)) => { - match type_of_autoref(cx, autoref) { - Some(ty) => Some(mk_rptr(cx, cx.mk_region(r), mt {mutbl: m, ty: ty})), - None => None - } - } - &AutoUnsafe(m, Some(box ref autoref)) => { - match type_of_autoref(cx, autoref) { - Some(ty) => Some(mk_ptr(cx, mt {mutbl: m, ty: ty})), - None => None - } - } - _ => None - } - } - - match adj { - &AdjustDerefRef(AutoDerefRef{autoref: Some(ref autoref), ..}) => { - type_of_autoref(cx, autoref) - } - _ => None - } + AutoUnsafe(ast::Mutability), } #[derive(Clone, Copy, RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Debug)] @@ -509,35 +396,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 - } - } - - pub fn autoobject(id: ast::NodeId) -> MethodCall { - MethodCall { - expr_id: id, - adjustment: AutoObject + autoderef: 0 } } pub fn autoderef(expr_id: ast::NodeId, autoderef: usize) -> MethodCall { MethodCall { expr_id: expr_id, - adjustment: AutoDeref(1 + autoderef) + autoderef: 1 + autoderef } } } @@ -4581,16 +4454,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,7 +4484,7 @@ pub fn adjust_ty<'tcx, F>(cx: &ctxt<'tcx>, if !ty::type_is_error(adjusted_ty) { for i in 0..adj.autoderefs { - let method_call = MethodCall::autoderef(expr_id, i); + let method_call = MethodCall::autoderef(expr_id, i as u32); match method_type(method_call) { Some(method_ty) => { // overloaded deref operators have all late-bound @@ -4639,7 +4511,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 +4524,16 @@ pub fn adjust_ty<'tcx, F>(cx: &ctxt<'tcx>, } pub fn adjust_ty_for_autoref<'tcx>(cx: &ctxt<'tcx>, - span: Span, ty: Ty<'tcx>, - autoref: Option<&AutoRef<'tcx>>) - -> Ty<'tcx> -{ + autoref: Option>) + -> Ty<'tcx> { match autoref { None => ty, - - Some(&AutoPtr(r, m, ref a)) => { - let adjusted_ty = match a { - &Some(box ref a) => adjust_ty_for_autoref(cx, span, ty, Some(a)), - &None => ty - }; - mk_rptr(cx, cx.mk_region(r), mt { - ty: adjusted_ty, - mutbl: m - }) + Some(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 +5790,47 @@ pub fn tup_fields<'tcx>(v: &[Ty<'tcx>]) -> Vec> { }).collect() } +/// Returns the deeply last field of nested structures, or the same type, +/// if not a structure at all. Corresponds to the only possible unsized +/// field, and its type can be used to determine unsizing strategy. +pub fn struct_tail<'tcx>(cx: &ctxt<'tcx>, mut ty: Ty<'tcx>) -> Ty<'tcx> { + while let ty_struct(def_id, substs) = ty.sty { + match struct_fields(cx, def_id, substs).last() { + Some(f) => ty = f.mt.ty, + None => break + } + } + ty +} + +/// Same as applying struct_tail on `source` and `target`, but only +/// keeps going as long as the two types are instances of the same +/// structure definitions. +/// For `(Foo>, Foo)`, the result will be `(Foo, Trait)`, +/// whereas struct_tail produces `T`, and `Trait`, respectively. +pub fn struct_lockstep_tails<'tcx>(cx: &ctxt<'tcx>, + source: Ty<'tcx>, + target: Ty<'tcx>) + -> (Ty<'tcx>, Ty<'tcx>) { + let (mut a, mut b) = (source, target); + while let (&ty_struct(a_did, a_substs), &ty_struct(b_did, b_substs)) = (&a.sty, &b.sty) { + if a_did != b_did { + continue; + } + if let Some(a_f) = struct_fields(cx, a_did, a_substs).last() { + if let Some(b_f) = struct_fields(cx, b_did, b_substs).last() { + a = a_f.mt.ty; + b = b_f.mt.ty; + } else { + break; + } + } else { + break; + } + } + (a, b) +} + #[derive(Copy, Clone)] pub struct ClosureUpvar<'tcx> { pub def: def::Def, @@ -6881,8 +6741,8 @@ pub fn with_freevars(tcx: &ty::ctxt, fid: ast::NodeId, f: F) -> T where impl<'tcx> AutoAdjustment<'tcx> { pub fn is_identity(&self) -> bool { match *self { - AdjustReifyFnPointer(..) => false, - AdjustUnsafeFnPointer(..) => false, + AdjustReifyFnPointer | + AdjustUnsafeFnPointer => false, AdjustDerefRef(ref r) => r.is_identity(), } } @@ -6890,7 +6750,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 +6911,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 +6924,21 @@ impl<'tcx> Repr<'tcx> for AutoAdjustment<'tcx> { } } -impl<'tcx> Repr<'tcx> for UnsizeKind<'tcx> { - fn repr(&self, tcx: &ctxt<'tcx>) -> String { - match *self { - UnsizeLength(n) => format!("UnsizeLength({})", n), - UnsizeStruct(ref k, n) => format!("UnsizeStruct({},{})", k.repr(tcx), n), - UnsizeVtable(ref a, ref b) => format!("UnsizeVtable({},{})", a.repr(tcx), b.repr(tcx)), - UnsizeUpcast(ref a) => format!("UnsizeUpcast({})", a.repr(tcx)), - } - } -} - impl<'tcx> Repr<'tcx> for AutoDerefRef<'tcx> { fn repr(&self, tcx: &ctxt<'tcx>) -> String { - format!("AutoDerefRef({}, {})", self.autoderefs, self.autoref.repr(tcx)) + format!("AutoDerefRef({}, unsize={}, {})", + self.autoderefs, self.unsize.repr(tcx), self.autoref.repr(tcx)) } } impl<'tcx> Repr<'tcx> for AutoRef<'tcx> { fn repr(&self, tcx: &ctxt<'tcx>) -> String { match *self { - AutoPtr(a, b, ref c) => { - format!("AutoPtr({},{:?},{})", a.repr(tcx), b, c.repr(tcx)) - } - AutoUnsize(ref a) => { - format!("AutoUnsize({})", a.repr(tcx)) - } - AutoUnsizeUniq(ref a) => { - format!("AutoUnsizeUniq({})", a.repr(tcx)) + AutoPtr(a, b) => { + format!("AutoPtr({},{:?})", a.repr(tcx), b) } - AutoUnsafe(ref a, ref b) => { - format!("AutoUnsafe({:?},{})", a, b.repr(tcx)) + AutoUnsafe(ref a) => { + format!("AutoUnsafe({:?})", a) } } } diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs index 5f77574f65ed4..19a82e3f35492 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -477,24 +477,6 @@ impl<'tcx> TypeFoldable<'tcx> for ty::InstantiatedPredicates<'tcx> { } } -impl<'tcx> TypeFoldable<'tcx> for ty::UnsizeKind<'tcx> { - fn fold_with>(&self, folder: &mut F) -> ty::UnsizeKind<'tcx> { - match *self { - ty::UnsizeLength(len) => ty::UnsizeLength(len), - ty::UnsizeStruct(box ref k, n) => ty::UnsizeStruct(box k.fold_with(folder), n), - ty::UnsizeVtable(ty::TyTrait{ref principal, ref bounds}, self_ty) => { - ty::UnsizeVtable( - ty::TyTrait { - principal: principal.fold_with(folder), - bounds: bounds.fold_with(folder), - }, - self_ty.fold_with(folder)) - } - ty::UnsizeUpcast(t) => ty::UnsizeUpcast(t.fold_with(folder)), - } - } -} - impl<'tcx,O> TypeFoldable<'tcx> for traits::Obligation<'tcx,O> where O : TypeFoldable<'tcx> { @@ -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::AutoUnsafe(m, None) => ty::AutoUnsafe(m, None), - ty::AutoUnsafe(m, Some(ref a)) => { - ty::AutoUnsafe(m, Some(box super_fold_autoref(this, &**a))) + ty::AutoPtr(r, m) => { + let r = r.fold_with(this); + ty::AutoPtr(this.tcx().mk_region(r), m) } - ty::AutoUnsize(ref k) => ty::AutoUnsize(k.fold_with(this)), - ty::AutoUnsizeUniq(ref k) => ty::AutoUnsizeUniq(k.fold_with(this)), + ty::AutoUnsafe(m) => ty::AutoUnsafe(m) } } diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 3bb737ddc1279..c1d71671eb3f6 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -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"); } diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs index 168a294159d4f..2ba963a42efbe 100644 --- a/src/librustc_trans/trans/common.rs +++ b/src/librustc_trans/trans/common.rs @@ -146,33 +146,6 @@ pub fn type_is_fat_ptr<'tcx>(cx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool { } } -// Return the smallest part of `ty` which is unsized. Fails if `ty` is sized. -// 'Smallest' here means component of the static representation of the type; not -// the size of an object at runtime. -pub fn unsized_part_of_type<'tcx>(cx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { - match ty.sty { - ty::ty_str | ty::ty_trait(..) | ty::ty_vec(..) => ty, - ty::ty_struct(def_id, substs) => { - let unsized_fields: Vec<_> = - ty::struct_fields(cx, def_id, substs) - .iter() - .map(|f| f.mt.ty) - .filter(|ty| !type_is_sized(cx, *ty)) - .collect(); - - // Exactly one of the fields must be unsized. - assert!(unsized_fields.len() == 1); - - unsized_part_of_type(cx, unsized_fields[0]) - } - _ => { - assert!(type_is_sized(cx, ty), - "unsized_part_of_type failed even though ty is unsized"); - panic!("called unsized_part_of_type with sized ty"); - } - } -} - // Some things don't need cleanups during unwinding because the // task can free them all at once later. Currently only things // that only contain scalars and shared boxes can avoid unwind diff --git a/src/librustc_trans/trans/consts.rs b/src/librustc_trans/trans/consts.rs index aff5f597bfd9f..cd56d19624224 100644 --- a/src/librustc_trans/trans/consts.rs +++ b/src/librustc_trans/trans/consts.rs @@ -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])); - - let unsized_ty = ty::unsize_ty(cx.tcx(), ty, k, e.span); - let ptr_ty = type_of::in_memory_type_of(cx, unsized_ty).ptr_to(); - let base = ptrcast(llconst, ptr_ty); - - let prev_const = cx.const_unsized().borrow_mut() - .insert(base, llconst); - assert!(prev_const.is_none() || prev_const == Some(llconst)); - assert_eq!(abi::FAT_PTR_ADDR, 0); - assert_eq!(abi::FAT_PTR_EXTRA, 1); - llconst = C_struct(cx, &[base, info], false); - } - Some(autoref) => { - cx.sess().span_bug(e.span, - &format!("unimplemented const second autoref {:?}", autoref)) - } + } else { + let (dv, dt) = const_deref(cx, llconst, ty); + llconst = dv; + + // If we derefed a fat pointer then we will have an + // open type here. So we need to update the type with + // the one returned from const_deref. + ety_adjusted = dt; + } + + if let Some(target) = adj.unsize { + let target = monomorphize::apply_param_substs(cx.tcx(), + param_substs, + &target); + + let pointee_ty = ty::deref(ty, true) + .expect("consts: unsizing got non-pointer type").ty; + let (base, old_info) = if !type_is_sized(cx.tcx(), pointee_ty) { + // Normally, the source is a thin pointer and we are + // adding extra info to make a fat pointer. The exception + // is when we are upcasting an existing object fat pointer + // to use a different vtable. In that case, we want to + // load out the original data pointer so we can repackage + // it. + (const_get_elt(cx, llconst, &[abi::FAT_PTR_ADDR as u32]), + Some(const_get_elt(cx, llconst, &[abi::FAT_PTR_EXTRA as u32]))) + } else { + (llconst, None) + }; + + let unsized_ty = ty::deref(target, true) + .expect("consts: unsizing got non-pointer target type").ty; + let ptr_ty = type_of::in_memory_type_of(cx, unsized_ty).ptr_to(); + let base = ptrcast(base, ptr_ty); + let info = expr::unsized_info(cx, pointee_ty, unsized_ty, + old_info, param_substs); + + let prev_const = cx.const_unsized().borrow_mut() + .insert(base, llconst); + assert!(prev_const.is_none() || prev_const == Some(llconst)); + assert_eq!(abi::FAT_PTR_ADDR, 0); + assert_eq!(abi::FAT_PTR_EXTRA, 1); + llconst = C_struct(cx, &[base, info], false); } } None => {} diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs index 757f3dc1db426..5d9d45e02a980 100644 --- a/src/librustc_trans/trans/expr.rs +++ b/src/librustc_trans/trans/expr.rs @@ -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, .. }, _) => { +/// Retrieve the information we are losing (making dynamic) in an unsizing +/// adjustment. +/// +/// The `old_info` argument is a bit funny. It is intended for use +/// in an upcast, where the new vtable for an object will be drived +/// from the old one. +pub fn unsized_info<'ccx, 'tcx>(ccx: &CrateContext<'ccx, 'tcx>, + source: Ty<'tcx>, + target: Ty<'tcx>, + old_info: Option, + param_substs: &'tcx 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. + old_info.expect("unsized_info: missing old info for trait upcast") + } + (_, &ty::ty_trait(box ty::TyTrait { ref principal, .. })) => { // Note that we preserve binding levels here: - let substs = principal.0.substs.with_self_ty(unadjusted_ty).erase_regions(); + let substs = principal.0.substs.with_self_ty(source).erase_regions(); let substs = ccx.tcx().mk_substs(substs); let trait_ref = ty::Binder(Rc::new(ty::TraitRef { def_id: principal.def_id(), - substs: substs })); - let trait_ref = monomorphize::apply_param_substs(ccx.tcx(), - param_substs, - &trait_ref); + substs: substs })); consts::ptrcast(meth::get_vtable(ccx, trait_ref, param_substs), Type::vtable_ptr(ccx)) } - &ty::UnsizeUpcast(_) => { - // For now, upcasts are limited to changes in marker - // traits, and hence never actually require an actual - // change to the vtable. - mk_upcast_vtable() - } + _ => ccx.sess().bug(&format!("unsized_info: invalid unsizing {} -> {}", + source.repr(ccx.tcx()), + target.repr(ccx.tcx()))) } } @@ -379,7 +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 to &T, etc. - ty::ty_rptr(..) => { - let method_call = MethodCall::autoderef(expr.id, adj.autoderefs-1); - let method = bcx.tcx().method_map.borrow().get(&method_call).is_some(); - if method { - // Don't skip an overloaded deref. - (adj.autoderefs, true) - } else { - (adj.autoderefs - 1, false) - } + // a different region or mutability, but we don't care here). + match datum.ty.sty { + // Don't skip a conversion from Box to &T, etc. + ty::ty_rptr(..) => { + let method_call = MethodCall::autoderef(expr.id, 0); + if bcx.tcx().method_map.borrow().contains_key(&method_call) { + // Don't skip an overloaded deref. + 0 + } else { + 1 } - _ => (adj.autoderefs, true), } + _ => 0 } - _ => (adj.autoderefs, true) + } else { + 0 }; - if autoderefs > 0 { + if adj.autoderefs > skip_reborrows { // Schedule cleanup. let lval = unpack_datum!(bcx, datum.to_lvalue_datum(bcx, "auto_deref", expr.id)); - datum = unpack_datum!( - bcx, deref_multiple(bcx, expr, lval.to_expr_datum(), autoderefs)); + datum = unpack_datum!(bcx, deref_multiple(bcx, expr, + lval.to_expr_datum(), + adj.autoderefs - skip_reborrows)); } // (You might think there is a more elegant way to do this than a - // use_autoref bool, but then you remember that the borrow checker exists). - if let (true, &Some(ref a)) = (use_autoref, &adj.autoref) { - datum = unpack_datum!(bcx, apply_autoref(a, - bcx, - expr, - datum)); + // 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 info = unsized_info_bcx(bcx, k, expr.id, datum_ty, datum.val, bcx.fcx.param_substs); - - // Arrange cleanup - let lval = unpack_datum!(bcx, datum.to_lvalue_datum(bcx, "into_fat_ptr", expr.id)); + 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())); - // 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) { + // 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")); + + 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` pointer that we have into // a `&T` pointer. We can then proceed down the normal // path (below) to dereference that `&T`. - let datum = match method_call.adjustment { + let datum = if method_call.autoderef == 0 { + datum + } else { // Always perform an AutoPtr when applying an overloaded auto-deref - ty::AutoDeref(_) => unpack_datum!(bcx, auto_ref(bcx, datum, expr)), - _ => datum + unpack_datum!(bcx, auto_ref(bcx, datum, expr)) }; let ref_ty = // invoked methods have their LB regions instantiated diff --git a/src/librustc_trans/trans/type_of.rs b/src/librustc_trans/trans/type_of.rs index 2e577a0bd19b0..8257dab20facb 100644 --- a/src/librustc_trans/trans/type_of.rs +++ b/src/librustc_trans/trans/type_of.rs @@ -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) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 355b866013b63..ff22127fdc615 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -59,6 +59,7 @@ use middle::ty::{self, RegionEscape, Ty}; use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope, 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>( diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index f54c0b7f8c4a4..b065eb2d2741c 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -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> { // 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 diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index ced6cec3ef0dc..acdeda3d546bd 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -61,21 +61,26 @@ //! 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, + trace: TypeTrace<'tcx>, + unsizing_obligation: Cell>> } type CoerceResult<'tcx> = RelateResult<'tcx, Option>>; @@ -144,11 +149,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 +189,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 +232,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { Some(_) => { Ok(Some(AdjustDerefRef(AutoDerefRef { autoderefs: autoderefs, - autoref: autoref + autoref: autoref, + unsize: None }))) } None => { @@ -257,183 +261,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 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 (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.trace.clone()); + 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.fcx.infcx().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> { 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 + 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(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 => {} + } + (_, &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); } - result } - _ => None + None } - }) - }) + _ => None + } + })) } fn coerce_from_fn_pointer(&self, @@ -451,29 +420,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 +452,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 +478,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 +497,61 @@ 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(|| { - fcx.infcx().commit_if_ok(|_| { - Coerce { + let (adjustment, unsizing_obligation) = try!(indent(|| { + fcx.infcx().commit_if_ok(|| { + let origin = infer::ExprAssignable(expr.span); + let coerce = Coerce { fcx: fcx, origin: infer::ExprAssignable(expr.span), - }.coerce(expr, a, b) + trace: infer::TypeTrace::types(origin, false, 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) } } diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 6aefcf5a47cc6..4e62542854fa8 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -24,7 +24,6 @@ use middle::infer::InferCtxt; use syntax::ast; use syntax::codemap::Span; use std::rc::Rc; -use std::mem; use std::iter::repeat; use util::ppaux::Repr; @@ -84,7 +83,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { -> MethodCallee<'tcx> { // Adjust the self expression the user provided and obtain the adjusted type. - let self_ty = self.adjust_self_ty(unadjusted_self_ty, &pick.adjustment); + let self_ty = self.adjust_self_ty(unadjusted_self_ty, &pick); // Make sure nobody calls `drop()` explicitly. self.enforce_illegal_method_limitations(&pick); @@ -134,11 +133,20 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { fn adjust_self_ty(&mut self, unadjusted_self_ty: Ty<'tcx>, - adjustment: &probe::PickAdjustment) + pick: &probe::Pick<'tcx>) -> Ty<'tcx> { - // Construct the actual adjustment and write it into the table - let auto_deref_ref = self.create_ty_adjustment(adjustment); + let (autoref, unsize) = if let Some(mutbl) = pick.autoref { + let region = self.infcx().next_region_var(infer::Autoref(self.span)); + let autoref = ty::AutoPtr(self.tcx().mk_region(region), mutbl); + (Some(autoref), pick.unsize.map(|target| { + ty::adjust_ty_for_autoref(self.tcx(), target, Some(autoref)) + })) + } else { + // No unsizing should be performed without autoref. + assert!(pick.unsize.is_none()); + (None, None) + }; // Commit the autoderefs by calling `autoderef again, but this // time writing the results into the various tables. @@ -149,47 +157,27 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { UnresolvedTypeAction::Error, NoPreference, |_, n| { - if n == auto_deref_ref.autoderefs { + if n == pick.autoderefs { Some(()) } else { None } }); - assert_eq!(n, auto_deref_ref.autoderefs); + assert_eq!(n, pick.autoderefs); assert_eq!(result, Some(())); - let final_ty = - ty::adjust_ty_for_autoref(self.tcx(), self.span, autoderefd_ty, - auto_deref_ref.autoref.as_ref()); - // Write out the final adjustment. - self.fcx.write_adjustment(self.self_expr.id, self.span, ty::AdjustDerefRef(auto_deref_ref)); - - final_ty - } + self.fcx.write_adjustment(self.self_expr.id, + ty::AdjustDerefRef(ty::AutoDerefRef { + autoderefs: pick.autoderefs, + autoref: autoref, + unsize: unsize + })); - fn create_ty_adjustment(&mut self, - adjustment: &probe::PickAdjustment) - -> ty::AutoDerefRef<'tcx> - { - match *adjustment { - probe::AutoDeref(num) => { - ty::AutoDerefRef { - autoderefs: num, - autoref: None, - } - } - probe::AutoUnsizeLength(autoderefs, len) => { - ty::AutoDerefRef { - autoderefs: autoderefs, - autoref: Some(ty::AutoUnsize(ty::UnsizeLength(len))), - } - } - probe::AutoRef(mutability, ref sub_adjustment) => { - let deref = self.create_ty_adjustment(&**sub_adjustment); - let region = self.infcx().next_region_var(infer::Autoref(self.span)); - wrap_autoref(deref, |base| ty::AutoPtr(region, mutability, base)) - } + if let Some(target) = unsize { + target + } else { + ty::adjust_ty_for_autoref(self.tcx(), autoderefd_ty, autoref) } } @@ -499,10 +487,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { .adjustments .borrow() .get(&expr.id) { - Some(&ty::AdjustDerefRef(ty::AutoDerefRef { - autoderefs: autoderef_count, - autoref: _ - })) => autoderef_count, + Some(&ty::AdjustDerefRef(ref adj)) => adj.autoderefs, Some(_) | None => 0, }; @@ -529,17 +514,6 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { if i != 0 { match expr.node { ast::ExprIndex(ref base_expr, ref index_expr) => { - let mut base_adjustment = - match self.fcx.inh.adjustments.borrow().get(&base_expr.id) { - Some(&ty::AdjustDerefRef(ref adr)) => (*adr).clone(), - None => ty::AutoDerefRef { autoderefs: 0, autoref: None }, - Some(_) => { - self.tcx().sess.span_bug( - base_expr.span, - "unexpected adjustment type"); - } - }; - // If this is an overloaded index, the // adjustment will include an extra layer of // autoref because the method is an &self/&mut @@ -548,21 +522,44 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { // expects. This is annoying and horrible. We // ought to recode this routine so it doesn't // (ab)use the normal type checking paths. - base_adjustment.autoref = match base_adjustment.autoref { - None => { None } - Some(ty::AutoPtr(_, _, None)) => { None } - Some(ty::AutoPtr(_, _, Some(box r))) => { Some(r) } + let adj = self.fcx.inh.adjustments.borrow().get(&base_expr.id).cloned(); + let (autoderefs, unsize) = match adj { + Some(ty::AdjustDerefRef(adr)) => match adr.autoref { + None => { + assert!(adr.unsize.is_none()); + (adr.autoderefs, None) + } + Some(ty::AutoPtr(_, _)) => { + (adr.autoderefs, adr.unsize.map(|target| { + ty::deref(target, false) + .expect("fixup: AutoPtr is not &T").ty + })) + } + Some(_) => { + self.tcx().sess.span_bug( + base_expr.span, + &format!("unexpected adjustment autoref {}", + adr.repr(self.tcx()))); + } + }, + None => (0, None), Some(_) => { self.tcx().sess.span_bug( base_expr.span, - "unexpected adjustment autoref"); + "unexpected adjustment type"); } }; - let adjusted_base_ty = - self.fcx.adjust_expr_ty( - &**base_expr, - Some(&ty::AdjustDerefRef(base_adjustment.clone()))); + let (adjusted_base_ty, unsize) = if let Some(target) = unsize { + (target, true) + } else { + (self.fcx.adjust_expr_ty(base_expr, + Some(&ty::AdjustDerefRef(ty::AutoDerefRef { + autoderefs: autoderefs, + autoref: None, + unsize: None + }))), false) + }; let index_expr_ty = self.fcx.expr_ty(&**index_expr); let result = check::try_index_step( @@ -571,7 +568,8 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { expr, &**base_expr, adjusted_base_ty, - base_adjustment, + autoderefs, + unsize, PreferMutLvalue, index_expr_ty); @@ -658,14 +656,3 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { self.span, infer::FnCall, value).0 } } - -fn wrap_autoref<'tcx, F>(mut deref: ty::AutoDerefRef<'tcx>, - base_fn: F) - -> ty::AutoDerefRef<'tcx> where - F: FnOnce(Option>>) -> ty::AutoRef<'tcx>, -{ - let autoref = mem::replace(&mut deref.autoref, None); - let autoref = autoref.map(|r| box r); - deref.autoref = Some(base_fn(autoref)); - deref -} diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index 677ab56852434..f1a4dbf7cd528 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -122,8 +122,7 @@ pub fn lookup_in_trait<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, -> Option> { lookup_in_trait_adjusted(fcx, span, self_expr, m_name, trait_def_id, - ty::AutoDerefRef { autoderefs: 0, autoref: None }, - self_ty, opt_input_types) + 0, false, self_ty, opt_input_types) } /// `lookup_in_trait_adjusted` is used for overloaded operators. It does a very narrow slice of @@ -140,7 +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>>) -> Option> @@ -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 + } })); } diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 41eae88158905..08e2f47c5a675 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -31,7 +31,6 @@ use std::rc::Rc; use util::ppaux::Repr; use self::CandidateKind::*; -pub use self::PickAdjustment::*; pub use self::PickKind::*; struct ProbeContext<'a, 'tcx:'a> { @@ -49,7 +48,8 @@ struct ProbeContext<'a, 'tcx:'a> { struct CandidateStep<'tcx> { self_ty: Ty<'tcx>, - adjustment: PickAdjustment, + autoderefs: usize, + unsize: bool } struct Candidate<'tcx> { @@ -70,8 +70,24 @@ enum CandidateKind<'tcx> { pub struct Pick<'tcx> { pub method_ty: Rc>, - pub adjustment: PickAdjustment, pub kind: PickKind<'tcx>, + + // Indicates that the source expression should be autoderef'd N times + // + // A = expr | *expr | **expr | ... + pub autoderefs: usize, + + // Indicates that an autoref is applied after the optional autoderefs + // + // B = A | &A | &mut A + pub autoref: Option, + + // Indicates that the source expression should be "unsized" to a + // target type. This should probably eventually go away in favor + // of just coercing method receivers. + // + // C = B | unsize(B) + pub unsize: Option>, } #[derive(Clone,Debug)] @@ -85,30 +101,6 @@ pub enum PickKind<'tcx> { pub type PickResult<'tcx> = Result, MethodError>; -// This is a kind of "abstracted" version of ty::AutoAdjustment. The -// difference is that it doesn't embed any regions or other -// specifics. The "confirmation" step recreates those details as -// needed. -#[derive(Clone,Debug)] -pub enum PickAdjustment { - // Indicates that the source expression should be autoderef'd N times - // - // A = expr | *expr | **expr - AutoDeref(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), -} - #[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(), - }; + if step.unsize { + return None; + } - return self.pick_method(step.self_ty).map(|r| self.adjust(r, adjustment.clone())); + self.pick_method(step.self_ty).map(|r| r.map(|mut pick| { + pick.autoderefs = step.autoderefs; - fn consider_reborrow<'tcx>(ty: Ty<'tcx>, d: 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 let ty::ty_rptr(_, mt) = step.self_ty.sty { + pick.autoderefs += 1; + pick.autoref = Some(mt.mutbl); } - } + + pick + })) } fn pick_autorefd_method(&mut self, @@ -947,46 +946,28 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { -> Option> { let tcx = self.tcx(); - self.search_mutabilities( - |m| AutoRef(m, box step.adjustment.clone()), - |m,r| ty::mk_rptr(tcx, tcx.mk_region(r), ty::mt {ty:step.self_ty, mutbl:m})) - } - fn search_mutabilities(&mut self, - mut mk_adjustment: F, - mut mk_autoref_ty: G) - -> Option> where - F: FnMut(ast::Mutability) -> PickAdjustment, - G: FnMut(ast::Mutability, ty::Region) -> Ty<'tcx>, - { // In general, during probing we erase regions. See // `impl_self_ty()` for an explanation. - let region = ty::ReStatic; + let region = tcx.mk_region(ty::ReStatic); // Search through mutabilities in order to find one where pick works: - [ast::MutImmutable, ast::MutMutable] - .iter() - .flat_map(|&m| { - let autoref_ty = mk_autoref_ty(m, region); - self.pick_method(autoref_ty) - .map(|r| self.adjust(r, mk_adjustment(m))) - .into_iter() - }) - .nth(0) - } - - fn adjust(&mut self, - result: PickResult<'tcx>, - adjustment: PickAdjustment) - -> PickResult<'tcx> - { - match result { - Err(e) => Err(e), - Ok(mut pick) => { - pick.adjustment = adjustment; - Ok(pick) - } - } + [ast::MutImmutable, ast::MutMutable].iter().filter_map(|&m| { + let autoref_ty = ty::mk_rptr(tcx, region, ty::mt { + ty: step.self_ty, + mutbl: m + }); + self.pick_method(autoref_ty).map(|r| r.map(|mut pick| { + pick.autoderefs = step.autoderefs; + pick.autoref = Some(m); + pick.unsize = if step.unsize { + Some(step.self_ty) + } else { + None + }; + pick + })) + }).nth(0) } fn pick_method(&mut self, self_ty: Ty<'tcx>) -> Option> { @@ -1122,8 +1103,10 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { let method_ty = probes[0].method_ty.clone(); Some(Pick { method_ty: method_ty, - adjustment: AutoDeref(0), - kind: TraitPick(trait_def_id, method_num) + kind: TraitPick(trait_def_id, method_num), + autoderefs: 0, + autoref: None, + unsize: None }) } @@ -1296,7 +1279,6 @@ impl<'tcx> Candidate<'tcx> { fn to_unadjusted_pick(&self) -> Pick<'tcx> { Pick { method_ty: self.method_ty.clone(), - adjustment: AutoDeref(0), kind: match self.kind { InherentImplCandidate(def_id, _) => { InherentImplPick(def_id) @@ -1323,7 +1305,10 @@ impl<'tcx> Candidate<'tcx> { ProjectionCandidate(def_id, index) => { TraitPick(def_id, index) } - } + }, + autoderefs: 0, + autoref: None, + unsize: None } } @@ -1392,15 +1377,10 @@ impl<'tcx> Repr<'tcx> for CandidateKind<'tcx> { impl<'tcx> Repr<'tcx> for CandidateStep<'tcx> { fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String { - format!("CandidateStep({},{:?})", + format!("CandidateStep({}, autoderefs={}, unsize={})", self.self_ty.repr(tcx), - self.adjustment) - } -} - -impl<'tcx> Repr<'tcx> for PickAdjustment { - fn repr(&self, _tcx: &ty::ctxt) -> String { - format!("{:?}", self) + self.autoderefs, + self.unsize) } } @@ -1412,9 +1392,12 @@ impl<'tcx> Repr<'tcx> for PickKind<'tcx> { impl<'tcx> Repr<'tcx> for Pick<'tcx> { fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String { - format!("Pick(method_ty={}, adjustment={:?}, kind={:?})", + format!("Pick(method_ty={}, autoderefs={}, + autoref={}, unsize={}, kind={:?})", self.method_ty.repr(tcx), - self.adjustment, + self.autoderefs, + self.autoref.repr(tcx), + self.unsize.repr(tcx), self.kind) } } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 862c454a38833..a54adb3533aaf 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -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 where - F: FnMut(Ty<'tcx>, ty::AutoDerefRef<'tcx>) -> Option, +fn lookup_indexing<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, + expr: &ast::Expr, + base_expr: &'tcx ast::Expr, + base_ty: Ty<'tcx>, + idx_ty: Ty<'tcx>, + lvalue_pref: LvaluePreference) + -> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)> { // FIXME(#18741) -- this is almost but not quite the same as the // autoderef that normal method probing does. They could likely be @@ -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, diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 9554e6ad8aad3..a7c2969fb7f72 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -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); } - - 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 diff --git a/src/librustc_typeck/check/vtable.rs b/src/librustc_typeck/check/vtable.rs index 63c34b65d7784..f301c89333e3a 100644 --- a/src/librustc_typeck/check/vtable.rs +++ b/src/librustc_typeck/check/vtable.rs @@ -15,7 +15,6 @@ 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 +132,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"); diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 37f43252483aa..f778a64f94969 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -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), }) } }; diff --git a/src/test/compile-fail/associated-type-projection-from-multiple-supertraits.rs b/src/test/compile-fail/associated-type-projection-from-multiple-supertraits.rs index c55e24e81adc2..c18d72c445b37 100644 --- a/src/test/compile-fail/associated-type-projection-from-multiple-supertraits.rs +++ b/src/test/compile-fail/associated-type-projection-from-multiple-supertraits.rs @@ -34,6 +34,8 @@ fn dent(c: C, color: C::Color) { fn dent_object(c: BoxCar) { //~^ ERROR ambiguous associated type + //~| ERROR the associated type `Color` (from the trait `Box`) must be specified + //~| ERROR the associated type `Color` (from the trait `Vehicle`) must be specified } fn paint(c: C, d: C::Color) { diff --git a/src/test/compile-fail/issue-18819.rs b/src/test/compile-fail/issue-18819.rs index 951d78410b814..01fc4fef03b1d 100644 --- a/src/test/compile-fail/issue-18819.rs +++ b/src/test/compile-fail/issue-18819.rs @@ -20,7 +20,7 @@ impl Foo for X { type Item = bool; } -fn print_x(_: &Foo, extra: &str) { +fn print_x(_: &Foo, extra: &str) { println!("{}", extra); } diff --git a/src/test/run-pass/issue-19121.rs b/src/test/compile-fail/issue-19482.rs similarity index 75% rename from src/test/run-pass/issue-19121.rs rename to src/test/compile-fail/issue-19482.rs index e02d001ee98ad..21a50f24d5e5c 100644 --- a/src/test/run-pass/issue-19121.rs +++ b/src/test/compile-fail/issue-19482.rs @@ -1,4 +1,4 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -9,7 +9,7 @@ // except according to those terms. // Test that a partially specified trait object with unspecified associated -// type does not ICE. +// type does not type-check. // pretty-expanded FIXME #23616 @@ -20,7 +20,6 @@ trait Foo { } fn bar(x: &Foo) {} -// FIXME(#19482) -- `Foo` should specify `A`, but this is not -// currently enforced except at object creation +//~^ ERROR the associated type `A` (from the trait `Foo`) must be specified pub fn main() {} diff --git a/src/test/compile-fail/retslot-cast.rs b/src/test/compile-fail/retslot-cast.rs index 4ef07ecb4382f..c5e26a26744df 100644 --- a/src/test/compile-fail/retslot-cast.rs +++ b/src/test/compile-fail/retslot-cast.rs @@ -11,7 +11,8 @@ #![feature(rustc_attrs)] #![allow(warnings)] -pub fn fail(x: Option<& (Iterator+Send)>) -> Option<&Iterator> { +pub fn fail(x: Option<&(Iterator+Send)>) + -> Option<&Iterator> { // This call used to trigger an LLVM assertion because the return // slot had type "Option<&Iterator>"* instead of // "Option<&(Iterator+Send)>"* -- but this now yields a @@ -23,7 +24,8 @@ pub fn fail(x: Option<& (Iterator+Send)>) -> Option<&Iterator> { inner(x) //~ ERROR mismatched types } -pub fn inner(x: Option<& (Iterator+Send)>) -> Option<&(Iterator+Send)> { +pub fn inner(x: Option<&(Iterator+Send)>) + -> Option<&(Iterator+Send)> { x } diff --git a/src/test/compile-fail/unboxed-closure-sugar-not-used-on-fn.rs b/src/test/compile-fail/unboxed-closure-sugar-not-used-on-fn.rs index 55156e28cd703..5a821ef1231cc 100644 --- a/src/test/compile-fail/unboxed-closure-sugar-not-used-on-fn.rs +++ b/src/test/compile-fail/unboxed-closure-sugar-not-used-on-fn.rs @@ -11,7 +11,7 @@ // Test that the `Fn` traits require `()` form without a feature gate. -fn bar1(x: &Fn<()>) { +fn bar1(x: &Fn<(), Output=()>) { //~^ ERROR angle-bracket notation is not stable when used with the `Fn` family } From 73c2e768d6ba55bdfb8292320ebac00e69ca2e42 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Fri, 10 Apr 2015 12:25:40 +1200 Subject: [PATCH 2/4] Rebased --- src/libcore/iter.rs | 2 +- src/librustc/middle/expr_use_visitor.rs | 67 ++++++------------- src/librustc/middle/ty.rs | 21 +++--- src/librustc_typeck/check/coercion.rs | 11 ++- src/librustc_typeck/check/op.rs | 12 +++- src/librustc_typeck/check/regionck.rs | 2 +- src/librustc_typeck/check/vtable.rs | 1 - ...pe-projection-from-multiple-supertraits.rs | 5 +- src/test/compile-fail/issue-22560.rs | 1 + src/test/run-make/save-analysis/foo.rs | 6 +- 10 files changed, 56 insertions(+), 72 deletions(-) diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs index 9f378748d2007..c756d3cb9c28c 100644 --- a/src/libcore/iter.rs +++ b/src/libcore/iter.rs @@ -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) {} /// 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 diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index c1c551c2be9eb..4f9ac3dd8ef22 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -799,18 +799,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { self.delegate_consume(expr.id, expr.span, cmt_unadjusted); } ty::AdjustDerefRef(ref adj) => { - self.walk_autoderefs(expr, adj.autoderefs); - if let Some(ref r) = adj.autoref { - self.walk_autoref(expr, r, adj.autoderefs); - } else if adj.unsize.is_some() { - assert!(adj.autoderefs == 0, - format!("Expected no derefs with \ - unsize AutoRefs, found: {}", - adj.repr(self.tcx()))); - let cmt_unadjusted = - return_if_err!(self.mc.cat_expr_unadjusted(expr)); - self.delegate_consume(expr.id, expr.span, cmt_unadjusted); - } + self.walk_autoderefref(expr, adj); } } } @@ -860,29 +849,29 @@ 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 + // from a Box to a Box 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)); + if let Some(ty) = adj.unsize { + if let ty::ty_uniq(_) = ty.sty { + assert!(adj.autoderefs == 0, + format!("Expected no derefs with unsize AutoRefs, found: {}", + adj.repr(self.tcx()))); let cmt_unadjusted = return_if_err!(self.mc.cat_expr_unadjusted(expr)); self.delegate_consume(expr.id, expr.span, cmt_unadjusted); return; } - _ => { } } - let autoref = adj.autoref.as_ref(); + //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); + self.walk_autoref(expr, cmt_derefd, adj.autoref); } + /// 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 @@ -893,25 +882,25 @@ 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>) -> 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; } }; - 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())); @@ -920,15 +909,13 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { ty::AutoPtr(r, m) => { self.delegate.borrow(expr.id, expr.span, - cmt_derefd, + cmt_base, *r, ty::BorrowKind::from_mutbl(m), AutoRef); } - 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())); @@ -953,24 +940,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>>) - -> 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 diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index ccb0fa7bfdb40..e0b32ed06a404 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -290,6 +290,12 @@ pub enum AutoAdjustment<'tcx> { #[derive(Copy, Clone, Debug)] pub struct AutoDerefRef<'tcx> { + // FIXME with more powerful date structures we could have a better design + // here. Some constraints: + // unsize => autoref + // unsize => autodefs == 0 + + /// Apply a number of dereferences, producing an lvalue. pub autoderefs: usize, @@ -303,11 +309,11 @@ pub struct AutoDerefRef<'tcx> { #[derive(Copy, Clone, PartialEq, Debug)] pub enum AutoRef<'tcx> { - /// Convert from T to &T + /// Convert from T to &T. AutoPtr(&'tcx Region, ast::Mutability), - /// Convert from T to *T - /// Value to thin pointer + /// Convert from T to *T. + /// Value to thin pointer. AutoUnsafe(ast::Mutability), } @@ -407,7 +413,7 @@ impl MethodCall { } } - 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, autoderef: 1 + autoderef @@ -4487,8 +4493,8 @@ pub fn adjust_ty<'tcx, F>(cx: &ctxt<'tcx>, 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(); @@ -4501,8 +4507,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)) ); diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index acdeda3d546bd..28df1c2159577 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -79,7 +79,6 @@ use syntax::ast; struct Coerce<'a, 'tcx: 'a> { fcx: &'a FnCtxt<'a, 'tcx>, origin: infer::TypeOrigin, - trace: TypeTrace<'tcx>, unsizing_obligation: Cell>> } @@ -266,7 +265,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { 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.trace.clone()); + 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) @@ -293,7 +292,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { }; let target = ty::adjust_ty_for_autoref(self.tcx(), target, reborrow); - try!(self.fcx.infcx().try(|_| self.subtype(target, b))); + try!(self.subtype(target, b)); let adjustment = AutoDerefRef { autoderefs: if reborrow.is_some() { 1 } else { 0 }, autoref: reborrow, @@ -374,7 +373,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { 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 { + for (i, (tp_a, tp_b)) in tps { if self.subtype(*tp_a, *tp_b).is_ok() { continue; } @@ -498,12 +497,10 @@ pub fn mk_assignty<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, -> RelateResult<'tcx, ()> { debug!("mk_assignty({} -> {})", a.repr(fcx.tcx()), b.repr(fcx.tcx())); let (adjustment, unsizing_obligation) = try!(indent(|| { - fcx.infcx().commit_if_ok(|| { - let origin = infer::ExprAssignable(expr.span); + fcx.infcx().commit_if_ok(|_| { let coerce = Coerce { fcx: fcx, origin: infer::ExprAssignable(expr.span), - trace: infer::TypeTrace::types(origin, false, a, b), unsizing_obligation: Cell::new(None) }; Ok((try!(coerce.coerce(expr, a, b)), diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index 7c1fea4e60f6e..b4000788d1998 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -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 }; diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index a7c2969fb7f72..6dfc1e0ea6c26 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -1134,7 +1134,7 @@ fn link_autoref(rcx: &Rcx, 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); } } } diff --git a/src/librustc_typeck/check/vtable.rs b/src/librustc_typeck/check/vtable.rs index f301c89333e3a..a9094fce57c61 100644 --- a/src/librustc_typeck/check/vtable.rs +++ b/src/librustc_typeck/check/vtable.rs @@ -13,7 +13,6 @@ 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::ppaux::{Repr, UserString}; diff --git a/src/test/compile-fail/associated-type-projection-from-multiple-supertraits.rs b/src/test/compile-fail/associated-type-projection-from-multiple-supertraits.rs index c18d72c445b37..2b34fcab24c04 100644 --- a/src/test/compile-fail/associated-type-projection-from-multiple-supertraits.rs +++ b/src/test/compile-fail/associated-type-projection-from-multiple-supertraits.rs @@ -34,8 +34,9 @@ fn dent(c: C, color: C::Color) { fn dent_object(c: BoxCar) { //~^ ERROR ambiguous associated type - //~| ERROR the associated type `Color` (from the trait `Box`) must be specified - //~| ERROR the associated type `Color` (from the trait `Vehicle`) must be specified + //~| 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: C, d: C::Color) { diff --git a/src/test/compile-fail/issue-22560.rs b/src/test/compile-fail/issue-22560.rs index b458e10a89c2f..a05bbe4960e7c 100644 --- a/src/test/compile-fail/issue-22560.rs +++ b/src/test/compile-fail/issue-22560.rs @@ -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 diff --git a/src/test/run-make/save-analysis/foo.rs b/src/test/run-make/save-analysis/foo.rs index 9d1ab00359dd9..56da6693939eb 100644 --- a/src/test/run-make/save-analysis/foo.rs +++ b/src/test/run-make/save-analysis/foo.rs @@ -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: Option<::Item>) { let s = sub_struct{ field2: 45, }; // import tests - fn foo(x: &Float) {} + fn foo(x: &One) {} let _: Option = from_i32(45); let x = 42; From 4ad4363870246040a69c18dad217b235113ecd1c Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Fri, 10 Apr 2015 22:11:52 +1200 Subject: [PATCH 3/4] Better explanation of AutoDerefRef --- src/librustc/middle/expr_use_visitor.rs | 3 +- src/librustc/middle/ty.rs | 39 ++++++++++++++++++++++--- 2 files changed, 36 insertions(+), 6 deletions(-) diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 4f9ac3dd8ef22..c0b4800bb0552 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -849,7 +849,7 @@ 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 Box to a Box etc, always comes in a stylized + // 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). @@ -865,7 +865,6 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { } } - //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, adj.autoref); diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index e0b32ed06a404..ce543845717ca 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -288,13 +288,44 @@ pub enum AutoAdjustment<'tcx> { AdjustDerefRef(AutoDerefRef<'tcx>), } +/// 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. +/// 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. +/// +/// A DST 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] +/// unsize: Some([i32]), // [i32; 4] -> [i32] +/// autoref: Some(AutoPtr), // [i32] -> &[i32] +/// } +/// Note that for a struct, the 'deep' unsizing of the struct is not recorded. +/// E.g., `struct Foo { 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]`. +/// +/// Box pointers are treated somewhat differently, the last deref is not counted, +/// nor is the 'ref' to a `Box<_>`. Imagine them more like structs. +/// E.g., Box<[i32; 4]> -> Box<[i32]> is represented by: +/// AutoDerefRef { +/// autoderefs: 0, +/// unsize: Some(Box<[i32]>), +/// autoref: None, +/// } #[derive(Copy, Clone, Debug)] pub struct AutoDerefRef<'tcx> { // FIXME with more powerful date structures we could have a better design - // here. Some constraints: - // unsize => autoref - // unsize => autodefs == 0 - + // here. /// Apply a number of dereferences, producing an lvalue. pub autoderefs: usize, From b35a587da144848e6f2ebe16018df3cf1c1b2a0e Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Tue, 14 Apr 2015 11:44:26 +1200 Subject: [PATCH 4/4] Reviewer comments --- src/librustc/middle/expr_use_visitor.rs | 28 +++----- src/librustc/middle/ty.rs | 78 ++++++++++++++------- src/librustc_typeck/check/method/confirm.rs | 5 +- src/test/compile-fail/issue-21950.rs | 2 +- 4 files changed, 66 insertions(+), 47 deletions(-) diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index c0b4800bb0552..5235bbdf9cf00 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -848,26 +848,16 @@ 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). - if let Some(ty) = adj.unsize { - if let ty::ty_uniq(_) = ty.sty { - assert!(adj.autoderefs == 0, - format!("Expected no derefs with unsize AutoRefs, found: {}", - adj.repr(self.tcx()))); - let cmt_unadjusted = - return_if_err!(self.mc.cat_expr_unadjusted(expr)); - self.delegate_consume(expr.id, expr.span, cmt_unadjusted); - return; - } - } + let cmt_derefd = + return_if_err!(self.mc.cat_expr_autoderefd(expr, adj.autoderefs)); - let cmt_derefd = return_if_err!( - self.mc.cat_expr_autoderefd(expr, adj.autoderefs)); - self.walk_autoref(expr, cmt_derefd, adj.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); + } } diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index ce543845717ca..be126b0b54c83 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -283,58 +283,84 @@ pub enum Variance { #[derive(Copy, Clone, Debug)] pub enum AutoAdjustment<'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 + 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>), } /// 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. -/// 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. /// -/// A DST 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: +/// 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] -/// unsize: Some([i32]), // [i32; 4] -> [i32] /// 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 { 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]`. /// -/// Box pointers are treated somewhat differently, the last deref is not counted, -/// nor is the 'ref' to a `Box<_>`. Imagine them more like structs. -/// E.g., Box<[i32; 4]> -> Box<[i32]> is represented by: +/// 3. Coercing a `Box` to `Box` 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, -/// unsize: Some(Box<[i32]>), /// autoref: None, +/// unsize: Some(Box<[i32]>), /// } +/// ``` #[derive(Copy, Clone, Debug)] pub struct AutoDerefRef<'tcx> { - // FIXME with more powerful date structures we could have a better design - // here. - - /// Apply a number of dereferences, producing an lvalue. + /// Step 1. Apply a number of dereferences, producing an lvalue. pub autoderefs: usize, - /// Produce a pointer/reference from the value. + /// Step 2. Optionally produce a pointer/reference from the value. pub autoref: Option>, - /// Unsize a pointer/reference value, e.g. &[T; n] to &[T]. - /// The stored type is the target pointer type. + /// 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>, } diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 4e62542854fa8..7eb15a1479634 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -143,7 +143,10 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { ty::adjust_ty_for_autoref(self.tcx(), target, Some(autoref)) })) } else { - // No unsizing should be performed without autoref. + // 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) }; diff --git a/src/test/compile-fail/issue-21950.rs b/src/test/compile-fail/issue-21950.rs index 315a4cd90c5f2..900ad5ce812e3 100644 --- a/src/test/compile-fail/issue-21950.rs +++ b/src/test/compile-fail/issue-21950.rs @@ -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 }