From ff8ee31666c73e89bdc23dc1ed2122d264d7b4c6 Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Mon, 16 Mar 2015 18:45:01 +0200 Subject: [PATCH 01/12] Revert obsoleted changes #14830 made to MethodCall. --- src/librustc/middle/astencode.rs | 46 +++++++++-------------- src/librustc/middle/expr_use_visitor.rs | 2 +- src/librustc/middle/mem_categorization.rs | 8 +--- src/librustc/middle/ty.rs | 36 +++--------------- src/librustc_trans/trans/expr.rs | 11 +++--- src/librustc_typeck/check/mod.rs | 3 +- src/librustc_typeck/check/regionck.rs | 2 +- src/librustc_typeck/check/writeback.rs | 8 +--- 8 files changed, 34 insertions(+), 82 deletions(-) diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index 801350e8a1e9c..2fa3859bcc278 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -597,18 +597,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)) @@ -624,13 +624,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(), @@ -684,7 +684,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>; @@ -709,12 +709,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() @@ -1254,7 +1254,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) }) } @@ -1267,31 +1267,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| { @@ -1918,10 +1906,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 97314b57ef656..845b114a2290a 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -827,7 +827,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) => { diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index bdcfc67f92b99..ad05f9da124d1 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -887,15 +887,9 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> { deref_cnt: uint, 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 92b444e85d8c3..9dabef00e5195 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -33,7 +33,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::*; @@ -368,17 +367,6 @@ pub fn adjusted_object_region(adj: &AutoAdjustment) -> Option { } } -// 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> { @@ -505,35 +493,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(uint), - 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: uint) -> MethodCall { + pub fn autoderef(expr_id: ast::NodeId, autoderef: u32) -> MethodCall { MethodCall { expr_id: expr_id, - adjustment: AutoDeref(1 + autoderef) + autoderef: 1 + autoderef } } } @@ -4581,7 +4555,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 diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs index 4d7431a20b707..9f1204f909d2b 100644 --- a/src/librustc_trans/trans/expr.rs +++ b/src/librustc_trans/trans/expr.rs @@ -402,7 +402,7 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, 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_call = MethodCall::autoderef(expr.id, (adj.autoderefs-1) as u32); let method = bcx.tcx().method_map.borrow().get(&method_call).is_some(); if method { // Don't skip an overloaded deref. @@ -2227,7 +2227,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 } @@ -2259,10 +2259,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_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 1e38a7d2d9f94..9f2d8a7cc8f53 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2018,7 +2018,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 diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 5a4ccc0b7b410..c419e145a3332 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -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) { diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 2537f9362bf31..7af9b3825ee93 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -259,7 +259,6 @@ 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) @@ -271,12 +270,7 @@ 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); } From 81a17dfd027611aedc5044e5f0ef3fd55cebbfd1 Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Tue, 17 Mar 2015 11:16:00 +0200 Subject: [PATCH 02/12] Move AutoUnsizeUniq from autorefs to a simple AdjustUnsize. --- src/librustc/middle/astencode.rs | 32 +++--- src/librustc/middle/expr_use_visitor.rs | 13 +-- src/librustc/middle/mem_categorization.rs | 1 + src/librustc/middle/ty.rs | 123 ++++----------------- src/librustc/middle/ty_fold.rs | 1 - src/librustc_trans/trans/consts.rs | 6 +- src/librustc_trans/trans/expr.rs | 129 +++++++--------------- src/librustc_typeck/check/coercion.rs | 8 +- src/librustc_typeck/check/mod.rs | 8 +- src/librustc_typeck/check/regionck.rs | 2 +- src/librustc_typeck/check/writeback.rs | 4 + 11 files changed, 101 insertions(+), 226 deletions(-) diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index 2fa3859bcc278..5c8442d414e2e 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -1026,6 +1026,12 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> { |this| Ok(this.emit_auto_deref_ref(ecx, auto_deref_ref))) }) } + + ty::AdjustUnsize(ref uk) => { + this.emit_enum_variant("AdjustUnsize", 3, 1, |this| { + this.emit_enum_variant_arg(0, |this| Ok(this.emit_unsize_kind(ecx, uk))) + }) + } } }); } @@ -1057,20 +1063,15 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> { this.emit_enum_variant_arg(0, |this| Ok(this.emit_unsize_kind(ecx, uk))) }) } - &ty::AutoUnsizeUniq(ref uk) => { - this.emit_enum_variant("AutoUnsizeUniq", 2, 1, |this| { - this.emit_enum_variant_arg(0, |this| Ok(this.emit_unsize_kind(ecx, uk))) - }) - } &ty::AutoUnsafe(m, None) => { - this.emit_enum_variant("AutoUnsafe", 3, 2, |this| { + this.emit_enum_variant("AutoUnsafe", 2, 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("AutoUnsafe", 2, 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))))) @@ -1624,7 +1625,7 @@ 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", "AdjustDerefRef", "AdjustUnsize"]; this.read_enum_variant(&variants, |this, i| { Ok(match i { 1 => { @@ -1643,6 +1644,13 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { ty::AdjustDerefRef(auto_deref_ref) } + 3 => { + let uk: ty::UnsizeKind = + this.read_enum_variant_arg(0, + |this| Ok(this.read_unsize_kind(dcx))).unwrap(); + + ty::AdjustUnsize(uk) + } _ => panic!("bad enum variant for ty::AutoAdjustment") }) }) @@ -1673,7 +1681,6 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { self.read_enum("AutoRef", |this| { let variants = ["AutoPtr", "AutoUnsize", - "AutoUnsizeUniq", "AutoUnsafe"]; this.read_enum_variant(&variants, |this, i| { Ok(match i { @@ -1701,13 +1708,6 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { ty::AutoUnsize(uk) } 2 => { - let uk: ty::UnsizeKind = - this.read_enum_variant_arg(0, - |this| Ok(this.read_unsize_kind(dcx))).unwrap(); - - ty::AutoUnsizeUniq(uk) - } - 3 => { let m: ast::Mutability = this.read_enum_variant_arg(0, |this| Decodable::decode(this)).unwrap(); let a: Option> = diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 845b114a2290a..15c55be2ebffa 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -791,11 +791,11 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { 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)"); + ty::AdjustUnsafeFnPointer(..) | + ty::AdjustUnsize(_) => { + // Creating a closure/fn-pointer or unsizing consumes + // the input and stores it into the resulting rvalue. + debug!("walk_adjustment(AdjustUnsize|AdjustReifyFnPointer)"); let cmt_unadjusted = return_if_err!(self.mc.cat_expr_unadjusted(expr)); self.delegate_consume(expr.id, expr.span, cmt_unadjusted); @@ -872,8 +872,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { ty::BorrowKind::from_mutbl(m), AutoRef); } - ty::AutoUnsize(_) | - ty::AutoUnsizeUniq(_) => { + ty::AutoUnsize(_) => { assert!(n == 1, format!("Expected exactly 1 deref with Uniq \ AutoRefs, found: {}", n)); let cmt_unadjusted = diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index ad05f9da124d1..2ce78df058aba 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -438,6 +438,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> { Ok(self.cat_rvalue_node(expr.id(), expr.span(), expr_ty)) } + ty::AdjustUnsize(_) | ty::AdjustDerefRef( ty::AutoDerefRef { autoref: Some(_), ..}) => { diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 9dabef00e5195..8488468416f79 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -282,7 +282,10 @@ pub enum Variance { pub enum AutoAdjustment<'tcx> { AdjustReifyFnPointer(ast::DefId), // go from a fn-item type to a fn-pointer type AdjustUnsafeFnPointer, // go from a safe fn pointer to an unsafe fn pointer - AdjustDerefRef(AutoDerefRef<'tcx>) + AdjustDerefRef(AutoDerefRef<'tcx>), + + /// Convert Box<[T, ..n]> to Box<[T]> or something similar in a Box. + AdjustUnsize(UnsizeKind<'tcx>), } #[derive(Clone, PartialEq, Debug)] @@ -311,103 +314,12 @@ pub enum AutoRef<'tcx> { /// Convert [T, ..n] to [T] (or similar, depending on the kind) AutoUnsize(UnsizeKind<'tcx>), - /// Convert Box<[T, ..n]> to Box<[T]> or something similar in a Box. - /// With DST and Box a library type, this should be replaced by UnsizeStruct. - AutoUnsizeUniq(UnsizeKind<'tcx>), - /// Convert from T to *T /// Value to thin pointer /// The second field allows us to wrap other AutoRef adjustments. AutoUnsafe(ast::Mutability, Option>>), } -// 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 - } -} - -// 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 - } -} - #[derive(Clone, Copy, RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Debug)] pub struct param_index { pub space: subst::ParamSpace, @@ -4529,11 +4441,10 @@ pub fn adjust_ty<'tcx, F>(cx: &ctxt<'tcx>, 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))); } } } @@ -4584,6 +4495,19 @@ pub fn adjust_ty<'tcx, F>(cx: &ctxt<'tcx>, adjust_ty_for_autoref(cx, span, adjusted_ty, adj.autoref.as_ref()) } + + AdjustUnsize(ref k) => { + match unadjusted_ty.sty { + ty::ty_uniq(ty) => { + ty::mk_uniq(cx, unsize_ty(cx, ty, k, span)) + } + _ => { + cx.sess.bug( + &format!("AdjustUnsize adjustment on non-Box type: \ + {}", unadjusted_ty.repr(cx))); + } + } + } } } None => unadjusted_ty @@ -4619,8 +4543,6 @@ pub fn adjust_ty_for_autoref<'tcx>(cx: &ctxt<'tcx>, } Some(&AutoUnsize(ref k)) => unsize_ty(cx, ty, k, span), - - Some(&AutoUnsizeUniq(ref k)) => ty::mk_uniq(cx, unsize_ty(cx, ty, k, span)), } } @@ -6683,6 +6605,7 @@ 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 { + AdjustUnsize(_) | AdjustReifyFnPointer(..) => false, AdjustUnsafeFnPointer(..) => false, AdjustDerefRef(ref r) => r.is_identity(), @@ -6840,6 +6763,9 @@ impl<'tcx> Repr<'tcx> for AutoAdjustment<'tcx> { AdjustDerefRef(ref data) => { data.repr(tcx) } + AdjustUnsize(ref a) => { + format!("AdjustUnsize({})", a.repr(tcx)) + } } } } @@ -6870,9 +6796,6 @@ impl<'tcx> Repr<'tcx> for AutoRef<'tcx> { AutoUnsize(ref a) => { format!("AutoUnsize({})", a.repr(tcx)) } - AutoUnsizeUniq(ref a) => { - format!("AutoUnsizeUniq({})", a.repr(tcx)) - } AutoUnsafe(ref a, ref b) => { format!("AutoUnsafe({:?},{})", a, b.repr(tcx)) } diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs index f17ba78007bb2..477dea1f687de 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -767,7 +767,6 @@ pub fn super_fold_autoref<'tcx, T: TypeFolder<'tcx>>(this: &mut T, ty::AutoUnsafe(m, Some(box super_fold_autoref(this, &**a))) } ty::AutoUnsize(ref k) => ty::AutoUnsize(k.fold_with(this)), - ty::AutoUnsizeUniq(ref k) => ty::AutoUnsizeUniq(k.fold_with(this)), } } diff --git a/src/librustc_trans/trans/consts.rs b/src/librustc_trans/trans/consts.rs index 4b1a03e47e7ae..f827a11eace3b 100644 --- a/src/librustc_trans/trans/consts.rs +++ b/src/librustc_trans/trans/consts.rs @@ -309,7 +309,7 @@ pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, Some(box ty::AutoUnsize(ref k)) => { let info = expr::unsized_info( - cx, k, e.id, ty, param_substs, + cx, k, 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); @@ -329,6 +329,10 @@ pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, } } } + Some(adj) => { + cx.sess().span_bug(e.span, + &format!("unimplemented const adjustment {:?}", adj)) + } None => {} }; diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs index 9f1204f909d2b..1fbddb6ddca99 100644 --- a/src/librustc_trans/trans/expr.rs +++ b/src/librustc_trans/trans/expr.rs @@ -290,16 +290,15 @@ 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. +/// 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>) @@ -307,7 +306,6 @@ pub fn unsized_info_bcx<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, unsized_info( bcx.ccx(), kind, - id, unadjusted_ty, param_substs, || Load(bcx, GEPi(bcx, unadjusted_val, &[0, abi::FAT_PTR_EXTRA]))) @@ -318,21 +316,18 @@ pub fn unsized_info_bcx<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, 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, + unsized_info(ccx, k, ty_substs[tp_index], param_substs, mk_upcast_vtable) } _ => ccx.sess().bug(&format!("UnsizeStruct with bad sty: {}", @@ -387,11 +382,7 @@ 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 = match adj.autoref { // 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 @@ -402,37 +393,39 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, 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) as u32); - let method = bcx.tcx().method_map.borrow().get(&method_call).is_some(); - if method { + let autoderef = (adj.autoderefs - 1) as u32; + let method_call = MethodCall::autoderef(expr.id, autoderef); + if bcx.tcx().method_map.borrow().contains_key(&method_call) { // Don't skip an overloaded deref. - (adj.autoderefs, true) + 0 } else { - (adj.autoderefs - 1, false) + 1 } } - _ => (adj.autoderefs, true), + _ => 0 } } - _ => (adj.autoderefs, true) + _ => 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 let (0, &Some(ref a)) = (skip_reborrows, &adj.autoref) { + datum = unpack_datum!(bcx, apply_autoref(a, bcx, expr, datum)); } } + ty::AdjustUnsize(ref k) => { + debug!(" AdjustUnsize"); + datum = unpack_datum!(bcx, unsize_unique_expr(bcx, expr, datum, k)) + } } debug!("after adjustments, datum={}", datum.to_string(bcx.ccx())); return DatumBlock::new(bcx, datum); @@ -462,15 +455,10 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } &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)) + // Arrange cleanup + let lval = unpack_datum!(bcx, + datum.to_lvalue_datum(bcx, "into_fat_ptr", expr.id)); + unpack_datum!(bcx, unsize_expr(bcx, expr, lval, k)) } }; @@ -479,33 +467,28 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, fn unsize_expr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr, - datum: Datum<'tcx, Expr>, + datum: Datum<'tcx, Lvalue>, k: &ty::UnsizeKind<'tcx>) -> DatumBlock<'blk, 'tcx, Expr> { - let mut bcx = bcx; - let tcx = bcx.tcx(); let datum_ty = datum.ty; - let unsized_ty = ty::unsize_ty(tcx, datum_ty, k, expr.span); - debug!("unsized_ty={}", unsized_ty.repr(bcx.tcx())); + let unsized_ty = ty::unsize_ty(bcx.tcx(), datum_ty, k, expr.span); + debug!("unsize_expr(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 info = unsized_info_bcx(bcx, k, datum_ty, datum.val, 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 = if !type_is_sized(bcx.tcx(), lval.ty) { + let base = if !type_is_sized(bcx.tcx(), datum.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)) } else { - lval.val + datum.val }; let base = PointerCast(bcx, base, ptr_ty); @@ -518,40 +501,6 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, 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: uint) - -> 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>, @@ -579,7 +528,7 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, 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); + let info = unsized_info_bcx(bcx, k, unboxed_ty, base, bcx.fcx.param_substs); Store(bcx, info, get_len(bcx, scratch.val)); DatumBlock::new(bcx, scratch.to_expr_datum()) diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index ae1dbbb1b00ad..1548e1065188d 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -307,12 +307,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { Some((ty, kind)) => { let ty = ty::mk_uniq(self.tcx(), ty); try!(self.fcx.infcx().try(|_| self.subtype(ty, b))); - debug!("Success, coerced with AutoDerefRef(1, \ - AutoUnsizeUniq({:?}))", kind); - Ok(Some(AdjustDerefRef(AutoDerefRef { - autoderefs: 1, - autoref: Some(ty::AutoUnsizeUniq(kind)) - }))) + debug!("Success, coerced with AdjustUnsize({:?})", kind); + Ok(Some(ty::AdjustUnsize(kind))) } _ => Err(ty::terr_mismatch) } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 9f2d8a7cc8f53..a0b32a7b1fff5 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1541,6 +1541,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { None => {} } } + ty::AdjustUnsize(ref unsize) => { + self.register_unsize_obligations(span, unsize); + } } } @@ -1548,9 +1551,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: Span, autoref: &ty::AutoRef<'tcx>) { match *autoref { - ty::AutoUnsize(ref unsize) => { - self.register_unsize_obligations(span, unsize); - } ty::AutoPtr(_, _, None) | ty::AutoUnsafe(_, None) => { } @@ -1558,7 +1558,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::AutoUnsafe(_, Some(ref a_r)) => { self.register_autoref_obligations(span, &**a_r) } - ty::AutoUnsizeUniq(ref unsize) => { + ty::AutoUnsize(ref unsize) => { self.register_unsize_obligations(span, unsize); } } diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index c419e145a3332..cf9fb79ab2e71 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -1132,7 +1132,7 @@ fn link_autoref(rcx: &Rcx, ty::BorrowKind::from_mutbl(m), expr_cmt); } - ty::AutoUnsafe(..) | ty::AutoUnsizeUniq(_) | ty::AutoUnsize(_) => {} + ty::AutoUnsafe(..) | ty::AutoUnsize(_) => {} } } diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 7af9b3825ee93..aa34eb8df73f7 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -279,6 +279,10 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { autoref: self.resolve(&adj.autoref, reason), }) } + + ty::AdjustUnsize(uk) => { + ty::AdjustUnsize(self.resolve(&uk, reason)) + } }; debug!("Adjustments for node {}: {:?}", id, resolved_adjustment); self.tcx().adjustments.borrow_mut().insert( From 562d10df0dc500151b769596e4475a9db1938dba Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Wed, 18 Mar 2015 00:22:35 +0200 Subject: [PATCH 03/12] Hoist lvalue unsizing from AutoRef to AutoDerefRef. --- src/librustc/middle/astencode.rs | 72 +++++++++------------ src/librustc/middle/expr_use_visitor.rs | 42 +++++------- src/librustc/middle/mem_categorization.rs | 2 +- src/librustc/middle/ty.rs | 48 +++++++------- src/librustc/middle/ty_fold.rs | 16 ++--- src/librustc_trans/trans/consts.rs | 56 ++++++++-------- src/librustc_trans/trans/expr.rs | 65 +++++++++---------- src/librustc_typeck/check/callee.rs | 6 +- src/librustc_typeck/check/coercion.rs | 20 +++--- src/librustc_typeck/check/method/confirm.rs | 27 +++++--- src/librustc_typeck/check/method/mod.rs | 5 +- src/librustc_typeck/check/mod.rs | 57 +++++++--------- src/librustc_typeck/check/regionck.rs | 6 +- src/librustc_typeck/check/writeback.rs | 1 + 14 files changed, 201 insertions(+), 222 deletions(-) diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index 5c8442d414e2e..bdb464a965a8c 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -842,7 +842,7 @@ trait rbml_writer_helpers<'tcx> { 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>); + autoref: &ty::AutoRef); 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>, @@ -1037,7 +1037,7 @@ 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>) { + autoref: &ty::AutoRef) { use serialize::Encoder; self.emit_enum("AutoRef", |this| { @@ -1058,23 +1058,9 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> { |this| this.emit_option_some(|this| Ok(this.emit_autoref(ecx, a))))) }) } - &ty::AutoUnsize(ref uk) => { - this.emit_enum_variant("AutoUnsize", 1, 1, |this| { - this.emit_enum_variant_arg(0, |this| Ok(this.emit_unsize_kind(ecx, uk))) - }) - } - &ty::AutoUnsafe(m, None) => { - this.emit_enum_variant("AutoUnsafe", 2, 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", 2, 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)) }) } } @@ -1087,7 +1073,17 @@ 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_struct_field("unsize", 1, |this| { + this.emit_option(|this| { + match auto_deref_ref.unsize { + None => this.emit_option_none(), + Some(ref uk) => this.emit_option_some(|this| Ok(this.emit_unsize_kind(ecx, uk))), + } + }) + }); + + this.emit_struct_field("autoref", 2, |this| { this.emit_option(|this| { match auto_deref_ref.autoref { None => this.emit_option_none(), @@ -1351,7 +1347,7 @@ trait rbml_decoder_decoder_helpers<'tcx> { fn read_auto_deref_ref<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) -> ty::AutoDerefRef<'tcx>; fn read_autoref<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) - -> ty::AutoRef<'tcx>; + -> ty::AutoRef; fn read_unsize_kind<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) -> ty::UnsizeKind<'tcx>; fn convert_def_id(&mut self, @@ -1664,7 +1660,16 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { autoderefs: this.read_struct_field("autoderefs", 0, |this| { Decodable::decode(this) }).unwrap(), - autoref: this.read_struct_field("autoref", 1, |this| { + unsize: this.read_struct_field("unsize", 1, |this| { + this.read_option(|this, b| { + if b { + Ok(Some(this.read_unsize_kind(dcx))) + } else { + Ok(None) + } + }) + }).unwrap(), + autoref: this.read_struct_field("autoref", 2, |this| { this.read_option(|this, b| { if b { Ok(Some(this.read_autoref(dcx))) @@ -1677,11 +1682,9 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { }).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 { self.read_enum("AutoRef", |this| { - let variants = ["AutoPtr", - "AutoUnsize", - "AutoUnsafe"]; + let variants = ["AutoPtr", "AutoUnsafe"]; this.read_enum_variant(&variants, |this, i| { Ok(match i { 0 => { @@ -1701,25 +1704,10 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { 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 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) + ty::AutoUnsafe(m) } _ => panic!("bad enum variant for ty::AutoRef") }) diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 15c55be2ebffa..5666605f71145 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -800,17 +800,17 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { return_if_err!(self.mc.cat_expr_unadjusted(expr)); self.delegate_consume(expr.id, expr.span, cmt_unadjusted); } - ty::AdjustDerefRef(ty::AutoDerefRef { - autoref: ref opt_autoref, - autoderefs: n - }) => { - self.walk_autoderefs(expr, n); - - match *opt_autoref { - None => { } - Some(ref r) => { - self.walk_autoref(expr, r, n); - } + 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 == 1, + format!("Expected exactly 1 deref with \ + unsize AutoRefs, found: {}", adj.autoderefs)); + let cmt_unadjusted = + return_if_err!(self.mc.cat_expr_unadjusted(expr)); + self.delegate_consume(expr.id, expr.span, cmt_unadjusted); } } } @@ -858,13 +858,13 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { n: uint) { debug!("walk_autoref expr={}", expr.repr(self.tcx())); + let cmt_derefd = return_if_err!( + self.mc.cat_expr_autoderefd(expr, n)); + debug!("walk_adjustment: cmt_derefd={}", + cmt_derefd.repr(self.tcx())); + match *autoref { ty::AutoPtr(r, m, _) => { - let cmt_derefd = return_if_err!( - self.mc.cat_expr_autoderefd(expr, n)); - debug!("walk_adjustment: cmt_derefd={}", - cmt_derefd.repr(self.tcx())); - self.delegate.borrow(expr.id, expr.span, cmt_derefd, @@ -872,15 +872,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { ty::BorrowKind::from_mutbl(m), AutoRef); } - ty::AutoUnsize(_) => { - assert!(n == 1, format!("Expected exactly 1 deref with Uniq \ - AutoRefs, found: {}", n)); - let cmt_unadjusted = - return_if_err!(self.mc.cat_expr_unadjusted(expr)); - self.delegate_consume(expr.id, expr.span, cmt_unadjusted); - } - ty::AutoUnsafe(..) => { - } + ty::AutoUnsafe(..) => {} } } diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 2ce78df058aba..3e4411fdfe06c 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -452,7 +452,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> { ty::AdjustDerefRef( ty::AutoDerefRef { - autoref: None, autoderefs}) => { + autoref: None, autoderefs, ..}) => { // Equivalent to *expr or something similar. self.cat_expr_autoderefd(expr, autoderefs) } diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 8488468416f79..db6ac02bbe123 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -301,23 +301,25 @@ pub enum UnsizeKind<'tcx> { #[derive(Clone, Debug)] pub struct AutoDerefRef<'tcx> { + /// Apply a number of dereferences, producing an lvalue. pub autoderefs: uint, - pub autoref: Option> + + /// Convert a lvalue from [T; n] to [T] (or similar, depending on the kind). + pub unsize: Option>, + + /// Produce a pointer/reference from the lvalue. + pub autoref: Option } #[derive(Clone, PartialEq, Debug)] -pub enum AutoRef<'tcx> { +pub enum AutoRef { /// 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>), + AutoPtr(Region, ast::Mutability, Option>), /// Convert from T to *T /// Value to thin pointer - /// The second field allows us to wrap other AutoRef adjustments. - AutoUnsafe(ast::Mutability, Option>>), + AutoUnsafe(ast::Mutability), } #[derive(Clone, Copy, RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Debug)] @@ -4493,6 +4495,10 @@ pub fn adjust_ty<'tcx, F>(cx: &ctxt<'tcx>, } } + if let Some(ref k) = adj.unsize { + adjusted_ty = unsize_ty(cx, adjusted_ty, k, span); + } + adjust_ty_for_autoref(cx, span, adjusted_ty, adj.autoref.as_ref()) } @@ -4517,7 +4523,7 @@ 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>>) + autoref: Option<&AutoRef>) -> Ty<'tcx> { match autoref { @@ -4534,15 +4540,9 @@ pub fn adjust_ty_for_autoref<'tcx>(cx: &ctxt<'tcx>, }) } - 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(&AutoUnsafe(m)) => { + mk_ptr(cx, mt {ty: ty, mutbl: m}) } - - Some(&AutoUnsize(ref k)) => unsize_ty(cx, ty, k, span), } } @@ -6615,7 +6615,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() } } @@ -6783,21 +6783,19 @@ impl<'tcx> Repr<'tcx> for UnsizeKind<'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> { +impl<'tcx> Repr<'tcx> for AutoRef { 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)) - } - 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 477dea1f687de..099a0c30bffb2 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -129,7 +129,7 @@ pub trait TypeFolder<'tcx> : Sized { super_fold_existential_bounds(self, s) } - fn fold_autoref(&mut self, ar: &ty::AutoRef<'tcx>) -> ty::AutoRef<'tcx> { + fn fold_autoref(&mut self, ar: &ty::AutoRef) -> ty::AutoRef { super_fold_autoref(self, ar) } @@ -292,8 +292,8 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ItemSubsts<'tcx> { } } -impl<'tcx> TypeFoldable<'tcx> for ty::AutoRef<'tcx> { - fn fold_with>(&self, folder: &mut F) -> ty::AutoRef<'tcx> { +impl<'tcx> TypeFoldable<'tcx> for ty::AutoRef { + fn fold_with>(&self, folder: &mut F) -> ty::AutoRef { folder.fold_autoref(self) } } @@ -754,19 +754,15 @@ pub fn super_fold_existential_bounds<'tcx, T: TypeFolder<'tcx>>( } pub fn super_fold_autoref<'tcx, T: TypeFolder<'tcx>>(this: &mut T, - autoref: &ty::AutoRef<'tcx>) - -> ty::AutoRef<'tcx> + autoref: &ty::AutoRef) + -> ty::AutoRef { 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::AutoUnsize(ref k) => ty::AutoUnsize(k.fold_with(this)), + ty::AutoUnsafe(m) => ty::AutoUnsafe(m) } } diff --git a/src/librustc_trans/trans/consts.rs b/src/librustc_trans/trans/consts.rs index f827a11eace3b..77b2c7fa8a810 100644 --- a/src/librustc_trans/trans/consts.rs +++ b/src/librustc_trans/trans/consts.rs @@ -260,7 +260,7 @@ pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, } } - let second_autoref = match adj.autoref { + match adj.autoref { None => { let (dv, dt) = const_deref(cx, llconst, ty); llconst = dv; @@ -269,10 +269,8 @@ pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, // 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)) => { + Some(_) => { if adj.autoderefs == 0 { // Don't copy data to do a deref+ref // (i.e., skip the last auto-deref). @@ -293,36 +291,40 @@ pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, } } } - opt_autoref - } - Some(autoref) => { - cx.sess().span_bug(e.span, - &format!("unimplemented const first autoref {:?}", autoref)) } + } + + if let Some(ref k) = adj.unsize { + // This works a reference, not an lvalue (like trans::expr does). + assert!(adj.autoref.is_some()); + + let info = expr::unsized_info(cx, k, 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); + } + + let second_autoref = if let Some(ty::AutoPtr(_, _, opt_autoref)) = adj.autoref { + opt_autoref + } else { + None }; + match second_autoref { None => {} - Some(box ty::AutoUnsafe(_, None)) | + Some(box ty::AutoUnsafe(_)) | Some(box ty::AutoPtr(_, _, None)) => { llconst = addr_of(cx, llconst, "autoref", e.id); } - Some(box ty::AutoUnsize(ref k)) => { - let info = - expr::unsized_info( - cx, k, 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)) diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs index 1fbddb6ddca99..2030d4a873a53 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; @@ -382,14 +381,14 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, // purely a type-level thing } AdjustDerefRef(ref adj) => { - let skip_reborrows = match adj.autoref { + let skip_reborrows = match (&adj.unsize, &adj.autoref) { // 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 => { + (&None, &Some(ty::AutoPtr(_, _, None))) | + (&None, &Some(ty::AutoUnsafe(_))) if adj.autoderefs == 1 => { match datum.ty.sty { // Don't skip a conversion from Box to &T, etc. ty::ty_rptr(..) => { @@ -416,6 +415,13 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, adj.autoderefs - skip_reborrows)); } + if let Some(ref k) = adj.unsize { + // Arrange cleanup + let lval = unpack_datum!(bcx, + datum.to_lvalue_datum(bcx, "into_fat_ptr", expr.id)); + datum = unpack_datum!(bcx, unsize_lvalue(bcx, expr, lval, k)); + } + // (You might think there is a more elegant way to do this than a // skip_reborrows bool, but then you remember that the borrow checker exists). if let (0, &Some(ref a)) = (skip_reborrows, &adj.autoref) { @@ -430,7 +436,7 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, debug!("after adjustments, datum={}", datum.to_string(bcx.ccx())); return DatumBlock::new(bcx, datum); - fn apply_autoref<'blk, 'tcx>(autoref: &ty::AutoRef<'tcx>, + fn apply_autoref<'blk, 'tcx>(autoref: &ty::AutoRef, bcx: Block<'blk, 'tcx>, expr: &ast::Expr, datum: Datum<'tcx, Expr>) @@ -438,41 +444,28 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, 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"); - // Arrange cleanup - let lval = unpack_datum!(bcx, - datum.to_lvalue_datum(bcx, "into_fat_ptr", expr.id)); - unpack_datum!(bcx, unsize_expr(bcx, expr, lval, k)) - } - }; + if let ty::AutoPtr(_, _, Some(ref a)) = *autoref { + datum = unpack_datum!(bcx, apply_autoref(a, bcx, expr, datum)); + } - 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, Lvalue>, - k: &ty::UnsizeKind<'tcx>) - -> DatumBlock<'blk, 'tcx, Expr> { + fn unsize_lvalue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, + expr: &ast::Expr, + datum: Datum<'tcx, Lvalue>, + k: &ty::UnsizeKind<'tcx>) + -> DatumBlock<'blk, 'tcx, Expr> { let datum_ty = datum.ty; let unsized_ty = ty::unsize_ty(bcx.tcx(), datum_ty, k, expr.span); - debug!("unsize_expr(unsized_ty={})", unsized_ty.repr(bcx.tcx())); + debug!("unsize_lvalue(unsized_ty={})", unsized_ty.repr(bcx.tcx())); let info = unsized_info_bcx(bcx, k, datum_ty, datum.val, bcx.fcx.param_substs); diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index 6ba21e25e1fe5..015a251be05bf 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -84,7 +84,11 @@ pub fn check_call<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, UnresolvedTypeAction::Error, LvaluePreference::NoPreference, |adj_ty, idx| { - let autoderefref = ty::AutoDerefRef { autoderefs: idx, autoref: None }; + let autoderefref = ty::AutoDerefRef { + autoderefs: idx, + unsize: None, + autoref: None + }; try_overloaded_call_step(fcx, call_expr, callee_expr, adj_ty, autoderefref) }); diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 1548e1065188d..e3350c08a24b4 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -66,7 +66,7 @@ use middle::infer::{self, cres, Coercion, TypeTrace}; use middle::infer::combine::Combine; use middle::infer::sub::Sub; use middle::subst; -use middle::ty::{AutoPtr, AutoDerefRef, AdjustDerefRef, AutoUnsize, AutoUnsafe}; +use middle::ty::{AutoDerefRef, AdjustDerefRef}; use middle::ty::{self, mt, Ty}; use util::common::indent; use util::ppaux; @@ -192,7 +192,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { let coercion = Coercion(self.trace.clone()); let r_borrow = self.fcx.infcx().next_region_var(coercion); - let autoref = Some(AutoPtr(r_borrow, mutbl_b, None)); + let autoref = Some(ty::AutoPtr(r_borrow, mutbl_b, None)); let r_borrow = self.tcx().mk_region(r_borrow); let lvalue_pref = match mutbl_b { @@ -228,6 +228,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { Some(_) => { Ok(Some(AdjustDerefRef(AutoDerefRef { autoderefs: autoderefs, + unsize: None, autoref: autoref }))) } @@ -271,11 +272,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { ty::mt{ty: ty, mutbl: mt_b.mutbl}); try!(self.fcx.infcx().try(|_| self.subtype(ty, b))); debug!("Success, coerced with AutoDerefRef(1, \ - AutoPtr(AutoUnsize({:?})))", kind); + unsize({:?}), AutoPtr)", kind); Ok(Some(AdjustDerefRef(AutoDerefRef { autoderefs: 1, - autoref: Some(ty::AutoPtr(r_borrow, mt_b.mutbl, - Some(box AutoUnsize(kind)))) + unsize: Some(kind), + autoref: Some(ty::AutoPtr(r_borrow, mt_b.mutbl, None)) }))) } _ => Err(ty::terr_mismatch) @@ -292,11 +293,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { ty::mt{ty: ty, mutbl: mt_b.mutbl}); try!(self.fcx.infcx().try(|_| self.subtype(ty, b))); debug!("Success, coerced with AutoDerefRef(1, \ - AutoPtr(AutoUnsize({:?})))", kind); + unsize({:?}), AutoUnsafe)", kind); Ok(Some(AdjustDerefRef(AutoDerefRef { autoderefs: 1, - autoref: Some(ty::AutoUnsafe(mt_b.mutbl, - Some(box AutoUnsize(kind)))) + unsize: Some(kind), + autoref: Some(ty::AutoUnsafe(mt_b.mutbl)) }))) } _ => Err(ty::terr_mismatch) @@ -521,7 +522,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // regionck knows that the region for `a` must be valid here. Ok(Some(AdjustDerefRef(AutoDerefRef { autoderefs: 1, - autoref: Some(ty::AutoUnsafe(mutbl_b, None)) + unsize: None, + autoref: Some(ty::AutoUnsafe(mutbl_b)) }))) } } diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 6aefcf5a47cc6..f9e5beb27a87f 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -158,8 +158,14 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { assert_eq!(n, auto_deref_ref.autoderefs); assert_eq!(result, Some(())); + let adjusted_ty = if let Some(ref k) = auto_deref_ref.unsize { + ty::unsize_ty(self.tcx(), autoderefd_ty, k, self.span) + } else { + autoderefd_ty + }; + let final_ty = - ty::adjust_ty_for_autoref(self.tcx(), self.span, autoderefd_ty, + ty::adjust_ty_for_autoref(self.tcx(), self.span, adjusted_ty, auto_deref_ref.autoref.as_ref()); // Write out the final adjustment. @@ -176,13 +182,15 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { probe::AutoDeref(num) => { ty::AutoDerefRef { autoderefs: num, - autoref: None, + unsize: None, + autoref: None } } probe::AutoUnsizeLength(autoderefs, len) => { ty::AutoDerefRef { autoderefs: autoderefs, - autoref: Some(ty::AutoUnsize(ty::UnsizeLength(len))), + unsize: Some(ty::UnsizeLength(len)), + autoref: None } } probe::AutoRef(mutability, ref sub_adjustment) => { @@ -499,10 +507,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, }; @@ -532,7 +537,11 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { 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 }, + None => ty::AutoDerefRef { + autoderefs: 0, + unsize: None, + autoref: None + }, Some(_) => { self.tcx().sess.span_bug( base_expr.span, @@ -662,7 +671,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { fn wrap_autoref<'tcx, F>(mut deref: ty::AutoDerefRef<'tcx>, base_fn: F) -> ty::AutoDerefRef<'tcx> where - F: FnOnce(Option>>) -> ty::AutoRef<'tcx>, + F: FnOnce(Option>) -> ty::AutoRef, { let autoref = mem::replace(&mut deref.autoref, None); let autoref = autoref.map(|r| box r); diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index 7ef2db2c28d88..09c1ebfec4da0 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -122,7 +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 }, + ty::AutoDerefRef { autoderefs: 0, unsize: None, autoref: None }, self_ty, opt_input_types) } @@ -260,13 +260,14 @@ 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 ty::AutoDerefRef { autoderefs, unsize, autoref } = autoderefref; let autoref = autoref.map(|r| box r); fcx.write_adjustment( self_expr.id, span, ty::AdjustDerefRef(ty::AutoDerefRef { autoderefs: autoderefs, + unsize: unsize, autoref: Some(ty::AutoPtr(*region, mutbl, autoref)) })); } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index a0b32a7b1fff5..336814721c3fe 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1444,7 +1444,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span, ty::AdjustDerefRef(ty::AutoDerefRef { autoderefs: derefs, - autoref: None }) + unsize: None, + autoref: None + }) ); } @@ -1531,34 +1533,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { 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 => {} - } - } - ty::AdjustUnsize(ref unsize) => { - self.register_unsize_obligations(span, unsize); - } - } - } + ty::AdjustReifyFnPointer(..) | + ty::AdjustUnsafeFnPointer | + ty::AdjustDerefRef(ty::AutoDerefRef { unsize: None, .. }) => {} - fn register_autoref_obligations(&self, - span: Span, - autoref: &ty::AutoRef<'tcx>) { - match *autoref { - 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::AutoUnsize(ref unsize) => { + ty::AdjustDerefRef(ty::AutoDerefRef { unsize: Some(ref unsize), .. }) | + ty::AdjustUnsize(ref unsize) => { self.register_unsize_obligations(span, unsize); } } @@ -2136,7 +2116,11 @@ 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 }; + let autoderefref = ty::AutoDerefRef { + autoderefs: idx, + unsize: None, + autoref: None + }; step(adj_ty, autoderefref) }); @@ -2151,7 +2135,8 @@ fn autoderef_for_index<'a, 'tcx, T, F>(fcx: &FnCtxt<'a, 'tcx>, let adjusted_ty = ty::mk_vec(fcx.tcx(), element_ty, None); let autoderefref = ty::AutoDerefRef { autoderefs: autoderefs, - autoref: Some(ty::AutoUnsize(ty::UnsizeLength(n))) + unsize: Some(ty::UnsizeLength(n)), + autoref: None }; step(adjusted_ty, autoderefref) } @@ -2837,11 +2822,19 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, fcx.mk_subr(infer::Reborrow(lhs.span), r_adj, *r_in); let adjusted_ty = ty::mk_rptr(fcx.tcx(), fcx.tcx().mk_region(r_adj), mt); let autoptr = ty::AutoPtr(r_adj, mt.mutbl, None); - let adjustment = ty::AutoDerefRef { autoderefs: 1, autoref: Some(autoptr) }; + let adjustment = ty::AutoDerefRef { + autoderefs: 1, + unsize: None, + autoref: Some(autoptr) + }; (adjusted_ty, adjustment) } _ => { - (lhs_ty, ty::AutoDerefRef { autoderefs: 0, autoref: None }) + (lhs_ty, ty::AutoDerefRef { + autoderefs: 0, + unsize: None, + autoref: None + }) } }; diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index cf9fb79ab2e71..8635e322ba388 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 @@ -1132,7 +1132,7 @@ fn link_autoref(rcx: &Rcx, ty::BorrowKind::from_mutbl(m), expr_cmt); } - ty::AutoUnsafe(..) | ty::AutoUnsize(_) => {} + ty::AutoUnsafe(_) => {} } } diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index aa34eb8df73f7..b764205882f16 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -276,6 +276,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { ty::AdjustDerefRef(ty::AutoDerefRef { autoderefs: adj.autoderefs, + unsize: self.resolve(&adj.unsize, reason), autoref: self.resolve(&adj.autoref, reason), }) } From 88ee3c8cd739cacc23fb439e9c876af1f97be89a Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Wed, 18 Mar 2015 21:53:33 +0200 Subject: [PATCH 04/12] Remove AdjustReifyFnPointer's unnecessary DefId field. --- src/librustc/middle/astencode.rs | 20 +++++--------- src/librustc/middle/expr_use_visitor.rs | 4 +-- src/librustc/middle/mem_categorization.rs | 4 +-- src/librustc/middle/ty.rs | 12 ++++----- src/librustc_trans/trans/consts.rs | 2 +- src/librustc_trans/trans/expr.rs | 2 +- src/librustc_typeck/check/coercion.rs | 33 +++++++++-------------- src/librustc_typeck/check/mod.rs | 2 +- src/librustc_typeck/check/writeback.rs | 4 +-- 9 files changed, 32 insertions(+), 51 deletions(-) diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index bdb464a965a8c..1f4bbd726967c 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -1008,10 +1008,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 => { @@ -1621,18 +1619,12 @@ 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 = ["AdjustReifyFnPointer", "AdjustDerefRef", "AdjustUnsize"]; + let variants = ["AdjustReifyFnPointer", "AdjustUnsafeFnPointer", + "AdjustDerefRef", "AdjustUnsize"]; 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, diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 5666605f71145..70a6cacdff731 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -790,8 +790,8 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { None => { } Some(adjustment) => { match *adjustment { - ty::AdjustReifyFnPointer(..) | - ty::AdjustUnsafeFnPointer(..) | + ty::AdjustReifyFnPointer | + ty::AdjustUnsafeFnPointer | ty::AdjustUnsize(_) => { // Creating a closure/fn-pointer or unsizing consumes // the input and stores it into the resulting rvalue. diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 3e4411fdfe06c..6ec7f9abf9c44 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -428,8 +428,8 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> { Some(adjustment) => { match *adjustment { - ty::AdjustReifyFnPointer(..) | - ty::AdjustUnsafeFnPointer(..) => { + ty::AdjustReifyFnPointer | + ty::AdjustUnsafeFnPointer => { debug!("cat_expr(AdjustReifyFnPointer): {}", expr.repr(self.tcx())); // Convert a bare fn to a closure by adding NULL env. diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index db6ac02bbe123..e794d5be29ab2 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -280,7 +280,7 @@ pub enum Variance { #[derive(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>), @@ -4438,7 +4438,7 @@ 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) @@ -6606,8 +6606,8 @@ impl<'tcx> AutoAdjustment<'tcx> { pub fn is_identity(&self) -> bool { match *self { AdjustUnsize(_) | - AdjustReifyFnPointer(..) => false, - AdjustUnsafeFnPointer(..) => false, + AdjustReifyFnPointer | + AdjustUnsafeFnPointer => false, AdjustDerefRef(ref r) => r.is_identity(), } } @@ -6754,8 +6754,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") diff --git a/src/librustc_trans/trans/consts.rs b/src/librustc_trans/trans/consts.rs index 77b2c7fa8a810..39e52afb146a3 100644 --- a/src/librustc_trans/trans/consts.rs +++ b/src/librustc_trans/trans/consts.rs @@ -242,7 +242,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 } diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs index 2030d4a873a53..8034c94555086 100644 --- a/src/librustc_trans/trans/expr.rs +++ b/src/librustc_trans/trans/expr.rs @@ -373,7 +373,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 } diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index e3350c08a24b4..bb15102b36114 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -143,11 +143,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 @@ -446,29 +446,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> { @@ -485,11 +478,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) } }) } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 336814721c3fe..8376867d072ad 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1533,7 +1533,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: Span, adj: &ty::AutoAdjustment<'tcx>) { match *adj { - ty::AdjustReifyFnPointer(..) | + ty::AdjustReifyFnPointer | ty::AdjustUnsafeFnPointer | ty::AdjustDerefRef(ty::AutoDerefRef { unsize: None, .. }) => {} diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index b764205882f16..96ef7678b3afb 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -260,9 +260,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { Some(adjustment) => { let resolved_adjustment = match adjustment { - ty::AdjustReifyFnPointer(def_id) => { - ty::AdjustReifyFnPointer(def_id) - } + ty::AdjustReifyFnPointer => ty::AdjustReifyFnPointer, ty::AdjustUnsafeFnPointer => { ty::AdjustUnsafeFnPointer From f1c6b886b8366ac477b85da27b7340772813e780 Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Thu, 19 Mar 2015 16:02:14 +0200 Subject: [PATCH 05/12] Do not use recursive storage for unsizing and autoref coercions. --- src/librustc/middle/astencode.rs | 155 ++++++-------------- src/librustc/middle/expr_use_visitor.rs | 2 +- src/librustc/middle/ty.rs | 118 +++++---------- src/librustc/middle/ty_fold.rs | 25 +--- src/librustc_lint/builtin.rs | 4 +- src/librustc_trans/trans/consts.rs | 43 +----- src/librustc_trans/trans/expr.rs | 117 ++++++--------- src/librustc_typeck/check/callee.rs | 57 ++++--- src/librustc_typeck/check/coercion.rs | 104 ++++++------- src/librustc_typeck/check/method/confirm.rs | 46 +++--- src/librustc_typeck/check/method/mod.rs | 24 +-- src/librustc_typeck/check/method/probe.rs | 58 ++++---- src/librustc_typeck/check/mod.rs | 144 +++++++----------- src/librustc_typeck/check/regionck.rs | 2 +- 14 files changed, 329 insertions(+), 570 deletions(-) diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index 1f4bbd726967c..7556ef30cfbc7 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -845,8 +845,8 @@ trait rbml_writer_helpers<'tcx> { autoref: &ty::AutoRef); 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>); + fn emit_auto_unsize<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, + unsize: &ty::AutoUnsize<'tcx>); } impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> { @@ -1026,8 +1026,8 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> { } ty::AdjustUnsize(ref uk) => { - this.emit_enum_variant("AdjustUnsize", 3, 1, |this| { - this.emit_enum_variant_arg(0, |this| Ok(this.emit_unsize_kind(ecx, uk))) + this.emit_enum_variant("AdjustUnsize", 4, 1, |this| { + this.emit_enum_variant_arg(0, |this| Ok(this.emit_auto_unsize(ecx, uk))) }) } } @@ -1040,20 +1040,10 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> { self.emit_enum("AutoRef", |this| { match autoref { - &ty::AutoPtr(r, m, None) => { - this.emit_enum_variant("AutoPtr", 0, 3, |this| { + &ty::AutoPtr(r, m) => { + this.emit_enum_variant("AutoPtr", 0, 2, |this| { this.emit_enum_variant_arg(0, |this| r.encode(this)); - this.emit_enum_variant_arg(1, |this| m.encode(this)); - this.emit_enum_variant_arg(2, - |this| this.emit_option(|this| this.emit_option_none())) - }) - } - &ty::AutoPtr(r, m, Some(box ref a)) => { - this.emit_enum_variant("AutoPtr", 0, 3, |this| { - this.emit_enum_variant_arg(0, |this| r.encode(this)); - this.emit_enum_variant_arg(1, |this| m.encode(this)); - this.emit_enum_variant_arg(2, |this| this.emit_option( - |this| this.emit_option_some(|this| Ok(this.emit_autoref(ecx, a))))) + this.emit_enum_variant_arg(1, |this| m.encode(this)) }) } &ty::AutoUnsafe(m) => { @@ -1076,7 +1066,7 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> { this.emit_option(|this| { match auto_deref_ref.unsize { None => this.emit_option_none(), - Some(ref uk) => this.emit_option_some(|this| Ok(this.emit_unsize_kind(ecx, uk))), + Some(ref uk) => this.emit_option_some(|this| Ok(this.emit_auto_unsize(ecx, uk))), } }) }); @@ -1092,44 +1082,20 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> { }); } - fn emit_unsize_kind<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>, - uk: &ty::UnsizeKind<'tcx>) { + fn emit_auto_unsize<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>, + unsize: &ty::AutoUnsize<'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))) - }) - } - } + self.emit_struct("AutoUnsize", 3, |this| { + this.emit_struct_field("leaf_source", 0, |this| { + Ok(this.emit_ty(ecx, unsize.leaf_source)) + }); + this.emit_struct_field("leaf_target", 1, |this| { + Ok(this.emit_ty(ecx, unsize.leaf_target)) + }); + this.emit_struct_field("root_target", 2, |this| { + Ok(this.emit_ty(ecx, unsize.root_target)) + }) }); } } @@ -1346,8 +1312,8 @@ trait rbml_decoder_decoder_helpers<'tcx> { -> ty::AutoDerefRef<'tcx>; fn read_autoref<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) -> ty::AutoRef; - fn read_unsize_kind<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) - -> ty::UnsizeKind<'tcx>; + fn read_auto_unsize<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) + -> ty::AutoUnsize<'tcx>; fn convert_def_id(&mut self, dcx: &DecodeContext, source: DefIdSource, @@ -1632,10 +1598,10 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { ty::AdjustDerefRef(auto_deref_ref) } - 3 => { - let uk: ty::UnsizeKind = + 4 => { + let uk: ty::AutoUnsize = this.read_enum_variant_arg(0, - |this| Ok(this.read_unsize_kind(dcx))).unwrap(); + |this| Ok(this.read_auto_unsize(dcx))).unwrap(); ty::AdjustUnsize(uk) } @@ -1655,7 +1621,7 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { unsize: this.read_struct_field("unsize", 1, |this| { this.read_option(|this, b| { if b { - Ok(Some(this.read_unsize_kind(dcx))) + Ok(Some(this.read_auto_unsize(dcx))) } else { Ok(None) } @@ -1684,16 +1650,8 @@ 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) + + ty::AutoPtr(r.tr(dcx), m) } 1 => { let m: ast::Mutability = @@ -1707,50 +1665,19 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { }).unwrap() } - fn read_unsize_kind<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) - -> ty::UnsizeKind<'tcx> { - self.read_enum("UnsizeKind", |this| { - let variants = &["UnsizeLength", "UnsizeStruct", "UnsizeVtable", "UnsizeUpcast"]; - this.read_enum_variant(variants, |this, i| { - Ok(match i { - 0 => { - let len: uint = - this.read_enum_variant_arg(0, |this| Decodable::decode(this)).unwrap(); - - ty::UnsizeLength(len) - } - 1 => { - let uk: ty::UnsizeKind = - this.read_enum_variant_arg(0, - |this| Ok(this.read_unsize_kind(dcx))).unwrap(); - let idx: uint = - this.read_enum_variant_arg(1, |this| Decodable::decode(this)).unwrap(); - - ty::UnsizeStruct(box uk, idx) - } - 2 => { - let ty_trait = try!(this.read_enum_variant_arg(0, |this| { - let principal = try!(this.read_struct_field("principal", 0, |this| { - Ok(this.read_poly_trait_ref(dcx)) - })); - Ok(ty::TyTrait { - principal: principal, - bounds: try!(this.read_struct_field("bounds", 1, |this| { - Ok(this.read_existential_bounds(dcx)) - })), - }) - })); - let self_ty = - this.read_enum_variant_arg(1, |this| Ok(this.read_ty(dcx))).unwrap(); - ty::UnsizeVtable(ty_trait, self_ty) - } - 3 => { - let target_ty = - this.read_enum_variant_arg(0, |this| Ok(this.read_ty(dcx))).unwrap(); - ty::UnsizeUpcast(target_ty) - } - _ => panic!("bad enum variant for ty::UnsizeKind") - }) + fn read_auto_unsize<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) + -> ty::AutoUnsize<'tcx> { + self.read_struct("AutoUnsize", 3, |this| { + Ok(ty::AutoUnsize { + leaf_source: this.read_struct_field("leaf_source", 0, |this| { + Ok(this.read_ty(dcx)) + }).unwrap(), + leaf_target: this.read_struct_field("leaf_target", 1, |this| { + Ok(this.read_ty(dcx)) + }).unwrap(), + root_target: this.read_struct_field("root_target", 1, |this| { + Ok(this.read_ty(dcx)) + }).unwrap() }) }).unwrap() } diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 70a6cacdff731..aaff6bc904a45 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -864,7 +864,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { cmt_derefd.repr(self.tcx())); match *autoref { - ty::AutoPtr(r, m, _) => { + ty::AutoPtr(r, m) => { self.delegate.borrow(expr.id, expr.span, cmt_derefd, diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index e794d5be29ab2..4046bc22ea7d5 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::*; @@ -285,18 +284,18 @@ pub enum AutoAdjustment<'tcx> { AdjustDerefRef(AutoDerefRef<'tcx>), /// Convert Box<[T, ..n]> to Box<[T]> or something similar in a Box. - AdjustUnsize(UnsizeKind<'tcx>), + AdjustUnsize(AutoUnsize<'tcx>), } -#[derive(Clone, PartialEq, Debug)] -pub enum UnsizeKind<'tcx> { - // [T, ..n] -> [T], the uint field is n. - UnsizeLength(uint), - // An unsize coercion applied to the tail field of a struct. - // The uint is the index of the type parameter which is unsized. - UnsizeStruct(Box>, uint), - UnsizeVtable(TyTrait<'tcx>, /* the self type of the trait */ Ty<'tcx>), - UnsizeUpcast(Ty<'tcx>), +// In the case of `&Struct<[T; N]>` -> `&Struct<[T]>`, the types are: +// * leaf_source: `[T; N]` +// * leaf_target: `[T]` +// * root_target: `Struct<[T]>` +#[derive(Copy, Clone, Debug)] +pub struct AutoUnsize<'tcx> { + pub leaf_source: Ty<'tcx>, + pub leaf_target: Ty<'tcx>, + pub root_target: Ty<'tcx> } #[derive(Clone, Debug)] @@ -305,17 +304,16 @@ pub struct AutoDerefRef<'tcx> { pub autoderefs: uint, /// Convert a lvalue from [T; n] to [T] (or similar, depending on the kind). - pub unsize: Option>, + pub unsize: Option>, /// Produce a pointer/reference from the lvalue. pub autoref: Option } -#[derive(Clone, PartialEq, Debug)] +#[derive(Copy, Clone, PartialEq, Debug)] pub enum AutoRef { /// Convert from T to &T - /// The third field allows us to wrap other AutoRef adjustments. - AutoPtr(Region, ast::Mutability, Option>), + AutoPtr(Region, ast::Mutability), /// Convert from T to *T /// Value to thin pointer @@ -4495,18 +4493,16 @@ pub fn adjust_ty<'tcx, F>(cx: &ctxt<'tcx>, } } - if let Some(ref k) = adj.unsize { - adjusted_ty = unsize_ty(cx, adjusted_ty, k, span); + if let Some(ref unsize) = adj.unsize { + adjusted_ty = unsize.root_target; } - adjust_ty_for_autoref(cx, span, adjusted_ty, adj.autoref.as_ref()) + adjust_ty_for_autoref(cx, adjusted_ty, adj.autoref.as_ref()) } - AdjustUnsize(ref k) => { + AdjustUnsize(ref unsize) => { match unadjusted_ty.sty { - ty::ty_uniq(ty) => { - ty::mk_uniq(cx, unsize_ty(cx, ty, k, span)) - } + ty::ty_uniq(_) => ty::mk_uniq(cx, unsize.root_target), _ => { cx.sess.bug( &format!("AdjustUnsize adjustment on non-Box type: \ @@ -4521,65 +4517,17 @@ 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>) -> 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, cx.mk_region(r), mt { ty: ty, mutbl: m }) } - Some(&AutoUnsafe(m)) => { - mk_ptr(cx, mt {ty: ty, mutbl: m}) - } - } -} - -// 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 + mk_ptr(cx, mt { ty: ty, mutbl: m }) } } } @@ -6770,14 +6718,12 @@ impl<'tcx> Repr<'tcx> for AutoAdjustment<'tcx> { } } -impl<'tcx> Repr<'tcx> for UnsizeKind<'tcx> { +impl<'tcx> Repr<'tcx> for AutoUnsize<'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)), - } + format!("unsize({} => {}) => {}", + self.leaf_source.repr(tcx), + self.leaf_target.repr(tcx), + self.root_target.repr(tcx)) } } @@ -6791,8 +6737,8 @@ impl<'tcx> Repr<'tcx> for AutoDerefRef<'tcx> { impl<'tcx> Repr<'tcx> for AutoRef { fn repr(&self, tcx: &ctxt<'tcx>) -> String { match *self { - AutoPtr(a, b, ref c) => { - format!("AutoPtr({},{:?},{})", a.repr(tcx), b, c.repr(tcx)) + AutoPtr(a, b) => { + format!("AutoPtr({},{:?})", a.repr(tcx), b) } AutoUnsafe(ref a) => { format!("AutoUnsafe({:?})", a) @@ -7211,6 +7157,14 @@ impl<'tcx> HasProjectionTypes for BareFnTy<'tcx> { } } +impl<'tcx> HasProjectionTypes for AutoUnsize<'tcx> { + fn has_projection_types(&self) -> bool { + self.leaf_source.has_projection_types() || + self.leaf_target.has_projection_types() || + self.root_target.has_projection_types() + } +} + pub trait ReferencesError { fn references_error(&self) -> bool; } diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs index 099a0c30bffb2..63b147523dfae 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -467,20 +467,12 @@ 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> TypeFoldable<'tcx> for ty::AutoUnsize<'tcx> { + fn fold_with>(&self, folder: &mut F) -> ty::AutoUnsize<'tcx> { + ty::AutoUnsize { + leaf_source: self.leaf_source.fold_with(folder), + leaf_target: self.leaf_target.fold_with(folder), + root_target: self.root_target.fold_with(folder) } } } @@ -758,10 +750,7 @@ pub fn super_fold_autoref<'tcx, T: TypeFolder<'tcx>>(this: &mut T, -> ty::AutoRef { match *autoref { - ty::AutoPtr(r, m, None) => ty::AutoPtr(this.fold_region(r), m, None), - ty::AutoPtr(r, m, Some(ref a)) => { - ty::AutoPtr(this.fold_region(r), m, Some(box super_fold_autoref(this, &**a))) - } + ty::AutoPtr(r, m) => ty::AutoPtr(this.fold_region(r), m), ty::AutoUnsafe(m) => ty::AutoUnsafe(m) } } diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 8b57a48f3ce72..2b25829b2ff4c 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -1406,11 +1406,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/consts.rs b/src/librustc_trans/trans/consts.rs index 39e52afb146a3..1ddd6093af92f 100644 --- a/src/librustc_trans/trans/consts.rs +++ b/src/librustc_trans/trans/consts.rs @@ -275,34 +275,21 @@ pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, // Don't copy data to do a deref+ref // (i.e., skip the last auto-deref). llconst = addr_of(cx, llconst, "autoref", e.id); - } 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))) - } - } } } } - if let Some(ref k) = adj.unsize { + if let Some(ref unsize) = adj.unsize { // This works a reference, not an lvalue (like trans::expr does). assert!(adj.autoref.is_some()); - let info = expr::unsized_info(cx, k, ty, param_substs, + let unsize = monomorphize::apply_param_substs(cx.tcx(), + param_substs, + unsize); + let info = expr::unsized_info(cx, &unsize, 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 ptr_ty = type_of::in_memory_type_of(cx, unsize.root_target).ptr_to(); let base = ptrcast(llconst, ptr_ty); let prev_const = cx.const_unsized().borrow_mut() @@ -312,24 +299,6 @@ pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, assert_eq!(abi::FAT_PTR_EXTRA, 1); llconst = C_struct(cx, &[base, info], false); } - - let second_autoref = if let Some(ty::AutoPtr(_, _, opt_autoref)) = adj.autoref { - opt_autoref - } else { - None - }; - - match second_autoref { - None => {} - Some(box ty::AutoUnsafe(_)) | - Some(box ty::AutoPtr(_, _, None)) => { - llconst = addr_of(cx, llconst, "autoref", e.id); - } - Some(autoref) => { - cx.sess().span_bug(e.span, - &format!("unimplemented const second autoref {:?}", autoref)) - } - } } Some(adj) => { cx.sess().span_bug(e.span, diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs index 8034c94555086..3cc42c4b248c1 100644 --- a/src/librustc_trans/trans/expr.rs +++ b/src/librustc_trans/trans/expr.rs @@ -296,60 +296,43 @@ pub fn copy_fat_ptr(bcx: Block, src_ptr: ValueRef, dst_ptr: ValueRef) { /// 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>, - unadjusted_ty: Ty<'tcx>, - unadjusted_val: ValueRef, // see above (*) - param_substs: &'tcx subst::Substs<'tcx>) - -> ValueRef { - unsized_info( - bcx.ccx(), - kind, - unadjusted_ty, - param_substs, +fn unsized_info_bcx<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, + unsize: &ty::AutoUnsize<'tcx>, + unadjusted_val: ValueRef) // see above (*)) + -> ValueRef { + unsized_info(bcx.ccx(), unsize, bcx.fcx.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 +// Same as `unsized_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>, - unadjusted_ty: Ty<'tcx>, + unsize: &ty::AutoUnsize<'tcx>, param_substs: &'tcx subst::Substs<'tcx>, mk_upcast_vtable: MK_UPCAST_VTABLE) // see notes above -> ValueRef where MK_UPCAST_VTABLE: FnOnce() -> ValueRef { - 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, 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, .. }, _) => { + match (&unsize.leaf_source.sty, &unsize.leaf_target.sty) { + (&ty::ty_vec(_, Some(len)), &ty::ty_vec(_, None)) => C_uint(ccx, len), + (&ty::ty_trait(_), &ty::ty_trait(_)) => { + // For now, upcasts are limited to changes in marker + // traits, and hence never actually require an actual + // change to the vtable. + mk_upcast_vtable() + } + (_, &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(unsize.leaf_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 {}", + unsize.repr(ccx.tcx()))) } } @@ -381,19 +364,17 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, // purely a type-level thing } AdjustDerefRef(ref adj) => { - let skip_reborrows = match (&adj.unsize, &adj.autoref) { - // 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). - (&None, &Some(ty::AutoPtr(_, _, None))) | - (&None, &Some(ty::AutoUnsafe(_))) if adj.autoderefs == 1 => { + let skip_reborrows = match *adj { + ty::AutoDerefRef { autoderefs: 1, unsize: None, autoref: 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). match datum.ty.sty { // Don't skip a conversion from Box to &T, etc. ty::ty_rptr(..) => { - let autoderef = (adj.autoderefs - 1) as u32; - let method_call = MethodCall::autoderef(expr.id, autoderef); + 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 @@ -415,38 +396,32 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, adj.autoderefs - skip_reborrows)); } - if let Some(ref k) = adj.unsize { + if let Some(ref unsize) = adj.unsize { // Arrange cleanup let lval = unpack_datum!(bcx, datum.to_lvalue_datum(bcx, "into_fat_ptr", expr.id)); - datum = unpack_datum!(bcx, unsize_lvalue(bcx, expr, lval, k)); + datum = unpack_datum!(bcx, unsize_lvalue(bcx, lval, unsize)); } // (You might think there is a more elegant way to do this than a // skip_reborrows bool, but then you remember that the borrow checker exists). - if let (0, &Some(ref a)) = (skip_reborrows, &adj.autoref) { - datum = unpack_datum!(bcx, apply_autoref(a, bcx, expr, datum)); + if skip_reborrows == 0 && adj.autoref.is_some() { + datum = unpack_datum!(bcx, apply_autoref(bcx, expr, datum)); } } - ty::AdjustUnsize(ref k) => { + ty::AdjustUnsize(ref unsize) => { debug!(" AdjustUnsize"); - datum = unpack_datum!(bcx, unsize_unique_expr(bcx, expr, datum, k)) + datum = unpack_datum!(bcx, unsize_unique_expr(bcx, datum, unsize)) } } debug!("after adjustments, datum={}", datum.to_string(bcx.ccx())); return DatumBlock::new(bcx, datum); - fn apply_autoref<'blk, 'tcx>(autoref: &ty::AutoRef, - 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; - - if let ty::AutoPtr(_, _, Some(ref a)) = *autoref { - datum = unpack_datum!(bcx, apply_autoref(a, bcx, expr, datum)); - } if !type_is_sized(bcx.tcx(), datum.ty) { // Arrange cleanup @@ -459,15 +434,14 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } fn unsize_lvalue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - expr: &ast::Expr, datum: Datum<'tcx, Lvalue>, - k: &ty::UnsizeKind<'tcx>) + unsize: &ty::AutoUnsize<'tcx>) -> DatumBlock<'blk, 'tcx, Expr> { - let datum_ty = datum.ty; - let unsized_ty = ty::unsize_ty(bcx.tcx(), datum_ty, k, expr.span); + let unsize = bcx.monomorphize(unsize); + let unsized_ty = unsize.root_target; debug!("unsize_lvalue(unsized_ty={})", unsized_ty.repr(bcx.tcx())); - let info = unsized_info_bcx(bcx, k, datum_ty, datum.val, bcx.fcx.param_substs); + let info = unsized_info_bcx(bcx, &unsize, datum.val); // Compute the base pointer. This doesn't change the pointer value, // but merely its type. @@ -495,20 +469,15 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } fn unsize_unique_expr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - expr: &ast::Expr, datum: Datum<'tcx, Expr>, - k: &ty::UnsizeKind<'tcx>) + unsize: &ty::AutoUnsize<'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)); + let unsize = bcx.monomorphize(unsize); + let result_ty = ty::mk_uniq(tcx, unsize.root_target); // We do not arrange cleanup ourselves; if we already are an // L-value, then cleanup will have already been scheduled (and @@ -521,7 +490,7 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, 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, unboxed_ty, base, bcx.fcx.param_substs); + let info = unsized_info_bcx(bcx, &unsize, base); Store(bcx, info, get_len(bcx, scratch.val)); DatumBlock::new(bcx, scratch.to_expr_datum()) diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index 015a251be05bf..25638015f3c78 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -83,15 +83,8 @@ pub fn check_call<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, Some(callee_expr), UnresolvedTypeAction::Error, LvaluePreference::NoPreference, - |adj_ty, idx| { - let autoderefref = ty::AutoDerefRef { - autoderefs: idx, - unsize: None, - autoref: None - }; - try_overloaded_call_step(fcx, call_expr, callee_expr, - adj_ty, autoderefref) - }); + |adj_ty, idx| try_overloaded_call_step(fcx, call_expr, callee_expr, + adj_ty, idx)); match result { None => { @@ -124,20 +117,23 @@ fn try_overloaded_call_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, call_expr: &'tcx ast::Expr, callee_expr: &'tcx ast::Expr, adjusted_ty: Ty<'tcx>, - autoderefref: ty::AutoDerefRef<'tcx>) + autoderefs: usize) -> Option> { - debug!("try_overloaded_call_step(call_expr={}, adjusted_ty={}, autoderefref={})", + debug!("try_overloaded_call_step(call_expr={}, adjusted_ty={}, autoderefs={})", call_expr.repr(fcx.tcx()), adjusted_ty.repr(fcx.tcx()), - autoderefref.repr(fcx.tcx())); + autoderefs); // 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)); + let adjustment = ty::AdjustDerefRef(ty::AutoDerefRef { + autoderefs: autoderefs, + unsize: None, + autoref: None + }); + fcx.write_adjustment(callee_expr.id, callee_expr.span, adjustment); return Some(CallStep::Builtin); } @@ -154,14 +150,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)); } } @@ -169,7 +165,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)) } @@ -177,7 +173,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. @@ -196,7 +192,8 @@ fn try_overloaded_call_traits<'a,'tcx>(fcx: &FnCtxt<'a, 'tcx>, Some(&*callee_expr), method_name, trait_def_id, - autoderefref.clone(), + autoderefs, + None, adjusted_ty, None) { None => continue, @@ -331,7 +328,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, } @@ -339,11 +336,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)) } @@ -360,7 +357,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 bb15102b36114..a152de382b012 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -192,7 +192,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { let coercion = Coercion(self.trace.clone()); let r_borrow = self.fcx.infcx().next_region_var(coercion); - let autoref = Some(ty::AutoPtr(r_borrow, mutbl_b, None)); + let autoref = Some(ty::AutoPtr(r_borrow, mutbl_b)); let r_borrow = self.tcx().mk_region(r_borrow); let lvalue_pref = match mutbl_b { @@ -260,7 +260,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { 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)) => { + Some(unsize) => { if !can_coerce_mutbls(mutbl_a, mt_b.mutbl) { return Err(ty::terr_mutability); } @@ -269,14 +269,15 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { 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}); + ty::mt { ty: unsize.root_target, + mutbl: mt_b.mutbl }); try!(self.fcx.infcx().try(|_| self.subtype(ty, b))); debug!("Success, coerced with AutoDerefRef(1, \ - unsize({:?}), AutoPtr)", kind); + unsize({:?}), AutoPtr)", unsize); Ok(Some(AdjustDerefRef(AutoDerefRef { autoderefs: 1, - unsize: Some(kind), - autoref: Some(ty::AutoPtr(r_borrow, mt_b.mutbl, None)) + unsize: Some(unsize), + autoref: Some(ty::AutoPtr(r_borrow, mt_b.mutbl)) }))) } _ => Err(ty::terr_mismatch) @@ -284,19 +285,20 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { } (&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)) => { + Some(unsize) => { 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}); + ty::mt { ty: unsize.root_target, + mutbl: mt_b.mutbl }); try!(self.fcx.infcx().try(|_| self.subtype(ty, b))); debug!("Success, coerced with AutoDerefRef(1, \ - unsize({:?}), AutoUnsafe)", kind); + unsize({:?}), AutoUnsafe)", unsize); Ok(Some(AdjustDerefRef(AutoDerefRef { autoderefs: 1, - unsize: Some(kind), + unsize: Some(unsize), autoref: Some(ty::AutoUnsafe(mt_b.mutbl)) }))) } @@ -305,11 +307,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { } (&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); + Some(unsize) => { + let ty = ty::mk_uniq(self.tcx(), unsize.root_target); try!(self.fcx.infcx().try(|_| self.subtype(ty, b))); - debug!("Success, coerced with AdjustUnsize({:?})", kind); - Ok(Some(ty::AdjustUnsize(kind))) + debug!("Success, coerced with AdjustUnsize({:?})", unsize); + Ok(Some(ty::AdjustUnsize(unsize))) } _ => Err(ty::terr_mismatch) } @@ -318,23 +320,25 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { } } - // 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)) => { + (&ty::ty_vec(t_a, Some(_)), &ty::ty_vec(_, None)) => { let ty = ty::mk_vec(tcx, t_a, None); - Some((ty, ty::UnsizeLength(len))) + Some(ty::AutoUnsize { + leaf_source: ty_a, + leaf_target: ty, + root_target: ty + }) } (&ty::ty_trait(ref data_a), &ty::ty_trait(ref data_b)) => { // Upcasts permit two things: @@ -371,19 +375,23 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // if that was successful, we have a coercion match result { - Ok(_) => Some((ty_b, ty::UnsizeUpcast(ty_b))), + Ok(_) => Some(ty::AutoUnsize { + leaf_source: ty_a, + leaf_target: ty_b, + root_target: 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_trait(_)) => { + Some(ty::AutoUnsize { + leaf_source: ty_a, + leaf_target: ty_b, + root_target: ty_b + }) } (&ty::ty_struct(did_a, substs_a), &ty::ty_struct(did_b, substs_b)) if did_a == did_b => { @@ -393,37 +401,33 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { 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.fcx.infcx().try(|_| 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.fcx.infcx().try(|_| 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))); + if let Some(unsize) = self.unsize_ty(*tp_a, *tp_b) { + // Check that the whole types match. + let mut new_substs = substs_a.clone(); + let new_tp = unsize.root_target; + 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.fcx.infcx().try(|_| 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; } - None => {} + + return Some(ty::AutoUnsize { root_target: ty, ..unsize }); } } - result + None } _ => None } diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index f9e5beb27a87f..82dd2d8810f82 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; @@ -134,7 +133,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { fn adjust_self_ty(&mut self, unadjusted_self_ty: Ty<'tcx>, - adjustment: &probe::PickAdjustment) + adjustment: &probe::PickAdjustment<'tcx>) -> Ty<'tcx> { // Construct the actual adjustment and write it into the table @@ -158,14 +157,14 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { assert_eq!(n, auto_deref_ref.autoderefs); assert_eq!(result, Some(())); - let adjusted_ty = if let Some(ref k) = auto_deref_ref.unsize { - ty::unsize_ty(self.tcx(), autoderefd_ty, k, self.span) + let adjusted_ty = if let Some(ref unsize) = auto_deref_ref.unsize { + unsize.root_target } else { autoderefd_ty }; let final_ty = - ty::adjust_ty_for_autoref(self.tcx(), self.span, adjusted_ty, + ty::adjust_ty_for_autoref(self.tcx(), adjusted_ty, auto_deref_ref.autoref.as_ref()); // Write out the final adjustment. @@ -175,7 +174,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { } fn create_ty_adjustment(&mut self, - adjustment: &probe::PickAdjustment) + adjustment: &probe::PickAdjustment<'tcx>) -> ty::AutoDerefRef<'tcx> { match *adjustment { @@ -186,17 +185,23 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { autoref: None } } - probe::AutoUnsizeLength(autoderefs, len) => { + probe::AutoDerefUnsize(autoderefs, source, target) => { ty::AutoDerefRef { autoderefs: autoderefs, - unsize: Some(ty::UnsizeLength(len)), + unsize: Some(ty::AutoUnsize { + leaf_source: source, + leaf_target: target, + root_target: target + }), autoref: None } } probe::AutoRef(mutability, ref sub_adjustment) => { - let deref = self.create_ty_adjustment(&**sub_adjustment); + let mut 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)) + assert!(deref.autoref.is_none()); + deref.autoref = Some(ty::AutoPtr(region, mutability)); + deref } } } @@ -558,13 +563,12 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { // 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) } + None | Some(ty::AutoPtr(_, _)) => None, Some(_) => { self.tcx().sess.span_bug( base_expr.span, - "unexpected adjustment autoref"); + &format!("unexpected adjustment autoref {}", + base_adjustment.repr(self.tcx()))); } }; @@ -580,7 +584,8 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { expr, &**base_expr, adjusted_base_ty, - base_adjustment, + base_adjustment.autoderefs, + base_adjustment.unsize, PreferMutLvalue, index_expr_ty); @@ -667,14 +672,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, -{ - 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 09c1ebfec4da0..e8a8a5667ddd5 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, unsize: None, autoref: None }, - self_ty, opt_input_types) + 0, None, 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: Option>, self_ty: Ty<'tcx>, opt_input_types: Option>>) -> Option> @@ -241,17 +241,23 @@ 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.repr(fcx.tcx()), + method_ty.explicit_self); match method_ty.explicit_self { ty::ByValueExplicitSelfCategory => { // Trait method is fn(self), no transformation needed. - if !autoderefref.is_identity() { + assert!(unsize.is_none()); + if autoderefs > 0 { fcx.write_adjustment( self_expr.id, span, - ty::AdjustDerefRef(autoderefref)); + ty::AdjustDerefRef(ty::AutoDerefRef { + autoderefs: autoderefs, + unsize: None, + autoref: None + })); } } @@ -260,15 +266,13 @@ 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, unsize, autoref } = autoderefref; - let autoref = autoref.map(|r| box r); fcx.write_adjustment( self_expr.id, span, ty::AdjustDerefRef(ty::AutoDerefRef { autoderefs: autoderefs, unsize: unsize, - autoref: Some(ty::AutoPtr(*region, mutbl, autoref)) + autoref: Some(ty::AutoPtr(*region, mutbl)) })); } diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index b95e0ce8cb3c5..9677faddb58a6 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -49,7 +49,7 @@ struct ProbeContext<'a, 'tcx:'a> { struct CandidateStep<'tcx> { self_ty: Ty<'tcx>, - adjustment: PickAdjustment, + adjustment: PickAdjustment<'tcx>, } struct Candidate<'tcx> { @@ -70,7 +70,7 @@ enum CandidateKind<'tcx> { pub struct Pick<'tcx> { pub method_ty: Rc>, - pub adjustment: PickAdjustment, + pub adjustment: PickAdjustment<'tcx>, pub kind: PickKind<'tcx>, } @@ -90,7 +90,7 @@ pub type PickResult<'tcx> = Result, MethodError>; // specifics. The "confirmation" step recreates those details as // needed. #[derive(Clone,Debug)] -pub enum PickAdjustment { +pub enum PickAdjustment<'tcx> { // Indicates that the source expression should be autoderef'd N times // // A = expr | *expr | **expr @@ -101,12 +101,13 @@ pub enum PickAdjustment { // away in favor of just coercing method receivers. // // A = unsize(expr | *expr | **expr) - AutoUnsizeLength(/* number of autoderefs */ uint, /* length*/ uint), + AutoDerefUnsize(/* number of autoderefs */ uint, + /* source */ Ty<'tcx>, /* target */ Ty<'tcx>), // Indicates that an autoref is applied after some number of other adjustments // // A = &A | &mut A - AutoRef(ast::Mutability, Box), + AutoRef(ast::Mutability, Box>), } #[derive(PartialEq, Eq, Copy)] @@ -206,10 +207,11 @@ fn create_steps<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, }); 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, + adjustment: AutoDerefUnsize(dereferences, final_ty, slice_ty), }); } ty::ty_err => return None, @@ -927,19 +929,17 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { */ let adjustment = match step.adjustment { - AutoDeref(d) => consider_reborrow(step.self_ty, d), - AutoUnsizeLength(..) | AutoRef(..) => step.adjustment.clone(), + AutoDeref(d) => { + // Insert a `&*` or `&mut *` if this is a reference type: + match step.self_ty.sty { + ty::ty_rptr(_, ref mt) => AutoRef(mt.mutbl, box AutoDeref(d+1)), + _ => AutoDeref(d), + } + } + AutoDerefUnsize(..) | AutoRef(..) => step.adjustment.clone(), }; - return self.pick_method(step.self_ty).map(|r| self.adjust(r, adjustment.clone())); - - fn consider_reborrow<'tcx>(ty: Ty<'tcx>, d: uint) -> 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), - } - } + self.pick_method(step.self_ty).map(|r| self.adjust(r, adjustment)) } fn pick_autorefd_method(&mut self, @@ -956,7 +956,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { mut mk_adjustment: F, mut mk_autoref_ty: G) -> Option> where - F: FnMut(ast::Mutability) -> PickAdjustment, + F: FnMut(ast::Mutability) -> PickAdjustment<'tcx>, G: FnMut(ast::Mutability, ty::Region) -> Ty<'tcx>, { // In general, during probing we erase regions. See @@ -964,20 +964,16 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { let 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) + [ast::MutImmutable, ast::MutMutable].iter().filter_map(|&m| { + let autoref_ty = mk_autoref_ty(m, region); + self.pick_method(autoref_ty) + .map(|r| self.adjust(r, mk_adjustment(m))) + }).nth(0) } fn adjust(&mut self, result: PickResult<'tcx>, - adjustment: PickAdjustment) + adjustment: PickAdjustment<'tcx>) -> PickResult<'tcx> { match result { @@ -1398,7 +1394,7 @@ impl<'tcx> Repr<'tcx> for CandidateStep<'tcx> { } } -impl<'tcx> Repr<'tcx> for PickAdjustment { +impl<'tcx> Repr<'tcx> for PickAdjustment<'tcx> { fn repr(&self, _tcx: &ty::ctxt) -> String { format!("{:?}", self) } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 8376867d072ad..70689d6758be0 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1546,15 +1546,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn register_unsize_obligations(&self, span: Span, - unsize: &ty::UnsizeKind<'tcx>) { + unsize: &ty::AutoUnsize<'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) => { + match (&unsize.leaf_source.sty, &unsize.leaf_target.sty) { + (&ty::ty_trait(_), &ty::ty_trait(_)) => {} + (_, &ty::ty_trait(ref ty_trait)) => { + let self_ty = unsize.leaf_source; + vtable::check_object_safety(self.tcx(), ty_trait, span); // If the type is `Foo+'a`, ensures that the type @@ -1571,7 +1570,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { code: traits::ObjectCastObligation(self_ty) }; self.register_region_obligation(self_ty, ty_trait.bounds.region_bound, cause); } - ty::UnsizeUpcast(_) => { } + _ => {} } } @@ -2097,13 +2096,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 @@ -2116,13 +2115,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, - unsize: None, - autoref: None - }; - step(adj_ty, autoderefref) - }); + try_index_step(fcx, MethodCall::expr(expr.id), expr, base_expr, + adj_ty, idx, None, lvalue_pref, idx_ty) + }); if final_mt.is_some() { return final_mt; @@ -2130,42 +2125,43 @@ 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, - unsize: Some(ty::UnsizeLength(n)), - autoref: None - }; - 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); + let unsize = ty::AutoUnsize { + leaf_source: ty, + leaf_target: adjusted_ty, + root_target: adjusted_ty + }; + try_index_step(fcx, MethodCall::expr(expr.id), expr, base_expr, + adjusted_ty, autoderefs, Some(unsize), 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: Option>, 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.repr(tcx), index_ty.repr(tcx)); let input_ty = fcx.infcx().next_ty_var(); @@ -2174,7 +2170,14 @@ 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.is_none()); + let adjustment = ty::AdjustDerefRef(ty::AutoDerefRef { + autoderefs: autoderefs, + unsize: None, + autoref: None + }); + fcx.write_adjustment(base_expr.id, base_expr.span, adjustment); return Some((tcx.types.uint, ty)); } _ => {} @@ -2188,7 +2191,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])) } @@ -2203,7 +2207,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])) } @@ -2806,44 +2811,8 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, { let method = match trait_did { Some(trait_did) => { - // We do eager coercions to make using operators - // more ergonomic: - // - // - If the input is of type &'a T (resp. &'a mut T), - // then reborrow it to &'b T (resp. &'b mut T) where - // 'b <= 'a. This makes things like `x == y`, where - // `x` and `y` are both region pointers, work. We - // could also solve this with variance or different - // traits that don't force left and right to have same - // type. - let (adj_ty, adjustment) = match lhs_ty.sty { - ty::ty_rptr(r_in, mt) => { - let r_adj = fcx.infcx().next_region_var(infer::Autoref(lhs.span)); - fcx.mk_subr(infer::Reborrow(lhs.span), r_adj, *r_in); - let adjusted_ty = ty::mk_rptr(fcx.tcx(), fcx.tcx().mk_region(r_adj), mt); - let autoptr = ty::AutoPtr(r_adj, mt.mutbl, None); - let adjustment = ty::AutoDerefRef { - autoderefs: 1, - unsize: None, - autoref: Some(autoptr) - }; - (adjusted_ty, adjustment) - } - _ => { - (lhs_ty, ty::AutoDerefRef { - autoderefs: 0, - unsize: None, - autoref: None - }) - } - }; - - debug!("adjusted_ty={} adjustment={:?}", - adj_ty.repr(fcx.tcx()), - adjustment); - method::lookup_in_trait_adjusted(fcx, op_ex.span, Some(lhs), opname, - trait_did, adjustment, adj_ty, None) + trait_did, 0, None, lhs_ty, None) } None => None }; @@ -4053,27 +4022,14 @@ 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)) => { // FIXME: we've already checked idx above, we should // probably just demand subtype or something here. check_expr_has_type(fcx, &**idx, index_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 8635e322ba388..71bb0b28b17ad 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -1127,7 +1127,7 @@ fn link_autoref(rcx: &Rcx, debug!("expr_cmt={}", expr_cmt.repr(rcx.tcx())); match *autoref { - ty::AutoPtr(r, m, _) => { + ty::AutoPtr(r, m) => { link_region(rcx, expr.span, r, ty::BorrowKind::from_mutbl(m), expr_cmt); } From 352a63c340839c4bf0c6c9528ecd5d7af6578328 Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Fri, 20 Mar 2015 10:57:23 +0200 Subject: [PATCH 06/12] Perform unsizing coercions only on pointers, not on lvalues and Box. --- src/librustc/middle/astencode.rs | 55 ++-- src/librustc/middle/expr_use_visitor.rs | 45 ++- src/librustc/middle/mem_categorization.rs | 31 +- src/librustc/middle/ty.rs | 61 ++-- src/librustc/middle/ty_fold.rs | 17 +- src/librustc_trans/trans/consts.rs | 61 ++-- src/librustc_trans/trans/expr.rs | 143 ++++----- src/librustc_typeck/check/callee.rs | 4 +- src/librustc_typeck/check/coercion.rs | 319 +++++++++----------- src/librustc_typeck/check/method/confirm.rs | 124 ++++---- src/librustc_typeck/check/method/mod.rs | 11 +- src/librustc_typeck/check/method/probe.rs | 155 +++++----- src/librustc_typeck/check/mod.rs | 13 +- src/librustc_typeck/check/regionck.rs | 14 +- src/librustc_typeck/check/writeback.rs | 6 +- 15 files changed, 467 insertions(+), 592 deletions(-) diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index 7556ef30cfbc7..198ca40be3f6e 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -841,8 +841,7 @@ 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); + 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_auto_unsize<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, @@ -1024,18 +1023,11 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> { |this| Ok(this.emit_auto_deref_ref(ecx, auto_deref_ref))) }) } - - ty::AdjustUnsize(ref uk) => { - this.emit_enum_variant("AdjustUnsize", 4, 1, |this| { - this.emit_enum_variant_arg(0, |this| Ok(this.emit_auto_unsize(ecx, uk))) - }) - } } }); } - fn emit_autoref<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>, - autoref: &ty::AutoRef) { + fn emit_autoref<'b>(&mut self, autoref: &ty::AutoRef<'tcx>) { use serialize::Encoder; self.emit_enum("AutoRef", |this| { @@ -1062,20 +1054,20 @@ 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("unsize", 1, |this| { + this.emit_struct_field("autoref", 1, |this| { this.emit_option(|this| { - match auto_deref_ref.unsize { + match auto_deref_ref.autoref { None => this.emit_option_none(), - Some(ref uk) => this.emit_option_some(|this| Ok(this.emit_auto_unsize(ecx, uk))), + Some(ref a) => this.emit_option_some(|this| Ok(this.emit_autoref(a))), } }) }); - this.emit_struct_field("autoref", 2, |this| { + this.emit_struct_field("unsize", 2, |this| { this.emit_option(|this| { - match auto_deref_ref.autoref { + match auto_deref_ref.unsize { None => this.emit_option_none(), - Some(ref a) => this.emit_option_some(|this| Ok(this.emit_autoref(ecx, a))), + Some(ref uk) => this.emit_option_some(|this| Ok(this.emit_auto_unsize(ecx, uk))), } }) }) @@ -1093,8 +1085,8 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> { this.emit_struct_field("leaf_target", 1, |this| { Ok(this.emit_ty(ecx, unsize.leaf_target)) }); - this.emit_struct_field("root_target", 2, |this| { - Ok(this.emit_ty(ecx, unsize.root_target)) + this.emit_struct_field("target", 2, |this| { + Ok(this.emit_ty(ecx, unsize.target)) }) }); } @@ -1311,7 +1303,7 @@ trait rbml_decoder_decoder_helpers<'tcx> { fn read_auto_deref_ref<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) -> ty::AutoDerefRef<'tcx>; fn read_autoref<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) - -> ty::AutoRef; + -> ty::AutoRef<'tcx>; fn read_auto_unsize<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) -> ty::AutoUnsize<'tcx>; fn convert_def_id(&mut self, @@ -1585,8 +1577,7 @@ 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 = ["AdjustReifyFnPointer", "AdjustUnsafeFnPointer", - "AdjustDerefRef", "AdjustUnsize"]; + let variants = ["AdjustReifyFnPointer", "AdjustUnsafeFnPointer", "AdjustDerefRef"]; this.read_enum_variant(&variants, |this, i| { Ok(match i { 1 => ty::AdjustReifyFnPointer, @@ -1598,13 +1589,6 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { ty::AdjustDerefRef(auto_deref_ref) } - 4 => { - let uk: ty::AutoUnsize = - this.read_enum_variant_arg(0, - |this| Ok(this.read_auto_unsize(dcx))).unwrap(); - - ty::AdjustUnsize(uk) - } _ => panic!("bad enum variant for ty::AutoAdjustment") }) }) @@ -1618,19 +1602,19 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { autoderefs: this.read_struct_field("autoderefs", 0, |this| { Decodable::decode(this) }).unwrap(), - unsize: this.read_struct_field("unsize", 1, |this| { + autoref: this.read_struct_field("autoref", 1, |this| { this.read_option(|this, b| { if b { - Ok(Some(this.read_auto_unsize(dcx))) + Ok(Some(this.read_autoref(dcx))) } else { Ok(None) } }) }).unwrap(), - autoref: this.read_struct_field("autoref", 2, |this| { + unsize: this.read_struct_field("unsize", 2, |this| { this.read_option(|this, b| { if b { - Ok(Some(this.read_autoref(dcx))) + Ok(Some(this.read_auto_unsize(dcx))) } else { Ok(None) } @@ -1640,7 +1624,8 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { }).unwrap() } - fn read_autoref<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) -> ty::AutoRef { + fn read_autoref<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) + -> ty::AutoRef<'tcx> { self.read_enum("AutoRef", |this| { let variants = ["AutoPtr", "AutoUnsafe"]; this.read_enum_variant(&variants, |this, i| { @@ -1651,7 +1636,7 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { let m: ast::Mutability = this.read_enum_variant_arg(1, |this| Decodable::decode(this)).unwrap(); - ty::AutoPtr(r.tr(dcx), m) + ty::AutoPtr(dcx.tcx.mk_region(r.tr(dcx)), m) } 1 => { let m: ast::Mutability = @@ -1675,7 +1660,7 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { leaf_target: this.read_struct_field("leaf_target", 1, |this| { Ok(this.read_ty(dcx)) }).unwrap(), - root_target: this.read_struct_field("root_target", 1, |this| { + target: this.read_struct_field("target", 2, |this| { Ok(this.read_ty(dcx)) }).unwrap() }) diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index aaff6bc904a45..af2d71428623d 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -786,33 +786,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 | - ty::AdjustUnsize(_) => { - // Creating a closure/fn-pointer or unsizing consumes - // the input and stores it into the resulting rvalue. - debug!("walk_adjustment(AdjustUnsize|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_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 == 1, - format!("Expected exactly 1 deref with \ - unsize AutoRefs, found: {}", adj.autoderefs)); - let cmt_unadjusted = - return_if_err!(self.mc.cat_expr_unadjusted(expr)); - self.delegate_consume(expr.id, expr.span, cmt_unadjusted); - } - } } } } @@ -868,7 +865,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { self.delegate.borrow(expr.id, expr.span, cmt_derefd, - r, + *r, ty::BorrowKind::from_mutbl(m), AutoRef); } diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 6ec7f9abf9c44..905a429ce8d06 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -428,34 +428,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::AdjustUnsize(_) | 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) - } } } } diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 4046bc22ea7d5..540a61091e1ff 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -277,43 +277,40 @@ pub enum Variance { Bivariant, // T <: T -- e.g., unused type parameter } -#[derive(Clone, Debug)] +#[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 AdjustDerefRef(AutoDerefRef<'tcx>), - - /// Convert Box<[T, ..n]> to Box<[T]> or something similar in a Box. - AdjustUnsize(AutoUnsize<'tcx>), } // In the case of `&Struct<[T; N]>` -> `&Struct<[T]>`, the types are: // * leaf_source: `[T; N]` // * leaf_target: `[T]` -// * root_target: `Struct<[T]>` +// * target: `&Struct<[T]>` #[derive(Copy, Clone, Debug)] pub struct AutoUnsize<'tcx> { pub leaf_source: Ty<'tcx>, pub leaf_target: Ty<'tcx>, - pub root_target: Ty<'tcx> + pub target: Ty<'tcx> } -#[derive(Clone, Debug)] +#[derive(Copy, Clone, Debug)] pub struct AutoDerefRef<'tcx> { /// Apply a number of dereferences, producing an lvalue. pub autoderefs: uint, - /// Convert a lvalue from [T; n] to [T] (or similar, depending on the kind). - pub unsize: Option>, + /// Produce a pointer/reference from the value. + pub autoref: Option>, - /// Produce a pointer/reference from the lvalue. - pub autoref: Option + /// Unsize a pointer/reference value, e.g. &[T; n] to &[T]. + pub unsize: Option>, } #[derive(Copy, Clone, PartialEq, Debug)] -pub enum AutoRef { +pub enum AutoRef<'tcx> { /// Convert from T to &T - AutoPtr(Region, ast::Mutability), + AutoPtr(&'tcx Region, ast::Mutability), /// Convert from T to *T /// Value to thin pointer @@ -4494,20 +4491,9 @@ pub fn adjust_ty<'tcx, F>(cx: &ctxt<'tcx>, } if let Some(ref unsize) = adj.unsize { - adjusted_ty = unsize.root_target; - } - - adjust_ty_for_autoref(cx, adjusted_ty, adj.autoref.as_ref()) - } - - AdjustUnsize(ref unsize) => { - match unadjusted_ty.sty { - ty::ty_uniq(_) => ty::mk_uniq(cx, unsize.root_target), - _ => { - cx.sess.bug( - &format!("AdjustUnsize adjustment on non-Box type: \ - {}", unadjusted_ty.repr(cx))); - } + unsize.target + } else { + adjust_ty_for_autoref(cx, adjusted_ty, adj.autoref) } } } @@ -4518,15 +4504,14 @@ pub fn adjust_ty<'tcx, F>(cx: &ctxt<'tcx>, pub fn adjust_ty_for_autoref<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>, - autoref: Option<&AutoRef>) - -> Ty<'tcx> -{ + autoref: Option>) + -> Ty<'tcx> { match autoref { None => ty, - Some(&AutoPtr(r, m)) => { - mk_rptr(cx, cx.mk_region(r), mt { ty: ty, mutbl: m }) + Some(AutoPtr(r, m)) => { + mk_rptr(cx, r, mt { ty: ty, mutbl: m }) } - Some(&AutoUnsafe(m)) => { + Some(AutoUnsafe(m)) => { mk_ptr(cx, mt { ty: ty, mutbl: m }) } } @@ -6553,7 +6538,6 @@ 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 { - AdjustUnsize(_) | AdjustReifyFnPointer | AdjustUnsafeFnPointer => false, AdjustDerefRef(ref r) => r.is_identity(), @@ -6711,9 +6695,6 @@ impl<'tcx> Repr<'tcx> for AutoAdjustment<'tcx> { AdjustDerefRef(ref data) => { data.repr(tcx) } - AdjustUnsize(ref a) => { - format!("AdjustUnsize({})", a.repr(tcx)) - } } } } @@ -6723,7 +6704,7 @@ impl<'tcx> Repr<'tcx> for AutoUnsize<'tcx> { format!("unsize({} => {}) => {}", self.leaf_source.repr(tcx), self.leaf_target.repr(tcx), - self.root_target.repr(tcx)) + self.target.repr(tcx)) } } @@ -6734,7 +6715,7 @@ impl<'tcx> Repr<'tcx> for AutoDerefRef<'tcx> { } } -impl<'tcx> Repr<'tcx> for AutoRef { +impl<'tcx> Repr<'tcx> for AutoRef<'tcx> { fn repr(&self, tcx: &ctxt<'tcx>) -> String { match *self { AutoPtr(a, b) => { @@ -7161,7 +7142,7 @@ impl<'tcx> HasProjectionTypes for AutoUnsize<'tcx> { fn has_projection_types(&self) -> bool { self.leaf_source.has_projection_types() || self.leaf_target.has_projection_types() || - self.root_target.has_projection_types() + self.target.has_projection_types() } } diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs index 63b147523dfae..2c51acc80e98e 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -129,7 +129,7 @@ pub trait TypeFolder<'tcx> : Sized { super_fold_existential_bounds(self, s) } - fn fold_autoref(&mut self, ar: &ty::AutoRef) -> ty::AutoRef { + fn fold_autoref(&mut self, ar: &ty::AutoRef<'tcx>) -> ty::AutoRef<'tcx> { super_fold_autoref(self, ar) } @@ -292,8 +292,8 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ItemSubsts<'tcx> { } } -impl<'tcx> TypeFoldable<'tcx> for ty::AutoRef { - fn fold_with>(&self, folder: &mut F) -> ty::AutoRef { +impl<'tcx> TypeFoldable<'tcx> for ty::AutoRef<'tcx> { + fn fold_with>(&self, folder: &mut F) -> ty::AutoRef<'tcx> { folder.fold_autoref(self) } } @@ -472,7 +472,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::AutoUnsize<'tcx> { ty::AutoUnsize { leaf_source: self.leaf_source.fold_with(folder), leaf_target: self.leaf_target.fold_with(folder), - root_target: self.root_target.fold_with(folder) + target: self.target.fold_with(folder) } } } @@ -746,11 +746,14 @@ pub fn super_fold_existential_bounds<'tcx, T: TypeFolder<'tcx>>( } pub fn super_fold_autoref<'tcx, T: TypeFolder<'tcx>>(this: &mut T, - autoref: &ty::AutoRef) - -> ty::AutoRef + autoref: &ty::AutoRef<'tcx>) + -> ty::AutoRef<'tcx> { match *autoref { - ty::AutoPtr(r, m) => ty::AutoPtr(this.fold_region(r), m), + ty::AutoPtr(r, m) => { + let r = r.fold_with(this); + ty::AutoPtr(this.tcx().mk_region(r), m) + } ty::AutoUnsafe(m) => ty::AutoUnsafe(m) } } diff --git a/src/librustc_trans/trans/consts.rs b/src/librustc_trans/trans/consts.rs index 1ddd6093af92f..ef61d6a37b456 100644 --- a/src/librustc_trans/trans/consts.rs +++ b/src/librustc_trans/trans/consts.rs @@ -260,37 +260,48 @@ pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, } } - 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; - } - 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", e.id); - } + 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", e.id); + ty = ty::mk_imm_rptr(cx.tcx(), cx.tcx().mk_region(ty::ReStatic), ty); } + } 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(ref unsize) = adj.unsize { - // This works a reference, not an lvalue (like trans::expr does). - assert!(adj.autoref.is_some()); - let unsize = monomorphize::apply_param_substs(cx.tcx(), param_substs, unsize); - let info = expr::unsized_info(cx, &unsize, param_substs, - || const_get_elt(cx, llconst, &[abi::FAT_PTR_EXTRA as u32])); - let ptr_ty = type_of::in_memory_type_of(cx, unsize.root_target).ptr_to(); - let base = ptrcast(llconst, ptr_ty); + 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(unsize.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, &unsize, old_info, param_substs); let prev_const = cx.const_unsized().borrow_mut() .insert(base, llconst); @@ -300,10 +311,6 @@ pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, llconst = C_struct(cx, &[base, info], false); } } - Some(adj) => { - cx.sess().span_bug(e.span, - &format!("unimplemented const adjustment {:?}", adj)) - } None => {} }; diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs index 3cc42c4b248c1..9ac7f7a13fcd5 100644 --- a/src/librustc_trans/trans/expr.rs +++ b/src/librustc_trans/trans/expr.rs @@ -296,31 +296,18 @@ pub fn copy_fat_ptr(bcx: Block, src_ptr: ValueRef, dst_ptr: ValueRef) { /// 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. -fn unsized_info_bcx<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +pub fn unsized_info<'ccx, 'tcx>(ccx: &CrateContext<'ccx, 'tcx>, unsize: &ty::AutoUnsize<'tcx>, - unadjusted_val: ValueRef) // see above (*)) + old_info: Option, + param_substs: &'tcx subst::Substs<'tcx>) -> ValueRef { - unsized_info(bcx.ccx(), unsize, bcx.fcx.param_substs, - || Load(bcx, GEPi(bcx, unadjusted_val, &[0, abi::FAT_PTR_EXTRA]))) -} - -// Same as `unsized_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>, - unsize: &ty::AutoUnsize<'tcx>, - param_substs: &'tcx subst::Substs<'tcx>, - mk_upcast_vtable: MK_UPCAST_VTABLE) // see notes above - -> ValueRef - where MK_UPCAST_VTABLE: FnOnce() -> ValueRef -{ match (&unsize.leaf_source.sty, &unsize.leaf_target.sty) { (&ty::ty_vec(_, Some(len)), &ty::ty_vec(_, None)) => C_uint(ccx, len), (&ty::ty_trait(_), &ty::ty_trait(_)) => { // For now, upcasts are limited to changes in marker // traits, and hence never actually require an actual // change to the vtable. - mk_upcast_vtable() + old_info.expect("unsized_info: missing old info for trait upcast") } (_, &ty::ty_trait(box ty::TyTrait { ref principal, .. })) => { // Note that we preserve binding levels here: @@ -364,28 +351,25 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, // purely a type-level thing } AdjustDerefRef(ref adj) => { - let skip_reborrows = match *adj { - ty::AutoDerefRef { autoderefs: 1, unsize: None, autoref: 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). - 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 - } + 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). + 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 } - _ => 0 } + _ => 0 } - _ => 0 + } else { + 0 }; if adj.autoderefs > skip_reborrows { @@ -396,22 +380,15 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, adj.autoderefs - skip_reborrows)); } - if let Some(ref unsize) = adj.unsize { - // Arrange cleanup - let lval = unpack_datum!(bcx, - datum.to_lvalue_datum(bcx, "into_fat_ptr", expr.id)); - datum = unpack_datum!(bcx, unsize_lvalue(bcx, lval, unsize)); - } - // (You might think there is a more elegant way to do this than a // 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)); } - } - ty::AdjustUnsize(ref unsize) => { - debug!(" AdjustUnsize"); - datum = unpack_datum!(bcx, unsize_unique_expr(bcx, datum, unsize)) + + if let Some(ref unsize) = adj.unsize { + datum = unpack_datum!(bcx, unsize_pointer(bcx, datum, unsize)); + } } } debug!("after adjustments, datum={}", datum.to_string(bcx.ccx())); @@ -433,67 +410,53 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } } - fn unsize_lvalue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - datum: Datum<'tcx, Lvalue>, - unsize: &ty::AutoUnsize<'tcx>) - -> DatumBlock<'blk, 'tcx, Expr> { + fn unsize_pointer<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, + datum: Datum<'tcx, Expr>, + unsize: &ty::AutoUnsize<'tcx>) + -> DatumBlock<'blk, 'tcx, Expr> { + let mut bcx = bcx; let unsize = bcx.monomorphize(unsize); - let unsized_ty = unsize.root_target; + let unsized_ty = ty::deref(unsize.target, true) + .expect("expr::unsize got non-pointer target type").ty; debug!("unsize_lvalue(unsized_ty={})", unsized_ty.repr(bcx.tcx())); - let info = unsized_info_bcx(bcx, &unsize, datum.val); - - // 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(), datum.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, datum.val)) + (Load(bcx, get_dataptr(bcx, datum.val)), + Some(Load(bcx, get_len(bcx, datum.val)))) } else { - datum.val + (datum.val, None) }; + + let info = unsized_info(bcx.ccx(), &unsize, 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(), unsize.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_expr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - datum: Datum<'tcx, Expr>, - unsize: &ty::AutoUnsize<'tcx>) - -> DatumBlock<'blk, 'tcx, Expr> { - let mut bcx = bcx; - let tcx = bcx.tcx(); - - let datum_ty = datum.ty; - let unsize = bcx.monomorphize(unsize); - let result_ty = ty::mk_uniq(tcx, unsize.root_target); - - // 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, &unsize, base); - Store(bcx, info, get_len(bcx, scratch.val)); - - DatumBlock::new(bcx, scratch.to_expr_datum()) + DatumBlock::new(bcx, Datum::new(scratch, unsize.target, + RvalueExpr(Rvalue::new(ByRef)))) } } diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index 25638015f3c78..1df0605daffc9 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -130,8 +130,8 @@ fn try_overloaded_call_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, ty::ty_bare_fn(..) => { let adjustment = ty::AdjustDerefRef(ty::AutoDerefRef { autoderefs: autoderefs, - unsize: None, - autoref: None + autoref: None, + unsize: None }); fcx.write_adjustment(callee_expr.id, callee_expr.span, adjustment); return Some(CallStep::Builtin); diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index a152de382b012..9671d81be31cc 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -183,18 +183,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.trace.clone()); let r_borrow = self.fcx.infcx().next_region_var(coercion); + let r_borrow = self.tcx().mk_region(r_borrow); let autoref = Some(ty::AutoPtr(r_borrow, mutbl_b)); - let r_borrow = self.tcx().mk_region(r_borrow); let lvalue_pref = match mutbl_b { ast::MutMutable => PreferMutLvalue, ast::MutImmutable => NoPreference @@ -228,8 +226,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { Some(_) => { Ok(Some(AdjustDerefRef(AutoDerefRef { autoderefs: autoderefs, - unsize: None, - autoref: autoref + autoref: autoref, + unsize: None }))) } None => { @@ -257,67 +255,50 @@ 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(unsize) => { - if !can_coerce_mutbls(mutbl_a, mt_b.mutbl) { - return Err(ty::terr_mutability); - } - - let coercion = Coercion(self.trace.clone()); - 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: unsize.root_target, - mutbl: mt_b.mutbl }); - try!(self.fcx.infcx().try(|_| self.subtype(ty, b))); - debug!("Success, coerced with AutoDerefRef(1, \ - unsize({:?}), AutoPtr)", unsize); - Ok(Some(AdjustDerefRef(AutoDerefRef { - autoderefs: 1, - unsize: Some(unsize), - autoref: Some(ty::AutoPtr(r_borrow, mt_b.mutbl)) - }))) - } - _ => Err(ty::terr_mismatch) + let (reborrow, unsize) = match (&a.sty, &b.sty) { + (&ty::ty_rptr(_, mt_a), &ty::ty_rptr(_, mt_b)) => { + if let Some(unsize) = 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)), unsize) + } 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(unsize) => { - if !can_coerce_mutbls(mutbl_a, mt_b.mutbl) { - return Err(ty::terr_mutability); - } - - let ty = ty::mk_ptr(self.tcx(), - ty::mt { ty: unsize.root_target, - mutbl: mt_b.mutbl }); - try!(self.fcx.infcx().try(|_| self.subtype(ty, b))); - debug!("Success, coerced with AutoDerefRef(1, \ - unsize({:?}), AutoUnsafe)", unsize); - Ok(Some(AdjustDerefRef(AutoDerefRef { - autoderefs: 1, - unsize: Some(unsize), - autoref: Some(ty::AutoUnsafe(mt_b.mutbl)) - }))) - } - _ => Err(ty::terr_mismatch) + (&ty::ty_rptr(_, mt_a), &ty::ty_ptr(mt_b)) => { + if let Some(unsize) = self.unsize_ty(mt_a.ty, mt_b.ty) { + try!(coerce_mutbls(mt_a.mutbl, mt_b.mutbl)); + (Some(ty::AutoUnsafe(mt_b.mutbl)), unsize) + } 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(unsize) => { - let ty = ty::mk_uniq(self.tcx(), unsize.root_target); - try!(self.fcx.infcx().try(|_| self.subtype(ty, b))); - debug!("Success, coerced with AdjustUnsize({:?})", unsize); - Ok(Some(ty::AdjustUnsize(unsize))) - } - _ => Err(ty::terr_mismatch) + if let Some(mut unsize) = self.unsize_ty(t_a, t_b) { + unsize.target = ty::mk_uniq(self.tcx(), unsize.target); + (None, unsize) + } else { + return Err(ty::terr_mismatch); } } - _ => Err(ty::terr_mismatch) - } + _ => return Err(ty::terr_mismatch) + }; + + let ty = ty::adjust_ty_for_autoref(self.tcx(), unsize.target, reborrow); + try!(self.fcx.infcx().try(|_| self.subtype(ty, b))); + let adjustment = AutoDerefRef { + autoderefs: if reborrow.is_some() { 1 } else { 0 }, + autoref: reborrow, + unsize: Some(ty::AutoUnsize { + target: ty, + ..unsize + }) + }; + debug!("Success, coerced with {}", adjustment.repr(self.tcx())); + Ok(Some(AdjustDerefRef(adjustment))) } // Takes a type and returns an unsized version. @@ -328,111 +309,109 @@ impl<'f, 'tcx> Coerce<'f, '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(_)), &ty::ty_vec(_, None)) => { - let ty = ty::mk_vec(tcx, t_a, None); - Some(ty::AutoUnsize { - leaf_source: ty_a, - leaf_target: ty, - root_target: ty - }) - } - (&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().try(|_| { - // it's ok to upcast from Foo+'a to Foo+'b so long as 'a : 'b - try!(self.outlives(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::AutoUnsize { - leaf_source: ty_a, - leaf_target: ty_b, - root_target: 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)) => { + let ty = ty::mk_vec(tcx, t_a, None); + Some(ty::AutoUnsize { + leaf_source: a, + leaf_target: ty, + target: ty + }) + } + (&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().try(|_| { + // it's ok to upcast from Foo+'a to Foo+'b so long as 'a : 'b + try!(self.outlives(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::AutoUnsize { + leaf_source: a, + leaf_target: ty_b, + target: ty_b + }), + Err(_) => None, } + } else { + None } - (_, &ty::ty_trait(_)) => { - Some(ty::AutoUnsize { - leaf_source: ty_a, - leaf_target: ty_b, - root_target: 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.fcx.infcx().try(|_| self.subtype(*tp_a, *tp_b)).is_ok() { - continue; - } - if let Some(unsize) = self.unsize_ty(*tp_a, *tp_b) { - // Check that the whole types match. - let mut new_substs = substs_a.clone(); - let new_tp = unsize.root_target; - 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.fcx.infcx().try(|_| 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::AutoUnsize { root_target: ty, ..unsize }); + } + (_, &ty::ty_trait(_)) => { + Some(ty::AutoUnsize { + leaf_source: a, + leaf_target: ty_b, + target: 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.fcx.infcx().try(|_| self.subtype(tp_a, tp_b)).is_ok() { + continue; + } + if let Some(unsize) = self.unsize_ty(tp_a, tp_b) { + // Check that the whole types match. + let mut new_substs = substs_a.clone(); + let new_tp = unsize.target; + 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.fcx.infcx().try(|_| 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::AutoUnsize { target: ty, ..unsize }); } - None } - _ => None + None } - }) - }) + _ => None + } + })) } fn coerce_from_fn_pointer(&self, @@ -508,17 +487,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, - unsize: None, - autoref: Some(ty::AutoUnsafe(mutbl_b)) + autoref: Some(ty::AutoUnsafe(mutbl_b)), + unsize: None }))) } } @@ -544,13 +521,13 @@ pub fn mk_assignty<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, 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 82dd2d8810f82..5172a4d27b1e6 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -83,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); @@ -133,11 +133,30 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { fn adjust_self_ty(&mut self, unadjusted_self_ty: Ty<'tcx>, - adjustment: &probe::PickAdjustment<'tcx>) + pick: &probe::Pick<'tcx>) -> Ty<'tcx> { + 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); + let unsize = pick.unsize.map(|(source, target)| ty::AutoUnsize { + leaf_source: source, + leaf_target: target, + target: ty::adjust_ty_for_autoref(self.tcx(), target, Some(autoref)) + }); + (Some(autoref), unsize) + } else { + // No unsizing should be performed without autoref. + assert!(pick.unsize.is_none()); + (None, None) + }; + // Construct the actual adjustment and write it into the table - let auto_deref_ref = self.create_ty_adjustment(adjustment); + let auto_deref_ref = ty::AutoDerefRef { + autoderefs: pick.autoderefs, + autoref: autoref, + unsize: unsize + }; // Commit the autoderefs by calling `autoderef again, but this // time writing the results into the various tables. @@ -157,55 +176,19 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { assert_eq!(n, auto_deref_ref.autoderefs); assert_eq!(result, Some(())); - let adjusted_ty = if let Some(ref unsize) = auto_deref_ref.unsize { - unsize.root_target + let final_ty = if let Some(ref unsize) = auto_deref_ref.unsize { + unsize.target } else { - autoderefd_ty + ty::adjust_ty_for_autoref(self.tcx(), autoderefd_ty, + auto_deref_ref.autoref) }; - let final_ty = - ty::adjust_ty_for_autoref(self.tcx(), adjusted_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 } - fn create_ty_adjustment(&mut self, - adjustment: &probe::PickAdjustment<'tcx>) - -> ty::AutoDerefRef<'tcx> - { - match *adjustment { - probe::AutoDeref(num) => { - ty::AutoDerefRef { - autoderefs: num, - unsize: None, - autoref: None - } - } - probe::AutoDerefUnsize(autoderefs, source, target) => { - ty::AutoDerefRef { - autoderefs: autoderefs, - unsize: Some(ty::AutoUnsize { - leaf_source: source, - leaf_target: target, - root_target: target - }), - autoref: None - } - } - probe::AutoRef(mutability, ref sub_adjustment) => { - let mut deref = self.create_ty_adjustment(&**sub_adjustment); - let region = self.infcx().next_region_var(infer::Autoref(self.span)); - assert!(deref.autoref.is_none()); - deref.autoref = Some(ty::AutoPtr(region, mutability)); - deref - } - } - } - /////////////////////////////////////////////////////////////////////////// // @@ -539,21 +522,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, - unsize: None, - 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 @@ -562,20 +530,42 @@ 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 | Some(ty::AutoPtr(_, _)) => None, + 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(|mut unsize| { + unsize.target = ty::deref(unsize.target, false) + .expect("fixup: AutoPtr is not &T").ty; + unsize + })) + } + 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, - &format!("unexpected adjustment autoref {}", - base_adjustment.repr(self.tcx()))); + "unexpected adjustment type"); } }; let adjusted_base_ty = - self.fcx.adjust_expr_ty( - &**base_expr, - Some(&ty::AdjustDerefRef(base_adjustment.clone()))); + self.fcx.adjust_expr_ty(base_expr, + Some(&ty::AdjustDerefRef(ty::AutoDerefRef { + autoderefs: autoderefs, + autoref: None, + unsize: unsize + }))); let index_expr_ty = self.fcx.expr_ty(&**index_expr); let result = check::try_index_step( @@ -584,8 +574,8 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { expr, &**base_expr, adjusted_base_ty, - base_adjustment.autoderefs, - base_adjustment.unsize, + autoderefs, + unsize, PreferMutLvalue, index_expr_ty); diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index e8a8a5667ddd5..91e4c1bbad350 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -255,8 +255,8 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, span, ty::AdjustDerefRef(ty::AutoDerefRef { autoderefs: autoderefs, - unsize: None, - autoref: None + autoref: None, + unsize: None })); } } @@ -271,8 +271,11 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, span, ty::AdjustDerefRef(ty::AutoDerefRef { autoderefs: autoderefs, - unsize: unsize, - autoref: Some(ty::AutoPtr(*region, mutbl)) + autoref: Some(ty::AutoPtr(region, mutbl)), + unsize: unsize.map(|unsize| ty::AutoUnsize { + target: transformed_self_ty, + ..unsize + }) })); } diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 9677faddb58a6..68f29c9a61baf 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<'tcx>, + autoderefs: usize, + unsize: Option> } struct Candidate<'tcx> { @@ -70,8 +70,24 @@ enum CandidateKind<'tcx> { pub struct Pick<'tcx> { pub method_ty: Rc>, - pub adjustment: PickAdjustment<'tcx>, 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". + // This should probably eventually go away in favor of just + // coercing method receivers. + // + // C = B | unsize(B) + pub unsize: Option<(/* source */ Ty<'tcx>, /* target */ Ty<'tcx>)>, } #[derive(Clone,Debug)] @@ -85,31 +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<'tcx> { - // Indicates that the source expression should be autoderef'd N times - // - // A = expr | *expr | **expr - AutoDeref(uint), - - // 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) - AutoDerefUnsize(/* number of autoderefs */ uint, - /* source */ Ty<'tcx>, /* target */ Ty<'tcx>), - - // Indicates that an autoref is applied after some number of other adjustments - // - // A = &A | &mut A - AutoRef(ast::Mutability, Box>), -} - #[derive(PartialEq, Eq, Copy)] pub enum Mode { // An expression of the form `receiver.method_name(...)`. @@ -150,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: None }] }; @@ -201,8 +193,11 @@ 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: None + }); None::<()> // keep iterating until we can't anymore }); @@ -211,7 +206,8 @@ fn create_steps<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, let slice_ty = ty::mk_vec(fcx.tcx(), elem_ty, None); steps.push(CandidateStep { self_ty: slice_ty, - adjustment: AutoDerefUnsize(dereferences, final_ty, slice_ty), + autoderefs: dereferences, + unsize: Some(final_ty) }); } ty::ty_err => return None, @@ -928,18 +924,21 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { * consuming them for their entire lifetime. */ - let adjustment = match step.adjustment { - AutoDeref(d) => { - // Insert a `&*` or `&mut *` if this is a reference type: - match step.self_ty.sty { - ty::ty_rptr(_, ref mt) => AutoRef(mt.mutbl, box AutoDeref(d+1)), - _ => AutoDeref(d), - } + if step.unsize.is_some() { + return None; + } + + self.pick_method(step.self_ty).map(|r| r.map(|mut pick| { + pick.autoderefs = step.autoderefs; + + // Insert a `&*` or `&mut *` if this is a reference type: + if let ty::ty_rptr(_, mt) = step.self_ty.sty { + pick.autoderefs += 1; + pick.autoref = Some(mt.mutbl); } - AutoDerefUnsize(..) | AutoRef(..) => step.adjustment.clone(), - }; - self.pick_method(step.self_ty).map(|r| self.adjust(r, adjustment)) + pick + })) } fn pick_autorefd_method(&mut self, @@ -947,44 +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<'tcx>, - 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().filter_map(|&m| { - let autoref_ty = mk_autoref_ty(m, region); - self.pick_method(autoref_ty) - .map(|r| self.adjust(r, mk_adjustment(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 = step.unsize.map(|source| { + (source, step.self_ty) + }); + pick + })) }).nth(0) } - fn adjust(&mut self, - result: PickResult<'tcx>, - adjustment: PickAdjustment<'tcx>) - -> PickResult<'tcx> - { - match result { - Err(e) => Err(e), - Ok(mut pick) => { - pick.adjustment = adjustment; - Ok(pick) - } - } - } - fn pick_method(&mut self, self_ty: Ty<'tcx>) -> Option> { debug!("pick_method(self_ty={})", self.infcx().ty_to_string(self_ty)); @@ -1118,8 +1101,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 }) } @@ -1292,7 +1277,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) @@ -1319,7 +1303,10 @@ impl<'tcx> Candidate<'tcx> { ProjectionCandidate(def_id, index) => { TraitPick(def_id, index) } - } + }, + autoderefs: 0, + autoref: None, + unsize: None } } @@ -1388,15 +1375,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<'tcx> { - fn repr(&self, _tcx: &ty::ctxt) -> String { - format!("{:?}", self) + self.autoderefs, + self.unsize.repr(tcx)) } } @@ -1408,9 +1390,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 70689d6758be0..303b6416d9243 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1444,8 +1444,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span, ty::AdjustDerefRef(ty::AutoDerefRef { autoderefs: derefs, - unsize: None, - autoref: None + autoref: None, + unsize: None }) ); } @@ -1537,8 +1537,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::AdjustUnsafeFnPointer | ty::AdjustDerefRef(ty::AutoDerefRef { unsize: None, .. }) => {} - ty::AdjustDerefRef(ty::AutoDerefRef { unsize: Some(ref unsize), .. }) | - ty::AdjustUnsize(ref unsize) => { + ty::AdjustDerefRef(ty::AutoDerefRef { unsize: Some(ref unsize), .. }) => { self.register_unsize_obligations(span, unsize); } } @@ -2130,7 +2129,7 @@ fn lookup_indexing<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, let unsize = ty::AutoUnsize { leaf_source: ty, leaf_target: adjusted_ty, - root_target: adjusted_ty + target: adjusted_ty }; try_index_step(fcx, MethodCall::expr(expr.id), expr, base_expr, adjusted_ty, autoderefs, Some(unsize), lvalue_pref, idx_ty) @@ -2174,8 +2173,8 @@ fn try_index_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, assert!(unsize.is_none()); let adjustment = ty::AdjustDerefRef(ty::AutoDerefRef { autoderefs: autoderefs, - unsize: None, - autoref: None + autoref: None, + unsize: None }); fcx.write_adjustment(base_expr.id, base_expr.span, adjustment); return Some((tcx.types.uint, ty)); diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 71bb0b28b17ad..fa9df2c1e0b55 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -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); } @@ -1147,7 +1147,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 @@ -1165,7 +1165,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); } } @@ -1175,7 +1175,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; @@ -1269,7 +1269,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, @@ -1314,7 +1314,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/writeback.rs b/src/librustc_typeck/check/writeback.rs index 96ef7678b3afb..05e0557d9ec0e 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -274,14 +274,10 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { ty::AdjustDerefRef(ty::AutoDerefRef { autoderefs: adj.autoderefs, - unsize: self.resolve(&adj.unsize, reason), autoref: self.resolve(&adj.autoref, reason), + unsize: self.resolve(&adj.unsize, reason), }) } - - ty::AdjustUnsize(uk) => { - ty::AdjustUnsize(self.resolve(&uk, reason)) - } }; debug!("Adjustments for node {}: {:?}", id, resolved_adjustment); self.tcx().adjustments.borrow_mut().insert( From bfb93efe1a488f5a12d979aa07c75c015ed5dad1 Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Fri, 20 Mar 2015 14:38:39 +0200 Subject: [PATCH 07/12] Drive unsizing coercions using just the target pointer type. --- src/librustc/middle/astencode.rs | 44 +-------- src/librustc/middle/ty.rs | 76 +++++++++------ src/librustc/middle/ty_fold.rs | 10 -- src/librustc_trans/trans/common.rs | 27 ------ src/librustc_trans/trans/consts.rs | 11 ++- src/librustc_trans/trans/expr.rs | 37 ++++---- src/librustc_trans/trans/type_of.rs | 4 +- src/librustc_typeck/check/callee.rs | 9 +- src/librustc_typeck/check/coercion.rs | 100 ++++++++++++-------- src/librustc_typeck/check/method/confirm.rs | 58 +++++------- src/librustc_typeck/check/method/mod.rs | 32 +++---- src/librustc_typeck/check/method/probe.rs | 28 +++--- src/librustc_typeck/check/mod.rs | 85 ++--------------- 13 files changed, 201 insertions(+), 320 deletions(-) diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index 198ca40be3f6e..baa9be9e774a2 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -844,8 +844,6 @@ trait rbml_writer_helpers<'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_auto_unsize<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, - unsize: &ty::AutoUnsize<'tcx>); } impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> { @@ -1067,29 +1065,14 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> { this.emit_option(|this| { match auto_deref_ref.unsize { None => this.emit_option_none(), - Some(ref uk) => this.emit_option_some(|this| Ok(this.emit_auto_unsize(ecx, uk))), + Some(target) => this.emit_option_some(|this| { + Ok(this.emit_ty(ecx, target)) + }) } }) }) }); } - - fn emit_auto_unsize<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>, - unsize: &ty::AutoUnsize<'tcx>) { - use serialize::Encoder; - - self.emit_struct("AutoUnsize", 3, |this| { - this.emit_struct_field("leaf_source", 0, |this| { - Ok(this.emit_ty(ecx, unsize.leaf_source)) - }); - this.emit_struct_field("leaf_target", 1, |this| { - Ok(this.emit_ty(ecx, unsize.leaf_target)) - }); - this.emit_struct_field("target", 2, |this| { - Ok(this.emit_ty(ecx, unsize.target)) - }) - }); - } } trait write_tag_and_id { @@ -1304,8 +1287,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_auto_unsize<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) - -> ty::AutoUnsize<'tcx>; fn convert_def_id(&mut self, dcx: &DecodeContext, source: DefIdSource, @@ -1614,7 +1595,7 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { unsize: this.read_struct_field("unsize", 2, |this| { this.read_option(|this, b| { if b { - Ok(Some(this.read_auto_unsize(dcx))) + Ok(Some(this.read_ty(dcx))) } else { Ok(None) } @@ -1650,23 +1631,6 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { }).unwrap() } - fn read_auto_unsize<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) - -> ty::AutoUnsize<'tcx> { - self.read_struct("AutoUnsize", 3, |this| { - Ok(ty::AutoUnsize { - leaf_source: this.read_struct_field("leaf_source", 0, |this| { - Ok(this.read_ty(dcx)) - }).unwrap(), - leaf_target: this.read_struct_field("leaf_target", 1, |this| { - Ok(this.read_ty(dcx)) - }).unwrap(), - target: this.read_struct_field("target", 2, |this| { - Ok(this.read_ty(dcx)) - }).unwrap() - }) - }).unwrap() - } - fn read_closure_kind<'b, 'c>(&mut self, _dcx: &DecodeContext<'b, 'c, 'tcx>) -> ty::ClosureKind { diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 540a61091e1ff..19f913a1fd144 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -284,17 +284,6 @@ pub enum AutoAdjustment<'tcx> { AdjustDerefRef(AutoDerefRef<'tcx>), } -// In the case of `&Struct<[T; N]>` -> `&Struct<[T]>`, the types are: -// * leaf_source: `[T; N]` -// * leaf_target: `[T]` -// * target: `&Struct<[T]>` -#[derive(Copy, Clone, Debug)] -pub struct AutoUnsize<'tcx> { - pub leaf_source: Ty<'tcx>, - pub leaf_target: Ty<'tcx>, - pub target: Ty<'tcx> -} - #[derive(Copy, Clone, Debug)] pub struct AutoDerefRef<'tcx> { /// Apply a number of dereferences, producing an lvalue. @@ -304,7 +293,8 @@ pub struct AutoDerefRef<'tcx> { pub autoref: Option>, /// Unsize a pointer/reference value, e.g. &[T; n] to &[T]. - pub unsize: Option>, + /// The stored type is the target pointer type. + pub unsize: Option>, } #[derive(Copy, Clone, PartialEq, Debug)] @@ -4490,8 +4480,8 @@ pub fn adjust_ty<'tcx, F>(cx: &ctxt<'tcx>, } } - if let Some(ref unsize) = adj.unsize { - unsize.target + if let Some(target) = adj.unsize { + target } else { adjust_ty_for_autoref(cx, adjusted_ty, adj.autoref) } @@ -5557,6 +5547,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, @@ -6699,15 +6730,6 @@ impl<'tcx> Repr<'tcx> for AutoAdjustment<'tcx> { } } -impl<'tcx> Repr<'tcx> for AutoUnsize<'tcx> { - fn repr(&self, tcx: &ctxt<'tcx>) -> String { - format!("unsize({} => {}) => {}", - self.leaf_source.repr(tcx), - self.leaf_target.repr(tcx), - self.target.repr(tcx)) - } -} - impl<'tcx> Repr<'tcx> for AutoDerefRef<'tcx> { fn repr(&self, tcx: &ctxt<'tcx>) -> String { format!("AutoDerefRef({}, unsize={}, {})", @@ -7138,14 +7160,6 @@ impl<'tcx> HasProjectionTypes for BareFnTy<'tcx> { } } -impl<'tcx> HasProjectionTypes for AutoUnsize<'tcx> { - fn has_projection_types(&self) -> bool { - self.leaf_source.has_projection_types() || - self.leaf_target.has_projection_types() || - self.target.has_projection_types() - } -} - pub trait ReferencesError { fn references_error(&self) -> bool; } diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs index 2c51acc80e98e..21802a70ee6c4 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -467,16 +467,6 @@ impl<'tcx> TypeFoldable<'tcx> for ty::InstantiatedPredicates<'tcx> { } } -impl<'tcx> TypeFoldable<'tcx> for ty::AutoUnsize<'tcx> { - fn fold_with>(&self, folder: &mut F) -> ty::AutoUnsize<'tcx> { - ty::AutoUnsize { - leaf_source: self.leaf_source.fold_with(folder), - leaf_target: self.leaf_target.fold_with(folder), - target: self.target.fold_with(folder) - } - } -} - impl<'tcx,O> TypeFoldable<'tcx> for traits::Obligation<'tcx,O> where O : TypeFoldable<'tcx> { diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs index 61cdde3bfbecd..13dcfda833989 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 ef61d6a37b456..5e7bbef4a68db 100644 --- a/src/librustc_trans/trans/consts.rs +++ b/src/librustc_trans/trans/consts.rs @@ -277,10 +277,10 @@ pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, ety_adjusted = dt; } - if let Some(ref unsize) = adj.unsize { - let unsize = monomorphize::apply_param_substs(cx.tcx(), + if let Some(target) = adj.unsize { + let target = monomorphize::apply_param_substs(cx.tcx(), param_substs, - unsize); + &target); let pointee_ty = ty::deref(ty, true) .expect("consts: unsizing got non-pointer type").ty; @@ -297,11 +297,12 @@ pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, (llconst, None) }; - let unsized_ty = ty::deref(unsize.target, true) + 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, &unsize, old_info, param_substs); + 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); diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs index 9ac7f7a13fcd5..f518c531c78eb 100644 --- a/src/librustc_trans/trans/expr.rs +++ b/src/librustc_trans/trans/expr.rs @@ -292,16 +292,17 @@ pub fn copy_fat_ptr(bcx: Block, src_ptr: ValueRef, dst_ptr: ValueRef) { /// 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. +/// 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>, - unsize: &ty::AutoUnsize<'tcx>, + source: Ty<'tcx>, + target: Ty<'tcx>, old_info: Option, param_substs: &'tcx subst::Substs<'tcx>) -> ValueRef { - match (&unsize.leaf_source.sty, &unsize.leaf_target.sty) { + 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 @@ -311,15 +312,16 @@ pub fn unsized_info<'ccx, 'tcx>(ccx: &CrateContext<'ccx, 'tcx>, } (_, &ty::ty_trait(box ty::TyTrait { ref principal, .. })) => { // Note that we preserve binding levels here: - let substs = principal.0.substs.with_self_ty(unsize.leaf_source).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 })); consts::ptrcast(meth::get_vtable(ccx, trait_ref, param_substs), Type::vtable_ptr(ccx)) } - _ => ccx.sess().bug(&format!("unsized_info: invalid unsizing {}", - unsize.repr(ccx.tcx()))) + _ => ccx.sess().bug(&format!("unsized_info: invalid unsizing {} -> {}", + source.repr(ccx.tcx()), + target.repr(ccx.tcx()))) } } @@ -386,8 +388,9 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, datum = unpack_datum!(bcx, apply_autoref(bcx, expr, datum)); } - if let Some(ref unsize) = adj.unsize { - datum = unpack_datum!(bcx, unsize_pointer(bcx, datum, unsize)); + if let Some(target) = adj.unsize { + datum = unpack_datum!(bcx, unsize_pointer(bcx, datum, + bcx.monomorphize(&target))); } } } @@ -412,11 +415,10 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, fn unsize_pointer<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, datum: Datum<'tcx, Expr>, - unsize: &ty::AutoUnsize<'tcx>) + target: Ty<'tcx>) -> DatumBlock<'blk, 'tcx, Expr> { let mut bcx = bcx; - let unsize = bcx.monomorphize(unsize); - let unsized_ty = ty::deref(unsize.target, true) + 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())); @@ -442,20 +444,21 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, (datum.val, None) }; - let info = unsized_info(bcx.ccx(), &unsize, old_info, bcx.fcx.param_substs); + 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(), unsize.target); + 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, unsize.target, + DatumBlock::new(bcx, Datum::new(scratch, target, RvalueExpr(Rvalue::new(ByRef)))) } } diff --git a/src/librustc_trans/trans/type_of.rs b/src/librustc_trans/trans/type_of.rs index 8d228c22c3cfa..b93fed22a77e5 100644 --- a/src/librustc_trans/trans/type_of.rs +++ b/src/librustc_trans/trans/type_of.rs @@ -358,14 +358,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(false)) } 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/check/callee.rs b/src/librustc_typeck/check/callee.rs index 1df0605daffc9..153ec5c5fc571 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -128,12 +128,7 @@ fn try_overloaded_call_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // 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(..) => { - let adjustment = ty::AdjustDerefRef(ty::AutoDerefRef { - autoderefs: autoderefs, - autoref: None, - unsize: None - }); - fcx.write_adjustment(callee_expr.id, callee_expr.span, adjustment); + fcx.write_autoderef_adjustment(callee_expr.id, autoderefs); return Some(CallStep::Builtin); } @@ -193,7 +188,7 @@ fn try_overloaded_call_traits<'a,'tcx>(fcx: &FnCtxt<'a, 'tcx>, method_name, trait_def_id, autoderefs, - None, + false, adjusted_ty, None) { None => continue, diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 9671d81be31cc..ef7a9ad78ffb5 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -61,22 +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, cres, Coercion, TypeTrace}; use middle::infer::combine::Combine; use middle::infer::sub::Sub; use middle::subst; +use middle::traits; use middle::ty::{AutoDerefRef, AdjustDerefRef}; use middle::ty::{self, mt, Ty}; 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>, - trace: TypeTrace<'tcx> + trace: TypeTrace<'tcx>, + unsizing_obligation: Cell>> } type CoerceResult<'tcx> = cres<'tcx, Option>>; @@ -255,31 +259,30 @@ 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. - let (reborrow, unsize) = match (&a.sty, &b.sty) { + let (reborrow, target) = match (&a.sty, &b.sty) { (&ty::ty_rptr(_, mt_a), &ty::ty_rptr(_, mt_b)) => { - if let Some(unsize) = self.unsize_ty(mt_a.ty, mt_b.ty) { + 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)), unsize) + (Some(ty::AutoPtr(region, mt_b.mutbl)), target) } else { return Err(ty::terr_mismatch); } } (&ty::ty_rptr(_, mt_a), &ty::ty_ptr(mt_b)) => { - if let Some(unsize) = self.unsize_ty(mt_a.ty, mt_b.ty) { + 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)), unsize) + (Some(ty::AutoUnsafe(mt_b.mutbl)), target) } else { return Err(ty::terr_mismatch); } } (&ty::ty_uniq(t_a), &ty::ty_uniq(t_b)) => { - if let Some(mut unsize) = self.unsize_ty(t_a, t_b) { - unsize.target = ty::mk_uniq(self.tcx(), unsize.target); - (None, unsize) + if let Some(target) = self.unsize_ty(t_a, t_b) { + (None, ty::mk_uniq(self.tcx(), target)) } else { return Err(ty::terr_mismatch); } @@ -287,15 +290,12 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { _ => return Err(ty::terr_mismatch) }; - let ty = ty::adjust_ty_for_autoref(self.tcx(), unsize.target, reborrow); - try!(self.fcx.infcx().try(|_| self.subtype(ty, b))); + 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(ty::AutoUnsize { - target: ty, - ..unsize - }) + unsize: Some(target) }; debug!("Success, coerced with {}", adjustment.repr(self.tcx())); Ok(Some(AdjustDerefRef(adjustment))) @@ -306,19 +306,14 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { fn unsize_ty(&self, ty_a: Ty<'tcx>, ty_b: Ty<'tcx>) - -> Option> { + -> 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(_)), &ty::ty_vec(_, None)) => { - let ty = ty::mk_vec(tcx, t_a, None); - Some(ty::AutoUnsize { - leaf_source: a, - leaf_target: ty, - target: ty - }) + Some(ty::mk_vec(tcx, t_a, None)) } (&ty::ty_trait(ref data_a), &ty::ty_trait(ref data_b)) => { // Upcasts permit two things: @@ -355,11 +350,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // if that was successful, we have a coercion match result { - Ok(_) => Some(ty::AutoUnsize { - leaf_source: a, - leaf_target: ty_b, - target: ty_b - }), + Ok(_) => Some(ty_b), Err(_) => None, } } else { @@ -367,11 +358,9 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { } } (_, &ty::ty_trait(_)) => { - Some(ty::AutoUnsize { - leaf_source: a, - leaf_target: ty_b, - target: ty_b - }) + 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 => { @@ -386,10 +375,9 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { if self.fcx.infcx().try(|_| self.subtype(tp_a, tp_b)).is_ok() { continue; } - if let Some(unsize) = self.unsize_ty(tp_a, tp_b) { + 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(); - let new_tp = unsize.target; 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.fcx.infcx().try(|_| self.subtype(ty, ty_b)).is_err() { @@ -404,7 +392,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { break; } - return Some(ty::AutoUnsize { target: ty, ..unsize }); + return Some(ty); } } None @@ -506,17 +494,49 @@ pub fn mk_assignty<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, b: Ty<'tcx>) -> cres<'tcx, ()> { debug!("mk_assignty({} -> {})", a.repr(fcx.tcx()), b.repr(fcx.tcx())); - let adjustment = try!(indent(|| { + let (adjustment, unsizing_obligation) = try!(indent(|| { fcx.infcx().commit_if_ok(|| { let origin = infer::ExprAssignable(expr.span); - Coerce { + let coerce = Coerce { fcx: fcx, - trace: infer::TypeTrace::types(origin, false, a, b) - }.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(()) } diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 5172a4d27b1e6..4e62542854fa8 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -139,25 +139,15 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { 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); - let unsize = pick.unsize.map(|(source, target)| ty::AutoUnsize { - leaf_source: source, - leaf_target: target, - target: ty::adjust_ty_for_autoref(self.tcx(), target, Some(autoref)) - }); - (Some(autoref), unsize) + (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) }; - // Construct the actual adjustment and write it into the table - let auto_deref_ref = ty::AutoDerefRef { - autoderefs: pick.autoderefs, - autoref: autoref, - unsize: unsize - }; - // Commit the autoderefs by calling `autoderef again, but this // time writing the results into the various tables. let (autoderefd_ty, n, result) = check::autoderef(self.fcx, @@ -167,26 +157,28 @@ 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 = if let Some(ref unsize) = auto_deref_ref.unsize { - unsize.target - } else { - ty::adjust_ty_for_autoref(self.tcx(), autoderefd_ty, - auto_deref_ref.autoref) - }; - // Write out the final adjustment. - self.fcx.write_adjustment(self.self_expr.id, self.span, ty::AdjustDerefRef(auto_deref_ref)); + self.fcx.write_adjustment(self.self_expr.id, + ty::AdjustDerefRef(ty::AutoDerefRef { + autoderefs: pick.autoderefs, + autoref: autoref, + unsize: unsize + })); - final_ty + if let Some(target) = unsize { + target + } else { + ty::adjust_ty_for_autoref(self.tcx(), autoderefd_ty, autoref) + } } /////////////////////////////////////////////////////////////////////////// @@ -538,10 +530,9 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { (adr.autoderefs, None) } Some(ty::AutoPtr(_, _)) => { - (adr.autoderefs, adr.unsize.map(|mut unsize| { - unsize.target = ty::deref(unsize.target, false) - .expect("fixup: AutoPtr is not &T").ty; - unsize + (adr.autoderefs, adr.unsize.map(|target| { + ty::deref(target, false) + .expect("fixup: AutoPtr is not &T").ty })) } Some(_) => { @@ -559,13 +550,16 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { } }; - let adjusted_base_ty = - self.fcx.adjust_expr_ty(base_expr, + 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: unsize - }))); + unsize: None + }))), false) + }; let index_expr_ty = self.fcx.expr_ty(&**index_expr); let result = check::try_index_step( diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index 91e4c1bbad350..bf89af606f540 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -122,7 +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, - 0, 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 +140,7 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, m_name: ast::Name, trait_def_id: DefId, autoderefs: usize, - unsize: Option>, + unsize: bool, self_ty: Ty<'tcx>, opt_input_types: Option>>) -> Option> @@ -242,23 +242,14 @@ 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={}, autoderefs={}, unsize={}, explicit_self={:?})", - self_expr.id, autoderefs, unsize.repr(fcx.tcx()), + self_expr.id, autoderefs, unsize, method_ty.explicit_self); match method_ty.explicit_self { ty::ByValueExplicitSelfCategory => { // Trait method is fn(self), no transformation needed. - assert!(unsize.is_none()); - if autoderefs > 0 { - fcx.write_adjustment( - self_expr.id, - span, - ty::AdjustDerefRef(ty::AutoDerefRef { - autoderefs: autoderefs, - autoref: None, - unsize: None - })); - } + assert!(!unsize); + fcx.write_autoderef_adjustment(self_expr.id, autoderefs); } ty::ByReferenceExplicitSelfCategory(..) => { @@ -266,16 +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: _ }) => { - 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)), - unsize: unsize.map(|unsize| ty::AutoUnsize { - target: transformed_self_ty, - ..unsize - }) + 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 68f29c9a61baf..cd6142355a1ad 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -49,7 +49,7 @@ struct ProbeContext<'a, 'tcx:'a> { struct CandidateStep<'tcx> { self_ty: Ty<'tcx>, autoderefs: usize, - unsize: Option> + unsize: bool } struct Candidate<'tcx> { @@ -82,12 +82,12 @@ pub struct Pick<'tcx> { // B = A | &A | &mut A pub autoref: Option, - // Indicates that the source expression should be "unsized". - // This should probably eventually go away in favor of just - // coercing method receivers. + // 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<(/* source */ Ty<'tcx>, /* target */ Ty<'tcx>)>, + pub unsize: Option>, } #[derive(Clone,Debug)] @@ -142,7 +142,7 @@ pub fn probe<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, vec![CandidateStep { self_ty: self_ty, autoderefs: 0, - unsize: None + unsize: false }] }; @@ -196,7 +196,7 @@ fn create_steps<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, steps.push(CandidateStep { self_ty: t, autoderefs: d, - unsize: None + unsize: false }); None::<()> // keep iterating until we can't anymore }); @@ -207,7 +207,7 @@ fn create_steps<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, steps.push(CandidateStep { self_ty: slice_ty, autoderefs: dereferences, - unsize: Some(final_ty) + unsize: true }); } ty::ty_err => return None, @@ -924,7 +924,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { * consuming them for their entire lifetime. */ - if step.unsize.is_some() { + if step.unsize { return None; } @@ -960,9 +960,11 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { self.pick_method(autoref_ty).map(|r| r.map(|mut pick| { pick.autoderefs = step.autoderefs; pick.autoref = Some(m); - pick.unsize = step.unsize.map(|source| { - (source, step.self_ty) - }); + pick.unsize = if step.unsize { + Some(step.self_ty) + } else { + None + }; pick })) }).nth(0) @@ -1378,7 +1380,7 @@ impl<'tcx> Repr<'tcx> for CandidateStep<'tcx> { format!("CandidateStep({}, autoderefs={}, unsize={})", self.self_ty.repr(tcx), self.autoderefs, - self.unsize.repr(tcx)) + self.unsize) } } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 303b6416d9243..bddd3914dfc9a 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1436,12 +1436,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn write_autoderef_adjustment(&self, node_id: ast::NodeId, - span: Span, - derefs: uint) { - if derefs == 0 { return; } + derefs: usize) { self.write_adjustment( node_id, - span, ty::AdjustDerefRef(ty::AutoDerefRef { autoderefs: derefs, autoref: None, @@ -1452,7 +1449,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { 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())); @@ -1460,13 +1456,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); } @@ -1529,50 +1518,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(ty::AutoDerefRef { unsize: None, .. }) => {} - - ty::AdjustDerefRef(ty::AutoDerefRef { unsize: Some(ref unsize), .. }) => { - self.register_unsize_obligations(span, unsize); - } - } - } - - fn register_unsize_obligations(&self, - span: Span, - unsize: &ty::AutoUnsize<'tcx>) { - debug!("register_unsize_obligations: unsize={:?}", unsize); - - match (&unsize.leaf_source.sty, &unsize.leaf_target.sty) { - (&ty::ty_trait(_), &ty::ty_trait(_)) => {} - (_, &ty::ty_trait(ref ty_trait)) => { - let self_ty = unsize.leaf_source; - - 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); - } - _ => {} - } - } - /// 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. @@ -2115,7 +2060,7 @@ fn lookup_indexing<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, lvalue_pref, |adj_ty, idx| { try_index_step(fcx, MethodCall::expr(expr.id), expr, base_expr, - adj_ty, idx, None, lvalue_pref, idx_ty) + adj_ty, idx, false, lvalue_pref, idx_ty) }); if final_mt.is_some() { @@ -2126,13 +2071,8 @@ fn lookup_indexing<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // do a final unsized coercion to yield [T]. if let ty::ty_vec(element_ty, Some(_)) = ty.sty { let adjusted_ty = ty::mk_vec(fcx.tcx(), element_ty, None); - let unsize = ty::AutoUnsize { - leaf_source: ty, - leaf_target: adjusted_ty, - target: adjusted_ty - }; try_index_step(fcx, MethodCall::expr(expr.id), expr, base_expr, - adjusted_ty, autoderefs, Some(unsize), lvalue_pref, idx_ty) + adjusted_ty, autoderefs, true, lvalue_pref, idx_ty) } else { None } @@ -2148,7 +2088,7 @@ fn try_index_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, base_expr: &'tcx ast::Expr, adjusted_ty: Ty<'tcx>, autoderefs: usize, - unsize: Option>, + unsize: bool, lvalue_pref: LvaluePreference, index_ty: Ty<'tcx>) -> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)> @@ -2160,7 +2100,7 @@ fn try_index_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, base_expr.repr(tcx), adjusted_ty.repr(tcx), autoderefs, - unsize.repr(tcx), + unsize, index_ty.repr(tcx)); let input_ty = fcx.infcx().next_ty_var(); @@ -2170,13 +2110,8 @@ fn try_index_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, (Some(ty), &ty::ty_uint(ast::TyUs(_))) | (Some(ty), &ty::ty_infer(ty::IntVar(_))) => { debug!("try_index_step: success, using built-in indexing"); // If we had `[T; N]`, we should've caught it before unsizing to `[T]`. - assert!(unsize.is_none()); - let adjustment = ty::AdjustDerefRef(ty::AutoDerefRef { - autoderefs: autoderefs, - autoref: None, - unsize: None - }); - fcx.write_adjustment(base_expr.id, base_expr.span, adjustment); + assert!(!unsize); + fcx.write_autoderef_adjustment(base_expr.id, autoderefs); return Some((tcx.types.uint, ty)); } _ => {} @@ -2811,7 +2746,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, let method = match trait_did { Some(trait_did) => { method::lookup_in_trait_adjusted(fcx, op_ex.span, Some(lhs), opname, - trait_did, 0, None, lhs_ty, None) + trait_did, 0, false, lhs_ty, None) } None => None }; @@ -3071,7 +3006,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 => {} @@ -3182,7 +3117,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 => {} From 7786e140bf4e23126066960d95a8afa3c92f9ec5 Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Tue, 24 Mar 2015 22:06:55 +0200 Subject: [PATCH 08/12] Forbid object types with incomplete projections, before coercions. --- src/librustc_typeck/astconv.rs | 50 ++++++++++++++++++- src/librustc_typeck/check/vtable.rs | 38 -------------- ...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 +- 7 files changed, 59 insertions(+), 48 deletions(-) rename src/test/{run-pass/issue-19121.rs => compile-fail/issue-19482.rs} (75%) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index e9de8bd879e20..5db7e474dd2a0 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, ObjectLifetimeDefaultRscope, ShiftedRscope, BindingRscope}; use util::common::{ErrorReported, FN_OUTPUT_NAME}; +use util::nodemap::FnvHashSet; use util::ppaux::{self, Repr, UserString}; use std::iter::{repeat, AdditiveIterator}; @@ -1026,13 +1027,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, @@ -1785,7 +1831,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/vtable.rs b/src/librustc_typeck/check/vtable.rs index 2858dc9b569fe..2aaa02fe330da 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}; @@ -134,46 +133,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/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 c5f6f84d59b853b6a3485380721b71b479ece337 Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Fri, 27 Mar 2015 11:17:36 +0200 Subject: [PATCH 09/12] Introduce a built-in Unsize trait and use it for unsizing in coercions. --- src/libcore/marker.rs | 8 + src/librustc/diagnostics.rs | 1 + src/librustc/middle/lang_items.rs | 1 + src/librustc/middle/traits/error_reporting.rs | 57 ++++- src/librustc/middle/traits/mod.rs | 10 +- src/librustc/middle/traits/select.rs | 240 +++++++++++++++++- src/librustc/middle/traits/util.rs | 21 +- src/librustc/middle/ty.rs | 25 +- src/librustc_typeck/check/coercion.rs | 216 ++++++---------- src/librustc_typeck/check/method/mod.rs | 4 +- src/librustc_typeck/check/mod.rs | 65 ++++- src/librustc_typeck/check/regionck.rs | 3 +- src/librustc_typeck/check/vtable.rs | 188 -------------- src/librustc_typeck/check/wf.rs | 4 +- src/librustc_typeck/coherence/orphan.rs | 7 +- src/librustc_typeck/diagnostics.rs | 2 +- .../object-lifetime-default-elision.rs | 2 +- .../object-lifetime-default-from-box-error.rs | 4 +- ...ions-close-over-type-parameter-multiple.rs | 3 +- .../regions-trait-object-subtyping.rs | 2 +- 20 files changed, 482 insertions(+), 381 deletions(-) delete mode 100644 src/librustc_typeck/check/vtable.rs diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index 88c10e3661e7a..60f21a526330f 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -53,6 +53,14 @@ pub trait Sized : MarkerTrait { // Empty. } +/// Types that can be "unsized" to a dynamically sized type. +#[unstable(feature = "core")] +#[cfg(not(stage0))] // SNAP c64d671 +#[lang="unsize"] +pub trait Unsize : PhantomFn { + // Empty. +} + /// Types that can be copied by simply copying bits (i.e. `memcpy`). /// /// By default, variable bindings have 'move semantics.' In other diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 70303bb3410b7..dc4aaf6be783a 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -68,6 +68,7 @@ register_diagnostics! { E0019, E0020, E0022, + E0038, E0109, E0110, E0133, diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index 73d31a1f6201d..e8c7774f135cb 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -259,6 +259,7 @@ lets_do_this! { SendTraitLangItem, "send", send_trait; SizedTraitLangItem, "sized", sized_trait; + UnsizeTraitLangItem, "unsize", unsize_trait; CopyTraitLangItem, "copy", copy_trait; SyncTraitLangItem, "sync", sync_trait; diff --git a/src/librustc/middle/traits/error_reporting.rs b/src/librustc/middle/traits/error_reporting.rs index d10ff060418cc..f0f99a4a118a9 100644 --- a/src/librustc/middle/traits/error_reporting.rs +++ b/src/librustc/middle/traits/error_reporting.rs @@ -15,8 +15,12 @@ use super::{ Obligation, ObligationCauseCode, OutputTypeParameterMismatch, + TraitNotObjectSafe, PredicateObligation, SelectionError, + ObjectSafetyViolation, + MethodViolationCode, + object_safety_violations, }; use fmt_macros::{Parser, Piece, Position}; @@ -246,6 +250,55 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, note_obligation_cause(infcx, obligation); } } + + TraitNotObjectSafe(ref trait_ref) => { + span_err!(infcx.tcx.sess, obligation.cause.span, E0038, + "cannot convert to a trait object because trait `{}` is not object-safe", + ty::item_path_str(infcx.tcx, trait_ref.def_id())); + + for violation in object_safety_violations(infcx.tcx, trait_ref.clone()) { + match violation { + ObjectSafetyViolation::SizedSelf => { + infcx.tcx.sess.span_note( + obligation.cause.span, + "the trait cannot require that `Self : Sized`"); + } + + ObjectSafetyViolation::SupertraitSelf => { + infcx.tcx.sess.span_note( + obligation.cause.span, + "the trait cannot use `Self` as a type parameter \ + in the supertrait listing"); + } + + ObjectSafetyViolation::Method(method, + MethodViolationCode::StaticMethod) => { + infcx.tcx.sess.span_note( + obligation.cause.span, + &format!("method `{}` has no receiver", + method.name.user_string(infcx.tcx))); + } + + ObjectSafetyViolation::Method(method, + MethodViolationCode::ReferencesSelf) => { + infcx.tcx.sess.span_note( + obligation.cause.span, + &format!("method `{}` references the `Self` type \ + in its arguments or return type", + method.name.user_string(infcx.tcx))); + } + + ObjectSafetyViolation::Method(method, + MethodViolationCode::Generic) => { + infcx.tcx.sess.span_note( + obligation.cause.span, + &format!("method `{}` has generic type parameters", + method.name.user_string(infcx.tcx))); + } + } + } + + } } } @@ -397,10 +450,6 @@ fn note_obligation_cause_code<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>, "only the last field of a struct or enum variant \ may have a dynamically sized type") } - ObligationCauseCode::ObjectSized => { - span_note!(tcx.sess, cause_span, - "only sized types can be made into objects"); - } ObligationCauseCode::SharedStatic => { span_note!(tcx.sess, cause_span, "shared static variables must have a type that implements `Sync`"); diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs index 24b201c960f16..bafc244dbd95d 100644 --- a/src/librustc/middle/traits/mod.rs +++ b/src/librustc/middle/traits/mod.rs @@ -27,6 +27,7 @@ use util::ppaux::Repr; pub use self::error_reporting::report_fulfillment_errors; pub use self::error_reporting::report_overflow_error; +pub use self::error_reporting::report_selection_error; pub use self::error_reporting::suggest_new_overflow_limit; pub use self::coherence::orphan_check; pub use self::coherence::overlapping_impls; @@ -46,6 +47,7 @@ pub use self::select::{MethodMatchedData}; // intentionally don't export variant pub use self::util::elaborate_predicates; pub use self::util::get_vtable_index_of_object_method; pub use self::util::trait_ref_for_builtin_bound; +pub use self::util::predicate_for_trait_def; pub use self::util::supertraits; pub use self::util::Supertraits; pub use self::util::transitive_bounds; @@ -117,9 +119,6 @@ pub enum ObligationCauseCode<'tcx> { // Types of fields (other than the last) in a struct must be sized. FieldSized, - // Only Sized types can be made into objects - ObjectSized, - // static items must have `Sync` type SharedStatic, @@ -155,6 +154,7 @@ pub enum SelectionError<'tcx> { OutputTypeParameterMismatch(ty::PolyTraitRef<'tcx>, ty::PolyTraitRef<'tcx>, ty::type_err<'tcx>), + TraitNotObjectSafe(ty::PolyTraitRef<'tcx>), } pub struct FulfillmentError<'tcx> { @@ -531,7 +531,9 @@ impl<'tcx, N> Vtable<'tcx, N> { } } - pub fn map_nested(&self, op: F) -> Vtable<'tcx, M> where F: FnMut(&N) -> M { + pub fn map_nested(&self, op: F) -> Vtable<'tcx, M> where + F: FnMut(&N) -> M, + { match *self { VtableImpl(ref i) => VtableImpl(i.map_nested(op)), VtableDefaultImpl(ref t) => VtableDefaultImpl(t.map_nested(op)), diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index 0d6a1f7df5e56..cdefe9dd72444 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -24,6 +24,8 @@ use super::{PredicateObligation, TraitObligation, ObligationCause}; use super::{report_overflow_error}; use super::{ObligationCauseCode, BuiltinDerivedObligation, ImplDerivedObligation}; use super::{SelectionError, Unimplemented, OutputTypeParameterMismatch}; +use super::{ObjectCastObligation, Obligation}; +use super::TraitNotObjectSafe; use super::{Selection}; use super::{SelectionResult}; use super::{VtableBuiltin, VtableImpl, VtableParam, VtableClosure, @@ -34,7 +36,7 @@ use super::{util}; use middle::fast_reject; use middle::subst::{Subst, Substs, TypeSpace, VecPerParamSpace}; -use middle::ty::{self, RegionEscape, ToPolyTraitRef, Ty}; +use middle::ty::{self, AsPredicate, RegionEscape, ToPolyTraitRef, Ty}; use middle::infer; use middle::infer::{InferCtxt, TypeFreshener}; use middle::ty_fold::TypeFoldable; @@ -155,6 +157,8 @@ enum SelectionCandidate<'tcx> { BuiltinObjectCandidate, + BuiltinUnsizeCandidate, + ErrorCandidate, } @@ -834,6 +838,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { try!(self.assemble_builtin_bound_candidates(bound, stack, &mut candidates)); } + None if self.tcx().lang_items.unsize_trait() == + Some(obligation.predicate.def_id()) => { + self.assemble_candidates_for_unsizing(obligation, &mut candidates); + } + Some(ty::BoundSend) | Some(ty::BoundSync) | None => { @@ -1265,6 +1274,63 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } + /// Search for unsizing that might apply to `obligation`. + fn assemble_candidates_for_unsizing(&mut self, + obligation: &TraitObligation<'tcx>, + candidates: &mut SelectionCandidateSet<'tcx>) { + let source = self.infcx.shallow_resolve(obligation.self_ty()); + let target = self.infcx.shallow_resolve(obligation.predicate.0.input_types()[0]); + + debug!("assemble_candidates_for_unsizing(source={}, target={})", + source.repr(self.tcx()), target.repr(self.tcx())); + + let may_apply = match (&source.sty, &target.sty) { + // Trait+Kx+'a -> Trait+Ky+'b (upcasts). + (&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). + data_a.principal.def_id() == data_a.principal.def_id() && + data_a.bounds.builtin_bounds.is_superset(&data_b.bounds.builtin_bounds) + } + + // T -> Trait. + (_, &ty::ty_trait(_)) => true, + + // Ambiguous handling is below T -> Trait, because inference + // variables can still implement Unsize and nested + // obligations will have the final say (likely deferred). + (&ty::ty_infer(ty::TyVar(_)), _) | + (_, &ty::ty_infer(ty::TyVar(_))) => { + debug!("assemble_candidates_for_unsizing: ambiguous"); + candidates.ambiguous = true; + false + } + + // [T; n] -> [T]. + (&ty::ty_vec(_, Some(_)), &ty::ty_vec(_, None)) => true, + + // Struct -> Struct. + (&ty::ty_struct(def_id_a, _), &ty::ty_struct(def_id_b, _)) => { + def_id_a == def_id_b + } + + _ => false + }; + + if may_apply { + candidates.vec.push(BuiltinUnsizeCandidate); + } + } + /////////////////////////////////////////////////////////////////////////// // WINNOW // @@ -1320,6 +1386,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { (&ClosureCandidate(..), &ParamCandidate(..)) | (&FnPointerCandidate(..), &ParamCandidate(..)) | (&BuiltinObjectCandidate(..), &ParamCandidate(_)) | + (&BuiltinUnsizeCandidate(..), &ParamCandidate(_)) | (&BuiltinCandidate(..), &ParamCandidate(..)) => { // We basically prefer always prefer to use a // where-clause over another option. Where clauses @@ -1747,12 +1814,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { derived_cause.clone(), trait_def_id, obligation.recursion_depth + 1, - skol_ty); - match skol_predicate { - Ok(skol_predicate) => Ok(self.infcx().plug_leaks(skol_map, snapshot, - &skol_predicate)), - Err(ErrorReported) => Err(ErrorReported) - } + skol_ty, + vec![]); + Ok(self.infcx().plug_leaks(skol_map, snapshot, &skol_predicate)) }) }).collect::>, _>>(); @@ -1837,6 +1901,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.confirm_projection_candidate(obligation); Ok(VtableParam(Vec::new())) } + + BuiltinUnsizeCandidate => { + self.infcx.try(|_| { + self.confirm_builtin_unsize_candidate(obligation) + }) + } } } @@ -2168,6 +2238,158 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } + fn confirm_builtin_unsize_candidate(&mut self, + obligation: &TraitObligation<'tcx>,) + -> Result, + SelectionError<'tcx>> { + let tcx = self.tcx(); + + let source = self.infcx.shallow_resolve(obligation.self_ty()); + let target = self.infcx.shallow_resolve(obligation.predicate.0.input_types()[0]); + + debug!("confirm_builtin_unsize_candidate(source={}, target={})", + source.repr(tcx), target.repr(tcx)); + + let mut nested = vec![]; + match (&source.sty, &target.sty) { + // Trait+Kx+'a -> Trait+Ky+'b (upcasts). + (&ty::ty_trait(ref data_a), &ty::ty_trait(ref data_b)) => { + // See assemble_candidates_for_unsizing for more info. + let bounds = ty::ExistentialBounds { + region_bound: data_b.bounds.region_bound, + builtin_bounds: data_b.bounds.builtin_bounds, + projection_bounds: data_a.bounds.projection_bounds.clone(), + }; + + let new_trait = ty::mk_trait(tcx, data_a.principal.clone(), bounds); + let origin = infer::Misc(obligation.cause.span); + if self.infcx.sub_types(false, origin, new_trait, target).is_err() { + return Err(Unimplemented); + } + + // Register one obligation for 'a: 'b. + let cause = ObligationCause::new(obligation.cause.span, + obligation.cause.body_id, + ObjectCastObligation(target)); + let outlives = ty::OutlivesPredicate(data_a.bounds.region_bound, + data_b.bounds.region_bound); + nested.push(Obligation::with_depth(cause, + obligation.recursion_depth + 1, + ty::Binder(outlives).as_predicate())); + } + + // T -> Trait. + (_, &ty::ty_trait(ref data)) => { + let object = data.principal_trait_ref_with_self_ty(tcx, tcx.types.err); + if !object_safety::is_object_safe(tcx, object.clone()) { + return Err(TraitNotObjectSafe(object)); + } + + let cause = ObligationCause::new(obligation.cause.span, + obligation.cause.body_id, + ObjectCastObligation(target)); + let mut push = |predicate| { + nested.push(Obligation::with_depth(cause.clone(), + obligation.recursion_depth + 1, + predicate)); + }; + + // Create the obligation for casting from T to Trait. + push(data.principal_trait_ref_with_self_ty(tcx, source).as_predicate()); + + // We can only make objects from sized types. + let mut builtin_bounds = data.bounds.builtin_bounds; + builtin_bounds.insert(ty::BoundSized); + + // Create additional obligations for all the various builtin + // bounds attached to the object cast. (In other words, if the + // object type is Foo+Send, this would create an obligation + // for the Send check.) + for bound in &builtin_bounds { + if let Ok(tr) = util::trait_ref_for_builtin_bound(tcx, bound, source) { + push(tr.as_predicate()); + } else { + return Err(Unimplemented); + } + } + + // Create obligations for the projection predicates. + for bound in data.projection_bounds_with_self_ty(tcx, source) { + push(bound.as_predicate()); + } + + // If the type is `Foo+'a`, ensures that the type + // being cast to `Foo+'a` outlives `'a`: + let outlives = ty::OutlivesPredicate(source, + data.bounds.region_bound); + push(ty::Binder(outlives).as_predicate()); + } + + // [T; n] -> [T]. + (&ty::ty_vec(a, Some(_)), &ty::ty_vec(b, None)) => { + let origin = infer::Misc(obligation.cause.span); + if self.infcx.sub_types(false, origin, a, b).is_err() { + return Err(Unimplemented); + } + } + + // Struct -> Struct. + (&ty::ty_struct(def_id, substs_a), &ty::ty_struct(_, substs_b)) => { + let fields = ty::lookup_struct_fields(tcx, def_id).iter().map(|f| { + ty::lookup_field_type_unsubstituted(tcx, def_id, f.id) + }).collect::>(); + + // The last field of the structure has to exist and be a + // type parameter (for now, to avoid tracking edge cases). + let i = if let Some(&ty::ty_param(p)) = fields.last().map(|ty| &ty.sty) { + assert!(p.space == TypeSpace); + p.idx as usize + } else { + return Err(Unimplemented); + }; + + // Replace the type parameter chosen for unsizing with + // ty_err and ensure it does not affect any other fields. + // This could be checked after type collection for any struct + // with a potentially unsized trailing field. + let mut new_substs = substs_a.clone(); + new_substs.types.get_mut_slice(TypeSpace)[i] = tcx.types.err; + for &ty in fields.init() { + if ty::type_is_error(ty.subst(tcx, &new_substs)) { + return Err(Unimplemented); + } + } + + // Extract T and U from Struct and Struct. + let inner_source = *substs_a.types.get(TypeSpace, i); + let inner_target = *substs_b.types.get(TypeSpace, i); + + // Check that all the source structure with the unsized + // type parameter is a subtype of the target. + new_substs.types.get_mut_slice(TypeSpace)[i] = inner_target; + let new_struct = ty::mk_struct(tcx, def_id, tcx.mk_substs(new_substs)); + let origin = infer::Misc(obligation.cause.span); + if self.infcx.sub_types(false, origin, new_struct, target).is_err() { + return Err(Unimplemented); + } + + // Construct the nested T: Unsize predicate. + nested.push(util::predicate_for_trait_def(tcx, + obligation.cause.clone(), + obligation.predicate.def_id(), + obligation.recursion_depth + 1, + inner_source, + vec![inner_target])); + } + + _ => unreachable!() + }; + + Ok(VtableBuiltin(VtableBuiltinData { + nested: VecPerParamSpace::new(nested, vec![], vec![]) + })) + } + /////////////////////////////////////////////////////////////////////////// // Matching // @@ -2527,6 +2749,7 @@ impl<'tcx> Repr<'tcx> for SelectionCandidate<'tcx> { ErrorCandidate => format!("ErrorCandidate"), BuiltinCandidate(b) => format!("BuiltinCandidate({:?})", b), BuiltinObjectCandidate => format!("BuiltinObjectCandidate"), + BuiltinUnsizeCandidate => format!("BuiltinUnsizeCandidate"), ParamCandidate(ref a) => format!("ParamCandidate({})", a.repr(tcx)), ImplCandidate(a) => format!("ImplCandidate({})", a.repr(tcx)), DefaultImplCandidate(t) => format!("DefaultImplCandidate({:?})", t), @@ -2580,7 +2803,8 @@ impl<'tcx> EvaluationResult<'tcx> { match *self { EvaluatedToOk | EvaluatedToAmbig | - EvaluatedToErr(OutputTypeParameterMismatch(..)) => + EvaluatedToErr(OutputTypeParameterMismatch(..)) | + EvaluatedToErr(TraitNotObjectSafe(_)) => true, EvaluatedToErr(Unimplemented) => diff --git a/src/librustc/middle/traits/util.rs b/src/librustc/middle/traits/util.rs index 965aaf12044ec..73e6edc3252d2 100644 --- a/src/librustc/middle/traits/util.rs +++ b/src/librustc/middle/traits/util.rs @@ -313,17 +313,17 @@ pub fn trait_ref_for_builtin_bound<'tcx>( } -pub fn predicate_for_trait_ref<'tcx>( +fn predicate_for_trait_ref<'tcx>( cause: ObligationCause<'tcx>, trait_ref: Rc>, recursion_depth: uint) - -> Result, ErrorReported> + -> PredicateObligation<'tcx> { - Ok(Obligation { + Obligation { cause: cause, recursion_depth: recursion_depth, predicate: trait_ref.as_predicate(), - }) + } } pub fn predicate_for_trait_def<'tcx>( @@ -331,12 +331,13 @@ pub fn predicate_for_trait_def<'tcx>( cause: ObligationCause<'tcx>, trait_def_id: ast::DefId, recursion_depth: uint, - param_ty: Ty<'tcx>) - -> Result, ErrorReported> + param_ty: Ty<'tcx>, + ty_params: Vec>) + -> PredicateObligation<'tcx> { let trait_ref = Rc::new(ty::TraitRef { def_id: trait_def_id, - substs: tcx.mk_substs(Substs::empty().with_self_ty(param_ty)) + substs: tcx.mk_substs(Substs::new_trait(ty_params, vec![], param_ty)) }); predicate_for_trait_ref(cause, trait_ref, recursion_depth) } @@ -350,7 +351,7 @@ pub fn predicate_for_builtin_bound<'tcx>( -> Result, ErrorReported> { let trait_ref = try!(trait_ref_for_builtin_bound(tcx, builtin_bound, param_ty)); - predicate_for_trait_ref(cause, trait_ref, recursion_depth) + Ok(predicate_for_trait_ref(cause, trait_ref, recursion_depth)) } /// Cast a trait reference into a reference to one of its super @@ -522,6 +523,10 @@ impl<'tcx> Repr<'tcx> for super::SelectionError<'tcx> { a.repr(tcx), b.repr(tcx), c.repr(tcx)), + + super::TraitNotObjectSafe(ref tr) => + format!("TraitNotObjectSafe({})", + tr.repr(tcx)) } } } diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 19f913a1fd144..13a9bf6b3cff0 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -5478,21 +5478,28 @@ pub fn lookup_repr_hints(tcx: &ctxt, did: DefId) -> Rc> { } // Look up a field ID, whether or not it's local -// Takes a list of type substs in case the struct is generic -pub fn lookup_field_type<'tcx>(tcx: &ctxt<'tcx>, - struct_id: DefId, - id: DefId, - substs: &Substs<'tcx>) - -> Ty<'tcx> { - let ty = if id.krate == ast::LOCAL_CRATE { +pub fn lookup_field_type_unsubstituted<'tcx>(tcx: &ctxt<'tcx>, + struct_id: DefId, + id: DefId) + -> Ty<'tcx> { + if id.krate == ast::LOCAL_CRATE { node_id_to_type(tcx, id.node) } else { let mut tcache = tcx.tcache.borrow_mut(); let pty = tcache.entry(id).get().unwrap_or_else( |vacant_entry| vacant_entry.insert(csearch::get_field_type(tcx, struct_id, id))); pty.ty - }; - ty.subst(tcx, substs) + } +} + +// Look up a field ID, whether or not it's local +// Takes a list of type substs in case the struct is generic +pub fn lookup_field_type<'tcx>(tcx: &ctxt<'tcx>, + struct_id: DefId, + id: DefId, + substs: &Substs<'tcx>) + -> Ty<'tcx> { + lookup_field_type_unsubstituted(tcx, struct_id, id).subst(tcx, substs) } // Look up the list of field names and IDs for a given struct. diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index ef7a9ad78ffb5..f15219a6ae8c5 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -61,26 +61,25 @@ //! we may want to adjust precisely when coercions occur. use check::{autoderef, FnCtxt, NoPreference, PreferMutLvalue, UnresolvedTypeAction}; -use check::vtable; use middle::infer::{self, cres, Coercion, TypeTrace}; use middle::infer::combine::Combine; use middle::infer::sub::Sub; -use middle::subst; -use middle::traits; +use middle::traits::{self, ObligationCause}; +use middle::traits::{predicate_for_trait_def, report_selection_error}; use middle::ty::{AutoDerefRef, AdjustDerefRef}; use middle::ty::{self, mt, Ty}; use util::common::indent; -use util::ppaux; use util::ppaux::Repr; -use std::cell::Cell; +use std::cell::RefCell; +use std::collections::VecDeque; use syntax::ast; struct Coerce<'a, 'tcx: 'a> { fcx: &'a FnCtxt<'a, 'tcx>, trace: TypeTrace<'tcx>, - unsizing_obligation: Cell>> + unsizing_obligations: RefCell>> } type CoerceResult<'tcx> = cres<'tcx, Option>>; @@ -96,12 +95,6 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { Ok(None) // No coercion required. } - fn outlives(&self, a: ty::Region, b: ty::Region) -> cres<'tcx, ()> { - let sub = Sub(self.fcx.infcx().combine_fields(false, self.trace.clone())); - try!(sub.regions(b, a)); - Ok(()) - } - fn unpack_actual_value(&self, a: Ty<'tcx>, f: F) -> T where F: FnOnce(Ty<'tcx>) -> T, { @@ -261,28 +254,28 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { 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) { + if self.can_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) + (Some(ty::AutoPtr(region, mt_b.mutbl)), mt_b.ty) } else { return 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) { + if self.can_unsize_ty(mt_a.ty, mt_b.ty) { try!(coerce_mutbls(mt_a.mutbl, mt_b.mutbl)); - (Some(ty::AutoUnsafe(mt_b.mutbl)), target) + (Some(ty::AutoUnsafe(mt_b.mutbl)), mt_b.ty) } else { return Err(ty::terr_mismatch); } } (&ty::ty_uniq(t_a), &ty::ty_uniq(t_b)) => { - if let Some(target) = self.unsize_ty(t_a, t_b) { - (None, ty::mk_uniq(self.tcx(), target)) + if self.can_unsize_ty(t_a, t_b) { + (None, b) } else { return Err(ty::terr_mismatch); } @@ -301,105 +294,69 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { Ok(Some(AdjustDerefRef(adjustment))) } - // 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> { - 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(_)), &ty::ty_vec(_, None)) => { - Some(ty::mk_vec(tcx, t_a, None)) + /// Returns true if the source type can be unsized to the target type. + /// E.g., `[T; n]` -> `[T]`. + fn can_unsize_ty(&self, + source: Ty<'tcx>, + target: Ty<'tcx>) + -> bool { + debug!("can_unsize_ty(source={}, target={})", + source.repr(self.tcx()), target.repr(self.tcx())); + + let unsize_def_id = if let Some(def_id) = self.tcx().lang_items.unsize_trait() { + def_id + } else { + return false; + }; + + let mut selcx = traits::SelectionContext::new(self.fcx.infcx(), self.fcx); + + // Use a FIFO queue for this custom fulfillment procedure. + let mut queue = VecDeque::new(); + let mut leftover_predicates = vec![]; + + // Create an obligation for `Source: Unsize`. + let cause = ObligationCause::misc(self.trace.span(), self.fcx.body_id); + queue.push_back(predicate_for_trait_def(self.tcx(), cause, unsize_def_id, + 0, source, vec![target])); + + // Keep resolving `Unsize` predicates to avoid emitting a coercion + // in cases like `Foo<$1>` -> `Foo<$2>`, where inference might unify + // those two inner type variables later. + while let Some(obligation) = queue.pop_front() { + let trait_ref = match obligation.predicate { + ty::Predicate::Trait(ref tr) if tr.def_id() == unsize_def_id => { + tr.clone() } - (&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().try(|_| { - // it's ok to upcast from Foo+'a to Foo+'b so long as 'a : 'b - try!(self.outlives(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 - } + _ => { + leftover_predicates.push(obligation); + continue; } - (_, &ty::ty_trait(_)) => { - assert!(self.unsizing_obligation.get().is_none()); - self.unsizing_obligation.set(Some(a)); - Some(ty_b) + }; + match selcx.select(&obligation.with(trait_ref)) { + // Uncertain or unimplemented. + Ok(None) | Err(traits::Unimplemented) => { + return false; } - (&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.fcx.infcx().try(|_| 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.fcx.infcx().try(|_| self.subtype(ty, ty_b)).is_err() { - debug!("Unsized type parameter '{}', but still \ - could not match types {} and {}", - ppaux::ty_to_string(tcx, tp_a), - ppaux::ty_to_string(tcx, ty), - ppaux::ty_to_string(tcx, ty_b)); - // We can only unsize a single type parameter, so - // if we unsize one and it doesn't give us the - // type we want, then we won't succeed later. - break; - } - - return Some(ty); - } - } - None + + // Object safety violations or miscellaneous. + Err(err) => { + report_selection_error(self.fcx.infcx(), &obligation, &err); + // Treat this like an obligation and follow through + // with the unsizing - the lack of a coercion should + // be silent, as it causes a type mismatch later. + } + + Ok(Some(vtable)) => { + vtable.map_move_nested(|o| queue.push_back(o)); } - _ => None } - })) + } + + let mut obligations = self.unsizing_obligations.borrow_mut(); + assert!(obligations.is_empty()); + *obligations = leftover_predicates; + true } fn coerce_from_fn_pointer(&self, @@ -494,42 +451,25 @@ pub fn mk_assignty<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, b: Ty<'tcx>) -> cres<'tcx, ()> { debug!("mk_assignty({} -> {})", a.repr(fcx.tcx()), b.repr(fcx.tcx())); - let (adjustment, unsizing_obligation) = try!(indent(|| { + let mut unsizing_obligations = vec![]; + let adjustment = try!(indent(|| { fcx.infcx().commit_if_ok(|| { let origin = infer::ExprAssignable(expr.span); let coerce = Coerce { fcx: fcx, trace: infer::TypeTrace::types(origin, false, a, b), - unsizing_obligation: Cell::new(None) + unsizing_obligations: RefCell::new(vec![]) }; - Ok((try!(coerce.coerce(expr, a, b)), - coerce.unsizing_obligation.get())) + let adjustment = try!(coerce.coerce(expr, a, b)); + unsizing_obligations = coerce.unsizing_obligations.into_inner(); + Ok(adjustment) }) })); 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 auto.unsize.is_some() { + for obligation in unsizing_obligations { + fcx.register_predicate(obligation); } } } diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index bf89af606f540..800c4b43fe1bd 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -12,8 +12,6 @@ use astconv::AstConv; use check::{FnCtxt}; -use check::vtable; -use check::vtable::select_new_fcx_obligations; use middle::def; use middle::privacy::{AllPublic, DependsOn, LastPrivate, LastMod}; use middle::subst; @@ -233,7 +231,7 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // FIXME(#18653) -- Try to resolve obligations, giving us more // typing information, which can sometimes be needed to avoid // pathological region inference failures. - vtable::select_new_fcx_obligations(fcx); + fcx.select_new_obligations(); // Insert any adjustments needed (always an autoref of some mutability). match self_expr { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index bddd3914dfc9a..978a52bc3036f 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -94,7 +94,7 @@ use middle::pat_util::{self, pat_id_map}; use middle::privacy::{AllPublic, LastMod}; use middle::region::{self, CodeExtent}; use middle::subst::{self, Subst, Substs, VecPerParamSpace, ParamSpace, TypeSpace}; -use middle::traits; +use middle::traits::{self, report_fulfillment_errors}; use middle::ty::{FnSig, GenericPredicates, VariantInfo, TypeScheme}; use middle::ty::{Disr, ParamTy, ParameterEnvironment}; use middle::ty::{self, HasProjectionTypes, RegionEscape, ToPolyTraitRef, Ty}; @@ -131,7 +131,6 @@ use syntax::visit::{self, Visitor}; mod assoc; pub mod dropck; pub mod _match; -pub mod vtable; pub mod writeback; pub mod implicator; pub mod regionck; @@ -531,9 +530,9 @@ fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let fcx = check_fn(ccx, fn_ty.unsafety, fn_id, &fn_sig, decl, fn_id, body, &inh); - vtable::select_all_fcx_obligations_and_apply_defaults(&fcx); + fcx.select_all_obligations_and_apply_defaults(); upvar::closure_analyze_fn(&fcx, fn_id, decl, body); - vtable::select_all_fcx_obligations_or_error(&fcx); + fcx.select_all_obligations_or_error(); fcx.check_casts(); regionck::regionck_fn(&fcx, fn_id, fn_span, decl, body); writeback::resolve_type_vars_in_fn(&fcx, decl, body); @@ -1334,7 +1333,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } // If not, try resolving any new fcx obligations that have cropped up. - vtable::select_new_fcx_obligations(self); + self.select_new_obligations(); ty = self.infcx().resolve_type_vars_if_possible(&ty); if !ty::type_has_ty_infer(ty) { return ty; @@ -1344,7 +1343,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // possible. This can help substantially when there are // indirect dependencies that don't seem worth tracking // precisely. - vtable::select_fcx_obligations_where_possible(self); + self.select_obligations_where_possible(); self.infcx().resolve_type_vars_if_possible(&ty) } @@ -1854,6 +1853,56 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { deferred_cast_checks.clear(); } + + fn select_all_obligations_and_apply_defaults(&self) { + debug!("select_all_obligations_and_apply_defaults"); + + self.select_obligations_where_possible(); + self.default_type_parameters(); + self.select_obligations_where_possible(); + } + + fn select_all_obligations_or_error(&self) { + debug!("select_all_obligations_or_error"); + + // upvar inference should have ensured that all deferred call + // resolutions are handled by now. + assert!(self.inh.deferred_call_resolutions.borrow().is_empty()); + + self.select_all_obligations_and_apply_defaults(); + let mut fulfillment_cx = self.inh.fulfillment_cx.borrow_mut(); + match fulfillment_cx.select_all_or_error(self.infcx(), self) { + Ok(()) => { } + Err(errors) => { report_fulfillment_errors(self.infcx(), &errors); } + } + } + + /// Select as many obligations as we can at present. + fn select_obligations_where_possible(&self) { + match + self.inh.fulfillment_cx + .borrow_mut() + .select_where_possible(self.infcx(), self) + { + Ok(()) => { } + Err(errors) => { report_fulfillment_errors(self.infcx(), &errors); } + } + } + + /// Try to select any fcx obligation that we haven't tried yet, in an effort to improve inference. + /// You could just call `select_obligations_where_possible` except that it leads to repeated + /// work. + fn select_new_obligations(&self) { + match + self.inh.fulfillment_cx + .borrow_mut() + .select_new_obligations(self.infcx(), self) + { + Ok(()) => { } + Err(errors) => { report_fulfillment_errors(self.infcx(), &errors); } + } + } + } impl<'a, 'tcx> RegionScope for FnCtxt<'a, 'tcx> { @@ -2311,7 +2360,7 @@ fn check_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // an "opportunistic" vtable resolution of any trait bounds on // the call. This helps coercions. if check_blocks { - vtable::select_new_fcx_obligations(fcx); + fcx.select_new_obligations(); } // For variadic functions, we don't have a declared type for all of @@ -4378,7 +4427,7 @@ fn check_const_with_ty<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, check_expr_with_hint(fcx, e, declty); demand::coerce(fcx, e.span, declty, e); - vtable::select_all_fcx_obligations_or_error(fcx); + fcx.select_all_obligations_or_error(); fcx.check_casts(); regionck::regionck_expr(fcx, e); writeback::resolve_type_vars_in_expr(fcx, e); diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index fa9df2c1e0b55..25f5be342608a 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -86,7 +86,6 @@ use astconv::AstConv; use check::dropck; use check::FnCtxt; use check::implicator; -use check::vtable; use middle::mem_categorization as mc; use middle::region::CodeExtent; use middle::subst::Substs; @@ -294,7 +293,7 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> { // region checking can introduce new pending obligations // which, when processed, might generate new region // obligations. So make sure we process those. - vtable::select_all_fcx_obligations_or_error(self.fcx); + self.fcx.select_all_obligations_or_error(); // Make a copy of the region obligations vec because we'll need // to be able to borrow the fulfillment-cx below when projecting. diff --git a/src/librustc_typeck/check/vtable.rs b/src/librustc_typeck/check/vtable.rs deleted file mode 100644 index 2aaa02fe330da..0000000000000 --- a/src/librustc_typeck/check/vtable.rs +++ /dev/null @@ -1,188 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use check::{FnCtxt}; -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}; - - -// Check that a trait is 'object-safe'. This should be checked whenever a trait object -// is created (by casting or coercion, etc.). A trait is object-safe if all its -// methods are object-safe. A trait method is object-safe if it does not take -// self by value, has no type parameters and does not use the `Self` type, except -// in self position. -pub fn check_object_safety<'tcx>(tcx: &ty::ctxt<'tcx>, - object_trait: &ty::TyTrait<'tcx>, - span: Span) -{ - let object_trait_ref = - object_trait.principal_trait_ref_with_self_ty(tcx, tcx.types.err); - - if traits::is_object_safe(tcx, object_trait_ref.clone()) { - return; - } - - span_err!(tcx.sess, span, E0038, - "cannot convert to a trait object because trait `{}` is not object-safe", - ty::item_path_str(tcx, object_trait_ref.def_id())); - - let violations = traits::object_safety_violations(tcx, object_trait_ref.clone()); - for violation in violations { - match violation { - ObjectSafetyViolation::SizedSelf => { - tcx.sess.span_note( - span, - "the trait cannot require that `Self : Sized`"); - } - - ObjectSafetyViolation::SupertraitSelf => { - tcx.sess.span_note( - span, - "the trait cannot use `Self` as a type parameter \ - in the supertrait listing"); - } - - ObjectSafetyViolation::Method(method, MethodViolationCode::StaticMethod) => { - tcx.sess.span_note( - span, - &format!("method `{}` has no receiver", - method.name.user_string(tcx))); - } - - ObjectSafetyViolation::Method(method, MethodViolationCode::ReferencesSelf) => { - tcx.sess.span_note( - span, - &format!("method `{}` references the `Self` type \ - in its arguments or return type", - method.name.user_string(tcx))); - } - - ObjectSafetyViolation::Method(method, MethodViolationCode::Generic) => { - tcx.sess.span_note( - span, - &format!("method `{}` has generic type parameters", - method.name.user_string(tcx))); - } - } - } -} - -pub fn register_object_cast_obligations<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - span: Span, - object_trait: &ty::TyTrait<'tcx>, - referent_ty: Ty<'tcx>) - -> ty::PolyTraitRef<'tcx> -{ - // We can only make objects from sized types. - fcx.register_builtin_bound( - referent_ty, - ty::BoundSized, - traits::ObligationCause::new(span, fcx.body_id, traits::ObjectSized)); - - // This is just for better error reporting. Kinda goofy. The object type stuff - // needs some refactoring so there is a more convenient type to pass around. - let object_trait_ty = - ty::mk_trait(fcx.tcx(), - object_trait.principal.clone(), - object_trait.bounds.clone()); - - debug!("register_object_cast_obligations: referent_ty={} object_trait_ty={}", - referent_ty.repr(fcx.tcx()), - object_trait_ty.repr(fcx.tcx())); - - let cause = ObligationCause::new(span, - fcx.body_id, - traits::ObjectCastObligation(object_trait_ty)); - - // Create the obligation for casting from T to Trait. - let object_trait_ref = - object_trait.principal_trait_ref_with_self_ty(fcx.tcx(), referent_ty); - let object_obligation = - Obligation::new(cause.clone(), object_trait_ref.as_predicate()); - fcx.register_predicate(object_obligation); - - // Create additional obligations for all the various builtin - // bounds attached to the object cast. (In other words, if the - // object type is Foo+Send, this would create an obligation - // for the Send check.) - for builtin_bound in &object_trait.bounds.builtin_bounds { - fcx.register_builtin_bound( - referent_ty, - builtin_bound, - cause.clone()); - } - - // Create obligations for the projection predicates. - let projection_bounds = - object_trait.projection_bounds_with_self_ty(fcx.tcx(), referent_ty); - for projection_bound in &projection_bounds { - let projection_obligation = - Obligation::new(cause.clone(), projection_bound.as_predicate()); - fcx.register_predicate(projection_obligation); - } - - object_trait_ref -} - -pub fn select_all_fcx_obligations_and_apply_defaults(fcx: &FnCtxt) { - debug!("select_all_fcx_obligations_and_apply_defaults"); - - select_fcx_obligations_where_possible(fcx); - fcx.default_type_parameters(); - select_fcx_obligations_where_possible(fcx); -} - -pub fn select_all_fcx_obligations_or_error(fcx: &FnCtxt) { - debug!("select_all_fcx_obligations_or_error"); - - // upvar inference should have ensured that all deferred call - // resolutions are handled by now. - assert!(fcx.inh.deferred_call_resolutions.borrow().is_empty()); - - select_all_fcx_obligations_and_apply_defaults(fcx); - let mut fulfillment_cx = fcx.inh.fulfillment_cx.borrow_mut(); - let r = fulfillment_cx.select_all_or_error(fcx.infcx(), fcx); - match r { - Ok(()) => { } - Err(errors) => { report_fulfillment_errors(fcx.infcx(), &errors); } - } -} - -/// Select as many obligations as we can at present. -pub fn select_fcx_obligations_where_possible(fcx: &FnCtxt) -{ - match - fcx.inh.fulfillment_cx - .borrow_mut() - .select_where_possible(fcx.infcx(), fcx) - { - Ok(()) => { } - Err(errors) => { report_fulfillment_errors(fcx.infcx(), &errors); } - } -} - -/// Try to select any fcx obligation that we haven't tried yet, in an effort to improve inference. -/// You could just call `select_fcx_obligations_where_possible` except that it leads to repeated -/// work. -pub fn select_new_fcx_obligations(fcx: &FnCtxt) { - match - fcx.inh.fulfillment_cx - .borrow_mut() - .select_new_obligations(fcx.infcx(), fcx) - { - Ok(()) => { } - Err(errors) => { report_fulfillment_errors(fcx.infcx(), &errors); } - } -} diff --git a/src/librustc_typeck/check/wf.rs b/src/librustc_typeck/check/wf.rs index adbf4c6b210e8..0cac0222dfe4b 100644 --- a/src/librustc_typeck/check/wf.rs +++ b/src/librustc_typeck/check/wf.rs @@ -9,7 +9,7 @@ // except according to those terms. use astconv::AstConv; -use check::{FnCtxt, Inherited, blank_fn_ctxt, vtable, regionck}; +use check::{FnCtxt, Inherited, blank_fn_ctxt, regionck}; use constrained_type_params::identify_constrained_type_params; use CrateCtxt; use middle::region; @@ -157,7 +157,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { let inh = Inherited::new(ccx.tcx, param_env); let fcx = blank_fn_ctxt(ccx, &inh, ty::FnConverging(type_scheme.ty), item.id); f(self, &fcx); - vtable::select_all_fcx_obligations_or_error(&fcx); + fcx.select_all_obligations_or_error(); regionck::regionck_item(&fcx, item); } diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs index ab694d26b155c..1a67a7fffbd32 100644 --- a/src/librustc_typeck/coherence/orphan.rs +++ b/src/librustc_typeck/coherence/orphan.rs @@ -320,12 +320,17 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> { } } - // Disallow *all* explicit impls of `Sized` for now. + // Disallow *all* explicit impls of `Sized` and `Unsize` for now. if Some(trait_def_id) == self.tcx.lang_items.sized_trait() { span_err!(self.tcx.sess, item.span, E0322, "explicit impls for the `Sized` trait are not permitted"); return; } + if Some(trait_def_id) == self.tcx.lang_items.unsize_trait() { + span_err!(self.tcx.sess, item.span, E0323, + "explicit impls for the `Unsize` trait are not permitted"); + return; + } } ast::ItemDefaultImpl(..) => { // "Trait" impl diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 95e06879fb223..3cf5d450b1a61 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -23,7 +23,6 @@ register_diagnostics! { E0034, E0035, E0036, - E0038, E0040, // explicit use of destructor method E0044, E0045, @@ -178,6 +177,7 @@ register_diagnostics! { E0320, // recursive overflow during dropck E0321, // extended coherence rules for defaulted traits violated E0322, // cannot implement Sized explicitly + E0323, // cannot implement Unsize explicitly E0366, // dropck forbid specialization to concrete type or region E0367 // dropck forbid specialization to predicate not in struct/enum } diff --git a/src/test/compile-fail/object-lifetime-default-elision.rs b/src/test/compile-fail/object-lifetime-default-elision.rs index 0077d10e6ca82..5d962a90c1ebf 100644 --- a/src/test/compile-fail/object-lifetime-default-elision.rs +++ b/src/test/compile-fail/object-lifetime-default-elision.rs @@ -82,7 +82,7 @@ fn load3<'a,'b>(ss: &'a SomeTrait) -> &'b SomeTrait { ss //~^ ERROR cannot infer - //~| ERROR mismatched types + //~| ERROR lifetime bound not satisfied } fn main() { diff --git a/src/test/compile-fail/object-lifetime-default-from-box-error.rs b/src/test/compile-fail/object-lifetime-default-from-box-error.rs index 70752cbfda19f..dd94dfe1e0823 100644 --- a/src/test/compile-fail/object-lifetime-default-from-box-error.rs +++ b/src/test/compile-fail/object-lifetime-default-from-box-error.rs @@ -25,7 +25,7 @@ fn load(ss: &mut SomeStruct) -> Box { // `Box` defaults to a `'static` bound, so this return // is illegal. - ss.r //~ ERROR mismatched types + ss.r //~ ERROR lifetime bound not satisfied } fn store(ss: &mut SomeStruct, b: Box) { @@ -38,7 +38,7 @@ fn store(ss: &mut SomeStruct, b: Box) { fn store1<'b>(ss: &mut SomeStruct, b: Box) { // Here we override the lifetimes explicitly, and so naturally we get an error. - ss.r = b; //~ ERROR mismatched types + ss.r = b; //~ ERROR lifetime bound not satisfied } fn main() { diff --git a/src/test/compile-fail/regions-close-over-type-parameter-multiple.rs b/src/test/compile-fail/regions-close-over-type-parameter-multiple.rs index 0f8bc6d684f12..c74f0d6a48d9f 100644 --- a/src/test/compile-fail/regions-close-over-type-parameter-multiple.rs +++ b/src/test/compile-fail/regions-close-over-type-parameter-multiple.rs @@ -27,7 +27,8 @@ fn make_object_good2<'a,'b,A:SomeTrait+'a+'b>(v: A) -> Box { fn make_object_bad<'a,'b,'c,A:SomeTrait+'a+'b>(v: A) -> Box { // A outlives 'a AND 'b...but not 'c. - box v as Box //~ ERROR mismatched types + box v as Box + //~^ ERROR lifetime bound not satisfied } fn main() { diff --git a/src/test/compile-fail/regions-trait-object-subtyping.rs b/src/test/compile-fail/regions-trait-object-subtyping.rs index 8d05cb67e77b1..b4e527972e476 100644 --- a/src/test/compile-fail/regions-trait-object-subtyping.rs +++ b/src/test/compile-fail/regions-trait-object-subtyping.rs @@ -22,7 +22,7 @@ fn foo2<'a:'b,'b>(x: &'b mut (Dummy+'a)) -> &'b mut (Dummy+'b) { fn foo3<'a,'b>(x: &'a mut Dummy) -> &'b mut Dummy { // Without knowing 'a:'b, we can't coerce - x //~ ERROR mismatched types + x //~ ERROR lifetime bound not satisfied //~^ ERROR cannot infer } From 9e5bdb25b4edd428bd038a9d6843dd4c620d15e3 Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Fri, 27 Mar 2015 18:23:44 +0200 Subject: [PATCH 10/12] Introduce a CoerceUnsized trait and use it for custom coercions. --- src/liballoc/boxed.rs | 8 + src/libcore/nonzero.rs | 5 + src/libcore/ops.rs | 36 +++- src/librustc/metadata/common.rs | 2 + src/librustc/metadata/csearch.rs | 8 + src/librustc/metadata/decoder.rs | 10 + src/librustc/metadata/encoder.rs | 10 + src/librustc/middle/lang_items.rs | 2 + src/librustc/middle/ty.rs | 30 +++ src/librustc_trans/trans/expr.rs | 201 ++++++++++++++------- src/librustc_typeck/check/coercion.rs | 107 ++++------- src/librustc_typeck/coherence/mod.rs | 172 +++++++++++++++++- src/librustc_typeck/diagnostics.rs | 11 +- src/test/compile-fail/dst-bad-coercions.rs | 14 -- 14 files changed, 468 insertions(+), 148 deletions(-) diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 8b18fbf554a4c..33896f3f6162b 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -59,6 +59,11 @@ use core::ops::{Deref, DerefMut}; use core::ptr::Unique; use core::raw::TraitObject; +#[cfg(not(stage0))] // SNAP c64d671 +use core::marker::Unsize; +#[cfg(not(stage0))] // SNAP c64d671 +use core::ops::CoerceUnsized; + /// A value that represents the heap. This is the default place that the `box` /// keyword allocates into when no place is supplied. /// @@ -327,3 +332,6 @@ impl<'a, E: Error + 'a> FromError for Box { Box::new(err) } } + +#[cfg(not(stage0))] // SNAP c64d671 +impl, U: ?Sized> CoerceUnsized> for Box {} diff --git a/src/libcore/nonzero.rs b/src/libcore/nonzero.rs index 230587b726fd1..cd1ce63aa79f6 100644 --- a/src/libcore/nonzero.rs +++ b/src/libcore/nonzero.rs @@ -12,6 +12,8 @@ use marker::{Sized, MarkerTrait}; use ops::Deref; +#[cfg(not(stage0))] // SNAP c64d671 +use ops::CoerceUnsized; /// Unsafe trait to indicate what types are usable with the NonZero struct pub unsafe trait Zeroable : MarkerTrait {} @@ -54,3 +56,6 @@ impl Deref for NonZero { inner } } + +#[cfg(not(stage0))] // SNAP c64d671 +impl, U: Zeroable> CoerceUnsized> for NonZero {} diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index fee40115f3952..26a32f38c7acc 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -67,9 +67,12 @@ #![stable(feature = "rust1", since = "1.0.0")] -use marker::Sized; +use marker::{PhantomFn, Sized}; use fmt; +#[cfg(not(stage0))] // SNAP c64d671 +use marker::Unsize; + /// The `Drop` trait is used to run some code when a value goes out of scope. This /// is sometimes called a 'destructor'. /// @@ -1223,3 +1226,34 @@ impl FnOnce for F self.call_mut(args) } } + +/// Trait that indicates that this is a pointer or a wrapper for one, +/// where unsizing can be performed on the pointee. +#[unstable(feature = "core")] +#[cfg(not(stage0))] // SNAP c64d671 +#[lang="coerce_unsized"] +pub trait CoerceUnsized : PhantomFn { + // Empty. +} + +#[cfg(not(stage0))] // SNAP c64d671 +impl<'a, 'b: 'a, T: ?Sized+Unsize, U: ?Sized> CoerceUnsized<&'a mut U> for &'b mut T {} +#[cfg(not(stage0))] // SNAP c64d671 +impl<'a, 'b: 'a, T: ?Sized+Unsize, U: ?Sized> CoerceUnsized<&'a U> for &'b mut T {} +#[cfg(not(stage0))] // SNAP c64d671 +impl<'a, T: ?Sized+Unsize, U: ?Sized> CoerceUnsized<*const U> for &'a mut T {} +#[cfg(not(stage0))] // SNAP c64d671 +impl<'a, T: ?Sized+Unsize, U: ?Sized> CoerceUnsized<*mut U> for &'a mut T {} + +#[cfg(not(stage0))] // SNAP c64d671 +impl<'a, 'b: 'a, T: ?Sized+Unsize, U: ?Sized> CoerceUnsized<&'a U> for &'b T {} +#[cfg(not(stage0))] // SNAP c64d671 +impl<'a, T: ?Sized+Unsize, U: ?Sized> CoerceUnsized<*const U> for &'a T {} + +#[cfg(not(stage0))] // SNAP c64d671 +impl, U: ?Sized> CoerceUnsized<*const U> for *mut T {} +#[cfg(not(stage0))] // SNAP c64d671 +impl, U: ?Sized> CoerceUnsized<*mut U> for *mut T {} + +#[cfg(not(stage0))] // SNAP c64d671 +impl, U: ?Sized> CoerceUnsized<*const U> for *const T {} diff --git a/src/librustc/metadata/common.rs b/src/librustc/metadata/common.rs index 081c64ecae881..9fa46e7c38690 100644 --- a/src/librustc/metadata/common.rs +++ b/src/librustc/metadata/common.rs @@ -256,3 +256,5 @@ pub const tag_codemap_filemap: uint = 0xa2; pub const tag_item_super_predicates: uint = 0xa3; pub const tag_defaulted_trait: uint = 0xa4; + +pub const tag_impl_coerce_unsized_kind: uint = 0xa5; diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs index ca8ae83ab80a8..541cd373924f3 100644 --- a/src/librustc/metadata/csearch.rs +++ b/src/librustc/metadata/csearch.rs @@ -272,6 +272,14 @@ pub fn get_impl_polarity<'tcx>(tcx: &ty::ctxt<'tcx>, decoder::get_impl_polarity(&*cdata, def.node) } +pub fn get_custom_coerce_unsized_kind<'tcx>(tcx: &ty::ctxt<'tcx>, + def: ast::DefId) + -> Option { + let cstore = &tcx.sess.cstore; + let cdata = cstore.get_crate_data(def.krate); + decoder::get_custom_coerce_unsized_kind(&*cdata, def.node) +} + // Given a def_id for an impl, return the trait it implements, // if there is one. pub fn get_impl_trait<'tcx>(tcx: &ty::ctxt<'tcx>, diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index c0bad80ab594a..8d54602577975 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -470,6 +470,16 @@ pub fn get_impl_polarity<'tcx>(cdata: Cmd, } } +pub fn get_custom_coerce_unsized_kind<'tcx>(cdata: Cmd, + id: ast::NodeId) + -> Option { + let item_doc = lookup_item(id, cdata.data()); + reader::maybe_get_doc(item_doc, tag_impl_coerce_unsized_kind).map(|kind_doc| { + let mut decoder = reader::Decoder::new(kind_doc); + Decodable::decode(&mut decoder).unwrap() + }) +} + pub fn get_impl_trait<'tcx>(cdata: Cmd, id: ast::NodeId, tcx: &ty::ctxt<'tcx>) diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index fa8d0b2a56e4e..9836bcb759ebd 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -1186,6 +1186,16 @@ fn encode_info_for_item(ecx: &EncodeContext, encode_attributes(rbml_w, &item.attrs); encode_unsafety(rbml_w, unsafety); encode_polarity(rbml_w, polarity); + + match tcx.custom_coerce_unsized_kinds.borrow().get(&local_def(item.id)) { + Some(&kind) => { + rbml_w.start_tag(tag_impl_coerce_unsized_kind); + kind.encode(rbml_w); + rbml_w.end_tag(); + } + None => {} + } + match ty.node { ast::TyPath(None, ref path) if path.segments.len() == 1 => { let ident = path.segments.last().unwrap().identifier; diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index e8c7774f135cb..19aac1da6046b 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -265,6 +265,8 @@ lets_do_this! { DropTraitLangItem, "drop", drop_trait; + CoerceUnsizedTraitLangItem, "coerce_unsized", coerce_unsized_trait; + AddTraitLangItem, "add", add_trait; SubTraitLangItem, "sub", sub_trait; MulTraitLangItem, "mul", mul_trait; diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 13a9bf6b3cff0..cf39f5aea1546 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -307,6 +307,12 @@ pub enum AutoRef<'tcx> { AutoUnsafe(ast::Mutability), } +#[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug)] +pub enum CustomCoerceUnsized { + /// Records the index of the field being coerced. + Struct(usize) +} + #[derive(Clone, Copy, RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Debug)] pub struct param_index { pub space: subst::ParamSpace, @@ -721,6 +727,9 @@ pub struct ctxt<'tcx> { /// Maps Expr NodeId's to their constant qualification. pub const_qualif_map: RefCell>, + + /// Caches CoerceUnsized kinds for impls on custom types. + pub custom_coerce_unsized_kinds: RefCell>, } // Flags that we track on types. These flags are propagated upwards @@ -2513,6 +2522,7 @@ pub fn mk_ctxt<'tcx>(s: Session, type_impls_sized_cache: RefCell::new(HashMap::new()), object_safety_cache: RefCell::new(DefIdMap()), const_qualif_map: RefCell::new(NodeMap()), + custom_coerce_unsized_kinds: RefCell::new(DefIdMap()), } } @@ -5022,6 +5032,26 @@ pub fn trait_impl_polarity<'tcx>(cx: &ctxt<'tcx>, id: ast::DefId) } } +pub fn custom_coerce_unsized_kind<'tcx>(cx: &ctxt<'tcx>, did: ast::DefId) + -> CustomCoerceUnsized { + memoized(&cx.custom_coerce_unsized_kinds, did, |did: DefId| { + let (kind, src) = if did.krate != ast::LOCAL_CRATE { + (csearch::get_custom_coerce_unsized_kind(cx, did), "external") + } else { + (None, "local") + }; + + match kind { + Some(kind) => kind, + None => { + cx.sess.bug(&format!("custom_coerce_unsized_kind: \ + {} impl `{}` is missing its kind", + src, item_path_str(cx, did))); + } + } + }) +} + pub fn impl_or_trait_item<'tcx>(cx: &ctxt<'tcx>, id: ast::DefId) -> ImplOrTraitItem<'tcx> { lookup_locally_or_in_crate_store("impl_or_trait_items", diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs index f518c531c78eb..4933b1a25f934 100644 --- a/src/librustc_trans/trans/expr.rs +++ b/src/librustc_trans/trans/expr.rs @@ -56,8 +56,10 @@ use back::abi; use llvm::{self, ValueRef}; use middle::check_const; use middle::def; +use middle::lang_items::CoerceUnsizedTraitLangItem; use middle::mem_categorization::Typer; -use middle::subst::{self, Substs}; +use middle::subst::{Subst, Substs, VecPerParamSpace}; +use middle::traits; use trans::{_match, adt, asm, base, callee, closure, consts, controlflow}; use trans::base::*; use trans::build::*; @@ -299,7 +301,7 @@ 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>) + param_substs: &'tcx Substs<'tcx>) -> ValueRef { let (source, target) = ty::struct_lockstep_tails(ccx.tcx(), source, target); match (&source.sty, &target.sty) { @@ -385,82 +387,155 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, // (You might think there is a more elegant way to do this than a // 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 !type_is_sized(bcx.tcx(), datum.ty) { + // Arrange cleanup + let lval = unpack_datum!(bcx, + datum.to_lvalue_datum(bcx, "ref_fat_ptr", expr.id)); + datum = unpack_datum!(bcx, ref_fat_ptr(bcx, lval)); + } else { + datum = unpack_datum!(bcx, auto_ref(bcx, datum, expr)); + } } if let Some(target) = adj.unsize { - datum = unpack_datum!(bcx, unsize_pointer(bcx, datum, - bcx.monomorphize(&target))); + // 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 source_datum = unpack_datum!(bcx, + datum.to_rvalue_datum(bcx, "__coerce_source")); + + let target = bcx.monomorphize(&target); + let llty = type_of::type_of(bcx.ccx(), target); + + // HACK(eddyb) get around issues with lifetime intrinsics. + let scratch = alloca_no_lifetime(bcx, llty, "__coerce_target"); + let target_datum = Datum::new(scratch, target, + Rvalue::new(ByRef)); + bcx = coerce_unsized(bcx, expr.span, source_datum, target_datum); + datum = Datum::new(scratch, target, + RvalueExpr(Rvalue::new(ByRef))); } } } debug!("after adjustments, datum={}", datum.to_string(bcx.ccx())); - return DatumBlock::new(bcx, datum); + DatumBlock::new(bcx, datum) +} - fn apply_autoref<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - expr: &ast::Expr, - datum: Datum<'tcx, Expr>) - -> DatumBlock<'blk, 'tcx, Expr> { - let mut bcx = bcx; +fn coerce_unsized<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, + span: codemap::Span, + source: Datum<'tcx, Rvalue>, + target: Datum<'tcx, Rvalue>) + -> Block<'blk, 'tcx> { + let mut bcx = bcx; + debug!("coerce_unsized({} -> {})", + source.to_string(bcx.ccx()), + target.to_string(bcx.ccx())); + + match (&source.ty.sty, &target.ty.sty) { + (&ty::ty_uniq(a), &ty::ty_uniq(b)) | + (&ty::ty_rptr(_, ty::mt { ty: a, .. }), &ty::ty_rptr(_, ty::mt { ty: b, .. })) | + (&ty::ty_rptr(_, ty::mt { ty: a, .. }), &ty::ty_ptr(ty::mt { ty: b, .. })) | + (&ty::ty_ptr(ty::mt { ty: a, .. }), &ty::ty_ptr(ty::mt { ty: b, .. })) => { + let (inner_source, inner_target) = (a, b); + + let (base, old_info) = if !type_is_sized(bcx.tcx(), inner_source) { + // 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, source.val)), + Some(Load(bcx, get_len(bcx, source.val)))) + } else { + let val = if source.kind.is_by_ref() { + load_ty(bcx, source.val, source.ty) + } else { + source.val + }; + (val, None) + }; - 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) + let info = unsized_info(bcx.ccx(), inner_source, inner_target, + 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(), inner_target).ptr_to(); + let base = PointerCast(bcx, base, ptr_ty); + + Store(bcx, base, get_dataptr(bcx, target.val)); + Store(bcx, info, get_len(bcx, target.val)); } - } - 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 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())); - - // 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, datum.val)), - Some(Load(bcx, get_len(bcx, datum.val)))) - } else { - (datum.val, None) - }; + // This can be extended to enums and tuples in the future. + // (&ty::ty_enum(def_id_a, substs_a), &ty::ty_enum(def_id_b, substs_b)) | + (&ty::ty_struct(def_id_a, substs_a), &ty::ty_struct(def_id_b, substs_b)) => { + assert_eq!(def_id_a, def_id_b); - let info = unsized_info(bcx.ccx(), pointee_ty, unsized_ty, - old_info, bcx.fcx.param_substs); + // The target is already by-ref because it's to be written to. + let source = unpack_datum!(bcx, source.to_ref_datum(bcx)); + assert!(target.kind.is_by_ref()); - // 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 trait_substs = Substs::erased(VecPerParamSpace::new(vec![target.ty], + vec![source.ty], + Vec::new())); + let trait_ref = ty::Binder(Rc::new(ty::TraitRef { + def_id: langcall(bcx, Some(span), "coercion", + CoerceUnsizedTraitLangItem), + substs: bcx.tcx().mk_substs(trait_substs) + })); + + let kind = match fulfill_obligation(bcx.ccx(), span, trait_ref) { + traits::VtableImpl(traits::VtableImplData { impl_def_id, .. }) => { + ty::custom_coerce_unsized_kind(bcx.tcx(), impl_def_id) + } + vtable => { + bcx.sess().span_bug(span, &format!("invalid CoerceUnsized vtable: {}", + vtable.repr(bcx.tcx()))); + } + }; - 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)); + let repr_source = adt::represent_type(bcx.ccx(), source.ty); + let repr_target = adt::represent_type(bcx.ccx(), target.ty); + let fields = ty::lookup_struct_fields(bcx.tcx(), def_id_a); - DatumBlock::new(bcx, Datum::new(scratch, target, - RvalueExpr(Rvalue::new(ByRef)))) + let coerce_index = match kind { + ty::CustomCoerceUnsized::Struct(i) => i + }; + assert!(coerce_index < fields.len()); + + for (i, field) in fields.iter().enumerate() { + let ll_source = adt::trans_field_ptr(bcx, &repr_source, source.val, 0, i); + let ll_target = adt::trans_field_ptr(bcx, &repr_target, target.val, 0, i); + + let ty = ty::lookup_field_type_unsubstituted(bcx.tcx(), + def_id_a, + field.id); + let field_source = ty.subst(bcx.tcx(), substs_a); + let field_target = ty.subst(bcx.tcx(), substs_b); + + // If this is the field we need to coerce, recurse on it. + if i == coerce_index { + coerce_unsized(bcx, span, + Datum::new(ll_source, field_source, + Rvalue::new(ByRef)), + Datum::new(ll_target, field_target, + Rvalue::new(ByRef))); + } else { + // Otherwise, simply copy the data from the source. + assert_eq!(field_source, field_target); + memcpy_ty(bcx, ll_target, ll_source, field_source); + } + } + } + _ => bcx.sess().bug(&format!("coerce_unsized: invalid coercion {} -> {}", + source.ty.repr(bcx.tcx()), + target.ty.repr(bcx.tcx()))) } + bcx } /// Translates an expression in "lvalue" mode -- meaning that it returns a reference to the memory @@ -1174,7 +1249,7 @@ fn trans_def_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, pub fn trans_def_fn_unadjusted<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ref_expr: &ast::Expr, def: def::Def, - param_substs: &'tcx subst::Substs<'tcx>) + param_substs: &'tcx Substs<'tcx>) -> Datum<'tcx, Rvalue> { let _icx = push_ctxt("trans_def_datum_unadjusted"); diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index f15219a6ae8c5..71be85211434d 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -240,74 +240,39 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // or &mut [T, ..n] -> &mut [T] // or &Concrete -> &Trait, etc. fn coerce_unsized(&self, - a: Ty<'tcx>, - b: Ty<'tcx>) + source: Ty<'tcx>, + target: Ty<'tcx>) -> CoerceResult<'tcx> { - debug!("coerce_unsized(a={}, b={})", - a.repr(self.tcx()), - b.repr(self.tcx())); + debug!("coerce_unsized(source={}, target={})", + source.repr(self.tcx()), + target.repr(self.tcx())); + + let traits = (self.tcx().lang_items.unsize_trait(), + self.tcx().lang_items.coerce_unsized_trait()); + let (unsize_did, coerce_unsized_did) = if let (Some(u), Some(cu)) = traits { + (u, cu) + } else { + return Err(ty::terr_mismatch); + }; // Note, we want to avoid unnecessary unsizing. We don't want to coerce to // a DST unless we have to. This currently comes out in the wash since // we can't unify [T] with U. But to properly support DST, we need to allow - // that, at which point we will need extra checks on b here. + // that, at which point we will need extra checks on the target here. - let (reborrow, target) = match (&a.sty, &b.sty) { + // Handle reborrows before selecting `Source: CoerceUnsized`. + let (source, reborrow) = match (&source.sty, &target.sty) { (&ty::ty_rptr(_, mt_a), &ty::ty_rptr(_, mt_b)) => { - if self.can_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)), mt_b.ty) - } else { - return Err(ty::terr_mismatch); - } - } - (&ty::ty_rptr(_, mt_a), &ty::ty_ptr(mt_b)) => { - if self.can_unsize_ty(mt_a.ty, mt_b.ty) { - try!(coerce_mutbls(mt_a.mutbl, mt_b.mutbl)); - (Some(ty::AutoUnsafe(mt_b.mutbl)), mt_b.ty) - } else { - return Err(ty::terr_mismatch); - } - } - (&ty::ty_uniq(t_a), &ty::ty_uniq(t_b)) => { - if self.can_unsize_ty(t_a, t_b) { - (None, b) - } else { - return 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))) - } + try!(coerce_mutbls(mt_a.mutbl, mt_b.mutbl)); - /// Returns true if the source type can be unsized to the target type. - /// E.g., `[T; n]` -> `[T]`. - fn can_unsize_ty(&self, - source: Ty<'tcx>, - target: Ty<'tcx>) - -> bool { - debug!("can_unsize_ty(source={}, target={})", - source.repr(self.tcx()), target.repr(self.tcx())); - - let unsize_def_id = if let Some(def_id) = self.tcx().lang_items.unsize_trait() { - def_id - } else { - return false; + let coercion = Coercion(self.trace.clone()); + let r_borrow = self.fcx.infcx().next_region_var(coercion); + let region = self.tcx().mk_region(r_borrow); + (mt_a.ty, Some(ty::AutoPtr(region, mt_b.mutbl))) + } + _ => (source, None) }; + let source = ty::adjust_ty_for_autoref(self.tcx(), source, reborrow); let mut selcx = traits::SelectionContext::new(self.fcx.infcx(), self.fcx); @@ -315,17 +280,18 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { let mut queue = VecDeque::new(); let mut leftover_predicates = vec![]; - // Create an obligation for `Source: Unsize`. + // Create an obligation for `Source: CoerceUnsized`. let cause = ObligationCause::misc(self.trace.span(), self.fcx.body_id); - queue.push_back(predicate_for_trait_def(self.tcx(), cause, unsize_def_id, + queue.push_back(predicate_for_trait_def(self.tcx(), cause, coerce_unsized_did, 0, source, vec![target])); - // Keep resolving `Unsize` predicates to avoid emitting a coercion - // in cases like `Foo<$1>` -> `Foo<$2>`, where inference might unify - // those two inner type variables later. + // Keep resolving `CoerceUnsized` and `Unsize` predicates to avoid + // emitting a coercion in cases like `Foo<$1>` -> `Foo<$2>`, where + // inference might unify those two inner type variables later. + let traits = [coerce_unsized_did, unsize_did]; while let Some(obligation) = queue.pop_front() { let trait_ref = match obligation.predicate { - ty::Predicate::Trait(ref tr) if tr.def_id() == unsize_def_id => { + ty::Predicate::Trait(ref tr) if traits.contains(&tr.def_id()) => { tr.clone() } _ => { @@ -336,7 +302,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { match selcx.select(&obligation.with(trait_ref)) { // Uncertain or unimplemented. Ok(None) | Err(traits::Unimplemented) => { - return false; + return Err(ty::terr_mismatch); } // Object safety violations or miscellaneous. @@ -356,7 +322,14 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { let mut obligations = self.unsizing_obligations.borrow_mut(); assert!(obligations.is_empty()); *obligations = leftover_predicates; - true + + 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))) } fn coerce_from_fn_pointer(&self, diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index ffd99ff2eece0..6458667378b60 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -18,7 +18,9 @@ use metadata::csearch::{each_impl, get_impl_trait}; use metadata::csearch; +use middle::lang_items::UnsizeTraitLangItem; use middle::subst::{self, Subst}; +use middle::traits; use middle::ty::RegionEscape; use middle::ty::{ImplContainer, ImplOrTraitItemId, MethodTraitItemId}; use middle::ty::{ParameterEnvironment, TypeTraitItemId, lookup_item_type}; @@ -31,8 +33,7 @@ use middle::ty::{ty_projection}; use middle::ty; use CrateCtxt; use middle::infer::combine::Combine; -use middle::infer::InferCtxt; -use middle::infer::{new_infer_ctxt}; +use middle::infer::{self, InferCtxt, new_infer_ctxt}; use std::collections::{HashSet}; use std::cell::RefCell; use std::rc::Rc; @@ -142,6 +143,10 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { // Check to make sure implementations of `Copy` are legal. self.check_implementations_of_copy(); + + // Check to make sure implementations of `CoerceUnsized` are legal + // and collect the necessary information from them. + self.check_implementations_of_coerce_unsized(); } fn check_implementation(&self, item: &Item, opt_trait: Option<&TraitRef>) { @@ -505,6 +510,169 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { } } } + + /// Process implementations of the built-in trait `CoerceUnsized`. + fn check_implementations_of_coerce_unsized(&self) { + let tcx = self.crate_context.tcx; + let coerce_unsized_trait = match tcx.lang_items.coerce_unsized_trait() { + Some(id) => id, + None => return, + }; + let unsize_trait = match tcx.lang_items.require(UnsizeTraitLangItem) { + Ok(id) => id, + Err(err) => { + tcx.sess.fatal(&format!("`CoerceUnsized` implementation {}", err)); + } + }; + + let trait_impls = match tcx.trait_impls + .borrow() + .get(&coerce_unsized_trait) + .cloned() { + None => { + debug!("check_implementations_of_coerce_unsized(): no types \ + with implementations of `CoerceUnsized` found"); + return + } + Some(found_impls) => found_impls + }; + + // Clone first to avoid a double borrow error. + let trait_impls = trait_impls.borrow().clone(); + + for &impl_did in &trait_impls { + debug!("check_implementations_of_coerce_unsized: impl_did={}", + impl_did.repr(tcx)); + + if impl_did.krate != ast::LOCAL_CRATE { + debug!("check_implementations_of_coerce_unsized(): impl not \ + in this crate"); + continue + } + + let source = self.get_self_type_for_implementation(impl_did).ty; + let trait_ref = ty::impl_id_to_trait_ref(self.crate_context.tcx, + impl_did.node); + let target = *trait_ref.substs.types.get(subst::TypeSpace, 0); + debug!("check_implementations_of_coerce_unsized: {} -> {} (bound)", + source.repr(tcx), target.repr(tcx)); + + let span = tcx.map.span(impl_did.node); + let param_env = ParameterEnvironment::for_item(tcx, impl_did.node); + let source = source.subst(tcx, ¶m_env.free_substs); + let target = target.subst(tcx, ¶m_env.free_substs); + assert!(!source.has_escaping_regions()); + + debug!("check_implementations_of_coerce_unsized: {} -> {} (free)", + source.repr(tcx), target.repr(tcx)); + + let infcx = new_infer_ctxt(tcx); + + let check_mutbl = |mt_a: ty::mt<'tcx>, mt_b: ty::mt<'tcx>, + mk_ptr: &Fn(Ty<'tcx>) -> Ty<'tcx>| { + if (mt_a.mutbl, mt_b.mutbl) == (ast::MutImmutable, ast::MutMutable) { + infcx.report_mismatched_types(span, mk_ptr(mt_b.ty), + target, &ty::terr_mutability); + } + (mt_a.ty, mt_b.ty, unsize_trait, None) + }; + let (source, target, trait_def_id, kind) = match (&source.sty, &target.sty) { + (&ty::ty_uniq(a), &ty::ty_uniq(b)) => (a, b, unsize_trait, None), + + (&ty::ty_rptr(r_a, mt_a), &ty::ty_rptr(r_b, mt_b)) => { + infer::mk_subr(&infcx, infer::RelateObjectBound(span), *r_b, *r_a); + check_mutbl(mt_a, mt_b, &|ty| ty::mk_imm_rptr(tcx, r_b, ty)) + } + + (&ty::ty_rptr(_, mt_a), &ty::ty_ptr(mt_b)) | + (&ty::ty_ptr(mt_a), &ty::ty_ptr(mt_b)) => { + check_mutbl(mt_a, mt_b, &|ty| ty::mk_imm_ptr(tcx, ty)) + } + + (&ty::ty_struct(def_id_a, substs_a), &ty::ty_struct(def_id_b, substs_b)) => { + if def_id_a != def_id_b { + let source_path = ty::item_path_str(tcx, def_id_a); + let target_path = ty::item_path_str(tcx, def_id_b); + span_err!(tcx.sess, span, E0370, + "the trait `CoerceUnsized` may only be implemented \ + for a coercion between structures with the same \ + definition; expected {}, found {}", + source_path, target_path); + continue; + } + + let origin = infer::Misc(span); + let fields = ty::lookup_struct_fields(tcx, def_id_a); + let diff_fields = fields.iter().enumerate().filter_map(|(i, f)| { + let ty = ty::lookup_field_type_unsubstituted(tcx, def_id_a, f.id); + let (a, b) = (ty.subst(tcx, substs_a), ty.subst(tcx, substs_b)); + if infcx.try(|_| infcx.sub_types(false, origin, b, a)).is_ok() { + None + } else { + Some((i, a, b)) + } + }).collect::>(); + + if diff_fields.is_empty() { + span_err!(tcx.sess, span, E0371, + "the trait `CoerceUnsized` may only be implemented \ + for a coercion between structures with one field \ + being coerced, none found"); + continue; + } else if diff_fields.len() > 1 { + span_err!(tcx.sess, span, E0372, + "the trait `CoerceUnsized` may only be implemented \ + for a coercion between structures with one field \ + being coerced, but {} fields need coercions: {}", + diff_fields.len(), diff_fields.iter().map(|&(i, a, b)| { + let name = fields[i].name; + format!("{} ({} to {})", + if name == token::special_names::unnamed_field { + i.to_string() + } else { + token::get_name(name).to_string() + }, + a.repr(tcx), + b.repr(tcx)) + }).collect::>().connect(", ")); + continue; + } + + let (i, a, b) = diff_fields[0]; + let kind = ty::CustomCoerceUnsized::Struct(i); + (a, b, coerce_unsized_trait, Some(kind)) + } + + _ => { + span_err!(tcx.sess, span, E0373, + "the trait `CoerceUnsized` may only be implemented \ + for a coercion between structures"); + continue; + } + }; + + let mut fulfill_cx = traits::FulfillmentContext::new(); + + // Register an obligation for `A: Trait`. + let cause = traits::ObligationCause::misc(span, impl_did.node); + let predicate = traits::predicate_for_trait_def(tcx, cause, trait_def_id, + 0, source, vec![target]); + fulfill_cx.register_predicate_obligation(&infcx, predicate); + + // Check that all transitive obligations are satisfied. + if let Err(errors) = fulfill_cx.select_all_or_error(&infcx, ¶m_env) { + traits::report_fulfillment_errors(&infcx, &errors); + } + + // Finally, resolve all regions. This catches wily misuses of lifetime + // parameters. + infcx.resolve_regions_and_report_errors(impl_did.node); + + if let Some(kind) = kind { + tcx.custom_coerce_unsized_kinds.borrow_mut().insert(impl_did, kind); + } + } + } } fn enforce_trait_manually_implementable(tcx: &ty::ctxt, sp: Span, trait_def_id: ast::DefId) { diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 3cf5d450b1a61..32c7e319b5822 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -179,7 +179,16 @@ register_diagnostics! { E0322, // cannot implement Sized explicitly E0323, // cannot implement Unsize explicitly E0366, // dropck forbid specialization to concrete type or region - E0367 // dropck forbid specialization to predicate not in struct/enum + E0367, // dropck forbid specialization to predicate not in struct/enum + E0370, // the trait `CoerceUnsized` may only be implemented for a coercion + // between structures with the same definition + E0371, // the trait `CoerceUnsized` may only be implemented for a coercion + // between structures with one field being coerced, none found + E0372, // the trait `CoerceUnsized` may only be implemented for a coercion + // between structures with one field being coerced, but multiple + // fields need coercions + E0373 // the trait `CoerceUnsized` may only be implemented for a coercion + // between structures } __build_diagnostic_array! { DIAGNOSTICS } diff --git a/src/test/compile-fail/dst-bad-coercions.rs b/src/test/compile-fail/dst-bad-coercions.rs index 8ec1034bc4d28..c0ddc15fb70c1 100644 --- a/src/test/compile-fail/dst-bad-coercions.rs +++ b/src/test/compile-fail/dst-bad-coercions.rs @@ -35,18 +35,4 @@ pub fn main() { let x: &mut T = &S; //~ ERROR mismatched types let x: *mut T = &S; //~ ERROR mismatched types let x: *mut S = &S; //~ ERROR mismatched types - - // The below four sets of tests test that we cannot implicitly deref a *-ptr - // during a coercion. - let x: *const S = &S; - let y: *const T = x; //~ ERROR mismatched types - - let x: *mut S = &mut S; - let y: *mut T = x; //~ ERROR mismatched types - - let x: *const Foo = &Foo {f: S}; - let y: *const Foo = x; //~ ERROR mismatched types - - let x: *mut Foo = &mut Foo {f: S}; - let y: *mut Foo = x; //~ ERROR mismatched types } From 89d4f5c7ceba91931dc2d3bb88177a156c067239 Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Fri, 27 Mar 2015 18:24:25 +0200 Subject: [PATCH 11/12] Implement {size,min_align}_of_val and drop_in_place intrinsics. --- src/libcore/intrinsics.rs | 9 ++++++- src/libcore/mem.rs | 34 +++++++++++++++++++++++++++ src/librustc_trans/trans/glue.rs | 4 ++-- src/librustc_trans/trans/intrinsic.rs | 26 ++++++++++++++++++++ src/librustc_typeck/check/mod.rs | 11 +++++++++ 5 files changed, 81 insertions(+), 3 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 1f1044b0b2152..89c0b5473c63e 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -182,8 +182,15 @@ extern "rust-intrinsic" { pub fn min_align_of() -> usize; pub fn pref_align_of() -> usize; + #[cfg(not(stage0))] // SNAP c64d671 + pub fn size_of_val(_: &T) -> usize; + #[cfg(not(stage0))] // SNAP c64d671 + pub fn min_align_of_val(_: &T) -> usize; + #[cfg(not(stage0))] // SNAP c64d671 + pub fn drop_in_place(_: *mut T); + /// Gets a static string slice containing the name of a type. - #[cfg(not(stage0))] + #[cfg(not(stage0))] // SNAP c64d671 pub fn type_name() -> &'static str; /// Gets an identifier which is globally unique to the specified type. This diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 1e6fb51a8a528..03636bbb1ec64 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -47,6 +47,22 @@ pub fn size_of() -> usize { unsafe { intrinsics::size_of::() } } +/// Returns the size of the type that `val` points to in bytes. +/// +/// # Examples +/// +/// ``` +/// use std::mem; +/// +/// assert_eq!(4, mem::size_of_val(&5i32)); +/// ``` +#[cfg(not(stage0))] // SNAP c64d671 +#[inline] +#[stable(feature = "rust1", since = "1.0.0")] +pub fn size_of_val(val: &T) -> usize { + unsafe { intrinsics::size_of_val(val) } +} + /// Returns the size of the type that `_val` points to in bytes. /// /// # Examples @@ -56,6 +72,7 @@ pub fn size_of() -> usize { /// /// assert_eq!(4, mem::size_of_val(&5i32)); /// ``` +#[cfg(stage0)] // SNAP c64d671 #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn size_of_val(_val: &T) -> usize { @@ -79,6 +96,22 @@ pub fn min_align_of() -> usize { unsafe { intrinsics::min_align_of::() } } +/// Returns the ABI-required minimum alignment of the type of the value that `val` points to +/// +/// # Examples +/// +/// ``` +/// use std::mem; +/// +/// assert_eq!(4, mem::min_align_of_val(&5i32)); +/// ``` +#[cfg(not(stage0))] // SNAP c64d671 +#[inline] +#[stable(feature = "rust1", since = "1.0.0")] +pub fn min_align_of_val(val: &T) -> usize { + unsafe { intrinsics::min_align_of_val(val) } +} + /// Returns the ABI-required minimum alignment of the type of the value that `_val` points to /// /// # Examples @@ -88,6 +121,7 @@ pub fn min_align_of() -> usize { /// /// assert_eq!(4, mem::min_align_of_val(&5i32)); /// ``` +#[cfg(stage0)] // SNAP c64d671 #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn min_align_of_val(_val: &T) -> usize { diff --git a/src/librustc_trans/trans/glue.rs b/src/librustc_trans/trans/glue.rs index b2de8435f641b..c1557a6f27ba6 100644 --- a/src/librustc_trans/trans/glue.rs +++ b/src/librustc_trans/trans/glue.rs @@ -328,8 +328,8 @@ fn trans_struct_drop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, }) } -fn size_and_align_of_dst<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, t: Ty<'tcx>, info: ValueRef) - -> (ValueRef, ValueRef) { +pub fn size_and_align_of_dst<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, t: Ty<'tcx>, info: ValueRef) + -> (ValueRef, ValueRef) { debug!("calculate size of DST: {}; with lost info: {}", bcx.ty_to_string(t), bcx.val_to_string(info)); if type_is_sized(bcx.tcx(), t) { diff --git a/src/librustc_trans/trans/intrinsic.rs b/src/librustc_trans/trans/intrinsic.rs index f714c5800c57b..90d37721d5115 100644 --- a/src/librustc_trans/trans/intrinsic.rs +++ b/src/librustc_trans/trans/intrinsic.rs @@ -322,10 +322,31 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, let lltp_ty = type_of::type_of(ccx, tp_ty); C_uint(ccx, machine::llsize_of_alloc(ccx, lltp_ty)) } + (_, "size_of_val") => { + let tp_ty = *substs.types.get(FnSpace, 0); + if !type_is_sized(tcx, tp_ty) { + let info = Load(bcx, expr::get_len(bcx, llargs[0])); + let (llsize, _) = glue::size_and_align_of_dst(bcx, tp_ty, info); + llsize + } else { + let lltp_ty = type_of::type_of(ccx, tp_ty); + C_uint(ccx, machine::llsize_of_alloc(ccx, lltp_ty)) + } + } (_, "min_align_of") => { let tp_ty = *substs.types.get(FnSpace, 0); C_uint(ccx, type_of::align_of(ccx, tp_ty)) } + (_, "min_align_of_val") => { + let tp_ty = *substs.types.get(FnSpace, 0); + if !type_is_sized(tcx, tp_ty) { + let info = Load(bcx, expr::get_len(bcx, llargs[0])); + let (_, llalign) = glue::size_and_align_of_dst(bcx, tp_ty, info); + llalign + } else { + C_uint(ccx, type_of::align_of(ccx, tp_ty)) + } + } (_, "pref_align_of") => { let tp_ty = *substs.types.get(FnSpace, 0); let lltp_ty = type_of::type_of(ccx, tp_ty); @@ -347,6 +368,11 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, bcx = src.store_to(bcx, llargs[0]); C_nil(ccx) } + (_, "drop_in_place") => { + let tp_ty = *substs.types.get(FnSpace, 0); + glue::drop_ty(bcx, llargs[0], tp_ty, call_debug_location); + C_nil(ccx) + } (_, "type_name") => { let tp_ty = *substs.types.get(FnSpace, 0); let ty_name = token::intern_and_get_ident(&ty_to_string(ccx.tcx(), tp_ty)); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 978a52bc3036f..770609788d464 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -5317,6 +5317,14 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) { "breakpoint" => (0, Vec::new(), ty::mk_nil(tcx)), "size_of" | "pref_align_of" | "min_align_of" => (1, Vec::new(), ccx.tcx.types.uint), + "size_of_val" | "min_align_of_val" => { + (1, vec![ + ty::mk_imm_rptr(tcx, + tcx.mk_region(ty::ReLateBound(ty::DebruijnIndex::new(1), + ty::BrAnon(0))), + param(ccx, 0)) + ], ccx.tcx.types.uint) + } "init" => (1, Vec::new(), param(ccx, 0)), "uninit" => (1, Vec::new(), param(ccx, 0)), "forget" => (1, vec!( param(ccx, 0) ), ty::mk_nil(tcx)), @@ -5332,6 +5340,9 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) { ), ty::mk_nil(tcx)) } + "drop_in_place" => { + (1, vec![ty::mk_mut_ptr(tcx, param(ccx, 0))], ty::mk_nil(tcx)) + } "needs_drop" => (1, Vec::new(), ccx.tcx.types.bool), "owns_managed" => (1, Vec::new(), ccx.tcx.types.bool), From 18a4eddee1510eb9708f2646dd78767defddc034 Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Fri, 27 Mar 2015 18:24:55 +0200 Subject: [PATCH 12/12] Add DST support to Rc. --- src/liballoc/rc.rs | 169 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 142 insertions(+), 27 deletions(-) diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index eb3c5c167268b..936596fd17f77 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -159,7 +159,7 @@ use core::cmp::{PartialEq, PartialOrd, Eq, Ord, Ordering}; use core::default::Default; use core::fmt; use core::hash::{Hasher, Hash}; -use core::marker; +use core::marker::{self, Sized}; use core::mem::{min_align_of, size_of, forget}; use core::nonzero::NonZero; use core::ops::{Deref, Drop}; @@ -170,12 +170,21 @@ use core::result::Result; use core::result::Result::{Ok, Err}; use core::intrinsics::assume; +#[cfg(not(stage0))] // SNAP c64d671 +use core::intrinsics::drop_in_place; +#[cfg(not(stage0))] // SNAP c64d671 +use core::marker::Unsize; +#[cfg(not(stage0))] // SNAP c64d671 +use core::mem::{min_align_of_val, size_of_val}; +#[cfg(not(stage0))] // SNAP c64d671 +use core::ops::CoerceUnsized; + use heap::deallocate; -struct RcBox { - value: T, +struct RcBox { strong: Cell, - weak: Cell + weak: Cell, + value: T } /// A reference-counted pointer type over an immutable value. @@ -183,15 +192,18 @@ struct RcBox { /// See the [module level documentation](./index.html) for more details. #[unsafe_no_drop_flag] #[stable(feature = "rust1", since = "1.0.0")] -pub struct Rc { +pub struct Rc { // FIXME #12808: strange names to try to avoid interfering with field // accesses of the contained type via Deref _ptr: NonZero<*mut RcBox>, } -impl !marker::Send for Rc {} +impl !marker::Send for Rc {} + +impl !marker::Sync for Rc {} -impl !marker::Sync for Rc {} +#[cfg(not(stage0))] // SNAP c64d671 +impl, U: ?Sized> CoerceUnsized> for Rc {} impl Rc { /// Constructs a new `Rc`. @@ -212,14 +224,16 @@ impl Rc { // the allocation while the strong destructor is running, even // if the weak pointer is stored inside the strong one. _ptr: NonZero::new(boxed::into_raw(box RcBox { - value: value, strong: Cell::new(1), - weak: Cell::new(1) + weak: Cell::new(1), + value: value })), } } } +} +impl Rc { /// Downgrades the `Rc` to a `Weak` reference. /// /// # Examples @@ -243,12 +257,12 @@ impl Rc { /// Get the number of weak references to this value. #[inline] #[unstable(feature = "alloc")] -pub fn weak_count(this: &Rc) -> usize { this.weak() - 1 } +pub fn weak_count(this: &Rc) -> usize { this.weak() - 1 } /// Get the number of strong references to this value. #[inline] #[unstable(feature = "alloc")] -pub fn strong_count(this: &Rc) -> usize { this.strong() } +pub fn strong_count(this: &Rc) -> usize { this.strong() } /// Returns true if there are no other `Rc` or `Weak` values that share the /// same inner value. @@ -366,7 +380,7 @@ impl Rc { } #[stable(feature = "rust1", since = "1.0.0")] -impl Deref for Rc { +impl Deref for Rc { type Target = T; #[inline(always)] @@ -375,6 +389,7 @@ impl Deref for Rc { } } +#[cfg(stage0)] // SNAP c64d671 #[unsafe_destructor] #[stable(feature = "rust1", since = "1.0.0")] impl Drop for Rc { @@ -426,8 +441,61 @@ impl Drop for Rc { } } +#[cfg(not(stage0))] // SNAP c64d671 +#[unsafe_destructor] +#[stable(feature = "rust1", since = "1.0.0")] +impl Drop for Rc { + /// Drops the `Rc`. + /// + /// This will decrement the strong reference count. If the strong reference + /// count becomes zero and the only other references are `Weak` ones, + /// `drop`s the inner value. + /// + /// # Examples + /// + /// ``` + /// # #![feature(alloc)] + /// use std::rc::Rc; + /// + /// { + /// let five = Rc::new(5); + /// + /// // stuff + /// + /// drop(five); // explicit drop + /// } + /// { + /// let five = Rc::new(5); + /// + /// // stuff + /// + /// } // implicit drop + /// ``` + fn drop(&mut self) { + unsafe { + let ptr = *self._ptr; + if !(*(&ptr as *const _ as *const *const ())).is_null() { + self.dec_strong(); + if self.strong() == 0 { + // destroy the contained object + drop_in_place(&mut (*ptr).value); + + // remove the implicit "strong weak" pointer now that we've + // destroyed the contents. + self.dec_weak(); + + if self.weak() == 0 { + deallocate(ptr as *mut u8, size_of_val(&*ptr), + min_align_of_val(&*ptr)) + } + } + } + } + } +} + #[stable(feature = "rust1", since = "1.0.0")] -impl Clone for Rc { +impl Clone for Rc { /// Makes a clone of the `Rc`. /// @@ -613,21 +681,21 @@ impl Ord for Rc { // FIXME (#18248) Make `T` `Sized?` #[stable(feature = "rust1", since = "1.0.0")] -impl Hash for Rc { +impl Hash for Rc { fn hash(&self, state: &mut H) { (**self).hash(state); } } #[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Display for Rc { +impl fmt::Display for Rc { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&**self, f) } } #[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for Rc { +impl fmt::Debug for Rc { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(&**self, f) } @@ -642,20 +710,20 @@ impl fmt::Debug for Rc { #[unsafe_no_drop_flag] #[unstable(feature = "alloc", reason = "Weak pointers may not belong in this module.")] -pub struct Weak { +pub struct Weak { // FIXME #12808: strange names to try to avoid interfering with // field accesses of the contained type via Deref _ptr: NonZero<*mut RcBox>, } -impl !marker::Send for Weak {} +impl !marker::Send for Weak {} -impl !marker::Sync for Weak {} +impl !marker::Sync for Weak {} #[unstable(feature = "alloc", reason = "Weak pointers may not belong in this module.")] -impl Weak { +impl Weak { /// Upgrades a weak reference to a strong reference. /// @@ -686,6 +754,7 @@ impl Weak { } } +#[cfg(stage0)] // SNAP c64d671 #[unsafe_destructor] #[stable(feature = "rust1", since = "1.0.0")] impl Drop for Weak { @@ -731,9 +800,55 @@ impl Drop for Weak { } } +#[cfg(not(stage0))] // SNAP c64d671 +#[unsafe_destructor] +#[stable(feature = "rust1", since = "1.0.0")] +impl Drop for Weak { + /// Drops the `Weak`. + /// + /// This will decrement the weak reference count. + /// + /// # Examples + /// + /// ``` + /// # #![feature(alloc)] + /// use std::rc::Rc; + /// + /// { + /// let five = Rc::new(5); + /// let weak_five = five.downgrade(); + /// + /// // stuff + /// + /// drop(weak_five); // explicit drop + /// } + /// { + /// let five = Rc::new(5); + /// let weak_five = five.downgrade(); + /// + /// // stuff + /// + /// } // implicit drop + /// ``` + fn drop(&mut self) { + unsafe { + let ptr = *self._ptr; + if !(*(&ptr as *const _ as *const *const ())).is_null() { + self.dec_weak(); + // the weak count starts at 1, and will only go to zero if all + // the strong pointers have disappeared. + if self.weak() == 0 { + deallocate(ptr as *mut u8, size_of_val(&*ptr), + min_align_of_val(&*ptr)) + } + } + } + } +} + #[unstable(feature = "alloc", reason = "Weak pointers may not belong in this module.")] -impl Clone for Weak { +impl Clone for Weak { /// Makes a clone of the `Weak`. /// @@ -757,14 +872,14 @@ impl Clone for Weak { } #[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for Weak { +impl fmt::Debug for Weak { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "(Weak)") } } #[doc(hidden)] -trait RcBoxPtr { +trait RcBoxPtr { fn inner(&self) -> &RcBox; #[inline] @@ -786,7 +901,7 @@ trait RcBoxPtr { fn dec_weak(&self) { self.inner().weak.set(self.weak() - 1); } } -impl RcBoxPtr for Rc { +impl RcBoxPtr for Rc { #[inline(always)] fn inner(&self) -> &RcBox { unsafe { @@ -794,13 +909,13 @@ impl RcBoxPtr for Rc { // the contract anyway. // This allows the null check to be elided in the destructor if we // manipulated the reference count in the same function. - assume(!self._ptr.is_null()); + assume(!(*(&self._ptr as *const _ as *const *const ())).is_null()); &(**self._ptr) } } } -impl RcBoxPtr for Weak { +impl RcBoxPtr for Weak { #[inline(always)] fn inner(&self) -> &RcBox { unsafe { @@ -808,7 +923,7 @@ impl RcBoxPtr for Weak { // the contract anyway. // This allows the null check to be elided in the destructor if we // manipulated the reference count in the same function. - assume(!self._ptr.is_null()); + assume(!(*(&self._ptr as *const _ as *const *const ())).is_null()); &(**self._ptr) } }