From c6651ffd8ef6717d89e48c4ad2bdd04f9d386791 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Tue, 16 May 2017 12:03:09 +0300 Subject: [PATCH 01/14] rustc: remove Copy from Adjustment and Adjust. --- src/librustc/ty/adjustment.rs | 4 ++-- src/librustc_passes/consts.rs | 14 +++++++------- src/librustc_typeck/check/coercion.rs | 11 ++++++----- src/librustc_typeck/check/mod.rs | 8 ++++---- 4 files changed, 19 insertions(+), 18 deletions(-) diff --git a/src/librustc/ty/adjustment.rs b/src/librustc/ty/adjustment.rs index 385591e10f744..9aa700e2b4487 100644 --- a/src/librustc/ty/adjustment.rs +++ b/src/librustc/ty/adjustment.rs @@ -16,13 +16,13 @@ use syntax_pos::Span; use hir; -#[derive(Copy, Clone, RustcEncodable, RustcDecodable)] +#[derive(Clone, RustcEncodable, RustcDecodable)] pub struct Adjustment<'tcx> { pub kind: Adjust<'tcx>, pub target: Ty<'tcx> } -#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)] +#[derive(Clone, Debug, RustcEncodable, RustcDecodable)] pub enum Adjust<'tcx> { /// Go from ! to any type. NeverToAny, diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index 698850f0e9e7f..8f087ac212e8a 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -442,15 +442,15 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node fn check_adjustments<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr) { use rustc::ty::adjustment::*; - match v.tables.adjustments.get(&e.id).map(|adj| adj.kind) { + match v.tables.adjustments.get(&e.id).map(|adj| &adj.kind) { None | - Some(Adjust::NeverToAny) | - Some(Adjust::ReifyFnPointer) | - Some(Adjust::UnsafeFnPointer) | - Some(Adjust::ClosureFnPointer) | - Some(Adjust::MutToConstPointer) => {} + Some(&Adjust::NeverToAny) | + Some(&Adjust::ReifyFnPointer) | + Some(&Adjust::UnsafeFnPointer) | + Some(&Adjust::ClosureFnPointer) | + Some(&Adjust::MutToConstPointer) => {} - Some(Adjust::DerefRef { autoderefs, .. }) => { + Some(&Adjust::DerefRef { autoderefs, .. }) => { if (0..autoderefs as u32) .any(|autoderef| v.tables.is_overloaded_autoderef(e.id, autoderef)) { v.promotable = false; diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 883a0a9d88a1c..2d8126225be5d 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -800,8 +800,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { match result { Ok(ok) => { let adjustment = self.register_infer_ok_obligations(ok); + let target = adjustment.target; self.apply_adjustment(new.id, adjustment); - return Ok(adjustment.target); + return Ok(target); } Err(e) => first_error = Some(e), } @@ -812,8 +813,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // previous expressions, other than noop reborrows (ignoring lifetimes). for expr in exprs { let expr = expr.as_coercion_site(); - let noop = match self.tables.borrow().adjustments.get(&expr.id).map(|adj| adj.kind) { - Some(Adjust::DerefRef { + let noop = match self.tables.borrow().adjustments.get(&expr.id).map(|adj| &adj.kind) { + Some(&Adjust::DerefRef { autoderefs: 1, autoref: Some(AutoBorrow::Ref(_, mutbl_adj)), unsize: false @@ -828,7 +829,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { _ => false, } } - Some(Adjust::NeverToAny) => true, + Some(&Adjust::NeverToAny) => true, Some(_) => false, None => true, }; @@ -857,7 +858,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let adjustment = self.register_infer_ok_obligations(ok); for expr in exprs { let expr = expr.as_coercion_site(); - self.apply_adjustment(expr.id, adjustment); + self.apply_adjustment(expr.id, adjustment.clone()); } Ok(adjustment.target) } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 3a6fd51693e73..bee4a18523e1e 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1805,16 +1805,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { Entry::Vacant(entry) => { entry.insert(adj); }, Entry::Occupied(mut entry) => { debug!(" - composing on top of {:?}", entry.get()); - let composed_kind = match (entry.get().kind, adj.kind) { + let composed_kind = match (&entry.get().kind, &adj.kind) { // Applying any adjustment on top of a NeverToAny // is a valid NeverToAny adjustment, because it can't // be reached. - (Adjust::NeverToAny, _) => Adjust::NeverToAny, - (Adjust::DerefRef { + (&Adjust::NeverToAny, _) => Adjust::NeverToAny, + (&Adjust::DerefRef { autoderefs: 1, autoref: Some(AutoBorrow::Ref(..)), unsize: false - }, Adjust::DerefRef { autoderefs, .. }) if autoderefs > 0 => { + }, &Adjust::DerefRef { autoderefs, .. }) if autoderefs > 0 => { // A reborrow has no effect before a dereference. adj.kind } From 9a53c3e90470c893a1b087babb03dec039c64b79 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Tue, 16 May 2017 17:54:03 +0300 Subject: [PATCH 02/14] rustc: remove unused field of mc::Categorization::Deref. --- src/librustc/middle/mem_categorization.rs | 55 +++++++++---------- .../borrowck/gather_loans/gather_moves.rs | 8 +-- .../borrowck/gather_loans/lifetime.rs | 20 +++---- .../borrowck/gather_loans/move_error.rs | 6 +- .../borrowck/gather_loans/restrictions.rs | 2 +- src/librustc_borrowck/borrowck/mod.rs | 2 +- src/librustc_passes/consts.rs | 2 +- src/librustc_typeck/check/regionck.rs | 10 ++-- src/librustc_typeck/check/upvar.rs | 20 +++---- 9 files changed, 61 insertions(+), 64 deletions(-) diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index d0adf51d79e68..13647d420c36a 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -94,7 +94,7 @@ pub enum Categorization<'tcx> { StaticItem, Upvar(Upvar), // upvar referenced by closure env Local(ast::NodeId), // local variable - Deref(cmt<'tcx>, usize, PointerKind<'tcx>), // deref of a ptr + Deref(cmt<'tcx>, PointerKind<'tcx>), // deref of a ptr Interior(cmt<'tcx>, InteriorKind), // something interior: field, tuple, etc Downcast(cmt<'tcx>, DefId), // selects a particular enum variant (*1) @@ -229,8 +229,8 @@ impl<'tcx> cmt_<'tcx> { pub fn immutability_blame(&self) -> Option> { match self.cat { - Categorization::Deref(ref base_cmt, _, BorrowedPtr(ty::ImmBorrow, _)) | - Categorization::Deref(ref base_cmt, _, Implicit(ty::ImmBorrow, _)) => { + Categorization::Deref(ref base_cmt, BorrowedPtr(ty::ImmBorrow, _)) | + Categorization::Deref(ref base_cmt, Implicit(ty::ImmBorrow, _)) => { // try to figure out where the immutable reference came from match base_cmt.cat { Categorization::Local(node_id) => @@ -255,13 +255,13 @@ impl<'tcx> cmt_<'tcx> { } Categorization::Rvalue(..) | Categorization::Upvar(..) | - Categorization::Deref(.., UnsafePtr(..)) => { + Categorization::Deref(_, UnsafePtr(..)) => { // This should not be reachable up to inference limitations. None } Categorization::Interior(ref base_cmt, _) | Categorization::Downcast(ref base_cmt, _) | - Categorization::Deref(ref base_cmt, _, _) => { + Categorization::Deref(ref base_cmt, _) => { base_cmt.immutability_blame() } Categorization::StaticItem => { @@ -569,7 +569,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { // is an rvalue. That is what we will be // dereferencing. let base_cmt = self.cat_rvalue_node(expr.id(), expr.span(), ret_ty); - Ok(self.cat_deref_common(expr, base_cmt, 1, elem_ty, true)) + Ok(self.cat_deref_common(expr, base_cmt, elem_ty, true)) } None => { self.cat_index(expr, self.cat_expr(&base)?, InteriorOffsetKind::Index) @@ -763,7 +763,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { cmt_ { id: id, span: span, - cat: Categorization::Deref(Rc::new(cmt_result), 0, ptr), + cat: Categorization::Deref(Rc::new(cmt_result), ptr), mutbl: MutabilityCategory::from_borrow_kind(upvar_borrow.kind), ty: var_ty, note: NoteUpvarRef(upvar_id) @@ -823,7 +823,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { let ret = cmt_ { id: id, span: span, - cat: Categorization::Deref(Rc::new(cmt_result), 0, env_ptr), + cat: Categorization::Deref(Rc::new(cmt_result), env_ptr), mutbl: deref_mutbl, ty: var_ty, note: NoteClosureEnv(upvar_id) @@ -957,7 +957,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { let base_cmt_ty = base_cmt.ty; match base_cmt_ty.builtin_deref(true, ty::NoPreference) { Some(mt) => { - let ret = self.cat_deref_common(node, base_cmt, deref_cnt, mt.ty, false); + let ret = self.cat_deref_common(node, base_cmt, mt.ty, false); debug!("cat_deref ret {:?}", ret); Ok(ret) } @@ -972,7 +972,6 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { fn cat_deref_common(&self, node: &N, base_cmt: cmt<'tcx>, - deref_cnt: usize, deref_ty: Ty<'tcx>, implicit: bool) -> cmt<'tcx> @@ -991,7 +990,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { span: node.span(), // For unique ptrs, we inherit mutability from the owning reference. mutbl: MutabilityCategory::from_pointer_kind(base_cmt.mutbl, ptr), - cat: Categorization::Deref(base_cmt, deref_cnt, ptr), + cat: Categorization::Deref(base_cmt, ptr), ty: deref_ty, note: NoteNone }); @@ -1300,15 +1299,15 @@ impl<'tcx> cmt_<'tcx> { Categorization::Rvalue(..) | Categorization::StaticItem | Categorization::Local(..) | - Categorization::Deref(.., UnsafePtr(..)) | - Categorization::Deref(.., BorrowedPtr(..)) | - Categorization::Deref(.., Implicit(..)) | + Categorization::Deref(_, UnsafePtr(..)) | + Categorization::Deref(_, BorrowedPtr(..)) | + Categorization::Deref(_, Implicit(..)) | Categorization::Upvar(..) => { Rc::new((*self).clone()) } Categorization::Downcast(ref b, _) | Categorization::Interior(ref b, _) | - Categorization::Deref(ref b, _, Unique) => { + Categorization::Deref(ref b, Unique) => { b.guarantor() } } @@ -1321,11 +1320,11 @@ impl<'tcx> cmt_<'tcx> { // aliased and eventually recused. match self.cat { - Categorization::Deref(ref b, _, BorrowedPtr(ty::MutBorrow, _)) | - Categorization::Deref(ref b, _, Implicit(ty::MutBorrow, _)) | - Categorization::Deref(ref b, _, BorrowedPtr(ty::UniqueImmBorrow, _)) | - Categorization::Deref(ref b, _, Implicit(ty::UniqueImmBorrow, _)) | - Categorization::Deref(ref b, _, Unique) | + Categorization::Deref(ref b, BorrowedPtr(ty::MutBorrow, _)) | + Categorization::Deref(ref b, Implicit(ty::MutBorrow, _)) | + Categorization::Deref(ref b, BorrowedPtr(ty::UniqueImmBorrow, _)) | + Categorization::Deref(ref b, Implicit(ty::UniqueImmBorrow, _)) | + Categorization::Deref(ref b, Unique) | Categorization::Downcast(ref b, _) | Categorization::Interior(ref b, _) => { // Aliasability depends on base cmt @@ -1335,7 +1334,7 @@ impl<'tcx> cmt_<'tcx> { Categorization::Rvalue(..) | Categorization::Local(..) | Categorization::Upvar(..) | - Categorization::Deref(.., UnsafePtr(..)) => { // yes, it's aliasable, but... + Categorization::Deref(_, UnsafePtr(..)) => { // yes, it's aliasable, but... NonAliasable } @@ -1347,8 +1346,8 @@ impl<'tcx> cmt_<'tcx> { } } - Categorization::Deref(_, _, BorrowedPtr(ty::ImmBorrow, _)) | - Categorization::Deref(_, _, Implicit(ty::ImmBorrow, _)) => { + Categorization::Deref(_, BorrowedPtr(ty::ImmBorrow, _)) | + Categorization::Deref(_, Implicit(ty::ImmBorrow, _)) => { FreelyAliasable(AliasableBorrowed) } } @@ -1360,9 +1359,9 @@ impl<'tcx> cmt_<'tcx> { match self.note { NoteClosureEnv(..) | NoteUpvarRef(..) => { Some(match self.cat { - Categorization::Deref(ref inner, ..) => { + Categorization::Deref(ref inner, _) => { match inner.cat { - Categorization::Deref(ref inner, ..) => inner.clone(), + Categorization::Deref(ref inner, _) => inner.clone(), Categorization::Upvar(..) => inner.clone(), _ => bug!() } @@ -1390,7 +1389,7 @@ impl<'tcx> cmt_<'tcx> { "local variable".to_string() } } - Categorization::Deref(.., pk) => { + Categorization::Deref(_, pk) => { let upvar = self.upvar(); match upvar.as_ref().map(|i| &i.cat) { Some(&Categorization::Upvar(ref var)) => { @@ -1467,8 +1466,8 @@ impl<'tcx> fmt::Debug for Categorization<'tcx> { Categorization::Upvar(upvar) => { write!(f, "upvar({:?})", upvar) } - Categorization::Deref(ref cmt, derefs, ptr) => { - write!(f, "{:?}-{:?}{}->", cmt.cat, ptr, derefs) + Categorization::Deref(ref cmt, ptr) => { + write!(f, "{:?}-{:?}->", cmt.cat, ptr) } Categorization::Interior(ref cmt, interior) => { write!(f, "{:?}.{:?}", cmt.cat, interior) diff --git a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs index f193588dd7d6c..baa18307510e6 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs @@ -222,9 +222,9 @@ fn check_and_get_illegal_move_origin<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, cmt: &mc::cmt<'tcx>) -> Option> { match cmt.cat { - Categorization::Deref(.., mc::BorrowedPtr(..)) | - Categorization::Deref(.., mc::Implicit(..)) | - Categorization::Deref(.., mc::UnsafePtr(..)) | + Categorization::Deref(_, mc::BorrowedPtr(..)) | + Categorization::Deref(_, mc::Implicit(..)) | + Categorization::Deref(_, mc::UnsafePtr(..)) | Categorization::StaticItem => { Some(cmt.clone()) } @@ -258,7 +258,7 @@ fn check_and_get_illegal_move_origin<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, Some(cmt.clone()) } - Categorization::Deref(ref b, _, mc::Unique) => { + Categorization::Deref(ref b, mc::Unique) => { check_and_get_illegal_move_origin(bccx, b) } } diff --git a/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs b/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs index 5fc5682a60b45..0a6375ab187d6 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs @@ -72,11 +72,11 @@ impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> { match cmt.cat { Categorization::Rvalue(..) | - Categorization::Local(..) | // L-Local + Categorization::Local(..) | // L-Local Categorization::Upvar(..) | - Categorization::Deref(.., mc::BorrowedPtr(..)) | // L-Deref-Borrowed - Categorization::Deref(.., mc::Implicit(..)) | - Categorization::Deref(.., mc::UnsafePtr(..)) => { + Categorization::Deref(_, mc::BorrowedPtr(..)) | // L-Deref-Borrowed + Categorization::Deref(_, mc::Implicit(..)) | + Categorization::Deref(_, mc::UnsafePtr(..)) => { self.check_scope(self.scope(cmt)) } @@ -85,8 +85,8 @@ impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> { } Categorization::Downcast(ref base, _) | - Categorization::Deref(ref base, _, mc::Unique) | // L-Deref-Send - Categorization::Interior(ref base, _) => { // L-Field + Categorization::Deref(ref base, mc::Unique) | // L-Deref-Send + Categorization::Interior(ref base, _) => { // L-Field self.check(base, discr_scope) } } @@ -119,15 +119,15 @@ impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> { self.bccx.region_maps.var_scope(local_id))) } Categorization::StaticItem | - Categorization::Deref(.., mc::UnsafePtr(..)) => { + Categorization::Deref(_, mc::UnsafePtr(..)) => { self.bccx.tcx.types.re_static } - Categorization::Deref(.., mc::BorrowedPtr(_, r)) | - Categorization::Deref(.., mc::Implicit(_, r)) => { + Categorization::Deref(_, mc::BorrowedPtr(_, r)) | + Categorization::Deref(_, mc::Implicit(_, r)) => { r } Categorization::Downcast(ref cmt, _) | - Categorization::Deref(ref cmt, _, mc::Unique) | + Categorization::Deref(ref cmt, mc::Unique) | Categorization::Interior(ref cmt, _) => { self.scope(cmt) } diff --git a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs index 1ee6d565d0d7d..f7c3bb36da7dd 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs @@ -138,9 +138,9 @@ fn report_cannot_move_out_of<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, move_from: mc::cmt<'tcx>) -> DiagnosticBuilder<'a> { match move_from.cat { - Categorization::Deref(.., mc::BorrowedPtr(..)) | - Categorization::Deref(.., mc::Implicit(..)) | - Categorization::Deref(.., mc::UnsafePtr(..)) | + Categorization::Deref(_, mc::BorrowedPtr(..)) | + Categorization::Deref(_, mc::Implicit(..)) | + Categorization::Deref(_, mc::UnsafePtr(..)) | Categorization::StaticItem => { let mut err = struct_span_err!(bccx, move_from.span, E0507, "cannot move out of {}", diff --git a/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs b/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs index 7f90a8b19d4a1..b7965f81b8826 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs @@ -133,7 +133,7 @@ impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> { RestrictionResult::Safe } - Categorization::Deref(cmt_base, _, pk) => { + Categorization::Deref(cmt_base, pk) => { match pk { mc::Unique => { // R-Deref-Send-Pointer diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 9b084acc1938f..0b2cb1b93f92a 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -426,7 +426,7 @@ pub fn opt_loan_path<'tcx>(cmt: &mc::cmt<'tcx>) -> Option>> { Some(new_lp(LpUpvar(id))) } - Categorization::Deref(ref cmt_base, _, pk) => { + Categorization::Deref(ref cmt_base, pk) => { opt_loan_path(cmt_base).map(|lp| { new_lp(LpExtend(lp, cmt.mutbl, LpDeref(pk))) }) diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index 8f087ac212e8a..09e90b78d604b 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -512,7 +512,7 @@ impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx> for CheckCrateVisitor<'a, 'gcx> { Categorization::StaticItem => { break; } - Categorization::Deref(ref cmt, ..) | + Categorization::Deref(ref cmt, _) | Categorization::Downcast(ref cmt, _) | Categorization::Interior(ref cmt, _) => { cur = cmt; diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index b29bf01ba1996..2c4188e392d8d 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -1224,10 +1224,8 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { borrow_kind, borrow_cmt); match borrow_cmt.cat.clone() { - Categorization::Deref(ref_cmt, _, - mc::Implicit(ref_kind, ref_region)) | - Categorization::Deref(ref_cmt, _, - mc::BorrowedPtr(ref_kind, ref_region)) => { + Categorization::Deref(ref_cmt, mc::Implicit(ref_kind, ref_region)) | + Categorization::Deref(ref_cmt, mc::BorrowedPtr(ref_kind, ref_region)) => { match self.link_reborrowed_region(span, borrow_region, borrow_kind, ref_cmt, ref_region, ref_kind, @@ -1243,7 +1241,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { } Categorization::Downcast(cmt_base, _) | - Categorization::Deref(cmt_base, _, mc::Unique) | + Categorization::Deref(cmt_base, mc::Unique) | Categorization::Interior(cmt_base, _) => { // Borrowing interior or owned data requires the base // to be valid and borrowable in the same fashion. @@ -1251,7 +1249,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { borrow_kind = borrow_kind; } - Categorization::Deref(.., mc::UnsafePtr(..)) | + Categorization::Deref(_, mc::UnsafePtr(..)) | Categorization::StaticItem | Categorization::Upvar(..) | Categorization::Local(..) | diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs index 114290c52d195..799d6186653e4 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/src/librustc_typeck/check/upvar.rs @@ -281,8 +281,8 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { debug!("adjust_upvar_borrow_kind_for_consume: guarantor={:?}", guarantor); match guarantor.cat { - Categorization::Deref(.., mc::BorrowedPtr(..)) | - Categorization::Deref(.., mc::Implicit(..)) => { + Categorization::Deref(_, mc::BorrowedPtr(..)) | + Categorization::Deref(_, mc::Implicit(..)) => { match cmt.note { mc::NoteUpvarRef(upvar_id) => { debug!("adjust_upvar_borrow_kind_for_consume: \ @@ -327,7 +327,7 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { cmt); match cmt.cat.clone() { - Categorization::Deref(base, _, mc::Unique) | + Categorization::Deref(base, mc::Unique) | Categorization::Interior(base, _) | Categorization::Downcast(base, _) => { // Interior or owned data is mutable if base is @@ -335,8 +335,8 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { self.adjust_upvar_borrow_kind_for_mut(base); } - Categorization::Deref(base, _, mc::BorrowedPtr(..)) | - Categorization::Deref(base, _, mc::Implicit(..)) => { + Categorization::Deref(base, mc::BorrowedPtr(..)) | + Categorization::Deref(base, mc::Implicit(..)) => { if !self.try_adjust_upvar_deref(cmt, ty::MutBorrow) { // assignment to deref of an `&mut` // borrowed pointer implies that the @@ -346,7 +346,7 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { } } - Categorization::Deref(.., mc::UnsafePtr(..)) | + Categorization::Deref(_, mc::UnsafePtr(..)) | Categorization::StaticItem | Categorization::Rvalue(..) | Categorization::Local(_) | @@ -361,7 +361,7 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { cmt); match cmt.cat.clone() { - Categorization::Deref(base, _, mc::Unique) | + Categorization::Deref(base, mc::Unique) | Categorization::Interior(base, _) | Categorization::Downcast(base, _) => { // Interior or owned data is unique if base is @@ -369,8 +369,8 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { self.adjust_upvar_borrow_kind_for_unique(base); } - Categorization::Deref(base, _, mc::BorrowedPtr(..)) | - Categorization::Deref(base, _, mc::Implicit(..)) => { + Categorization::Deref(base, mc::BorrowedPtr(..)) | + Categorization::Deref(base, mc::Implicit(..)) => { if !self.try_adjust_upvar_deref(cmt, ty::UniqueImmBorrow) { // for a borrowed pointer to be unique, its // base must be unique @@ -378,7 +378,7 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { } } - Categorization::Deref(.., mc::UnsafePtr(..)) | + Categorization::Deref(_, mc::UnsafePtr(..)) | Categorization::StaticItem | Categorization::Rvalue(..) | Categorization::Local(_) | From b4988f07920324830558e79a1a5b3233511cfbd9 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Wed, 17 May 2017 00:54:04 +0300 Subject: [PATCH 03/14] rustc: keep overloaded autoderef MethodCallee's in Adjust. --- src/librustc/cfg/construct.rs | 3 +- src/librustc/ich/impls_ty.rs | 15 +- src/librustc/infer/mod.rs | 40 ++-- src/librustc/middle/dead.rs | 4 +- src/librustc/middle/effect.rs | 4 +- src/librustc/middle/expr_use_visitor.rs | 53 ++---- src/librustc/middle/liveness.rs | 3 +- src/librustc/middle/mem_categorization.rs | 87 ++++----- src/librustc/middle/reachable.rs | 3 +- src/librustc/ty/adjustment.rs | 73 +++----- src/librustc/ty/context.rs | 8 +- src/librustc/ty/mod.rs | 38 ---- src/librustc_lint/builtin.rs | 13 +- src/librustc_mir/hair/cx/expr.rs | 97 +++++----- src/librustc_passes/consts.rs | 10 +- src/librustc_save_analysis/lib.rs | 3 +- src/librustc_typeck/check/autoderef.rs | 86 ++++----- src/librustc_typeck/check/callee.rs | 119 ++++++------ src/librustc_typeck/check/coercion.rs | 63 +++---- src/librustc_typeck/check/method/confirm.rs | 42 ++--- src/librustc_typeck/check/method/mod.rs | 59 ++---- src/librustc_typeck/check/mod.rs | 192 ++++++++++---------- src/librustc_typeck/check/op.rs | 31 ++-- src/librustc_typeck/check/regionck.rs | 135 ++++++-------- src/librustc_typeck/check/upvar.rs | 4 +- src/librustc_typeck/check/writeback.rs | 38 ++-- 26 files changed, 518 insertions(+), 705 deletions(-) diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs index c1c195852f949..2246621f83ca0 100644 --- a/src/librustc/cfg/construct.rs +++ b/src/librustc/cfg/construct.rs @@ -412,8 +412,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { pred: CFGIndex, func_or_rcvr: &hir::Expr, args: I) -> CFGIndex { - let method_call = ty::MethodCall::expr(call_expr.id); - let fn_ty = match self.tables.method_map.get(&method_call) { + let fn_ty = match self.tables.method_map.get(&call_expr.id) { Some(method) => method.ty, None => self.tables.expr_ty_adjusted(func_or_rcvr), }; diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 3bbac8d6a6425..0575bfcf926f5 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -102,7 +102,7 @@ impl<'a, 'tcx> HashStable> for ty::adjustment::Ad ty::adjustment::Adjust::UnsafeFnPointer | ty::adjustment::Adjust::ClosureFnPointer | ty::adjustment::Adjust::MutToConstPointer => {} - ty::adjustment::Adjust::DerefRef { autoderefs, ref autoref, unsize } => { + ty::adjustment::Adjust::DerefRef { ref autoderefs, ref autoref, unsize } => { autoderefs.hash_stable(hcx, hasher); autoref.hash_stable(hcx, hasher); unsize.hash_stable(hcx, hasher); @@ -112,7 +112,6 @@ impl<'a, 'tcx> HashStable> for ty::adjustment::Ad } impl_stable_hash_for!(struct ty::adjustment::Adjustment<'tcx> { kind, target }); -impl_stable_hash_for!(struct ty::MethodCall { expr_id, autoderef }); impl_stable_hash_for!(struct ty::MethodCallee<'tcx> { def_id, ty, substs }); impl_stable_hash_for!(struct ty::UpvarId { var_id, closure_expr_id }); impl_stable_hash_for!(struct ty::UpvarBorrow<'tcx> { kind, region }); @@ -626,17 +625,7 @@ impl<'a, 'tcx> HashStable> for ty::TypeckTables<' ich::hash_stable_nodemap(hcx, hasher, node_types); ich::hash_stable_nodemap(hcx, hasher, item_substs); ich::hash_stable_nodemap(hcx, hasher, adjustments); - - ich::hash_stable_hashmap(hcx, hasher, method_map, |hcx, method_call| { - let ty::MethodCall { - expr_id, - autoderef - } = *method_call; - - let def_id = hcx.tcx().hir.local_def_id(expr_id); - (hcx.def_path_hash(def_id), autoderef) - }); - + ich::hash_stable_nodemap(hcx, hasher, method_map); ich::hash_stable_hashmap(hcx, hasher, upvar_capture_map, |hcx, up_var_id| { let ty::UpvarId { var_id, diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index a6dbbee79a48c..f05f411945089 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -564,13 +564,14 @@ impl<'tcx, T> InferOk<'tcx, T> { } #[must_use = "once you start a snapshot, you should always consume it"] -pub struct CombinedSnapshot { +pub struct CombinedSnapshot<'a, 'tcx:'a> { projection_cache_snapshot: traits::ProjectionCacheSnapshot, type_snapshot: type_variable::Snapshot, int_snapshot: unify::Snapshot, float_snapshot: unify::Snapshot, region_vars_snapshot: RegionSnapshot, was_in_snapshot: bool, + _in_progress_tables: Option>>, } /// Helper trait for shortening the lifetimes inside a @@ -888,7 +889,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { result } - fn start_snapshot(&self) -> CombinedSnapshot { + fn start_snapshot<'b>(&'b self) -> CombinedSnapshot<'b, 'tcx> { debug!("start_snapshot()"); let in_snapshot = self.in_snapshot.get(); @@ -901,6 +902,12 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { float_snapshot: self.float_unification_table.borrow_mut().snapshot(), region_vars_snapshot: self.region_vars.start_snapshot(), was_in_snapshot: in_snapshot, + // Borrow tables "in progress" (i.e. during typeck) + // to ban writes from within a snapshot to them. + _in_progress_tables: match self.tables { + InferTables::InProgress(ref tables) => tables.try_borrow().ok(), + _ => None + } } } @@ -911,7 +918,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { int_snapshot, float_snapshot, region_vars_snapshot, - was_in_snapshot } = snapshot; + was_in_snapshot, + _in_progress_tables } = snapshot; self.in_snapshot.set(was_in_snapshot); @@ -938,7 +946,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { int_snapshot, float_snapshot, region_vars_snapshot, - was_in_snapshot } = snapshot; + was_in_snapshot, + _in_progress_tables } = snapshot; self.in_snapshot.set(was_in_snapshot); @@ -1645,29 +1654,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { !traits::type_known_to_meet_bound(self, ty, copy_def_id, span) } - pub fn node_method_ty(&self, method_call: ty::MethodCall) - -> Option> { - self.tables - .borrow() - .method_map - .get(&method_call) - .map(|method| method.ty) - .map(|ty| self.resolve_type_vars_if_possible(&ty)) - } - - pub fn node_method_id(&self, method_call: ty::MethodCall) - -> Option { - self.tables - .borrow() - .method_map - .get(&method_call) - .map(|method| method.def_id) - } - - pub fn is_method_call(&self, id: ast::NodeId) -> bool { - self.tables.borrow().method_map.contains_key(&ty::MethodCall::expr(id)) - } - pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option> { self.tables.borrow().upvar_capture_map.get(&upvar_id).cloned() } diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 84ead6506c85c..ebae3933bddb1 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -95,9 +95,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { } fn lookup_and_handle_method(&mut self, id: ast::NodeId) { - let method_call = ty::MethodCall::expr(id); - let method = self.tables.method_map[&method_call]; - self.check_def_id(method.def_id); + self.check_def_id(self.tables.method_map[&id].def_id); } fn handle_field_access(&mut self, lhs: &hir::Expr, name: ast::Name) { diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs index 2261f296454ef..1d3f8e426e713 100644 --- a/src/librustc/middle/effect.rs +++ b/src/librustc/middle/effect.rs @@ -13,7 +13,6 @@ use self::RootUnsafeContext::*; use ty::{self, Ty, TyCtxt}; -use ty::MethodCall; use lint; use syntax::ast; @@ -174,8 +173,7 @@ impl<'a, 'tcx> Visitor<'tcx> for EffectCheckVisitor<'a, 'tcx> { fn visit_expr(&mut self, expr: &'tcx hir::Expr) { match expr.node { hir::ExprMethodCall(..) => { - let method_call = MethodCall::expr(expr.id); - let base_type = self.tables.method_map[&method_call].ty; + let base_type = self.tables.method_map[&expr.id].ty; debug!("effect: method call case, base type is {:?}", base_type); if type_is_unsafe_function(base_type) { diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 99b140f690a48..64880bf4fadf4 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -563,19 +563,8 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { } ty::TyError => { } _ => { - let overloaded_call_type = - match self.mc.infcx.node_method_id(ty::MethodCall::expr(call.id)) { - Some(method_id) => { - OverloadedCallType::from_method_id(self.tcx(), method_id) - } - None => { - span_bug!( - callee.span, - "unexpected callee type {}", - callee_ty) - } - }; - match overloaded_call_type { + let method = self.mc.infcx.tables.borrow().method_map[&call.id]; + match OverloadedCallType::from_method_id(self.tcx(), method.def_id) { FnMutOverloadedCall => { let call_scope_r = self.tcx().node_scope_region(call.id); self.borrow_expr(callee, @@ -717,7 +706,9 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { fn walk_adjustment(&mut self, expr: &hir::Expr) { let infcx = self.mc.infcx; //NOTE(@jroesch): mixed RefCell borrow causes crash - let adj = infcx.tables.borrow().adjustments.get(&expr.id).map(|x| x.clone()); + let adj = infcx.tables.borrow().adjustments.get(&expr.id).cloned(); + let cmt_unadjusted = + return_if_err!(self.mc.cat_expr_unadjusted(expr)); if let Some(adjustment) = adj { match adjustment.kind { adjustment::Adjust::NeverToAny | @@ -728,17 +719,13 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { // Creating a closure/fn-pointer or unsizing consumes // the input and stores it into the resulting rvalue. debug!("walk_adjustment: trivial adjustment"); - let cmt_unadjusted = - return_if_err!(self.mc.cat_expr_unadjusted(expr)); self.delegate_consume(expr.id, expr.span, cmt_unadjusted); } - adjustment::Adjust::DerefRef { autoderefs, autoref, unsize } => { + adjustment::Adjust::DerefRef { ref autoderefs, autoref, unsize } => { debug!("walk_adjustment expr={:?} adj={:?}", expr, adjustment); - self.walk_autoderefs(expr, autoderefs); - let cmt_derefd = - return_if_err!(self.mc.cat_expr_autoderefd(expr, autoderefs)); + return_if_err!(self.walk_autoderefs(expr, cmt_unadjusted, autoderefs)); let cmt_refd = self.walk_autoref(expr, cmt_derefd, autoref); @@ -757,30 +744,30 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { /// `deref()` is declared with `&self`, this is an autoref of `x`. fn walk_autoderefs(&mut self, expr: &hir::Expr, - autoderefs: usize) { - debug!("walk_autoderefs expr={:?} autoderefs={}", expr, autoderefs); - - for i in 0..autoderefs { - let deref_id = ty::MethodCall::autoderef(expr.id, i as u32); - if let Some(method_ty) = self.mc.infcx.node_method_ty(deref_id) { - let cmt = return_if_err!(self.mc.cat_expr_autoderefd(expr, i)); + mut cmt: mc::cmt<'tcx>, + autoderefs: &[Option>]) + -> mc::McResult> { + debug!("walk_autoderefs expr={:?} autoderefs={:?}", expr, autoderefs); + for &overloaded in autoderefs { + if let Some(method) = overloaded { // the method call infrastructure should have // replaced all late-bound regions with variables: - let self_ty = method_ty.fn_sig().input(0); + let self_ty = method.ty.fn_sig().input(0); + let self_ty = self.mc.infcx.resolve_type_vars_if_possible(&self_ty); let self_ty = self.tcx().no_late_bound_regions(&self_ty).unwrap(); let (m, r) = match self_ty.sty { ty::TyRef(r, ref m) => (m.mutbl, r), - _ => span_bug!(expr.span, - "bad overloaded deref type {:?}", - method_ty) + _ => span_bug!(expr.span, "bad overloaded deref type {:?}", self_ty) }; let bk = ty::BorrowKind::from_mutbl(m); - self.delegate.borrow(expr.id, expr.span, cmt, + self.delegate.borrow(expr.id, expr.span, cmt.clone(), r, bk, AutoRef); } + cmt = self.mc.cat_deref(expr, cmt, overloaded)?; } + Ok(cmt) } /// Walks the autoref `opt_autoref` applied to the autoderef'd @@ -863,7 +850,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { pass_args: PassArgs) -> bool { - if !self.mc.infcx.is_method_call(expr.id) { + if !self.mc.infcx.tables.borrow().is_method_call(expr.id) { return false; } diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index ecd350d127368..d5c0a67f71ce9 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -1084,8 +1084,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { } hir::ExprMethodCall(.., ref args) => { - let method_call = ty::MethodCall::expr(expr.id); - let method_ty = self.tables.method_map[&method_call].ty; + let method_ty = self.tables.method_map[&expr.id].ty; // FIXME(canndrew): This is_never should really be an is_uninhabited let succ = if method_ty.fn_ret().0.is_never() { self.s.exit_ln diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 13647d420c36a..4e2150dc2c61f 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -480,14 +480,21 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { } Some(adjustment) => { + debug!("cat_expr({:?}): {:?}", adjustment, expr); match adjustment.kind { adjustment::Adjust::DerefRef { - autoderefs, + ref autoderefs, autoref: None, unsize: false } => { // Equivalent to *expr or something similar. - self.cat_expr_autoderefd(expr, autoderefs) + let mut cmt = self.cat_expr_unadjusted(expr)?; + debug!("cat_expr: autoderefs={:?}, cmt={:?}", + autoderefs, cmt); + for &overloaded in autoderefs { + cmt = self.cat_deref(expr, cmt, overloaded)?; + } + return Ok(cmt); } adjustment::Adjust::NeverToAny | @@ -496,9 +503,6 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { adjustment::Adjust::ClosureFnPointer | adjustment::Adjust::MutToConstPointer | adjustment::Adjust::DerefRef {..} => { - debug!("cat_expr({:?}): {:?}", - adjustment, - expr); // Result is an rvalue. let expr_ty = self.expr_ty_adjusted(expr)?; Ok(self.cat_rvalue_node(expr.id(), expr.span(), expr_ty)) @@ -508,20 +512,6 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { } } - pub fn cat_expr_autoderefd(&self, - expr: &hir::Expr, - autoderefs: usize) - -> McResult> { - let mut cmt = self.cat_expr_unadjusted(expr)?; - debug!("cat_expr_autoderefd: autoderefs={}, cmt={:?}", - autoderefs, - cmt); - for deref in 1..autoderefs + 1 { - cmt = self.cat_deref(expr, cmt, deref)?; - } - return Ok(cmt); - } - pub fn cat_expr_unadjusted(&self, expr: &hir::Expr) -> McResult> { debug!("cat_expr: id={} expr={:?}", expr.id, expr); @@ -529,7 +519,9 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { match expr.node { hir::ExprUnary(hir::UnDeref, ref e_base) => { let base_cmt = self.cat_expr(&e_base)?; - self.cat_deref(expr, base_cmt, 0) + let method = self.infcx.tables.borrow().method_map + .get(&expr.id).cloned(); + self.cat_deref(expr, base_cmt, method) } hir::ExprField(ref base, f_name) => { @@ -547,12 +539,12 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { } hir::ExprIndex(ref base, _) => { - let method_call = ty::MethodCall::expr(expr.id()); - match self.infcx.node_method_ty(method_call) { - Some(method_ty) => { + let method = self.infcx.tables.borrow().method_map.get(&expr.id()).cloned(); + match method { + Some(method) => { // If this is an index implemented by a method call, then it // will include an implicit deref of the result. - let ret_ty = self.overloaded_method_return_ty(method_ty); + let ret_ty = self.overloaded_method_return_ty(method); // The index method always returns an `&T`, so // dereference it to find the result type. @@ -932,24 +924,16 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { ret } - fn cat_deref(&self, - node: &N, - base_cmt: cmt<'tcx>, - deref_cnt: usize) - -> McResult> { - let method_call = ty::MethodCall { - expr_id: node.id(), - autoderef: deref_cnt as u32 - }; - let method_ty = self.infcx.node_method_ty(method_call); - - debug!("cat_deref: method_call={:?} method_ty={:?}", - method_call, method_ty.map(|ty| ty)); + pub fn cat_deref(&self, + node: &N, + base_cmt: cmt<'tcx>, + overloaded: Option>) + -> McResult> { + debug!("cat_deref: overloaded={:?}", overloaded); - let base_cmt = match method_ty { - Some(method_ty) => { - let ref_ty = - self.tcx().no_late_bound_regions(&method_ty.fn_ret()).unwrap(); + let base_cmt = match overloaded { + Some(method) => { + let ref_ty = self.overloaded_method_return_ty(method); self.cat_rvalue_node(node.id(), node.span(), ref_ty) } None => base_cmt @@ -1020,12 +1004,10 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { //! - `elt`: the AST node being indexed //! - `base_cmt`: the cmt of `elt` - let method_call = ty::MethodCall::expr(elt.id()); - let method_ty = self.infcx.node_method_ty(method_call); - - let (element_ty, element_kind) = match method_ty { - Some(method_ty) => { - let ref_ty = self.overloaded_method_return_ty(method_ty); + let method = self.infcx.tables.borrow().method_map.get(&elt.id()).cloned(); + let (element_ty, element_kind) = match method { + Some(method) => { + let ref_ty = self.overloaded_method_return_ty(method); base_cmt = self.cat_rvalue_node(elt.id(), elt.span(), ref_ty); (ref_ty.builtin_deref(false, ty::NoPreference).unwrap().ty, @@ -1234,7 +1216,9 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { // box p1, &p1, &mut p1. we can ignore the mutability of // PatKind::Ref since that information is already contained // in the type. - let subcmt = self.cat_deref(pat, cmt, 0)?; + let method = self.infcx.tables.borrow().method_map + .get(&pat.id).cloned(); + let subcmt = self.cat_deref(pat, cmt, method)?; self.cat_pattern_(subcmt, &subpat, op)?; } @@ -1262,7 +1246,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { } fn overloaded_method_return_ty(&self, - method_ty: Ty<'tcx>) + method: ty::MethodCallee<'tcx>) -> Ty<'tcx> { // When we process an overloaded `*` or `[]` etc, we often @@ -1270,8 +1254,9 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { // types are generated by method resolution and always have // all late-bound regions fully instantiated, so we just want // to skip past the binder. - self.tcx().no_late_bound_regions(&method_ty.fn_ret()) - .unwrap() + let ret_ty = method.ty.fn_ret(); + let ret_ty = self.infcx.resolve_type_vars_if_possible(&ret_ty); + self.tcx().no_late_bound_regions(&ret_ty).unwrap() } } diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index 939d7364d9e06..e5cc7aae4e9ce 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -110,8 +110,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ReachableContext<'a, 'tcx> { Some(self.tables.qpath_def(qpath, expr.id)) } hir::ExprMethodCall(..) => { - let method_call = ty::MethodCall::expr(expr.id); - let def_id = self.tables.method_map[&method_call].def_id; + let def_id = self.tables.method_map[&expr.id].def_id; Some(Def::Method(def_id)) } _ => None diff --git a/src/librustc/ty/adjustment.rs b/src/librustc/ty/adjustment.rs index 9aa700e2b4487..629f94609aa37 100644 --- a/src/librustc/ty/adjustment.rs +++ b/src/librustc/ty/adjustment.rs @@ -9,10 +9,6 @@ // except according to those terms. use ty::{self, Ty, TyCtxt, TypeAndMut}; -use ty::LvaluePreference::{NoPreference}; - -use syntax::ast; -use syntax_pos::Span; use hir; @@ -43,10 +39,10 @@ pub enum Adjust<'tcx> { /// here means either or both of raw vs borrowed vs unique and fat vs thin. /// /// We transform pointers by following the following steps in order: - /// 1. Deref the pointer `self.autoderefs` times (may be 0). + /// 1. Deref the pointer through `self.autoderefs` steps (may be no steps). /// 2. If `autoref` is `Some(_)`, then take the address and produce either a /// `&` or `*` pointer. - /// 3. If `unsize` is `Some(_)`, then apply the unsize transformation, + /// 3. If `unsize` is `true`, then apply the unsize transformation, /// which will do things like convert thin pointers to fat /// pointers, or convert structs containing thin pointers to /// structs containing fat pointers, or convert between fat @@ -61,23 +57,26 @@ pub enum Adjust<'tcx> { /// 1. The simplest cases are where the pointer is not adjusted fat vs thin. /// Here the pointer will be dereferenced N times (where a dereference can /// happen to raw or borrowed pointers or any smart pointer which implements - /// Deref, including Box<_>). The number of dereferences is given by + /// Deref, including Box<_>). The types of dereferences is given by /// `autoderefs`. It can then be auto-referenced zero or one times, indicated /// by `autoref`, to either a raw or borrowed pointer. In these cases unsize is - /// None. + /// `false`. /// /// 2. A thin-to-fat coercon involves unsizing the underlying data. We start /// with a thin pointer, deref a number of times, unsize the underlying data, /// then autoref. The 'unsize' phase may change a fixed length array to a /// dynamically sized one, a concrete object to a trait object, or statically - /// sized struct to a dyncamically sized one. E.g., &[i32; 4] -> &[i32] is + /// sized struct to a dynamically sized one. E.g., &[i32; 4] -> &[i32] is /// represented by: /// /// ``` - /// Adjust::DerefRef { - /// autoderefs: 1, // &[i32; 4] -> [i32; 4] - /// autoref: Some(AutoBorrow::Ref), // [i32] -> &[i32] - /// unsize: Some([i32]), // [i32; 4] -> [i32] + /// Adjustment { + /// kind: Adjust::DerefRef { + /// autoderefs: vec![None], // &[i32; 4] -> [i32; 4] + /// autoref: Some(AutoBorrow::Ref), // [i32; 4] -> &[i32; 4] + /// unsize: true, // &[i32; 4] -> &[i32] + /// }, + /// target: `[i32]`, /// } /// ``` /// @@ -95,15 +94,18 @@ pub enum Adjust<'tcx> { /// Box<[i32]> is represented by: /// /// ``` - /// Adjust::DerefRef { - /// autoderefs: 0, - /// autoref: None, - /// unsize: Some(Box<[i32]>), + /// Adjustment { + /// Adjust::DerefRef { + /// autoderefs: vec![], + /// autoref: None, + /// unsize: true, + /// }, + /// target: `Box<[i32]>`, /// } /// ``` DerefRef { /// Step 1. Apply a number of dereferences, producing an lvalue. - autoderefs: usize, + autoderefs: Vec>>, /// Step 2. Optionally produce a pointer/reference from the value. autoref: Option>, @@ -119,7 +121,11 @@ impl<'tcx> Adjustment<'tcx> { match self.kind { Adjust::NeverToAny => self.target.is_never(), - Adjust::DerefRef { autoderefs: 0, autoref: None, unsize: false } => true, + Adjust::DerefRef { + ref autoderefs, + autoref: None, + unsize: false + } if autoderefs.is_empty() => true, Adjust::ReifyFnPointer | Adjust::UnsafeFnPointer | @@ -161,35 +167,6 @@ pub enum CustomCoerceUnsized { } impl<'a, 'gcx, 'tcx> ty::TyS<'tcx> { - pub fn adjust_for_autoderef(&'tcx self, - tcx: TyCtxt<'a, 'gcx, 'tcx>, - expr_id: ast::NodeId, - expr_span: Span, - autoderef: u32, // how many autoderefs so far? - mut method_type: F) - -> Ty<'tcx> where - F: FnMut(ty::MethodCall) -> Option>, - { - let method_call = ty::MethodCall::autoderef(expr_id, autoderef); - let mut adjusted_ty = self; - if let Some(method_ty) = method_type(method_call) { - // Method calls always have all late-bound regions - // fully instantiated. - adjusted_ty = tcx.no_late_bound_regions(&method_ty.fn_ret()).unwrap(); - } - match adjusted_ty.builtin_deref(true, NoPreference) { - Some(mt) => mt.ty, - None => { - span_bug!( - expr_span, - "the {}th autoderef for {} failed: {}", - autoderef, - expr_id, - adjusted_ty); - } - } - } - pub fn adjust_for_autoref(&'tcx self, tcx: TyCtxt<'a, 'gcx, 'tcx>, autoref: Option>) -> Ty<'tcx> { diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index e3d7aeb22e1fa..76882b9431537 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -222,7 +222,7 @@ pub struct TypeckTables<'tcx> { pub adjustments: NodeMap>, - pub method_map: ty::MethodMap<'tcx>, + pub method_map: NodeMap>, /// Borrows pub upvar_capture_map: ty::UpvarCaptureMap<'tcx>, @@ -358,11 +358,7 @@ impl<'tcx> TypeckTables<'tcx> { } pub fn is_method_call(&self, expr_id: NodeId) -> bool { - self.method_map.contains_key(&ty::MethodCall::expr(expr_id)) - } - - pub fn is_overloaded_autoderef(&self, expr_id: NodeId, autoderefs: u32) -> bool { - self.method_map.contains_key(&ty::MethodCall::autoderef(expr_id, autoderefs)) + self.method_map.contains_key(&expr_id) } pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option> { diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index aeffd71a09649..08016ac91bf29 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -398,44 +398,6 @@ pub struct MethodCallee<'tcx> { pub substs: &'tcx Substs<'tcx> } -/// With method calls, we store some extra information in -/// side tables (i.e method_map). We use -/// MethodCall as a key to index into these tables instead of -/// just directly using the expression's NodeId. The reason -/// for this being that we may apply adjustments (coercions) -/// with the resulting expression also needing to use the -/// side tables. The problem with this is that we don't -/// assign a separate NodeId to this new expression -/// and so it would clash with the base expression if both -/// needed to add to the side tables. Thus to disambiguate -/// we also keep track of whether there's an adjustment in -/// our key. -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] -pub struct MethodCall { - pub expr_id: NodeId, - pub autoderef: u32 -} - -impl MethodCall { - pub fn expr(id: NodeId) -> MethodCall { - MethodCall { - expr_id: id, - autoderef: 0 - } - } - - pub fn autoderef(expr_id: NodeId, autoderef: u32) -> MethodCall { - MethodCall { - expr_id: expr_id, - autoderef: 1 + autoderef - } - } -} - -// maps from an expression id that corresponds to a method call to the details -// of the method to be invoked -pub type MethodMap<'tcx> = FxHashMap>; - // Contains information needed to resolve types and (in the future) look up // the types of AST nodes. #[derive(Copy, Clone, PartialEq, Eq, Hash)] diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index f1d014692a4b8..13c69d105302f 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -882,19 +882,18 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnconditionalRecursion { use rustc::ty::adjustment::*; // Check for method calls and overloaded operators. - let opt_m = cx.tables.method_map.get(&ty::MethodCall::expr(id)).cloned(); - if let Some(m) = opt_m { + if let Some(m) = cx.tables.method_map.get(&id).cloned() { if method_call_refers_to_method(cx.tcx, method, m.def_id, m.substs, id) { return true; } } // Check for overloaded autoderef method calls. - let opt_adj = cx.tables.adjustments.get(&id).cloned(); - if let Some(Adjustment { kind: Adjust::DerefRef { autoderefs, .. }, .. }) = opt_adj { - for i in 0..autoderefs { - let method_call = ty::MethodCall::autoderef(id, i as u32); - if let Some(m) = cx.tables.method_map.get(&method_call).cloned() { + if let Some(Adjustment { + kind: Adjust::DerefRef { ref autoderefs, .. }, .. + }) = cx.tables.adjustments.get(&id).cloned() { + for &overloaded in autoderefs { + if let Some(m) = overloaded { if method_call_refers_to_method(cx.tcx, method, m.def_id, m.substs, id) { return true; } diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index b180d982e86b6..6c48e0120ba7e 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -31,16 +31,16 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { debug!("Expr::make_mirror(): id={}, span={:?}", self.id, self.span); let mut expr = make_mirror_unadjusted(cx, self); - let adj = cx.tables().adjustments.get(&self.id).cloned(); + let adj = cx.tables().adjustments.get(&self.id); debug!("make_mirror: unadjusted-expr={:?} applying adjustments={:?}", expr, adj); // Now apply adjustments, if any. - match adj.map(|adj| (adj.kind, adj.target)) { + match adj.map(|adj| (&adj.kind, adj.target)) { None => {} - Some((ty::adjustment::Adjust::ReifyFnPointer, adjusted_ty)) => { + Some((&ty::adjustment::Adjust::ReifyFnPointer, adjusted_ty)) => { expr = Expr { temp_lifetime: temp_lifetime, temp_lifetime_was_shrunk: was_shrunk, @@ -49,7 +49,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { kind: ExprKind::ReifyFnPointer { source: expr.to_ref() }, }; } - Some((ty::adjustment::Adjust::UnsafeFnPointer, adjusted_ty)) => { + Some((&ty::adjustment::Adjust::UnsafeFnPointer, adjusted_ty)) => { expr = Expr { temp_lifetime: temp_lifetime, temp_lifetime_was_shrunk: was_shrunk, @@ -58,7 +58,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { kind: ExprKind::UnsafeFnPointer { source: expr.to_ref() }, }; } - Some((ty::adjustment::Adjust::ClosureFnPointer, adjusted_ty)) => { + Some((&ty::adjustment::Adjust::ClosureFnPointer, adjusted_ty)) => { expr = Expr { temp_lifetime: temp_lifetime, temp_lifetime_was_shrunk: was_shrunk, @@ -67,7 +67,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { kind: ExprKind::ClosureFnPointer { source: expr.to_ref() }, }; } - Some((ty::adjustment::Adjust::NeverToAny, adjusted_ty)) => { + Some((&ty::adjustment::Adjust::NeverToAny, adjusted_ty)) => { expr = Expr { temp_lifetime: temp_lifetime, temp_lifetime_was_shrunk: was_shrunk, @@ -76,7 +76,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { kind: ExprKind::NeverToAny { source: expr.to_ref() }, }; } - Some((ty::adjustment::Adjust::MutToConstPointer, adjusted_ty)) => { + Some((&ty::adjustment::Adjust::MutToConstPointer, adjusted_ty)) => { expr = Expr { temp_lifetime: temp_lifetime, temp_lifetime_was_shrunk: was_shrunk, @@ -85,25 +85,18 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { kind: ExprKind::Cast { source: expr.to_ref() }, }; } - Some((ty::adjustment::Adjust::DerefRef { autoderefs, autoref, unsize }, + Some((&ty::adjustment::Adjust::DerefRef { ref autoderefs, autoref, unsize }, adjusted_ty)) => { - for i in 0..autoderefs { - let i = i as u32; - let adjusted_ty = - expr.ty.adjust_for_autoderef(cx.tcx, self.id, self.span, i, |mc| { - cx.tables().method_map.get(&mc).map(|m| m.ty) - }); - debug!("make_mirror: autoderef #{}, adjusted_ty={:?}", - i, - adjusted_ty); - let method_key = ty::MethodCall::autoderef(self.id, i); - let meth_ty = cx.tables().method_map.get(&method_key).map(|m| m.ty); - let kind = if let Some(meth_ty) = meth_ty { - debug!("make_mirror: overloaded autoderef (meth_ty={:?})", meth_ty); - - let ref_ty = cx.tcx.no_late_bound_regions(&meth_ty.fn_ret()); - let (region, mutbl) = match ref_ty { - Some(&ty::TyS { sty: ty::TyRef(region, mt), .. }) => (region, mt.mutbl), + for &overloaded in autoderefs { + let mut ref_ty = expr.ty; + let kind = if let Some(method) = overloaded { + debug!("make_mirror: overloaded autoderef (method={:?})", method); + + // Method calls always have all late-bound regions + // fully instantiated. + ref_ty = cx.tcx.no_late_bound_regions(&method.ty.fn_ret()).unwrap(); + let (region, mutbl) = match ref_ty.sty { + ty::TyRef(region, mt) => (region, mt.mutbl), _ => span_bug!(expr.span, "autoderef returned bad type"), }; @@ -125,7 +118,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { overloaded_lvalue(cx, self, - method_key, + method, PassArgs::ByRef, expr.to_ref(), vec![]) @@ -133,6 +126,14 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { debug!("make_mirror: built-in autoderef"); ExprKind::Deref { arg: expr.to_ref() } }; + let adjusted_ty = match ref_ty.builtin_deref(true, + ty::LvaluePreference::NoPreference) { + Some(mt) => mt.ty, + None => { + span_bug!(self.span, "autoderef for {} failed: {}", self.id, ref_ty); + } + }; + debug!("make_mirror: autoderef adjusted_ty={:?}", adjusted_ty); expr = Expr { temp_lifetime: temp_lifetime, temp_lifetime_was_shrunk: was_shrunk, @@ -243,7 +244,8 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, // Here comes the interesting stuff: hir::ExprMethodCall(.., ref args) => { // Rewrite a.b(c) into UFCS form like Trait::b(a, c) - let expr = method_callee(cx, expr, ty::MethodCall::expr(expr.id)); + let method = cx.tables().method_map[&expr.id]; + let expr = method_callee(cx, expr, method); let args = args.iter() .map(|e| e.to_ref()) .collect(); @@ -255,7 +257,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } hir::ExprCall(ref fun, ref args) => { - if cx.tables().is_method_call(expr.id) { + if let Some(&method) = cx.tables().method_map.get(&expr.id) { // The callee is something implementing Fn, FnMut, or FnOnce. // Find the actual method implementation being called and // build the appropriate UFCS call expression with the @@ -263,7 +265,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, // rewrite f(u, v) into FnOnce::call_once(f, (u, v)) - let method = method_callee(cx, expr, ty::MethodCall::expr(expr.id)); + let method = method_callee(cx, expr, method); let sig = method.ty.fn_sig(); @@ -352,7 +354,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } hir::ExprAssignOp(op, ref lhs, ref rhs) => { - if cx.tables().is_method_call(expr.id) { + if let Some(&method) = cx.tables().method_map.get(&expr.id) { let pass_args = if op.node.is_by_value() { PassArgs::ByValue } else { @@ -360,7 +362,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, }; overloaded_operator(cx, expr, - ty::MethodCall::expr(expr.id), + method, pass_args, lhs.to_ref(), vec![rhs]) @@ -376,7 +378,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, hir::ExprLit(..) => ExprKind::Literal { literal: cx.const_eval_literal(expr) }, hir::ExprBinary(op, ref lhs, ref rhs) => { - if cx.tables().is_method_call(expr.id) { + if let Some(&method) = cx.tables().method_map.get(&expr.id) { let pass_args = if op.node.is_by_value() { PassArgs::ByValue } else { @@ -384,7 +386,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, }; overloaded_operator(cx, expr, - ty::MethodCall::expr(expr.id), + method, pass_args, lhs.to_ref(), vec![rhs]) @@ -436,10 +438,10 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } hir::ExprIndex(ref lhs, ref index) => { - if cx.tables().is_method_call(expr.id) { + if let Some(&method) = cx.tables().method_map.get(&expr.id) { overloaded_lvalue(cx, expr, - ty::MethodCall::expr(expr.id), + method, PassArgs::ByValue, lhs.to_ref(), vec![index]) @@ -452,10 +454,10 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } hir::ExprUnary(hir::UnOp::UnDeref, ref arg) => { - if cx.tables().is_method_call(expr.id) { + if let Some(&method) = cx.tables().method_map.get(&expr.id) { overloaded_lvalue(cx, expr, - ty::MethodCall::expr(expr.id), + method, PassArgs::ByValue, arg.to_ref(), vec![]) @@ -465,10 +467,10 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } hir::ExprUnary(hir::UnOp::UnNot, ref arg) => { - if cx.tables().is_method_call(expr.id) { + if let Some(&method) = cx.tables().method_map.get(&expr.id) { overloaded_operator(cx, expr, - ty::MethodCall::expr(expr.id), + method, PassArgs::ByValue, arg.to_ref(), vec![]) @@ -481,10 +483,10 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } hir::ExprUnary(hir::UnOp::UnNeg, ref arg) => { - if cx.tables().is_method_call(expr.id) { + if let Some(&method) = cx.tables().method_map.get(&expr.id) { overloaded_operator(cx, expr, - ty::MethodCall::expr(expr.id), + method, PassArgs::ByValue, arg.to_ref(), vec![]) @@ -703,9 +705,8 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, fn method_callee<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, expr: &hir::Expr, - method_call: ty::MethodCall) + callee: ty::MethodCallee<'tcx>) -> Expr<'tcx> { - let callee = cx.tables().method_map[&method_call]; let (temp_lifetime, was_shrunk) = cx.region_maps.temporary_scope2(expr.id); Expr { temp_lifetime: temp_lifetime, @@ -948,7 +949,7 @@ enum PassArgs { fn overloaded_operator<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, expr: &'tcx hir::Expr, - method_call: ty::MethodCall, + method: ty::MethodCallee<'tcx>, pass_args: PassArgs, receiver: ExprRef<'tcx>, args: Vec<&'tcx P>) @@ -991,7 +992,7 @@ fn overloaded_operator<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } // now create the call itself - let fun = method_callee(cx, expr, method_call); + let fun = method_callee(cx, expr, method); ExprKind::Call { ty: fun.ty, fun: fun.to_ref(), @@ -1001,7 +1002,7 @@ fn overloaded_operator<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, fn overloaded_lvalue<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, expr: &'tcx hir::Expr, - method_call: ty::MethodCall, + method: ty::MethodCallee<'tcx>, pass_args: PassArgs, receiver: ExprRef<'tcx>, args: Vec<&'tcx P>) @@ -1011,14 +1012,14 @@ fn overloaded_lvalue<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, // line up (this is because `*x` and `x[y]` represent lvalues): // to find the type &T of the content returned by the method; - let ref_ty = cx.tables().method_map[&method_call].ty.fn_ret(); + let ref_ty = method.ty.fn_ret(); let ref_ty = cx.tcx.no_late_bound_regions(&ref_ty).unwrap(); // callees always have all late-bound regions fully instantiated, // construct the complete expression `foo()` for the overloaded call, // which will yield the &T type let (temp_lifetime, was_shrunk) = cx.region_maps.temporary_scope2(expr.id); - let ref_kind = overloaded_operator(cx, expr, method_call, pass_args, receiver, args); + let ref_kind = overloaded_operator(cx, expr, method, pass_args, receiver, args); let ref_expr = Expr { temp_lifetime: temp_lifetime, temp_lifetime_was_shrunk: was_shrunk, diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index 09e90b78d604b..712f5f7ad3906 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -280,11 +280,10 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node _ => {} } - let method_call = ty::MethodCall::expr(e.id); match e.node { hir::ExprUnary(..) | hir::ExprBinary(..) | - hir::ExprIndex(..) if v.tables.method_map.contains_key(&method_call) => { + hir::ExprIndex(..) if v.tables.method_map.contains_key(&e.id) => { v.promotable = false; } hir::ExprBox(_) => { @@ -381,7 +380,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node } } hir::ExprMethodCall(..) => { - let method = v.tables.method_map[&method_call]; + let method = v.tables.method_map[&e.id]; match v.tcx.associated_item(method.def_id).container { ty::ImplContainer(_) => v.handle_const_fn_call(method.def_id, node_ty), ty::TraitContainer(_) => v.promotable = false @@ -450,9 +449,8 @@ fn check_adjustments<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Exp Some(&Adjust::ClosureFnPointer) | Some(&Adjust::MutToConstPointer) => {} - Some(&Adjust::DerefRef { autoderefs, .. }) => { - if (0..autoderefs as u32) - .any(|autoderef| v.tables.is_overloaded_autoderef(e.id, autoderef)) { + Some(&Adjust::DerefRef { ref autoderefs, .. }) => { + if autoderefs.iter().any(|overloaded| overloaded.is_some()) { v.promotable = false; } } diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index d83740936d5d4..d0809f0f6429d 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -564,8 +564,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { } } ast::ExprKind::MethodCall(..) => { - let method_call = ty::MethodCall::expr(expr.id); - let method_id = self.tables.method_map[&method_call].def_id; + let method_id = self.tables.method_map[&expr.id].def_id; let (def_id, decl_id) = match self.tcx.associated_item(method_id).container { ty::ImplContainer(_) => (Some(method_id), None), ty::TraitContainer(_) => (None, Some(method_id)), diff --git a/src/librustc_typeck/check/autoderef.rs b/src/librustc_typeck/check/autoderef.rs index f03451c04ed00..098674519b4d8 100644 --- a/src/librustc_typeck/check/autoderef.rs +++ b/src/librustc_typeck/check/autoderef.rs @@ -12,14 +12,12 @@ use astconv::AstConv; use super::{FnCtxt, LvalueOp}; -use check::coercion::AsCoercionSite; use rustc::infer::InferOk; use rustc::traits; use rustc::ty::{self, Ty, TraitRef}; use rustc::ty::{ToPredicate, TypeFoldable}; -use rustc::ty::{MethodCall, MethodCallee}; use rustc::ty::{LvaluePreference, NoPreference}; -use rustc::hir; +use rustc::ty::adjustment::AutoBorrow; use syntax_pos::Span; use syntax::symbol::Symbol; @@ -149,52 +147,45 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> { self.fcx.resolve_type_vars_if_possible(&self.cur_ty) } - pub fn finalize(self, pref: LvaluePreference, expr: &hir::Expr) { - let fcx = self.fcx; - fcx.register_infer_ok_obligations(self.finalize_as_infer_ok(pref, &[expr])); + pub fn step_count(&self) -> usize { + self.steps.len() + } + + /// Returns the steps required in adjustments (overloaded deref calls). + pub fn adjust_steps(&self, pref: LvaluePreference) + -> Vec>> { + self.fcx.register_infer_ok_obligations(self.adjust_steps_as_infer_ok(pref)) } - pub fn finalize_as_infer_ok(self, pref: LvaluePreference, exprs: &[E]) - -> InferOk<'tcx, ()> - where E: AsCoercionSite - { - let Autoderef { fcx, span, mut obligations, steps, .. } = self; - let methods: Vec<_> = steps - .iter() - .map(|&(ty, kind)| { - if let AutoderefKind::Overloaded = kind { - fcx.try_overloaded_deref(span, None, ty, pref) - .map(|InferOk { value, obligations: o }| { - obligations.extend(o); - value - }) - } else { - None - } - }) - .collect(); - - debug!("finalize({:?}) - {:?},{:?}", - pref, - methods, - obligations); - - for expr in exprs { - let expr = expr.as_coercion_site(); - debug!("finalize - finalizing #{} - {:?}", expr.id, expr); - for (n, method) in methods.iter().enumerate() { - if let &Some(method) = method { - let method_call = MethodCall::autoderef(expr.id, n as u32); - fcx.tables.borrow_mut().method_map.insert(method_call, method); - } + pub fn adjust_steps_as_infer_ok(&self, pref: LvaluePreference) + -> InferOk<'tcx, Vec>>> { + let mut obligations = vec![]; + let steps: Vec<_> = self.steps.iter().map(|&(ty, kind)| { + if let AutoderefKind::Overloaded = kind { + self.fcx.try_overloaded_deref(self.span, ty, pref) + .map(|InferOk { value: (_, method), obligations: o }| { + obligations.extend(o); + method + }) + } else { + None } - } + }).collect(); InferOk { - value: (), - obligations + obligations, + value: steps } } + + pub fn finalize(self) { + let fcx = self.fcx; + fcx.register_predicates(self.into_obligations()); + } + + pub fn into_obligations(self) -> Vec> { + self.obligations + } } impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { @@ -211,14 +202,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn try_overloaded_deref(&self, span: Span, - base_expr: Option<&hir::Expr>, base_ty: Ty<'tcx>, pref: LvaluePreference) - -> Option>> { - let rcvr = base_expr.map(|base_expr| super::AdjustedRcvr { - rcvr_expr: base_expr, autoderefs: 0, unsize: false - }); - - self.try_overloaded_lvalue_op(span, rcvr, base_ty, &[], pref, LvalueOp::Deref) + -> Option>, + ty::MethodCallee<'tcx>)>> { + self.try_overloaded_lvalue_op(span, base_ty, &[], pref, LvalueOp::Deref) } } diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index dde5f598a6832..ce3dbf8c23ed4 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -8,13 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use super::{DeferredCallResolution, Expectation, FnCtxt, TupleArgumentsFlag}; +use super::{Expectation, FnCtxt, TupleArgumentsFlag}; +use super::autoderef::Autoderef; use hir::def::Def; use hir::def_id::{DefId, LOCAL_CRATE}; use rustc::{infer, traits}; use rustc::ty::{self, TyCtxt, LvaluePreference, Ty}; use rustc::ty::subst::Subst; +use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow}; use syntax::abi; use syntax::symbol::Symbol; use syntax_pos::Span; @@ -33,7 +35,7 @@ pub fn check_legal_trait_for_method_call(tcx: TyCtxt, span: Span, trait_id: DefI } enum CallStep<'tcx> { - Builtin, + Builtin(Ty<'tcx>), DeferredClosure(ty::FnSig<'tcx>), Overloaded(ty::MethodCallee<'tcx>), } @@ -49,13 +51,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let expr_ty = self.structurally_resolved_type(call_expr.span, original_callee_ty); let mut autoderef = self.autoderef(callee_expr.span, expr_ty); - let result = autoderef.by_ref() - .flat_map(|(adj_ty, idx)| { - self.try_overloaded_call_step(call_expr, callee_expr, adj_ty, idx) - }) - .next(); - let callee_ty = autoderef.unambiguous_final_ty(); - autoderef.finalize(LvaluePreference::NoPreference, callee_expr); + let mut result = None; + while result.is_none() && autoderef.next().is_some() { + result = self.try_overloaded_call_step(call_expr, callee_expr, &autoderef); + } + autoderef.finalize(); let output = match result { None => { @@ -63,7 +63,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.confirm_builtin_call(call_expr, original_callee_ty, arg_exprs, expected) } - Some(CallStep::Builtin) => { + Some(CallStep::Builtin(callee_ty)) => { self.confirm_builtin_call(call_expr, callee_ty, arg_exprs, expected) } @@ -89,19 +89,19 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn try_overloaded_call_step(&self, call_expr: &'gcx hir::Expr, callee_expr: &'gcx hir::Expr, - adjusted_ty: Ty<'tcx>, - autoderefs: usize) + autoderef: &Autoderef<'a, 'gcx, 'tcx>) -> Option> { - debug!("try_overloaded_call_step(call_expr={:?}, adjusted_ty={:?}, autoderefs={})", + let adjusted_ty = autoderef.unambiguous_final_ty(); + debug!("try_overloaded_call_step(call_expr={:?}, adjusted_ty={:?})", call_expr, - adjusted_ty, - autoderefs); + adjusted_ty); // If the callee is a bare function or a closure, then we're all set. - match self.structurally_resolved_type(callee_expr.span, adjusted_ty).sty { + match adjusted_ty.sty { ty::TyFnDef(..) | ty::TyFnPtr(_) => { + let autoderefs = autoderef.adjust_steps(LvaluePreference::NoPreference); self.apply_autoderef_adjustment(callee_expr.id, autoderefs, adjusted_ty); - return Some(CallStep::Builtin); + return Some(CallStep::Builtin(adjusted_ty)); } ty::TyClosure(def_id, substs) => { @@ -116,15 +116,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { infer::FnCall, &closure_ty) .0; - self.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, - })); + let autoderefs = autoderef.adjust_steps(LvaluePreference::NoPreference); + self.record_deferred_call_resolution(def_id, DeferredCallResolution { + 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)); } } @@ -137,23 +137,32 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // over the top. The simplest fix by far is to just ignore // this case and deref again, so we wind up with // `FnMut::call_mut(&mut *x, ())`. - ty::TyRef(..) if autoderefs == 0 => { + ty::TyRef(..) if autoderef.step_count() == 0 => { return None; } _ => {} } - self.try_overloaded_call_traits(call_expr, callee_expr, adjusted_ty, autoderefs) - .map(|method_callee| CallStep::Overloaded(method_callee)) + self.try_overloaded_call_traits(call_expr, adjusted_ty).map(|(autoref, method)| { + let autoderefs = autoderef.adjust_steps(LvaluePreference::NoPreference); + self.apply_adjustment(callee_expr.id, Adjustment { + kind: Adjust::DerefRef { + autoderefs, + autoref, + unsize: false + }, + target: *method.ty.fn_sig().input(0).skip_binder() + }); + CallStep::Overloaded(method) + }) } fn try_overloaded_call_traits(&self, call_expr: &hir::Expr, - callee_expr: &hir::Expr, - adjusted_ty: Ty<'tcx>, - autoderefs: usize) - -> Option> { + adjusted_ty: Ty<'tcx>) + -> Option<(Option>, + ty::MethodCallee<'tcx>)> { // Try the options that are least restrictive on the caller first. for &(opt_trait_def_id, method_name) in &[(self.tcx.lang_items.fn_trait(), Symbol::intern("call")), @@ -165,20 +174,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }; match self.lookup_method_in_trait_adjusted(call_expr.span, - Some(super::AdjustedRcvr { - rcvr_expr: callee_expr, - autoderefs, - unsize: false - }), method_name, trait_def_id, adjusted_ty, None) { None => continue, - Some(ok) => { - let method_callee = self.register_infer_ok_obligations(ok); - return Some(method_callee); - } + Some(ok) => return Some(self.register_infer_ok_obligations(ok)) } } @@ -313,30 +314,23 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { TupleArgumentsFlag::TupleArguments, expected); - self.write_overloaded_call_method_map(call_expr, method_callee); + self.tables.borrow_mut().method_map.insert(call_expr.id, method_callee); output_type } - - fn write_overloaded_call_method_map(&self, - call_expr: &hir::Expr, - method_callee: ty::MethodCallee<'tcx>) { - let method_call = ty::MethodCall::expr(call_expr.id); - self.tables.borrow_mut().method_map.insert(method_call, method_callee); - } } #[derive(Debug)] -struct CallResolution<'gcx: 'tcx, 'tcx> { +pub struct DeferredCallResolution<'gcx: 'tcx, 'tcx> { call_expr: &'gcx hir::Expr, callee_expr: &'gcx hir::Expr, adjusted_ty: Ty<'tcx>, - autoderefs: usize, + autoderefs: Vec>>, fn_sig: ty::FnSig<'tcx>, closure_def_id: DefId, } -impl<'gcx, 'tcx> DeferredCallResolution<'gcx, 'tcx> for CallResolution<'gcx, 'tcx> { - fn resolve<'a>(&mut self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) { +impl<'a, 'gcx, 'tcx> DeferredCallResolution<'gcx, 'tcx> { + pub fn resolve(self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) { debug!("DeferredCallResolution::resolve() {:?}", self); // we should not be invoked until the closure kind has been @@ -345,10 +339,8 @@ impl<'gcx, 'tcx> DeferredCallResolution<'gcx, 'tcx> for CallResolution<'gcx, 'tc // We may now know enough to figure out fn vs fnmut etc. match fcx.try_overloaded_call_traits(self.call_expr, - self.callee_expr, - self.adjusted_ty, - self.autoderefs) { - Some(method_callee) => { + self.adjusted_ty) { + Some((autoref, method_callee)) => { // One problem is that when we get here, we are going // to have a newly instantiated function signature // from the call trait. This has to be reconciled with @@ -370,7 +362,16 @@ impl<'gcx, 'tcx> DeferredCallResolution<'gcx, 'tcx> for CallResolution<'gcx, 'tc fcx.demand_eqtype(self.call_expr.span, method_sig.output(), self.fn_sig.output()); - fcx.write_overloaded_call_method_map(self.call_expr, method_callee); + fcx.apply_adjustment(self.callee_expr.id, Adjustment { + kind: Adjust::DerefRef { + autoderefs: self.autoderefs, + autoref, + unsize: false + }, + target: method_sig.inputs()[0] + }); + + fcx.tables.borrow_mut().method_map.insert(self.call_expr.id, method_callee); } None => { span_bug!(self.call_expr.span, diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 2d8126225be5d..78559e470aee5 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -110,7 +110,7 @@ fn coerce_mutbls<'tcx>(from_mutbl: hir::Mutability, fn identity<'tcx>() -> Adjust<'tcx> { Adjust::DerefRef { - autoderefs: 0, + autoderefs: vec![], autoref: None, unsize: false, } @@ -157,13 +157,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { }) } - fn coerce(&self, - exprs: &[E], - a: Ty<'tcx>, - b: Ty<'tcx>) - -> CoerceResult<'tcx> - where E: AsCoercionSite - { + fn coerce(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { let a = self.shallow_resolve(a); debug!("Coerce.tys({:?} => {:?})", a, b); @@ -210,7 +204,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { } ty::TyRef(r_b, mt_b) => { - return self.coerce_borrowed_pointer(exprs, a, b, r_b, mt_b); + return self.coerce_borrowed_pointer(a, b, r_b, mt_b); } _ => {} @@ -245,15 +239,12 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { /// Reborrows `&mut A` to `&mut B` and `&(mut) A` to `&B`. /// To match `A` with `B`, autoderef will be performed, /// calling `deref`/`deref_mut` where necessary. - fn coerce_borrowed_pointer(&self, - exprs: &[E], - a: Ty<'tcx>, - b: Ty<'tcx>, - r_b: ty::Region<'tcx>, - mt_b: TypeAndMut<'tcx>) - -> CoerceResult<'tcx> - where E: AsCoercionSite - { + fn coerce_borrowed_pointer(&self, + a: Ty<'tcx>, + b: Ty<'tcx>, + r_b: ty::Region<'tcx>, + mt_b: TypeAndMut<'tcx>) + -> CoerceResult<'tcx> { debug!("coerce_borrowed_pointer(a={:?}, b={:?})", a, b); @@ -375,7 +366,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { }); match self.unify(derefd_ty_a, b) { Ok(ok) => { - found = Some((ok, autoderefs)); + found = Some(ok); break; } Err(err) => { @@ -391,7 +382,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { // (e.g., in example above, the failure from relating `Vec` // to the target type), since that should be the least // confusing. - let (InferOk { value: ty, mut obligations }, autoderefs) = match found { + let InferOk { value: ty, mut obligations } = match found { Some(d) => d, None => { let err = first_error.expect("coerce_borrowed_pointer had no error"); @@ -400,7 +391,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { } }; - if ty == a && mt_a.mutbl == hir::MutImmutable && autoderefs == 1 { + if ty == a && mt_a.mutbl == hir::MutImmutable && autoderef.step_count() == 1 { // As a special case, if we would produce `&'a *x`, that's // a total no-op. We end up with the type `&'a T` just as // we started with. In that case, just skip it @@ -423,17 +414,21 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { _ => span_bug!(span, "expected a ref type, got {:?}", ty), }; let autoref = Some(AutoBorrow::Ref(r_borrow, mt_b.mutbl)); + + let pref = LvaluePreference::from_mutbl(mt_b.mutbl); + let InferOk { value: autoderefs, obligations: o } + = autoderef.adjust_steps_as_infer_ok(pref); + obligations.extend(o); + obligations.extend(autoderef.into_obligations()); + debug!("coerce_borrowed_pointer: succeeded ty={:?} autoderefs={:?} autoref={:?}", ty, autoderefs, autoref); - let pref = LvaluePreference::from_mutbl(mt_b.mutbl); - obligations.extend(autoderef.finalize_as_infer_ok(pref, exprs).obligations); - success(Adjust::DerefRef { - autoderefs: autoderefs, - autoref: autoref, + autoderefs, + autoref, unsize: false, }, ty, obligations) } @@ -477,7 +472,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { let coerce_source = source.adjust_for_autoref(self.tcx, reborrow); let adjust = Adjust::DerefRef { - autoderefs: if reborrow.is_some() { 1 } else { 0 }, + autoderefs: if reborrow.is_some() { vec![None] } else { vec![] }, autoref: reborrow, unsize: true, }; @@ -668,7 +663,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { // regionck knows that the region for `a` must be valid here. self.unify_and(a_unsafe, b, if is_ref { Adjust::DerefRef { - autoderefs: 1, + autoderefs: vec![None], autoref: Some(AutoBorrow::RawPtr(mutbl_b)), unsize: false, } @@ -703,7 +698,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let cause = self.cause(expr.span, ObligationCauseCode::ExprAssignable); let coerce = Coerce::new(self, cause); - let ok = self.commit_if_ok(|_| coerce.coerce(&[expr], source, target))?; + let ok = self.commit_if_ok(|_| coerce.coerce(source, target))?; let adjustment = self.register_infer_ok_obligations(ok); self.apply_adjustment(expr.id, adjustment); @@ -721,7 +716,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let cause = self.cause(syntax_pos::DUMMY_SP, ObligationCauseCode::ExprAssignable); let coerce = Coerce::new(self, cause); - self.probe(|_| coerce.coerce::(&[], source, target)).is_ok() + self.probe(|_| coerce.coerce(source, target)).is_ok() } /// Given some expressions, their known unified type and another expression, @@ -796,7 +791,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // but only if the new expression has no coercion already applied to it. let mut first_error = None; if !self.tables.borrow().adjustments.contains_key(&new.id) { - let result = self.commit_if_ok(|_| coerce.coerce(&[new], new_ty, prev_ty)); + let result = self.commit_if_ok(|_| coerce.coerce(new_ty, prev_ty)); match result { Ok(ok) => { let adjustment = self.register_infer_ok_obligations(ok); @@ -815,10 +810,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let expr = expr.as_coercion_site(); let noop = match self.tables.borrow().adjustments.get(&expr.id).map(|adj| &adj.kind) { Some(&Adjust::DerefRef { - autoderefs: 1, + ref autoderefs, autoref: Some(AutoBorrow::Ref(_, mutbl_adj)), unsize: false - }) => { + }) if autoderefs.len() == 1 => { match self.node_ty(expr.id).sty { ty::TyRef(_, mt_orig) => { // Reborrow that we can safely ignore, because @@ -842,7 +837,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } - match self.commit_if_ok(|_| coerce.coerce(&exprs, prev_ty, new_ty)) { + match self.commit_if_ok(|_| coerce.coerce(prev_ty, new_ty)) { Err(_) => { // Avoid giving strange errors on failed attempts. if let Some(e) = first_error { diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index a9e82a0601fee..b6cd1dfc3d012 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -136,8 +136,10 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { let (autoderefd_ty, n) = autoderef.nth(pick.autoderefs).unwrap(); assert_eq!(n, pick.autoderefs); + let autoderefs = autoderef.adjust_steps(LvaluePreference::NoPreference); + autoderef.unambiguous_final_ty(); - autoderef.finalize(LvaluePreference::NoPreference, self.self_expr); + autoderef.finalize(); let target = pick.unsize.unwrap_or(autoderefd_ty); let target = target.adjust_for_autoref(self.tcx, autoref); @@ -145,8 +147,8 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { // Write out the final adjustment. self.apply_adjustment(self.self_expr.id, Adjustment { kind: Adjust::DerefRef { - autoderefs: pick.autoderefs, - autoref: autoref, + autoderefs, + autoref, unsize: pick.unsize.is_some(), }, target: target @@ -436,19 +438,18 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { // Fix up the autoderefs. Autorefs can only occur immediately preceding // overloaded lvalue ops, and will be fixed by them in order to get // the correct region. - let autoderefs = match self.tables.borrow().adjustments.get(&expr.id) { - Some(&Adjustment { kind: Adjust::DerefRef { autoderefs, .. }, .. }) => autoderefs, - Some(_) | None => 0 - }; - - if autoderefs > 0 { - let mut autoderef = self.autoderef(expr.span, self.node_ty(expr.id)); - autoderef.nth(autoderefs).unwrap_or_else(|| { - span_bug!(expr.span, - "expr was deref-able {} times but now isn't?", - autoderefs); - }); - autoderef.finalize(PreferMutLvalue, expr); + let expr_ty = self.node_ty(expr.id); + if let Some(adj) = self.tables.borrow_mut().adjustments.get_mut(&expr.id) { + if let Adjust::DerefRef { ref mut autoderefs, .. } = adj.kind { + let mut autoderef = self.autoderef(expr.span, expr_ty); + autoderef.nth(autoderefs.len()).unwrap_or_else(|| { + span_bug!(expr.span, + "expr was deref-able as {:?} but now isn't?", + autoderefs); + }); + *autoderefs = autoderef.adjust_steps(LvaluePreference::PreferMutLvalue); + autoderef.finalize(); + } } match expr.node { @@ -474,8 +475,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { { debug!("convert_lvalue_op_to_mutable({:?}, {:?}, {:?}, {:?})", op, expr, base_expr, arg_tys); - let method_call = ty::MethodCall::expr(expr.id); - if !self.tables.borrow().method_map.contains_key(&method_call) { + if !self.tables.borrow().method_map.contains_key(&expr.id) { debug!("convert_lvalue_op_to_mutable - builtin, nothing to do"); return } @@ -490,14 +490,14 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { .ty; let method = self.try_overloaded_lvalue_op( - expr.span, None, base_ty, arg_tys, PreferMutLvalue, op); + expr.span, base_ty, arg_tys, PreferMutLvalue, op); let ok = match method { Some(method) => method, None => return self.tcx.sess.delay_span_bug(expr.span, "re-trying op failed") }; - let method = self.register_infer_ok_obligations(ok); + let (_, method) = self.register_infer_ok_obligations(ok); debug!("convert_lvalue_op_to_mutable: method={:?}", method); - self.tables.borrow_mut().method_map.insert(method_call, method); + self.tables.borrow_mut().method_map.insert(expr.id, method); // Convert the autoref in the base expr to mutable with the correct // region and mutability. diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index 43bf702935ac3..7397c3d48e799 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -10,13 +10,13 @@ //! Method lookup: the secret sauce of Rust. See `README.md`. -use check::{FnCtxt, AdjustedRcvr}; +use check::FnCtxt; use hir::def::Def; use hir::def_id::DefId; use rustc::ty::subst::Substs; use rustc::traits; use rustc::ty::{self, ToPredicate, ToPolyTraitRef, TraitRef, TypeFoldable}; -use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow}; +use rustc::ty::adjustment::AutoBorrow; use rustc::ty::subst::Subst; use rustc::infer::{self, InferOk}; @@ -166,16 +166,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { /// this method is basically the same as confirmation. pub fn lookup_method_in_trait_adjusted(&self, span: Span, - self_info: Option, m_name: ast::Name, trait_def_id: DefId, self_ty: ty::Ty<'tcx>, - opt_input_types: Option>>) - -> Option>> { - debug!("lookup_in_trait_adjusted(self_ty={:?}, self_info={:?}, \ + opt_input_types: Option<&[ty::Ty<'tcx>]>) + -> Option>, + ty::MethodCallee<'tcx>)>> { + debug!("lookup_in_trait_adjusted(self_ty={:?}, \ m_name={}, trait_def_id={:?})", self_ty, - self_info, m_name, trait_def_id); @@ -237,7 +237,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { value } }; - let transformed_self_ty = fn_sig.inputs()[0]; let method_ty = tcx.mk_fn_def(def_id, substs, ty::Binder(fn_sig)); debug!("lookup_in_trait_adjusted: matched method method_ty={:?} obligation={:?}", @@ -267,36 +266,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Also add an obligation for the method type being well-formed. obligations.push(traits::Obligation::new(cause, ty::Predicate::WellFormed(method_ty))); - // Insert any adjustments needed (always an autoref of some mutability). - if let Some(AdjustedRcvr { rcvr_expr, autoderefs, unsize }) = self_info { - debug!("lookup_in_trait_adjusted: inserting adjustment if needed \ - (self-id={}, autoderefs={}, unsize={}, fty={:?})", - rcvr_expr.id, autoderefs, unsize, original_method_ty); - - let original_sig = original_method_ty.fn_sig(); - let autoref = match (&original_sig.input(0).skip_binder().sty, - &transformed_self_ty.sty) { - (&ty::TyRef(..), &ty::TyRef(region, ty::TypeAndMut { mutbl, ty: _ })) => { - // Trait method is fn(&self) or fn(&mut self), need an - // autoref. Pull the region etc out of the type of first argument. - Some(AutoBorrow::Ref(region, mutbl)) - } - _ => { - // Trait method is fn(self), no transformation needed. - assert!(!unsize); - None - } - }; - - self.apply_adjustment(rcvr_expr.id, Adjustment { - kind: Adjust::DerefRef { - autoderefs: autoderefs, - autoref: autoref, - unsize: unsize - }, - target: transformed_self_ty - }); - } + let autoref = match (&original_method_ty.fn_sig().input(0).skip_binder().sty, + &method_ty.fn_sig().input(0).skip_binder().sty) { + (&ty::TyRef(..), &ty::TyRef(region, ty::TypeAndMut { mutbl, ty: _ })) => { + // Trait method is fn(&self) or fn(&mut self), need an + // autoref. Pull the region etc out of the type of first argument. + Some(AutoBorrow::Ref(region, mutbl)) + } + _ => { + // Trait method is fn(self), no transformation needed. + None + } + }; let callee = ty::MethodCallee { def_id: def_id, @@ -308,7 +289,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { Some(InferOk { obligations, - value: callee + value: (autoref, callee) }) } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index bee4a18523e1e..ed37b55d03057 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -77,6 +77,8 @@ type parameter). */ pub use self::Expectation::*; +use self::autoderef::Autoderef; +use self::callee::DeferredCallResolution; use self::coercion::{CoerceMany, DynamicCoerceMany}; pub use self::compare_method::{compare_impl_method, compare_const_impl}; use self::TupleArgumentsFlag::*; @@ -93,7 +95,7 @@ use rustc::ty::subst::{Kind, Subst, Substs}; use rustc::traits::{self, FulfillmentContext, ObligationCause, ObligationCauseCode, Reveal}; use rustc::ty::{ParamTy, LvaluePreference, NoPreference, PreferMutLvalue}; use rustc::ty::{self, Ty, TyCtxt, Visibility}; -use rustc::ty::{MethodCall, MethodCallee}; +use rustc::ty::{MethodCallee}; use rustc::ty::adjustment::{Adjust, Adjustment, AutoBorrow}; use rustc::ty::fold::{BottomUpFolder, TypeFoldable}; use rustc::ty::maps::Providers; @@ -168,7 +170,7 @@ pub struct Inherited<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { // decision. We keep these deferred resolutions grouped by the // def-id of the closure, so that once we decide, we can easily go // back and process them. - deferred_call_resolutions: RefCell>>>, + deferred_call_resolutions: RefCell>>>, deferred_cast_checks: RefCell>>, @@ -194,12 +196,6 @@ impl<'a, 'gcx, 'tcx> Deref for Inherited<'a, 'gcx, 'tcx> { } } -trait DeferredCallResolution<'gcx, 'tcx> { - fn resolve<'a>(&mut self, fcx: &FnCtxt<'a, 'gcx, 'tcx>); -} - -type DeferredCallResolutionHandler<'gcx, 'tcx> = Box+'tcx>; - /// When type-checking an expression, we propagate downward /// whatever type hint we are able in the form of an `Expectation`. #[derive(Copy, Clone, Debug)] @@ -375,13 +371,6 @@ pub enum LvalueOp { Index } -#[derive(Copy, Clone, Debug)] -pub struct AdjustedRcvr<'a> { - pub rcvr_expr: &'a hir::Expr, - pub autoderefs: usize, - pub unsize: bool -} - /// Tracks whether executing a node may exit normally (versus /// return/break/panic, which "diverge", leaving dead code in their /// wake). Tracked semi-automatically (through type variables marked @@ -1729,17 +1718,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn record_deferred_call_resolution(&self, closure_def_id: DefId, - r: DeferredCallResolutionHandler<'gcx, 'tcx>) { + r: DeferredCallResolution<'gcx, 'tcx>) { let mut deferred_call_resolutions = self.deferred_call_resolutions.borrow_mut(); deferred_call_resolutions.entry(closure_def_id).or_insert(vec![]).push(r); } fn remove_deferred_call_resolutions(&self, closure_def_id: DefId) - -> Vec> + -> Vec> { let mut deferred_call_resolutions = self.deferred_call_resolutions.borrow_mut(); - deferred_call_resolutions.remove(&closure_def_id).unwrap_or(Vec::new()) + deferred_call_resolutions.remove(&closure_def_id).unwrap_or(vec![]) } pub fn tag(&self) -> String { @@ -1782,11 +1771,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn apply_autoderef_adjustment(&self, node_id: ast::NodeId, - derefs: usize, + autoderefs: Vec>>, adjusted_ty: Ty<'tcx>) { self.apply_adjustment(node_id, Adjustment { kind: Adjust::DerefRef { - autoderefs: derefs, + autoderefs, autoref: None, unsize: false }, @@ -1805,18 +1794,19 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { Entry::Vacant(entry) => { entry.insert(adj); }, Entry::Occupied(mut entry) => { debug!(" - composing on top of {:?}", entry.get()); - let composed_kind = match (&entry.get().kind, &adj.kind) { + match (&entry.get().kind, &adj.kind) { // Applying any adjustment on top of a NeverToAny // is a valid NeverToAny adjustment, because it can't // be reached. - (&Adjust::NeverToAny, _) => Adjust::NeverToAny, + (&Adjust::NeverToAny, _) => return, (&Adjust::DerefRef { - autoderefs: 1, + autoderefs: ref old, autoref: Some(AutoBorrow::Ref(..)), unsize: false - }, &Adjust::DerefRef { autoderefs, .. }) if autoderefs > 0 => { + }, &Adjust::DerefRef { + autoderefs: ref new, .. + }) if old.len() == 1 && new.len() >= 1 => { // A reborrow has no effect before a dereference. - adj.kind } // FIXME: currently we never try to compose autoderefs // and ReifyFnPointer/UnsafeFnPointer, but we could. @@ -1824,10 +1814,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { bug!("while adjusting {}, can't compose {:?} and {:?}", node_id, entry.get(), adj) }; - *entry.get_mut() = Adjustment { - kind: composed_kind, - target: adj.target - }; + *entry.get_mut() = adj; } } } @@ -2189,32 +2176,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // consolidated. let mut autoderef = self.autoderef(base_expr.span, base_ty); - - while let Some((adj_ty, autoderefs)) = autoderef.next() { - if let Some(final_mt) = self.try_index_step( - MethodCall::expr(expr.id), expr, Some(AdjustedRcvr { - rcvr_expr: base_expr, - autoderefs, - unsize: false - }), base_expr.span, adj_ty, lvalue_pref, idx_ty) - { - autoderef.finalize(lvalue_pref, base_expr); - return Some(final_mt); - } - - if let ty::TyArray(element_ty, _) = adj_ty.sty { - autoderef.finalize(lvalue_pref, base_expr); - let adj_ty = self.tcx.mk_slice(element_ty); - return self.try_index_step( - MethodCall::expr(expr.id), expr, Some(AdjustedRcvr { - rcvr_expr: base_expr, - autoderefs, - unsize: true - }), base_expr.span, adj_ty, lvalue_pref, idx_ty) - } + let mut result = None; + while result.is_none() && autoderef.next().is_some() { + result = self.try_index_step(expr, base_expr, &autoderef, lvalue_pref, idx_ty); } - autoderef.unambiguous_final_ty(); - None + autoderef.finalize(); + result } /// To type-check `base_expr[index_expr]`, we progressively autoderef @@ -2223,16 +2190,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { /// This loop implements one step in that search; the autoderef loop /// is implemented by `lookup_indexing`. fn try_index_step(&self, - method_call: MethodCall, expr: &hir::Expr, - base_expr: Option, - base_span: Span, - adjusted_ty: Ty<'tcx>, + base_expr: &hir::Expr, + autoderef: &Autoderef<'a, 'gcx, 'tcx>, lvalue_pref: LvaluePreference, index_ty: Ty<'tcx>) -> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)> { - let tcx = self.tcx; + let mut adjusted_ty = autoderef.unambiguous_final_ty(); debug!("try_index_step(expr={:?}, base_expr={:?}, adjusted_ty={:?}, \ index_ty={:?})", expr, @@ -2240,35 +2205,59 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { adjusted_ty, index_ty); - let input_ty = self.next_ty_var(TypeVariableOrigin::AutoDeref(base_span)); // First, try built-in indexing. match (adjusted_ty.builtin_index(), &index_ty.sty) { (Some(ty), &ty::TyUint(ast::UintTy::Us)) | (Some(ty), &ty::TyInfer(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]`. - if let Some(base_expr) = base_expr { - assert!(!base_expr.unsize); - self.apply_autoderef_adjustment( - base_expr.rcvr_expr.id, base_expr.autoderefs, adjusted_ty); - } - return Some((tcx.types.usize, ty)); + let autoderefs = autoderef.adjust_steps(lvalue_pref); + self.apply_autoderef_adjustment( + base_expr.id, autoderefs, adjusted_ty); + return Some((self.tcx.types.usize, ty)); } _ => {} } - // If some lookup succeeds, write callee into table and extract index/element - // type from the method signature. - // If some lookup succeeded, install method in table - let method = self.try_overloaded_lvalue_op( - expr.span, base_expr, adjusted_ty, &[input_ty], lvalue_pref, LvalueOp::Index); - - method.map(|ok| { - debug!("try_index_step: success, using overloaded indexing"); - let method = self.register_infer_ok_obligations(ok); - self.tables.borrow_mut().method_map.insert(method_call, method); - (input_ty, self.make_overloaded_lvalue_return_type(method).ty) - }) + for &unsize in &[false, true] { + if unsize { + // We only unsize arrays here. + if let ty::TyArray(element_ty, _) = adjusted_ty.sty { + adjusted_ty = self.tcx.mk_slice(element_ty); + } else { + continue; + } + } + + // If some lookup succeeds, write callee into table and extract index/element + // type from the method signature. + // If some lookup succeeded, install method in table + let input_ty = self.next_ty_var(TypeVariableOrigin::AutoDeref(base_expr.span)); + let method = self.try_overloaded_lvalue_op( + expr.span, adjusted_ty, &[input_ty], lvalue_pref, LvalueOp::Index); + + let result = method.map(|ok| { + debug!("try_index_step: success, using overloaded indexing"); + let (autoref, method) = self.register_infer_ok_obligations(ok); + + let autoderefs = autoderef.adjust_steps(lvalue_pref); + self.apply_adjustment(base_expr.id, Adjustment { + kind: Adjust::DerefRef { + autoderefs, + autoref, + unsize + }, + target: *method.ty.fn_sig().input(0).skip_binder() + }); + + self.tables.borrow_mut().method_map.insert(expr.id, method); + (input_ty, self.make_overloaded_lvalue_return_type(method).ty) + }); + if result.is_some() { + return result; + } + } + + None } fn resolve_lvalue_op(&self, op: LvalueOp, is_mut: bool) -> (Option, Symbol) { @@ -2287,16 +2276,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn try_overloaded_lvalue_op(&self, span: Span, - base_expr: Option, base_ty: Ty<'tcx>, arg_tys: &[Ty<'tcx>], lvalue_pref: LvaluePreference, op: LvalueOp) - -> Option>> + -> Option>, + ty::MethodCallee<'tcx>)>> { - debug!("try_overloaded_lvalue_op({:?},{:?},{:?},{:?},{:?})", + debug!("try_overloaded_lvalue_op({:?},{:?},{:?},{:?})", span, - base_expr, base_ty, lvalue_pref, op); @@ -2306,11 +2295,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let method = match (lvalue_pref, mut_tr) { (PreferMutLvalue, Some(trait_did)) => { self.lookup_method_in_trait_adjusted(span, - base_expr, mut_op, trait_did, base_ty, - Some(arg_tys.to_owned())) + Some(arg_tys)) } _ => None, }; @@ -2320,11 +2308,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let method = match (method, imm_tr) { (None, Some(trait_did)) => { self.lookup_method_in_trait_adjusted(span, - base_expr, imm_op, trait_did, base_ty, - Some(arg_tys.to_owned())) + Some(arg_tys)) } (method, _) => method, }; @@ -2802,10 +2789,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { expr, rcvr) { Ok(method) => { - let method_ty = method.ty; - let method_call = MethodCall::expr(expr.id); - self.tables.borrow_mut().method_map.insert(method_call, method); - method_ty + self.tables.borrow_mut().method_map.insert(expr.id, method); + method.ty } Err(error) => { if method_name.node != keywords::Invalid.name() { @@ -2912,7 +2897,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { expr_t); let mut private_candidate = None; let mut autoderef = self.autoderef(expr.span, expr_t); - while let Some((base_t, autoderefs)) = autoderef.next() { + while let Some((base_t, _)) = autoderef.next() { match base_t.sty { ty::TyAdt(base_def, substs) if !base_def.is_enum() => { debug!("struct named {:?}", base_t); @@ -2922,8 +2907,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let Some(field) = fields.iter().find(|f| f.name.to_ident() == ident) { let field_ty = self.field_ty(expr.span, field, substs); if field.vis.is_accessible_from(def_scope, self.tcx) { - autoderef.finalize(lvalue_pref, base); + let autoderefs = autoderef.adjust_steps(lvalue_pref); self.apply_autoderef_adjustment(base.id, autoderefs, base_t); + autoderef.finalize(); self.tcx.check_stability(field.did, expr.id, expr.span); @@ -3020,7 +3006,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let mut private_candidate = None; let mut tuple_like = false; let mut autoderef = self.autoderef(expr.span, expr_t); - while let Some((base_t, autoderefs)) = autoderef.next() { + while let Some((base_t, _)) = autoderef.next() { let field = match base_t.sty { ty::TyAdt(base_def, substs) if base_def.is_struct() => { tuple_like = base_def.struct_variant().ctor_kind == CtorKind::Fn; @@ -3055,8 +3041,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }; if let Some(field_ty) = field { - autoderef.finalize(lvalue_pref, base); + let autoderefs = autoderef.adjust_steps(lvalue_pref); self.apply_autoderef_adjustment(base.id, autoderefs, base_t); + autoderef.finalize(); return field_ty; } } @@ -3470,11 +3457,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let Some(mt) = oprnd_t.builtin_deref(true, NoPreference) { oprnd_t = mt.ty; } else if let Some(ok) = self.try_overloaded_deref( - expr.span, Some(&oprnd), oprnd_t, lvalue_pref) { - let method = self.register_infer_ok_obligations(ok); + expr.span, oprnd_t, lvalue_pref) { + let (autoref, method) = self.register_infer_ok_obligations(ok); + self.apply_adjustment(oprnd.id, Adjustment { + kind: Adjust::DerefRef { + autoderefs: vec![], + autoref, + unsize: false + }, + target: *method.ty.fn_sig().input(0).skip_binder() + }); oprnd_t = self.make_overloaded_lvalue_return_type(method).ty; - self.tables.borrow_mut().method_map.insert(MethodCall::expr(expr.id), - method); + self.tables.borrow_mut().method_map.insert(expr.id, method); } else { self.type_error_message(expr.span, |actual| { format!("type `{}` cannot be \ diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index 3709260acc997..0ac568f2090b6 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -14,6 +14,7 @@ use super::FnCtxt; use hir::def_id::DefId; use rustc::ty::{Ty, TypeFoldable, PreferMutLvalue, TypeVariants}; use rustc::ty::TypeVariants::{TyStr, TyRef}; +use rustc::ty::adjustment::{Adjustment, Adjust}; use rustc::infer::type_variable::TypeVariableOrigin; use errors; use syntax::ast; @@ -184,7 +185,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // particularly for things like `String + &String`. let rhs_ty_var = self.next_ty_var(TypeVariableOrigin::MiscVariable(rhs_expr.span)); - let return_ty = self.lookup_op_method(expr, lhs_ty, vec![rhs_ty_var], + let return_ty = self.lookup_op_method(expr, lhs_ty, &[rhs_ty_var], Symbol::intern(name), trait_def_id, lhs_expr); @@ -214,7 +215,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let TypeVariants::TyRef(_, ref ty_mut) = lhs_ty.sty { if !self.infcx.type_moves_by_default(ty_mut.ty, lhs_expr.span) && - self.lookup_op_method(expr, ty_mut.ty, vec![rhs_ty], + self.lookup_op_method(expr, ty_mut.ty, &[rhs_ty], Symbol::intern(name), trait_def_id, lhs_expr).is_ok() { err.note( @@ -313,7 +314,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { { assert!(op.is_by_value()); let mname = Symbol::intern(mname); - match self.lookup_op_method(ex, operand_ty, vec![], mname, trait_did, operand_expr) { + match self.lookup_op_method(ex, operand_ty, &[], mname, trait_did, operand_expr) { Ok(t) => t, Err(()) => { let actual = self.resolve_type_vars_if_possible(&operand_ty); @@ -382,7 +383,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn lookup_op_method(&self, expr: &'gcx hir::Expr, lhs_ty: Ty<'tcx>, - other_tys: Vec>, + other_tys: &[Ty<'tcx>], opname: ast::Name, trait_did: Option, lhs_expr: &'a hir::Expr) @@ -398,11 +399,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let method = match trait_did { Some(trait_did) => { - let lhs_expr = Some(super::AdjustedRcvr { - rcvr_expr: lhs_expr, autoderefs: 0, unsize: false - }); self.lookup_method_in_trait_adjusted(expr.span, - lhs_expr, opname, trait_did, lhs_ty, @@ -413,18 +410,22 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { match method { Some(ok) => { - let method = self.register_infer_ok_obligations(ok); + let (autoref, method) = self.register_infer_ok_obligations(ok); self.select_obligations_where_possible(); - let method_ty = method.ty; - - // HACK(eddyb) Fully qualified path to work around a resolve bug. - let method_call = ::rustc::ty::MethodCall::expr(expr.id); - self.tables.borrow_mut().method_map.insert(method_call, method); + self.apply_adjustment(lhs_expr.id, Adjustment { + kind: Adjust::DerefRef { + autoderefs: vec![], + autoref, + unsize: false + }, + target: *method.ty.fn_sig().input(0).skip_binder() + }); + self.tables.borrow_mut().method_map.insert(expr.id, method); // extract return type for method; all late bound regions // should have been instantiated by now - let ret_ty = method_ty.fn_ret(); + let ret_ty = method.ty.fn_ret(); Ok(self.tcx.no_late_bound_regions(&ret_ty).unwrap()) } None => { diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 2c4188e392d8d..6cb9375c5de79 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -91,7 +91,7 @@ use middle::region::{CodeExtent, RegionMaps}; use rustc::hir::def_id::DefId; use rustc::ty::subst::Substs; use rustc::traits; -use rustc::ty::{self, Ty, MethodCall, TypeFoldable}; +use rustc::ty::{self, Ty, TypeFoldable}; use rustc::infer::{self, GenericKind, SubregionOrigin, VerifyBound}; use rustc::ty::adjustment; use rustc::ty::wf::ImpliedBound; @@ -520,8 +520,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> { self.type_must_outlive(infer::ExprTypeIsNotInScope(expr_ty, expr.span), expr_ty, expr_region); - let method_call = MethodCall::expr(expr.id); - let opt_method_callee = self.tables.borrow().method_map.get(&method_call).cloned(); + let opt_method_callee = self.tables.borrow().method_map.get(&expr.id).cloned(); let has_method_map = opt_method_callee.is_some(); // If we are calling a method (either explicitly or via an @@ -548,11 +547,10 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> { if let Some(adjustment) = adjustment { debug!("adjustment={:?}", adjustment); match adjustment.kind { - adjustment::Adjust::DerefRef { autoderefs, ref autoref, .. } => { - let expr_ty = self.resolve_node_type(expr.id); - self.constrain_autoderefs(expr, autoderefs, expr_ty); + adjustment::Adjust::DerefRef { ref autoderefs, ref autoref, .. } => { + let cmt = ignore_err!(self.constrain_autoderefs(expr, autoderefs)); if let Some(ref autoref) = *autoref { - self.link_autoref(expr, autoderefs, autoref); + self.link_autoref(expr, cmt, autoref); // Require that the resulting region encompasses // the current node. @@ -690,8 +688,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> { hir::ExprUnary(hir::UnDeref, ref base) => { // For *a, the lifetime of a must enclose the deref - let method_call = MethodCall::expr(expr.id); - let base_ty = match self.tables.borrow().method_map.get(&method_call) { + let base_ty = match self.tables.borrow().method_map.get(&expr.id) { Some(method) => { self.constrain_call(expr, Some(&base), None::.iter(), true); @@ -914,79 +911,68 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { /// dereferenced, the lifetime of the pointer includes the deref expr. fn constrain_autoderefs(&mut self, deref_expr: &hir::Expr, - derefs: usize, - mut derefd_ty: Ty<'tcx>) + autoderefs: &[Option>]) + -> mc::McResult> { - debug!("constrain_autoderefs(deref_expr={:?}, derefs={}, derefd_ty={:?})", + debug!("constrain_autoderefs(deref_expr={:?}, autoderefs={:?})", deref_expr, - derefs, - derefd_ty); + autoderefs); + + let mut cmt = { + let mc = mc::MemCategorizationContext::new(self, &self.region_maps); + mc.cat_expr_unadjusted(deref_expr)? + }; let r_deref_expr = self.tcx.node_scope_region(deref_expr.id); - for i in 0..derefs { - let method_call = MethodCall::autoderef(deref_expr.id, i as u32); - debug!("constrain_autoderefs: method_call={:?} (of {:?} total)", method_call, derefs); - - let method = self.tables.borrow().method_map.get(&method_call).map(|m| m.clone()); - - derefd_ty = match method { - Some(method) => { - debug!("constrain_autoderefs: #{} is overloaded, method={:?}", - i, method); - - let origin = infer::ParameterOrigin::OverloadedDeref; - self.substs_wf_in_scope(origin, method.substs, deref_expr.span, r_deref_expr); - - // Treat overloaded autoderefs as if an AutoBorrow adjustment - // was applied on the base type, as that is always the case. - let fn_sig = method.ty.fn_sig(); - let fn_sig = // late-bound regions should have been instantiated - self.tcx.no_late_bound_regions(&fn_sig).unwrap(); - let self_ty = fn_sig.inputs()[0]; - let (m, r) = match self_ty.sty { - ty::TyRef(r, ref m) => (m.mutbl, r), - _ => { - span_bug!( - deref_expr.span, - "bad overloaded deref type {:?}", - method.ty) - } - }; - - debug!("constrain_autoderefs: receiver r={:?} m={:?}", - r, m); - - { - let mc = mc::MemCategorizationContext::new(self, &self.region_maps); - let self_cmt = ignore_err!(mc.cat_expr_autoderefd(deref_expr, i)); - debug!("constrain_autoderefs: self_cmt={:?}", - self_cmt); - self.link_region(deref_expr.span, r, - ty::BorrowKind::from_mutbl(m), self_cmt); + for &overloaded in autoderefs { + if let Some(method) = overloaded { + debug!("constrain_autoderefs: overloaded, method={:?}", method); + + let origin = infer::ParameterOrigin::OverloadedDeref; + self.substs_wf_in_scope(origin, method.substs, deref_expr.span, r_deref_expr); + + // Treat overloaded autoderefs as if an AutoBorrow adjustment + // was applied on the base type, as that is always the case. + let fn_sig = method.ty.fn_sig(); + let fn_sig = // late-bound regions should have been instantiated + self.tcx.no_late_bound_regions(&fn_sig).unwrap(); + let self_ty = fn_sig.inputs()[0]; + let (m, r) = match self_ty.sty { + ty::TyRef(r, ref m) => (m.mutbl, r), + _ => { + span_bug!( + deref_expr.span, + "bad overloaded deref type {:?}", + method.ty) } + }; - // Specialized version of constrain_call. - self.type_must_outlive(infer::CallRcvr(deref_expr.span), - self_ty, r_deref_expr); - self.type_must_outlive(infer::CallReturn(deref_expr.span), - fn_sig.output(), r_deref_expr); - fn_sig.output() - } - None => derefd_ty - }; + debug!("constrain_autoderefs: receiver r={:?} m={:?}", + r, m); - if let ty::TyRef(r_ptr, _) = derefd_ty.sty { - self.mk_subregion_due_to_dereference(deref_expr.span, - r_deref_expr, r_ptr); + debug!("constrain_autoderefs: self_cmt={:?}", cmt); + self.link_region(deref_expr.span, r, + ty::BorrowKind::from_mutbl(m), cmt.clone()); + + // Specialized version of constrain_call. + self.type_must_outlive(infer::CallRcvr(deref_expr.span), + self_ty, r_deref_expr); + self.type_must_outlive(infer::CallReturn(deref_expr.span), + fn_sig.output(), r_deref_expr); } - match derefd_ty.builtin_deref(true, ty::NoPreference) { - Some(mt) => derefd_ty = mt.ty, - /* if this type can't be dereferenced, then there's already an error - in the session saying so. Just bail out for now */ - None => break + { + let mc = mc::MemCategorizationContext::new(self, &self.region_maps); + cmt = mc.cat_deref(deref_expr, cmt, overloaded)?; + } + + if let Categorization::Deref(_, mc::BorrowedPtr(_, r_ptr)) = cmt.cat { + self.mk_subregion_due_to_dereference(deref_expr.span, + r_deref_expr, r_ptr); } } + + Ok(cmt) } pub fn mk_subregion_due_to_dereference(&mut self, @@ -1151,13 +1137,10 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { /// autoref'd. fn link_autoref(&self, expr: &hir::Expr, - autoderefs: usize, + expr_cmt: mc::cmt<'tcx>, autoref: &adjustment::AutoBorrow<'tcx>) { - debug!("link_autoref(autoderefs={}, autoref={:?})", autoderefs, autoref); - let mc = mc::MemCategorizationContext::new(self, &self.region_maps); - let expr_cmt = ignore_err!(mc.cat_expr_autoderefd(expr, autoderefs)); - debug!("expr_cmt={:?}", expr_cmt); + debug!("link_autoref(autoref={:?}, expr_cmt={:?})", autoref, expr_cmt); match *autoref { adjustment::AutoBorrow::Ref(r, m) => { diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs index 799d6186653e4..286d0ad1b35a3 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/src/librustc_typeck/check/upvar.rs @@ -216,9 +216,9 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { let closure_def_id = self.fcx.tcx.hir.local_def_id(id); debug!("closure_kind({:?}) = {:?}", closure_def_id, kind); - let mut deferred_call_resolutions = + let deferred_call_resolutions = self.fcx.remove_deferred_call_resolutions(closure_def_id); - for deferred_call_resolution in &mut deferred_call_resolutions { + for deferred_call_resolution in deferred_call_resolutions { deferred_call_resolution.resolve(self.fcx); } } diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index b43e2423757d1..5fa5bb8f7af99 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -16,7 +16,7 @@ use check::FnCtxt; use rustc::hir; use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; use rustc::infer::{InferCtxt}; -use rustc::ty::{self, Ty, TyCtxt, MethodCall, MethodCallee}; +use rustc::ty::{self, Ty, TyCtxt, MethodCallee}; use rustc::ty::adjustment; use rustc::ty::fold::{TypeFolder,TypeFoldable}; use rustc::util::nodemap::DefIdSet; @@ -106,7 +106,7 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { let inner_ty = self.fcx.resolve_type_vars_if_possible(&inner_ty); if inner_ty.is_scalar() { - self.fcx.tables.borrow_mut().method_map.remove(&MethodCall::expr(e.id)); + self.fcx.tables.borrow_mut().method_map.remove(&e.id); } } hir::ExprBinary(ref op, ref lhs, ref rhs) | @@ -118,7 +118,7 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { let rhs_ty = self.fcx.resolve_type_vars_if_possible(&rhs_ty); if lhs_ty.is_scalar() && rhs_ty.is_scalar() { - self.fcx.tables.borrow_mut().method_map.remove(&MethodCall::expr(e.id)); + self.fcx.tables.borrow_mut().method_map.remove(&e.id); // weird but true: the by-ref binops put an // adjustment on the lhs but not the rhs; the @@ -164,7 +164,7 @@ impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> { self.fix_scalar_builtin_expr(e); self.visit_node_id(e.span, e.id); - self.visit_method_map_entry(e.span, MethodCall::expr(e.id)); + self.visit_method_map_entry(e.span, e.id); if let hir::ExprClosure(_, _, body, _) = e.node { let body = self.fcx.tcx.hir.body(body); @@ -335,13 +335,16 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { } adjustment::Adjust::DerefRef { autoderefs, autoref, unsize } => { - for autoderef in 0..autoderefs { - let method_call = MethodCall::autoderef(node_id, autoderef as u32); - self.visit_method_map_entry(span, method_call); - } - adjustment::Adjust::DerefRef { - autoderefs: autoderefs, + autoderefs: autoderefs.iter().map(|overloaded| { + overloaded.map(|method| { + MethodCallee { + def_id: method.def_id, + ty: self.resolve(&method.ty, &span), + substs: self.resolve(&method.substs, &span), + } + }) + }).collect(), autoref: self.resolve(&autoref, &span), unsize: unsize, } @@ -359,27 +362,22 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { fn visit_method_map_entry(&mut self, method_span: Span, - method_call: MethodCall) { + node_id: ast::NodeId) { // Resolve any method map entry - let new_method = match self.fcx.tables.borrow_mut().method_map.remove(&method_call) { + let new_method = match self.fcx.tables.borrow_mut().method_map.remove(&node_id) { Some(method) => { - debug!("writeback::resolve_method_map_entry(call={:?}, entry={:?})", - method_call, - method); - let new_method = MethodCallee { + Some(MethodCallee { def_id: method.def_id, ty: self.resolve(&method.ty, &method_span), substs: self.resolve(&method.substs, &method_span), - }; - - Some(new_method) + }) } None => None }; //NB(jroesch): We need to match twice to avoid a double borrow which would cause an ICE if let Some(method) = new_method { - self.tables.method_map.insert(method_call, method); + self.tables.method_map.insert(node_id, method); } } From 22510f32666d0c9c230c9d09e5bcd9eb3a6200b3 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Wed, 17 May 2017 22:51:18 +0300 Subject: [PATCH 04/14] rustc: replace TyFnDef in MethodCallee with just the FnSig. --- src/librustc/ich/impls_ty.rs | 2 +- src/librustc/middle/effect.rs | 6 +- src/librustc/middle/expr_use_visitor.rs | 5 +- src/librustc/middle/liveness.rs | 6 +- src/librustc/middle/mem_categorization.rs | 10 +-- src/librustc/ty/mod.rs | 8 ++- src/librustc/ty/sty.rs | 9 --- src/librustc_mir/build/expr/into.rs | 9 +-- src/librustc_mir/hair/cx/expr.rs | 18 ++--- src/librustc_typeck/check/_match.rs | 3 +- src/librustc_typeck/check/callee.rs | 16 ++--- src/librustc_typeck/check/method/confirm.rs | 18 ++--- src/librustc_typeck/check/method/mod.rs | 4 +- src/librustc_typeck/check/mod.rs | 79 ++++++++++----------- src/librustc_typeck/check/op.rs | 7 +- src/librustc_typeck/check/regionck.rs | 19 +++-- src/librustc_typeck/check/writeback.rs | 4 +- 17 files changed, 88 insertions(+), 135 deletions(-) diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 0575bfcf926f5..63dc2e2d8e13f 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -112,7 +112,7 @@ impl<'a, 'tcx> HashStable> for ty::adjustment::Ad } impl_stable_hash_for!(struct ty::adjustment::Adjustment<'tcx> { kind, target }); -impl_stable_hash_for!(struct ty::MethodCallee<'tcx> { def_id, ty, substs }); +impl_stable_hash_for!(struct ty::MethodCallee<'tcx> { def_id, substs, sig }); impl_stable_hash_for!(struct ty::UpvarId { var_id, closure_expr_id }); impl_stable_hash_for!(struct ty::UpvarBorrow<'tcx> { kind, region }); diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs index 1d3f8e426e713..e84265cb60f74 100644 --- a/src/librustc/middle/effect.rs +++ b/src/librustc/middle/effect.rs @@ -173,10 +173,10 @@ impl<'a, 'tcx> Visitor<'tcx> for EffectCheckVisitor<'a, 'tcx> { fn visit_expr(&mut self, expr: &'tcx hir::Expr) { match expr.node { hir::ExprMethodCall(..) => { - let base_type = self.tables.method_map[&expr.id].ty; + let method_sig = self.tables.method_map[&expr.id].sig; debug!("effect: method call case, base type is {:?}", - base_type); - if type_is_unsafe_function(base_type) { + method_sig); + if method_sig.unsafety == hir::Unsafety::Unsafe { self.require_unsafe(expr.span, "invocation of unsafe method") } diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 64880bf4fadf4..73598d0bb1a05 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -751,11 +751,8 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { for &overloaded in autoderefs { if let Some(method) = overloaded { - // the method call infrastructure should have - // replaced all late-bound regions with variables: - let self_ty = method.ty.fn_sig().input(0); + let self_ty = method.sig.inputs()[0]; let self_ty = self.mc.infcx.resolve_type_vars_if_possible(&self_ty); - let self_ty = self.tcx().no_late_bound_regions(&self_ty).unwrap(); let (m, r) = match self_ty.sty { ty::TyRef(r, ref m) => (m.mutbl, r), diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index d5c0a67f71ce9..fd8ca332a6449 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -1073,7 +1073,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { hir::ExprCall(ref f, ref args) => { // FIXME(canndrew): This is_never should really be an is_uninhabited let diverges = !self.tables.is_method_call(expr.id) && - self.tables.expr_ty_adjusted(&f).fn_ret().0.is_never(); + self.tables.expr_ty_adjusted(&f).fn_sig().output().0.is_never(); let succ = if diverges { self.s.exit_ln } else { @@ -1084,9 +1084,9 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { } hir::ExprMethodCall(.., ref args) => { - let method_ty = self.tables.method_map[&expr.id].ty; + let ret_ty = self.tables.method_map[&expr.id].sig.output(); // FIXME(canndrew): This is_never should really be an is_uninhabited - let succ = if method_ty.fn_ret().0.is_never() { + let succ = if ret_ty.is_never() { self.s.exit_ln } else { succ diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 4e2150dc2c61f..aa729c75796af 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -1250,13 +1250,9 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { -> Ty<'tcx> { // When we process an overloaded `*` or `[]` etc, we often - // need to extract the return type of the method. These method - // types are generated by method resolution and always have - // all late-bound regions fully instantiated, so we just want - // to skip past the binder. - let ret_ty = method.ty.fn_ret(); - let ret_ty = self.infcx.resolve_type_vars_if_possible(&ret_ty); - self.tcx().no_late_bound_regions(&ret_ty).unwrap() + // need to extract the return type of the method. + let ret_ty = method.sig.output(); + self.infcx.resolve_type_vars_if_possible(&ret_ty) } } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 08016ac91bf29..d138b306732ca 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -394,8 +394,12 @@ impl Variance { pub struct MethodCallee<'tcx> { /// Impl method ID, for inherent methods, or trait method ID, otherwise. pub def_id: DefId, - pub ty: Ty<'tcx>, - pub substs: &'tcx Substs<'tcx> + pub substs: &'tcx Substs<'tcx>, + + /// Instantiated method signature, i.e. it has been substituted, + /// normalized, and has had late-bound lifetimes replaced + /// (with inference variables, during type-checking). + pub sig: FnSig<'tcx>, } // Contains information needed to resolve types and (in the future) look up diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 348d164af4190..df7c2e567f7e6 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -1313,15 +1313,6 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { } } - /// Type accessors for substructures of types - pub fn fn_args(&self) -> ty::Binder<&'tcx [Ty<'tcx>]> { - self.fn_sig().inputs() - } - - pub fn fn_ret(&self) -> Binder> { - self.fn_sig().output() - } - pub fn is_fn(&self) -> bool { match self.sty { TyFnDef(..) | TyFnPtr(_) => true, diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index 5982d3bdc81a4..d456bc3ded390 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -201,13 +201,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { exit_block.unit() } ExprKind::Call { ty, fun, args } => { - let diverges = match ty.sty { - ty::TyFnDef(_, _, ref f) | ty::TyFnPtr(ref f) => { - // FIXME(canndrew): This is_never should probably be an is_uninhabited - f.output().skip_binder().is_never() - } - _ => false - }; + // FIXME(canndrew): This is_never should probably be an is_uninhabited + let diverges = expr.ty.is_never(); let intrinsic = match ty.sty { ty::TyFnDef(def_id, _, ref f) if f.abi() == Abi::RustIntrinsic || diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 6c48e0120ba7e..6428146525cd4 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -18,6 +18,7 @@ use rustc::hir::def::{Def, CtorKind}; use rustc::middle::const_val::ConstVal; use rustc::ty::{self, AdtKind, VariantDef, Ty}; use rustc::ty::cast::CastKind as TyCastKind; +use rustc::ty::subst::Subst; use rustc::hir; use syntax::ptr::P; @@ -92,9 +93,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { let kind = if let Some(method) = overloaded { debug!("make_mirror: overloaded autoderef (method={:?})", method); - // Method calls always have all late-bound regions - // fully instantiated. - ref_ty = cx.tcx.no_late_bound_regions(&method.ty.fn_ret()).unwrap(); + ref_ty = method.sig.output(); let (region, mutbl) = match ref_ty.sty { ty::TyRef(region, mt) => (region, mt.mutbl), _ => span_bug!(expr.span, "autoderef returned bad type"), @@ -265,14 +264,9 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, // rewrite f(u, v) into FnOnce::call_once(f, (u, v)) + let sig = method.sig; let method = method_callee(cx, expr, method); - let sig = method.ty.fn_sig(); - - let sig = cx.tcx - .no_late_bound_regions(&sig) - .unwrap_or_else(|| span_bug!(expr.span, "method call has late-bound regions")); - assert_eq!(sig.inputs().len(), 2); let tupled_args = Expr { @@ -711,7 +705,7 @@ fn method_callee<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, Expr { temp_lifetime: temp_lifetime, temp_lifetime_was_shrunk: was_shrunk, - ty: callee.ty, + ty: cx.tcx.type_of(callee.def_id).subst(cx.tcx, callee.substs), span: expr.span, kind: ExprKind::Literal { literal: Literal::Value { @@ -1012,9 +1006,7 @@ fn overloaded_lvalue<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, // line up (this is because `*x` and `x[y]` represent lvalues): // to find the type &T of the content returned by the method; - let ref_ty = method.ty.fn_ret(); - let ref_ty = cx.tcx.no_late_bound_regions(&ref_ty).unwrap(); - // callees always have all late-bound regions fully instantiated, + let ref_ty = method.sig.output(); // construct the complete expression `foo()` for the overloaded call, // which will yield the &T type diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index bbe34f37950dc..33f0b0282d173 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -619,7 +619,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Type check the path. let pat_ty = self.instantiate_value_path(segments, opt_ty, def, pat.span, pat.id); // Replace constructor type with constructed type for tuple struct patterns. - let pat_ty = tcx.no_late_bound_regions(&pat_ty.fn_ret()).expect("expected fn type"); + let pat_ty = pat_ty.fn_sig().output(); + let pat_ty = tcx.no_late_bound_regions(&pat_ty).expect("expected fn type"); self.demand_eqtype(pat.span, expected, pat_ty); // Type check subpatterns. diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index ce3dbf8c23ed4..5302ba0029192 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -72,11 +72,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } Some(CallStep::Overloaded(method_callee)) => { - self.confirm_overloaded_call(call_expr, - callee_expr, - arg_exprs, - expected, - method_callee) + self.confirm_overloaded_call(call_expr, arg_exprs, expected, method_callee) } }; @@ -152,7 +148,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { autoref, unsize: false }, - target: *method.ty.fn_sig().input(0).skip_binder() + target: method.sig.inputs()[0] }); CallStep::Overloaded(method) }) @@ -302,14 +298,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn confirm_overloaded_call(&self, call_expr: &hir::Expr, - callee_expr: &'gcx hir::Expr, arg_exprs: &'gcx [hir::Expr], expected: Expectation<'tcx>, method_callee: ty::MethodCallee<'tcx>) -> Ty<'tcx> { let output_type = self.check_method_argument_types(call_expr.span, - method_callee.ty, - callee_expr, + Ok(method_callee), arg_exprs, TupleArgumentsFlag::TupleArguments, expected); @@ -349,9 +343,7 @@ impl<'a, 'gcx, 'tcx> DeferredCallResolution<'gcx, 'tcx> { // can't because of the annoying need for a TypeTrace. // (This always bites me, should find a way to // refactor it.) - let method_sig = fcx.tcx - .no_late_bound_regions(&method_callee.ty.fn_sig()) - .unwrap(); + let method_sig = method_callee.sig; debug!("attempt_resolution: method_callee={:?}", method_callee); diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index b6cd1dfc3d012..71bcff84cc2d6 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -88,19 +88,20 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { debug!("all_substs={:?}", all_substs); // Create the final signature for the method, replacing late-bound regions. - let (method_ty, method_predicates) = self.instantiate_method_sig(&pick, all_substs); + let (method_sig, method_predicates) = self.instantiate_method_sig(&pick, all_substs); // Unify the (adjusted) self type with what the method expects. - self.unify_receivers(self_ty, method_ty.fn_sig().input(0).skip_binder()); + self.unify_receivers(self_ty, method_sig.inputs()[0]); // Add any trait/regions obligations specified on the method's type parameters. + let method_ty = self.tcx.mk_fn_ptr(ty::Binder(method_sig)); self.add_obligations(method_ty, all_substs, &method_predicates); // Create the final `MethodCallee`. let callee = ty::MethodCallee { def_id: pick.item.def_id, - ty: method_ty, substs: all_substs, + sig: method_sig, }; if let Some(hir::MutMutable) = pick.autoref { @@ -351,7 +352,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { fn instantiate_method_sig(&mut self, pick: &probe::Pick<'tcx>, all_substs: &'tcx Substs<'tcx>) - -> (Ty<'tcx>, ty::InstantiatedPredicates<'tcx>) { + -> (ty::FnSig<'tcx>, ty::InstantiatedPredicates<'tcx>) { debug!("instantiate_method_sig(pick={:?}, all_substs={:?})", pick, all_substs); @@ -382,8 +383,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { let method_sig = self.instantiate_type_scheme(self.span, all_substs, &method_sig); debug!("type scheme substituted, method_sig={:?}", method_sig); - (self.tcx.mk_fn_def(def_id, all_substs, ty::Binder(method_sig)), - method_predicates) + (method_sig, method_predicates) } fn add_obligations(&mut self, @@ -508,11 +508,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { }) = self.tables.borrow_mut().adjustments.get_mut(&base_expr.id) { debug!("convert_lvalue_op_to_mutable: converting autoref of {:?}", target); - // extract method return type, which will be &mut T; - // all LB regions should have been instantiated during method lookup - let method_sig = self.tcx.no_late_bound_regions(&method.ty.fn_sig()).unwrap(); - - *target = method_sig.inputs()[0]; + *target = method.sig.inputs()[0]; if let ty::TyRef(r_, mt) = target.sty { *r = r_; *mutbl = mt.mutbl; diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index 7397c3d48e799..dd58fdbf073ab 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -267,7 +267,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { obligations.push(traits::Obligation::new(cause, ty::Predicate::WellFormed(method_ty))); let autoref = match (&original_method_ty.fn_sig().input(0).skip_binder().sty, - &method_ty.fn_sig().input(0).skip_binder().sty) { + &fn_sig.inputs()[0].sty) { (&ty::TyRef(..), &ty::TyRef(region, ty::TypeAndMut { mutbl, ty: _ })) => { // Trait method is fn(&self) or fn(&mut self), need an // autoref. Pull the region etc out of the type of first argument. @@ -281,8 +281,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let callee = ty::MethodCallee { def_id: def_id, - ty: method_ty, substs: trait_ref.substs, + sig: fn_sig, }; debug!("callee = {:?}", callee); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index ed37b55d03057..f8020794b98a3 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2156,8 +2156,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { { // extract method return type, which will be &T; // all LB regions should have been instantiated during method lookup - let ret_ty = method.ty.fn_ret(); - let ret_ty = self.tcx.no_late_bound_regions(&ret_ty).unwrap(); + let ret_ty = method.sig.output(); // method returns &T, but the type as visible to user is T, so deref ret_ty.builtin_deref(true, NoPreference).unwrap() @@ -2246,7 +2245,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { autoref, unsize }, - target: *method.ty.fn_sig().input(0).skip_binder() + target: method.sig.inputs()[0] }); self.tables.borrow_mut().method_map.insert(expr.id, method); @@ -2321,13 +2320,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn check_method_argument_types(&self, sp: Span, - method_fn_ty: Ty<'tcx>, - callee_expr: &'gcx hir::Expr, + method: Result, ()>, args_no_rcvr: &'gcx [hir::Expr], tuple_arguments: TupleArgumentsFlag, expected: Expectation<'tcx>) -> Ty<'tcx> { - if method_fn_ty.references_error() { + let has_error = match method { + Ok(method) => { + method.substs.references_error() || method.sig.references_error() + } + Err(_) => true + }; + if has_error { let err_inputs = self.err_args(args_no_rcvr.len()); let err_inputs = match tuple_arguments { @@ -2337,27 +2341,21 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.check_argument_types(sp, &err_inputs[..], &[], args_no_rcvr, false, tuple_arguments, None); - self.tcx.types.err - } else { - match method_fn_ty.sty { - ty::TyFnDef(def_id, .., ref fty) => { - // HACK(eddyb) ignore self in the definition (see above). - let expected_arg_tys = self.expected_inputs_for_expected_output( - sp, - expected, - fty.0.output(), - &fty.0.inputs()[1..] - ); - self.check_argument_types(sp, &fty.0.inputs()[1..], &expected_arg_tys[..], - args_no_rcvr, fty.0.variadic, tuple_arguments, - self.tcx.hir.span_if_local(def_id)); - fty.0.output() - } - _ => { - span_bug!(callee_expr.span, "method without bare fn type"); - } - } + return self.tcx.types.err; } + + let method = method.unwrap(); + // HACK(eddyb) ignore self in the definition (see above). + let expected_arg_tys = self.expected_inputs_for_expected_output( + sp, + expected, + method.sig.output(), + &method.sig.inputs()[1..] + ); + self.check_argument_types(sp, &method.sig.inputs()[1..], &expected_arg_tys[..], + args_no_rcvr, method.sig.variadic, tuple_arguments, + self.tcx.hir.span_if_local(method.def_id)); + method.sig.output() } /// Generic function that factors out common logic from function calls, @@ -2782,15 +2780,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let expr_t = self.structurally_resolved_type(expr.span, rcvr_t); let tps = tps.iter().map(|ast_ty| self.to_ty(&ast_ty)).collect::>(); - let fn_ty = match self.lookup_method(method_name.span, - method_name.node, - expr_t, - tps, - expr, - rcvr) { + let method = match self.lookup_method(method_name.span, + method_name.node, + expr_t, + tps, + expr, + rcvr) { Ok(method) => { self.tables.borrow_mut().method_map.insert(expr.id, method); - method.ty + Ok(method) } Err(error) => { if method_name.node != keywords::Invalid.name() { @@ -2801,18 +2799,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { error, Some(args)); } - self.write_error(expr.id); - self.tcx.types.err + Err(()) } }; // Call the generic checker. - let ret_ty = self.check_method_argument_types(method_name.span, fn_ty, - expr, &args[1..], - DontTupleArguments, - expected); - - ret_ty + self.check_method_argument_types(method_name.span, method, + &args[1..], + DontTupleArguments, + expected) } fn check_return_expr(&self, return_expr: &'gcx hir::Expr) { @@ -3465,7 +3460,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { autoref, unsize: false }, - target: *method.ty.fn_sig().input(0).skip_binder() + target: method.sig.inputs()[0] }); oprnd_t = self.make_overloaded_lvalue_return_type(method).ty; self.tables.borrow_mut().method_map.insert(expr.id, method); diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index 0ac568f2090b6..267b2b0097866 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -419,14 +419,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { autoref, unsize: false }, - target: *method.ty.fn_sig().input(0).skip_binder() + target: method.sig.inputs()[0] }); self.tables.borrow_mut().method_map.insert(expr.id, method); - // extract return type for method; all late bound regions - // should have been instantiated by now - let ret_ty = method.ty.fn_ret(); - Ok(self.tcx.no_late_bound_regions(&ret_ty).unwrap()) + Ok(method.sig.output()) } None => { Err(()) diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 6cb9375c5de79..9b609cac2fc68 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -538,8 +538,10 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> { }; self.substs_wf_in_scope(origin, &callee.substs, expr.span, expr_region); - self.type_must_outlive(infer::ExprTypeIsNotInScope(callee.ty, expr.span), - callee.ty, expr_region); + for &ty in callee.sig.inputs() { + self.type_must_outlive(infer::ExprTypeIsNotInScope(ty, expr.span), + ty, expr_region); + } } // Check any autoderefs or autorefs that appear. @@ -692,9 +694,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> { Some(method) => { self.constrain_call(expr, Some(&base), None::.iter(), true); - // late-bound regions in overloaded method calls are instantiated - let fn_ret = self.tcx.no_late_bound_regions(&method.ty.fn_ret()); - fn_ret.unwrap() + method.sig.output() } None => self.resolve_node_type(base.id) }; @@ -933,17 +933,14 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { // Treat overloaded autoderefs as if an AutoBorrow adjustment // was applied on the base type, as that is always the case. - let fn_sig = method.ty.fn_sig(); - let fn_sig = // late-bound regions should have been instantiated - self.tcx.no_late_bound_regions(&fn_sig).unwrap(); - let self_ty = fn_sig.inputs()[0]; + let self_ty = method.sig.inputs()[0]; let (m, r) = match self_ty.sty { ty::TyRef(r, ref m) => (m.mutbl, r), _ => { span_bug!( deref_expr.span, "bad overloaded deref type {:?}", - method.ty) + method.sig) } }; @@ -958,7 +955,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { self.type_must_outlive(infer::CallRcvr(deref_expr.span), self_ty, r_deref_expr); self.type_must_outlive(infer::CallReturn(deref_expr.span), - fn_sig.output(), r_deref_expr); + method.sig.output(), r_deref_expr); } { diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 5fa5bb8f7af99..455a8e1cf1610 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -340,8 +340,8 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { overloaded.map(|method| { MethodCallee { def_id: method.def_id, - ty: self.resolve(&method.ty, &span), substs: self.resolve(&method.substs, &span), + sig: self.resolve(&method.sig, &span), } }) }).collect(), @@ -368,8 +368,8 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { Some(method) => { Some(MethodCallee { def_id: method.def_id, - ty: self.resolve(&method.ty, &method_span), substs: self.resolve(&method.substs, &method_span), + sig: self.resolve(&method.sig, &method_span), }) } None => None From a65ced5d161d31e7e5b097b36bff0f51ec0843bc Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Fri, 19 May 2017 12:46:34 +0300 Subject: [PATCH 05/14] rustc: avoid using MethodCallee's signature where possible. --- src/librustc/cfg/construct.rs | 7 +- src/librustc/middle/effect.rs | 7 +- src/librustc/middle/expr_use_visitor.rs | 4 +- src/librustc/middle/liveness.rs | 7 +- src/librustc/middle/mem_categorization.rs | 205 ++++++++---------- src/librustc_borrowck/borrowck/check_loans.rs | 2 +- .../borrowck/gather_loans/gather_moves.rs | 4 +- .../borrowck/gather_loans/move_error.rs | 2 +- src/librustc_borrowck/borrowck/mod.rs | 8 +- src/librustc_borrowck/borrowck/move_data.rs | 2 +- src/librustc_mir/hair/cx/expr.rs | 36 ++- src/librustc_typeck/check/regionck.rs | 26 +-- 12 files changed, 147 insertions(+), 163 deletions(-) diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs index 2246621f83ca0..affc84382a526 100644 --- a/src/librustc/cfg/construct.rs +++ b/src/librustc/cfg/construct.rs @@ -412,15 +412,10 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { pred: CFGIndex, func_or_rcvr: &hir::Expr, args: I) -> CFGIndex { - let fn_ty = match self.tables.method_map.get(&call_expr.id) { - Some(method) => method.ty, - None => self.tables.expr_ty_adjusted(func_or_rcvr), - }; - let func_or_rcvr_exit = self.expr(func_or_rcvr, pred); let ret = self.straightline(call_expr, func_or_rcvr_exit, args); // FIXME(canndrew): This is_never should probably be an is_uninhabited. - if fn_ty.fn_ret().0.is_never() { + if self.tables.expr_ty(call_expr).is_never() { self.add_unreachable_node() } else { ret diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs index e84265cb60f74..c9593e54a867d 100644 --- a/src/librustc/middle/effect.rs +++ b/src/librustc/middle/effect.rs @@ -173,10 +173,11 @@ impl<'a, 'tcx> Visitor<'tcx> for EffectCheckVisitor<'a, 'tcx> { fn visit_expr(&mut self, expr: &'tcx hir::Expr) { match expr.node { hir::ExprMethodCall(..) => { - let method_sig = self.tables.method_map[&expr.id].sig; + let method = self.tables.method_map[&expr.id]; + let base_type = self.tcx.type_of(method.def_id); debug!("effect: method call case, base type is {:?}", - method_sig); - if method_sig.unsafety == hir::Unsafety::Unsafe { + base_type); + if type_is_unsafe_function(base_type) { self.require_unsafe(expr.span, "invocation of unsafe method") } diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 73598d0bb1a05..45afc17f33967 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -761,8 +761,10 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { let bk = ty::BorrowKind::from_mutbl(m); self.delegate.borrow(expr.id, expr.span, cmt.clone(), r, bk, AutoRef); + cmt = self.mc.cat_overloaded_autoderef(expr, method)?; + } else { + cmt = self.mc.cat_deref(expr, cmt, false)?; } - cmt = self.mc.cat_deref(expr, cmt, overloaded)?; } Ok(cmt) } diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index fd8ca332a6449..6a74af6eb8aad 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -1072,9 +1072,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { hir::ExprCall(ref f, ref args) => { // FIXME(canndrew): This is_never should really be an is_uninhabited - let diverges = !self.tables.is_method_call(expr.id) && - self.tables.expr_ty_adjusted(&f).fn_sig().output().0.is_never(); - let succ = if diverges { + let succ = if self.tables.expr_ty(expr).is_never() { self.s.exit_ln } else { succ @@ -1084,9 +1082,8 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { } hir::ExprMethodCall(.., ref args) => { - let ret_ty = self.tables.method_map[&expr.id].sig.output(); // FIXME(canndrew): This is_never should really be an is_uninhabited - let succ = if ret_ty.is_never() { + let succ = if self.tables.expr_ty(expr).is_never() { self.s.exit_ln } else { succ diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index aa729c75796af..cc65777bfce87 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -63,7 +63,6 @@ pub use self::PointerKind::*; pub use self::InteriorKind::*; pub use self::FieldName::*; -pub use self::ElementKind::*; pub use self::MutabilityCategory::*; pub use self::AliasableReason::*; pub use self::Note::*; @@ -129,7 +128,7 @@ pub enum PointerKind<'tcx> { #[derive(Clone, Copy, PartialEq, Eq, Hash)] pub enum InteriorKind { InteriorField(FieldName), - InteriorElement(InteriorOffsetKind, ElementKind), + InteriorElement(InteriorOffsetKind), } #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] @@ -144,12 +143,6 @@ pub enum InteriorOffsetKind { Pattern, // e.g. `fn foo([_, a, _, _]: [A; 4]) { ... }` } -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] -pub enum ElementKind { - VecElement, - OtherElement, -} - #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] pub enum MutabilityCategory { McImmutable, // Immutable. @@ -492,7 +485,11 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { debug!("cat_expr: autoderefs={:?}, cmt={:?}", autoderefs, cmt); for &overloaded in autoderefs { - cmt = self.cat_deref(expr, cmt, overloaded)?; + if let Some(method) = overloaded { + cmt = self.cat_overloaded_autoderef(expr, method)?; + } else { + cmt = self.cat_deref(expr, cmt, false)?; + } } return Ok(cmt); } @@ -518,10 +515,12 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { let expr_ty = self.expr_ty(expr)?; match expr.node { hir::ExprUnary(hir::UnDeref, ref e_base) => { - let base_cmt = self.cat_expr(&e_base)?; - let method = self.infcx.tables.borrow().method_map - .get(&expr.id).cloned(); - self.cat_deref(expr, base_cmt, method) + if self.infcx.tables.borrow().is_method_call(expr.id) { + self.cat_overloaded_lvalue(expr, e_base, false) + } else { + let base_cmt = self.cat_expr(&e_base)?; + self.cat_deref(expr, base_cmt, false) + } } hir::ExprField(ref base, f_name) => { @@ -539,33 +538,16 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { } hir::ExprIndex(ref base, _) => { - let method = self.infcx.tables.borrow().method_map.get(&expr.id()).cloned(); - match method { - Some(method) => { - // If this is an index implemented by a method call, then it - // will include an implicit deref of the result. - let ret_ty = self.overloaded_method_return_ty(method); - - // The index method always returns an `&T`, so - // dereference it to find the result type. - let elem_ty = match ret_ty.sty { - ty::TyRef(_, mt) => mt.ty, - _ => { - debug!("cat_expr_unadjusted: return type of overloaded index is {:?}?", - ret_ty); - return Err(()); - } - }; - - // The call to index() returns a `&T` value, which - // is an rvalue. That is what we will be - // dereferencing. - let base_cmt = self.cat_rvalue_node(expr.id(), expr.span(), ret_ty); - Ok(self.cat_deref_common(expr, base_cmt, elem_ty, true)) - } - None => { - self.cat_index(expr, self.cat_expr(&base)?, InteriorOffsetKind::Index) - } + if self.infcx.tables.borrow().is_method_call(expr.id()) { + // If this is an index implemented by a method call, then it + // will include an implicit deref of the result. + // The call to index() returns a `&T` value, which + // is an rvalue. That is what we will be + // dereferencing. + self.cat_overloaded_lvalue(expr, base, true) + } else { + let base_cmt = self.cat_expr(&base)?; + self.cat_index(expr, base_cmt, expr_ty, InteriorOffsetKind::Index) } } @@ -924,42 +906,63 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { ret } + fn cat_overloaded_lvalue(&self, + expr: &hir::Expr, + base: &hir::Expr, + implicit: bool) + -> McResult> { + debug!("cat_overloaded_lvalue: implicit={}", implicit); + + // Reconstruct the output assuming it's a reference with the + // same region and mutability as the receiver. This holds for + // `Deref(Mut)::Deref(_mut)` and `Index(Mut)::index(_mut)`. + let lvalue_ty = self.expr_ty(expr)?; + let base_ty = self.expr_ty_adjusted(base)?; + + let (region, mutbl) = match base_ty.sty { + ty::TyRef(region, mt) => (region, mt.mutbl), + _ => { + span_bug!(expr.span, "cat_overloaded_lvalue: base is not a reference") + } + }; + let ref_ty = self.tcx().mk_ref(region, ty::TypeAndMut { + ty: lvalue_ty, + mutbl, + }); + + let base_cmt = self.cat_rvalue_node(expr.id, expr.span, ref_ty); + self.cat_deref(expr, base_cmt, implicit) + } + + pub fn cat_overloaded_autoderef(&self, + expr: &hir::Expr, + method: ty::MethodCallee<'tcx>) + -> McResult> { + debug!("cat_overloaded_autoderef: method={:?}", method); + + let ref_ty = method.sig.output(); + let ref_ty = self.infcx.resolve_type_vars_if_possible(&ref_ty); + let base_cmt = self.cat_rvalue_node(expr.id, expr.span, ref_ty); + self.cat_deref(expr, base_cmt, false) + } + pub fn cat_deref(&self, node: &N, base_cmt: cmt<'tcx>, - overloaded: Option>) + implicit: bool) -> McResult> { - debug!("cat_deref: overloaded={:?}", overloaded); + debug!("cat_deref: base_cmt={:?}", base_cmt); - let base_cmt = match overloaded { - Some(method) => { - let ref_ty = self.overloaded_method_return_ty(method); - self.cat_rvalue_node(node.id(), node.span(), ref_ty) - } - None => base_cmt - }; let base_cmt_ty = base_cmt.ty; - match base_cmt_ty.builtin_deref(true, ty::NoPreference) { - Some(mt) => { - let ret = self.cat_deref_common(node, base_cmt, mt.ty, false); - debug!("cat_deref ret {:?}", ret); - Ok(ret) - } + let deref_ty = match base_cmt_ty.builtin_deref(true, ty::NoPreference) { + Some(mt) => mt.ty, None => { debug!("Explicit deref of non-derefable type: {:?}", base_cmt_ty); return Err(()); } - } - } + }; - fn cat_deref_common(&self, - node: &N, - base_cmt: cmt<'tcx>, - deref_ty: Ty<'tcx>, - implicit: bool) - -> cmt<'tcx> - { let ptr = match base_cmt.ty.sty { ty::TyAdt(def, ..) if def.is_box() => Unique, ty::TyRawPtr(ref mt) => UnsafePtr(mt.mutbl), @@ -967,7 +970,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { let bk = ty::BorrowKind::from_mutbl(mt.mutbl); if implicit { Implicit(bk, r) } else { BorrowedPtr(bk, r) } } - ref ty => bug!("unexpected type in cat_deref_common: {:?}", ty) + ref ty => bug!("unexpected type in cat_deref: {:?}", ty) }; let ret = Rc::new(cmt_ { id: node.id(), @@ -978,15 +981,16 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { ty: deref_ty, note: NoteNone }); - debug!("cat_deref_common ret {:?}", ret); - ret + debug!("cat_deref ret {:?}", ret); + Ok(ret) } - pub fn cat_index(&self, - elt: &N, - mut base_cmt: cmt<'tcx>, - context: InteriorOffsetKind) - -> McResult> { + fn cat_index(&self, + elt: &N, + base_cmt: cmt<'tcx>, + element_ty: Ty<'tcx>, + context: InteriorOffsetKind) + -> McResult> { //! Creates a cmt for an indexing operation (`[]`). //! //! One subtle aspect of indexing that may not be @@ -1004,29 +1008,9 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { //! - `elt`: the AST node being indexed //! - `base_cmt`: the cmt of `elt` - let method = self.infcx.tables.borrow().method_map.get(&elt.id()).cloned(); - let (element_ty, element_kind) = match method { - Some(method) => { - let ref_ty = self.overloaded_method_return_ty(method); - base_cmt = self.cat_rvalue_node(elt.id(), elt.span(), ref_ty); - - (ref_ty.builtin_deref(false, ty::NoPreference).unwrap().ty, - ElementKind::OtherElement) - } - None => { - match base_cmt.ty.builtin_index() { - Some(ty) => (ty, ElementKind::VecElement), - None => { - debug!("Explicit index of non-indexable type {:?}", base_cmt); - return Err(()); - } - } - } - }; - - let interior_elem = InteriorElement(context, element_kind); + let interior_elem = InteriorElement(context); let ret = - self.cat_imm_interior(elt, base_cmt.clone(), element_ty, interior_elem); + self.cat_imm_interior(elt, base_cmt, element_ty, interior_elem); debug!("cat_index ret {:?}", ret); return Ok(ret); } @@ -1216,15 +1200,20 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { // box p1, &p1, &mut p1. we can ignore the mutability of // PatKind::Ref since that information is already contained // in the type. - let method = self.infcx.tables.borrow().method_map - .get(&pat.id).cloned(); - let subcmt = self.cat_deref(pat, cmt, method)?; + let subcmt = self.cat_deref(pat, cmt, false)?; self.cat_pattern_(subcmt, &subpat, op)?; } PatKind::Slice(ref before, ref slice, ref after) => { + let element_ty = match cmt.ty.builtin_index() { + Some(ty) => ty, + None => { + debug!("Explicit index of non-indexable type {:?}", cmt); + return Err(()); + } + }; let context = InteriorOffsetKind::Pattern; - let elt_cmt = self.cat_index(pat, cmt, context)?; + let elt_cmt = self.cat_index(pat, cmt, element_ty, context)?; for before_pat in before { self.cat_pattern_(elt_cmt.clone(), &before_pat, op)?; } @@ -1244,16 +1233,6 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { Ok(()) } - - fn overloaded_method_return_ty(&self, - method: ty::MethodCallee<'tcx>) - -> Ty<'tcx> - { - // When we process an overloaded `*` or `[]` etc, we often - // need to extract the return type of the method. - let ret_ty = method.sig.output(); - self.infcx.resolve_type_vars_if_possible(&ret_ty) - } } #[derive(Clone, Debug)] @@ -1401,16 +1380,10 @@ impl<'tcx> cmt_<'tcx> { Categorization::Interior(_, InteriorField(PositionalField(_))) => { "anonymous field".to_string() } - Categorization::Interior(_, InteriorElement(InteriorOffsetKind::Index, - VecElement)) | - Categorization::Interior(_, InteriorElement(InteriorOffsetKind::Index, - OtherElement)) => { + Categorization::Interior(_, InteriorElement(InteriorOffsetKind::Index)) => { "indexed content".to_string() } - Categorization::Interior(_, InteriorElement(InteriorOffsetKind::Pattern, - VecElement)) | - Categorization::Interior(_, InteriorElement(InteriorOffsetKind::Pattern, - OtherElement)) => { + Categorization::Interior(_, InteriorElement(InteriorOffsetKind::Pattern)) => { "pattern-bound indexed content".to_string() } Categorization::Upvar(ref var) => { diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs index 722ec6424fece..0fe8865f4a268 100644 --- a/src/librustc_borrowck/borrowck/check_loans.rs +++ b/src/librustc_borrowck/borrowck/check_loans.rs @@ -805,7 +805,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { self.check_if_assigned_path_is_moved(id, span, use_kind, lp_base); } - LpExtend(ref lp_base, _, LpInterior(_, InteriorElement(..))) | + LpExtend(ref lp_base, _, LpInterior(_, InteriorElement)) | LpExtend(ref lp_base, _, LpDeref(_)) => { // assigning to `P[i]` requires `P` is initialized // assigning to `(*P)` requires `P` is initialized diff --git a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs index baa18307510e6..3d98c2a23dc67 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs @@ -237,7 +237,7 @@ fn check_and_get_illegal_move_origin<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, Categorization::Downcast(ref b, _) | Categorization::Interior(ref b, mc::InteriorField(_)) | - Categorization::Interior(ref b, mc::InteriorElement(Kind::Pattern, _)) => { + Categorization::Interior(ref b, mc::InteriorElement(Kind::Pattern)) => { match b.ty.sty { ty::TyAdt(def, _) => { if def.has_dtor(bccx.tcx) { @@ -253,7 +253,7 @@ fn check_and_get_illegal_move_origin<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, } } - Categorization::Interior(_, mc::InteriorElement(Kind::Index, _)) => { + Categorization::Interior(_, mc::InteriorElement(Kind::Index)) => { // Forbid move of arr[i] for arr: [T; 3]; see RFC 533. Some(cmt.clone()) } diff --git a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs index f7c3bb36da7dd..cceb4a7b3cc21 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs @@ -152,7 +152,7 @@ fn report_cannot_move_out_of<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, err } - Categorization::Interior(ref b, mc::InteriorElement(ik, _)) => { + Categorization::Interior(ref b, mc::InteriorElement(ik)) => { match (&b.ty.sty, ik) { (&ty::TySlice(..), _) | (_, Kind::Index) => { diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 0b2cb1b93f92a..2b5bbe0e8a5df 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -284,7 +284,7 @@ const DOWNCAST_PRINTED_OPERATOR: &'static str = " as "; #[derive(Clone, Copy, PartialEq, Eq, Hash)] pub enum InteriorKind { InteriorField(mc::FieldName), - InteriorElement(mc::ElementKind), + InteriorElement, } trait ToInteriorKind { fn cleaned(self) -> InteriorKind; } @@ -292,7 +292,7 @@ impl ToInteriorKind for mc::InteriorKind { fn cleaned(self) -> InteriorKind { match self { mc::InteriorField(name) => InteriorField(name), - mc::InteriorElement(_, elem_kind) => InteriorElement(elem_kind), + mc::InteriorElement(_) => InteriorElement, } } } @@ -1232,7 +1232,7 @@ before rustc 1.16, this temporary lived longer - see issue #39283 \ } } - LpExtend(ref lp_base, _, LpInterior(_, InteriorElement(..))) => { + LpExtend(ref lp_base, _, LpInterior(_, InteriorElement)) => { self.append_autoderefd_loan_path_to_string(&lp_base, out); out.push_str("[..]"); } @@ -1318,7 +1318,7 @@ impl<'tcx> fmt::Debug for InteriorKind { match *self { InteriorField(mc::NamedField(fld)) => write!(f, "{}", fld), InteriorField(mc::PositionalField(i)) => write!(f, "#{}", i), - InteriorElement(..) => write!(f, "[]"), + InteriorElement => write!(f, "[]"), } } } diff --git a/src/librustc_borrowck/borrowck/move_data.rs b/src/librustc_borrowck/borrowck/move_data.rs index 1b364596a23f7..0a31905c7928a 100644 --- a/src/librustc_borrowck/borrowck/move_data.rs +++ b/src/librustc_borrowck/borrowck/move_data.rs @@ -191,7 +191,7 @@ fn loan_path_is_precise(loan_path: &LoanPath) -> bool { LpVar(_) | LpUpvar(_) => { true } - LpExtend(.., LpInterior(_, InteriorKind::InteriorElement(..))) => { + LpExtend(.., LpInterior(_, InteriorKind::InteriorElement)) => { // Paths involving element accesses a[i] do not refer to a unique // location, as there is no accurate tracking of the indices. // diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 6428146525cd4..eee1f1a9712d2 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -94,8 +94,8 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { debug!("make_mirror: overloaded autoderef (method={:?})", method); ref_ty = method.sig.output(); - let (region, mutbl) = match ref_ty.sty { - ty::TyRef(region, mt) => (region, mt.mutbl), + let (region, mt) = match ref_ty.sty { + ty::TyRef(region, mt) => (region, mt), _ => span_bug!(expr.span, "autoderef returned bad type"), }; @@ -105,18 +105,19 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { ty: cx.tcx.mk_ref(region, ty::TypeAndMut { ty: expr.ty, - mutbl: mutbl, + mutbl: mt.mutbl, }), span: expr.span, kind: ExprKind::Borrow { region: region, - borrow_kind: to_borrow_kind(mutbl), + borrow_kind: to_borrow_kind(mt.mutbl), arg: expr.to_ref(), }, }; overloaded_lvalue(cx, self, + mt.ty, method, PassArgs::ByRef, expr.to_ref(), @@ -264,13 +265,11 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, // rewrite f(u, v) into FnOnce::call_once(f, (u, v)) - let sig = method.sig; let method = method_callee(cx, expr, method); - assert_eq!(sig.inputs().len(), 2); - + let arg_tys = args.iter().map(|e| cx.tables().expr_ty_adjusted(e)); let tupled_args = Expr { - ty: sig.inputs()[1], + ty: cx.tcx.mk_tup(arg_tys, false), temp_lifetime: temp_lifetime, temp_lifetime_was_shrunk: was_shrunk, span: expr.span, @@ -435,6 +434,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, if let Some(&method) = cx.tables().method_map.get(&expr.id) { overloaded_lvalue(cx, expr, + expr_ty, method, PassArgs::ByValue, lhs.to_ref(), @@ -451,6 +451,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, if let Some(&method) = cx.tables().method_map.get(&expr.id) { overloaded_lvalue(cx, expr, + expr_ty, method, PassArgs::ByValue, arg.to_ref(), @@ -996,6 +997,7 @@ fn overloaded_operator<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, fn overloaded_lvalue<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, expr: &'tcx hir::Expr, + lvalue_ty: Ty<'tcx>, method: ty::MethodCallee<'tcx>, pass_args: PassArgs, receiver: ExprRef<'tcx>, @@ -1005,8 +1007,22 @@ fn overloaded_lvalue<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, // call returns an &T and we must add the deref so that the types // line up (this is because `*x` and `x[y]` represent lvalues): - // to find the type &T of the content returned by the method; - let ref_ty = method.sig.output(); + let recv_ty = match receiver { + ExprRef::Hair(e) => cx.tables().expr_ty_adjusted(e), + ExprRef::Mirror(ref e) => e.ty + }; + + // Reconstruct the output assuming it's a reference with the + // same region and mutability as the receiver. This holds for + // `Deref(Mut)::Deref(_mut)` and `Index(Mut)::index(_mut)`. + let (region, mutbl) = match recv_ty.sty { + ty::TyRef(region, mt) => (region, mt.mutbl), + _ => span_bug!(expr.span, "overloaded_lvalue: receiver is not a reference"), + }; + let ref_ty = cx.tcx.mk_ref(region, ty::TypeAndMut { + ty: lvalue_ty, + mutbl, + }); // construct the complete expression `foo()` for the overloaded call, // which will yield the &T type diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 9b609cac2fc68..5cda50b428b7c 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -538,10 +538,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> { }; self.substs_wf_in_scope(origin, &callee.substs, expr.span, expr_region); - for &ty in callee.sig.inputs() { - self.type_must_outlive(infer::ExprTypeIsNotInScope(ty, expr.span), - ty, expr_region); - } + // Arguments (sub-expressions) are checked via `constrain_call`, below. } // Check any autoderefs or autorefs that appear. @@ -690,14 +687,13 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> { hir::ExprUnary(hir::UnDeref, ref base) => { // For *a, the lifetime of a must enclose the deref - let base_ty = match self.tables.borrow().method_map.get(&expr.id) { - Some(method) => { - self.constrain_call(expr, Some(&base), - None::.iter(), true); - method.sig.output() - } - None => self.resolve_node_type(base.id) - }; + if self.tables.borrow().is_method_call(expr.id) { + self.constrain_call(expr, Some(base), + None::.iter(), true); + } + // For overloaded derefs, base_ty is the input to `Deref::deref`, + // but it's a reference type uing the same region as the output. + let base_ty = self.resolve_expr_type_adjusted(base); if let ty::TyRef(r_ptr, _) = base_ty.sty { self.mk_subregion_due_to_dereference(expr.span, expr_region, r_ptr); } @@ -960,7 +956,11 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { { let mc = mc::MemCategorizationContext::new(self, &self.region_maps); - cmt = mc.cat_deref(deref_expr, cmt, overloaded)?; + if let Some(method) = overloaded { + cmt = mc.cat_overloaded_autoderef(deref_expr, method)?; + } else { + cmt = mc.cat_deref(deref_expr, cmt, false)?; + } } if let Categorization::Deref(_, mc::BorrowedPtr(_, r_ptr)) = cmt.cat { From 9eae6ba7fad883300c83d77782ae78b0db6f3bb7 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Sat, 20 May 2017 10:26:08 +0300 Subject: [PATCH 06/14] rustc: remove unnecessary ItemSubsts wrapper. --- src/librustc/ich/impls_ty.rs | 6 ++---- src/librustc/ty/context.rs | 8 +++---- src/librustc/ty/mod.rs | 13 ----------- src/librustc/ty/structural_impls.rs | 23 -------------------- src/librustc/util/ppaux.rs | 6 ------ src/librustc_const_eval/eval.rs | 3 +-- src/librustc_const_eval/pattern.rs | 3 +-- src/librustc_lint/builtin.rs | 3 +-- src/librustc_mir/hair/cx/expr.rs | 6 ++---- src/librustc_typeck/check/mod.rs | 30 ++++++-------------------- src/librustc_typeck/check/regionck.rs | 7 +++--- src/librustc_typeck/check/writeback.rs | 14 ++++++------ 12 files changed, 27 insertions(+), 95 deletions(-) diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 63dc2e2d8e13f..2615fdd86d68d 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -19,8 +19,6 @@ use std::mem; use syntax_pos::symbol::InternedString; use ty; -impl_stable_hash_for!(struct ty::ItemSubsts<'tcx> { substs }); - impl<'a, 'tcx, T> HashStable> for &'tcx ty::Slice where T: HashStable> { fn hash_stable(&self, @@ -602,7 +600,7 @@ impl<'a, 'tcx> HashStable> for ty::TypeckTables<' let ty::TypeckTables { ref type_relative_path_defs, ref node_types, - ref item_substs, + ref node_substs, ref adjustments, ref method_map, ref upvar_capture_map, @@ -623,7 +621,7 @@ impl<'a, 'tcx> HashStable> for ty::TypeckTables<' hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { ich::hash_stable_nodemap(hcx, hasher, type_relative_path_defs); ich::hash_stable_nodemap(hcx, hasher, node_types); - ich::hash_stable_nodemap(hcx, hasher, item_substs); + ich::hash_stable_nodemap(hcx, hasher, node_substs); ich::hash_stable_nodemap(hcx, hasher, adjustments); ich::hash_stable_nodemap(hcx, hasher, method_map); ich::hash_stable_hashmap(hcx, hasher, upvar_capture_map, |hcx, up_var_id| { diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 76882b9431537..a0ad3da45e07c 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -218,7 +218,7 @@ pub struct TypeckTables<'tcx> { /// of this node. This only applies to nodes that refer to entities /// parameterized by type parameters, such as generic fns, types, or /// other items. - pub item_substs: NodeMap>, + pub node_substs: NodeMap<&'tcx Substs<'tcx>>, pub adjustments: NodeMap>, @@ -273,7 +273,7 @@ impl<'tcx> TypeckTables<'tcx> { TypeckTables { type_relative_path_defs: NodeMap(), node_types: FxHashMap(), - item_substs: NodeMap(), + node_substs: NodeMap(), adjustments: NodeMap(), method_map: FxHashMap(), upvar_capture_map: FxHashMap(), @@ -313,8 +313,8 @@ impl<'tcx> TypeckTables<'tcx> { self.node_types.get(&id).cloned() } - pub fn node_id_item_substs(&self, id: NodeId) -> Option<&'tcx Substs<'tcx>> { - self.item_substs.get(&id).map(|ts| ts.substs) + pub fn node_substs(&self, id: NodeId) -> &'tcx Substs<'tcx> { + self.node_substs.get(&id).cloned().unwrap_or(Substs::empty()) } // Returns the type of a pattern as a monotype. Like @expr_ty, this function diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index d138b306732ca..a45f85db4c257 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1809,13 +1809,6 @@ impl<'a, 'gcx, 'tcx> FieldDef { } } -/// Records the substitutions used to translate the polytype for an -/// item into the monotype of an item reference. -#[derive(Clone, RustcEncodable, RustcDecodable)] -pub struct ItemSubsts<'tcx> { - pub substs: &'tcx Substs<'tcx>, -} - #[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] pub enum ClosureKind { // Warning: Ordering is significant here! The ordering is chosen @@ -1893,12 +1886,6 @@ impl<'tcx> TyS<'tcx> { } } -impl<'tcx> ItemSubsts<'tcx> { - pub fn is_noop(&self) -> bool { - self.substs.is_noop() - } -} - #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum LvaluePreference { PreferMutLvalue, diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 53d516e581b2a..9336e7beae20a 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -220,17 +220,6 @@ impl<'a, 'tcx> Lift<'tcx> for ty::ClosureSubsts<'a> { } } -impl<'a, 'tcx> Lift<'tcx> for ty::ItemSubsts<'a> { - type Lifted = ty::ItemSubsts<'tcx>; - fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { - tcx.lift(&self.substs).map(|substs| { - ty::ItemSubsts { - substs: substs - } - }) - } -} - impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::AutoBorrow<'a> { type Lifted = ty::adjustment::AutoBorrow<'tcx>; fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { @@ -654,18 +643,6 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ClosureSubsts<'tcx> { } } -impl<'tcx> TypeFoldable<'tcx> for ty::ItemSubsts<'tcx> { - fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - ty::ItemSubsts { - substs: self.substs.fold_with(folder), - } - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.substs.visit_with(visitor) - } -} - impl<'tcx> TypeFoldable<'tcx> for ty::adjustment::AutoBorrow<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { match *self { diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 340e4f2cfccbc..6f6d48cdf58af 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -361,12 +361,6 @@ impl<'tcx> fmt::Display for ty::TypeAndMut<'tcx> { } } -impl<'tcx> fmt::Debug for ty::ItemSubsts<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "ItemSubsts({:?})", self.substs) - } -} - impl<'tcx> fmt::Debug for ty::TraitRef<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { // when printing out the debug representation, we don't need diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index e79f23aee1145..a6b39f22277de 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -286,8 +286,7 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, } } hir::ExprPath(ref qpath) => { - let substs = cx.tables.node_id_item_substs(e.id) - .unwrap_or_else(|| tcx.intern_substs(&[])); + let substs = cx.tables.node_substs(e.id); // Avoid applying substitutions if they're empty, that'd ICE. let substs = if cx.substs.is_empty() { diff --git a/src/librustc_const_eval/pattern.rs b/src/librustc_const_eval/pattern.rs index e15d63a63c258..d8e76218a4a0b 100644 --- a/src/librustc_const_eval/pattern.rs +++ b/src/librustc_const_eval/pattern.rs @@ -585,8 +585,7 @@ impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> { let kind = match def { Def::Const(def_id) | Def::AssociatedConst(def_id) => { let tcx = self.tcx.global_tcx(); - let substs = self.tables.node_id_item_substs(id) - .unwrap_or_else(|| tcx.intern_substs(&[])); + let substs = self.tables.node_substs(id); match eval::lookup_const_by_id(tcx, def_id, substs) { Some((def_id, _substs)) => { // Enter the inlined constant's tables temporarily. diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 13c69d105302f..8a374358bb998 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -911,8 +911,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnconditionalRecursion { }; match def { Def::Method(def_id) => { - let substs = cx.tables.node_id_item_substs(callee.id) - .unwrap_or_else(|| cx.tcx.intern_substs(&[])); + let substs = cx.tables.node_substs(callee.id); method_call_refers_to_method( cx.tcx, method, def_id, substs, id) } diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index eee1f1a9712d2..c11cd38fe3437 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -297,8 +297,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, None }; if let Some((adt_def, index)) = adt_data { - let substs = cx.tables().node_id_item_substs(fun.id) - .unwrap_or_else(|| cx.tcx.intern_substs(&[])); + let substs = cx.tables().node_substs(fun.id); let field_refs = args.iter() .enumerate() .map(|(idx, e)| { @@ -735,8 +734,7 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, expr: &'tcx hir::Expr, def: Def) -> ExprKind<'tcx> { - let substs = cx.tables().node_id_item_substs(expr.id) - .unwrap_or_else(|| cx.tcx.intern_substs(&[])); + let substs = cx.tables().node_substs(expr.id); match def { // A regular function, constructor function or a constant. Def::Fn(def_id) | diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index f8020794b98a3..0b0233103ef7b 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -52,7 +52,7 @@ can be broken down into several distinct phases: While type checking a function, the intermediate types for the expressions, blocks, and so forth contained within the function are -stored in `fcx.node_types` and `fcx.item_substs`. These types +stored in `fcx.node_types` and `fcx.node_substs`. These types may contain unresolved type variables. After type checking is complete, the functions in the writeback module are used to take the types from this table, resolve them, and then write them into their @@ -1758,14 +1758,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } - pub fn write_substs(&self, node_id: ast::NodeId, substs: ty::ItemSubsts<'tcx>) { - if !substs.substs.is_noop() { + pub fn write_substs(&self, node_id: ast::NodeId, substs: &'tcx Substs<'tcx>) { + if !substs.is_noop() { debug!("write_substs({}, {:?}) in fcx {}", node_id, substs, self.tag()); - self.tables.borrow_mut().item_substs.insert(node_id, substs); + self.tables.borrow_mut().node_substs.insert(node_id, substs); } } @@ -1959,16 +1959,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } - pub fn opt_node_ty_substs(&self, - id: ast::NodeId, - f: F) where - F: FnOnce(&ty::ItemSubsts<'tcx>), - { - if let Some(s) = self.tables.borrow().item_substs.get(&id) { - f(s); - } - } - /// Registers an obligation for checking later, during regionck, that the type `ty` must /// outlive the region `r`. pub fn register_region_obligation(&self, @@ -3550,9 +3540,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // We always require that the type provided as the value for // a type parameter outlives the moment of instantiation. - self.opt_node_ty_substs(expr.id, |item_substs| { - self.add_wf_bounds(&item_substs.substs, expr); - }); + let substs = self.tables.borrow().node_substs(expr.id); + self.add_wf_bounds(substs, expr); ty } @@ -4375,9 +4364,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let ty = self.local_ty(span, nid); let ty = self.normalize_associated_types_in(span, &ty); self.write_ty(node_id, ty); - self.write_substs(node_id, ty::ItemSubsts { - substs: self.tcx.intern_substs(&[]) - }); return ty; } _ => {} @@ -4509,9 +4495,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { debug!("instantiate_value_path: type of {:?} is {:?}", node_id, ty_substituted); - self.write_substs(node_id, ty::ItemSubsts { - substs: substs - }); + self.write_substs(node_id, substs); ty_substituted } diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 5cda50b428b7c..2fae9d8e70e5c 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -608,10 +608,9 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> { expr, self.repeating_scope); match expr.node { hir::ExprPath(_) => { - self.fcx.opt_node_ty_substs(expr.id, |item_substs| { - let origin = infer::ParameterOrigin::Path; - self.substs_wf_in_scope(origin, &item_substs.substs, expr.span, expr_region); - }); + let substs = self.tables.borrow().node_substs(expr.id); + let origin = infer::ParameterOrigin::Path; + self.substs_wf_in_scope(origin, substs, expr.span, expr_region); } hir::ExprCall(ref callee, ref args) => { diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 455a8e1cf1610..dcdfed6cbd888 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -295,14 +295,12 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { debug!("Node {} has type {:?}", node_id, n_ty); // Resolve any substitutions - self.fcx.opt_node_ty_substs(node_id, |item_substs| { - let item_substs = self.resolve(item_substs, &span); - if !item_substs.is_noop() { - debug!("write_substs_to_tcx({}, {:?})", node_id, item_substs); - assert!(!item_substs.substs.needs_infer()); - self.tables.item_substs.insert(node_id, item_substs); - } - }); + if let Some(&substs) = self.fcx.tables.borrow().node_substs.get(&node_id) { + let substs = self.resolve(&substs, &span); + debug!("write_substs_to_tcx({}, {:?})", node_id, substs); + assert!(!substs.needs_infer()); + self.tables.node_substs.insert(node_id, substs); + } } fn visit_adjustments(&mut self, span: Span, node_id: ast::NodeId) { From 552ab37a100231f8f2416b5ecc7e350c17e6487f Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Sat, 20 May 2017 16:11:07 +0300 Subject: [PATCH 07/14] rustc: replace method_map with Def::Method and node_substs entries. --- src/librustc/cfg/construct.rs | 4 +- src/librustc/ich/impls_ty.rs | 6 +-- src/librustc/middle/dead.rs | 2 +- src/librustc/middle/effect.rs | 4 +- src/librustc/middle/expr_use_visitor.rs | 6 +-- src/librustc/middle/liveness.rs | 4 +- src/librustc/middle/mem_categorization.rs | 4 +- src/librustc/middle/reachable.rs | 3 +- src/librustc/ty/context.rs | 25 ++++++---- src/librustc/ty/sty.rs | 2 - src/librustc_lint/builtin.rs | 29 ++++++++---- src/librustc_mir/hair/cx/expr.rs | 51 +++++++++++---------- src/librustc_passes/consts.rs | 8 ++-- src/librustc_save_analysis/lib.rs | 2 +- src/librustc_typeck/check/callee.rs | 4 +- src/librustc_typeck/check/method/confirm.rs | 4 +- src/librustc_typeck/check/mod.rs | 19 +++++--- src/librustc_typeck/check/op.rs | 2 +- src/librustc_typeck/check/regionck.rs | 20 ++++---- src/librustc_typeck/check/writeback.rs | 40 +++++----------- 20 files changed, 120 insertions(+), 119 deletions(-) diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs index affc84382a526..85b1858c875bc 100644 --- a/src/librustc/cfg/construct.rs +++ b/src/librustc/cfg/construct.rs @@ -355,11 +355,11 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { } hir::ExprIndex(ref l, ref r) | - hir::ExprBinary(_, ref l, ref r) if self.tables.is_method_call(expr.id) => { + hir::ExprBinary(_, ref l, ref r) if self.tables.is_method_call(expr) => { self.call(expr, pred, &l, Some(&**r).into_iter()) } - hir::ExprUnary(_, ref e) if self.tables.is_method_call(expr.id) => { + hir::ExprUnary(_, ref e) if self.tables.is_method_call(expr) => { self.call(expr, pred, &e, None::.iter()) } diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 2615fdd86d68d..e607a6bf74a60 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -598,11 +598,10 @@ impl<'a, 'tcx> HashStable> for ty::TypeckTables<' hcx: &mut StableHashingContext<'a, 'tcx>, hasher: &mut StableHasher) { let ty::TypeckTables { - ref type_relative_path_defs, + ref type_dependent_defs, ref node_types, ref node_substs, ref adjustments, - ref method_map, ref upvar_capture_map, ref closure_tys, ref closure_kinds, @@ -619,11 +618,10 @@ impl<'a, 'tcx> HashStable> for ty::TypeckTables<' } = *self; hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { - ich::hash_stable_nodemap(hcx, hasher, type_relative_path_defs); + ich::hash_stable_nodemap(hcx, hasher, type_dependent_defs); ich::hash_stable_nodemap(hcx, hasher, node_types); ich::hash_stable_nodemap(hcx, hasher, node_substs); ich::hash_stable_nodemap(hcx, hasher, adjustments); - ich::hash_stable_nodemap(hcx, hasher, method_map); ich::hash_stable_hashmap(hcx, hasher, upvar_capture_map, |hcx, up_var_id| { let ty::UpvarId { var_id, diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index ebae3933bddb1..6077b7863e2c3 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -95,7 +95,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { } fn lookup_and_handle_method(&mut self, id: ast::NodeId) { - self.check_def_id(self.tables.method_map[&id].def_id); + self.check_def_id(self.tables.type_dependent_defs[&id].def_id()); } fn handle_field_access(&mut self, lhs: &hir::Expr, name: ast::Name) { diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs index c9593e54a867d..74e1225f3948b 100644 --- a/src/librustc/middle/effect.rs +++ b/src/librustc/middle/effect.rs @@ -173,8 +173,8 @@ impl<'a, 'tcx> Visitor<'tcx> for EffectCheckVisitor<'a, 'tcx> { fn visit_expr(&mut self, expr: &'tcx hir::Expr) { match expr.node { hir::ExprMethodCall(..) => { - let method = self.tables.method_map[&expr.id]; - let base_type = self.tcx.type_of(method.def_id); + let def_id = self.tables.type_dependent_defs[&expr.id].def_id(); + let base_type = self.tcx.type_of(def_id); debug!("effect: method call case, base type is {:?}", base_type); if type_is_unsafe_function(base_type) { diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 45afc17f33967..340a929331ffa 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -563,8 +563,8 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { } ty::TyError => { } _ => { - let method = self.mc.infcx.tables.borrow().method_map[&call.id]; - match OverloadedCallType::from_method_id(self.tcx(), method.def_id) { + let def_id = self.mc.infcx.tables.borrow().type_dependent_defs[&call.id].def_id(); + match OverloadedCallType::from_method_id(self.tcx(), def_id) { FnMutOverloadedCall => { let call_scope_r = self.tcx().node_scope_region(call.id); self.borrow_expr(callee, @@ -849,7 +849,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { pass_args: PassArgs) -> bool { - if !self.mc.infcx.tables.borrow().is_method_call(expr.id) { + if !self.mc.infcx.tables.borrow().is_method_call(expr) { return false; } diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index 6a74af6eb8aad..c6a42be6135cc 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -1045,7 +1045,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { hir::ExprAssignOp(_, ref l, ref r) => { // an overloaded assign op is like a method call - if self.tables.is_method_call(expr.id) { + if self.tables.is_method_call(expr) { let succ = self.propagate_through_expr(&l, succ); self.propagate_through_expr(&r, succ) } else { @@ -1366,7 +1366,7 @@ fn check_expr<'a, 'tcx>(this: &mut Liveness<'a, 'tcx>, expr: &'tcx Expr) { } hir::ExprAssignOp(_, ref l, _) => { - if !this.tables.is_method_call(expr.id) { + if !this.tables.is_method_call(expr) { this.check_lvalue(&l); } diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index cc65777bfce87..f971700b2c86c 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -515,7 +515,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { let expr_ty = self.expr_ty(expr)?; match expr.node { hir::ExprUnary(hir::UnDeref, ref e_base) => { - if self.infcx.tables.borrow().is_method_call(expr.id) { + if self.infcx.tables.borrow().is_method_call(expr) { self.cat_overloaded_lvalue(expr, e_base, false) } else { let base_cmt = self.cat_expr(&e_base)?; @@ -538,7 +538,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { } hir::ExprIndex(ref base, _) => { - if self.infcx.tables.borrow().is_method_call(expr.id()) { + if self.infcx.tables.borrow().is_method_call(expr) { // If this is an index implemented by a method call, then it // will include an implicit deref of the result. // The call to index() returns a `&T` value, which diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index e5cc7aae4e9ce..c2f69147e3a56 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -110,8 +110,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ReachableContext<'a, 'tcx> { Some(self.tables.qpath_def(qpath, expr.id)) } hir::ExprMethodCall(..) => { - let def_id = self.tables.method_map[&expr.id].def_id; - Some(Def::Method(def_id)) + Some(self.tables.type_dependent_defs[&expr.id]) } _ => None }; diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index a0ad3da45e07c..f0cee2fe2b1ca 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -206,8 +206,9 @@ pub struct CommonTypes<'tcx> { #[derive(RustcEncodable, RustcDecodable)] pub struct TypeckTables<'tcx> { - /// Resolved definitions for `::X` associated paths. - pub type_relative_path_defs: NodeMap, + /// Resolved definitions for `::X` associated paths and + /// method calls, including those of overloaded operators. + pub type_dependent_defs: NodeMap, /// Stores the types for various nodes in the AST. Note that this table /// is not guaranteed to be populated until after typeck. See @@ -222,8 +223,6 @@ pub struct TypeckTables<'tcx> { pub adjustments: NodeMap>, - pub method_map: NodeMap>, - /// Borrows pub upvar_capture_map: ty::UpvarCaptureMap<'tcx>, @@ -271,11 +270,10 @@ pub struct TypeckTables<'tcx> { impl<'tcx> TypeckTables<'tcx> { pub fn empty() -> TypeckTables<'tcx> { TypeckTables { - type_relative_path_defs: NodeMap(), + type_dependent_defs: NodeMap(), node_types: FxHashMap(), node_substs: NodeMap(), adjustments: NodeMap(), - method_map: FxHashMap(), upvar_capture_map: FxHashMap(), closure_tys: NodeMap(), closure_kinds: NodeMap(), @@ -294,7 +292,7 @@ impl<'tcx> TypeckTables<'tcx> { match *qpath { hir::QPath::Resolved(_, ref path) => path.def, hir::QPath::TypeRelative(..) => { - self.type_relative_path_defs.get(&id).cloned().unwrap_or(Def::Err) + self.type_dependent_defs.get(&id).cloned().unwrap_or(Def::Err) } } } @@ -357,8 +355,17 @@ impl<'tcx> TypeckTables<'tcx> { .map(|adj| adj.target).or_else(|| self.expr_ty_opt(expr)) } - pub fn is_method_call(&self, expr_id: NodeId) -> bool { - self.method_map.contains_key(&expr_id) + pub fn is_method_call(&self, expr: &hir::Expr) -> bool { + // Only paths and method calls/overloaded operators have + // entries in type_dependent_defs, ignore the former here. + if let hir::ExprPath(_) = expr.node { + return false; + } + + match self.type_dependent_defs.get(&expr.id) { + Some(&Def::Method(_)) => true, + _ => false + } } pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option> { diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index df7c2e567f7e6..76132cab2cd0f 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -141,8 +141,6 @@ pub enum TypeVariants<'tcx> { TyFnDef(DefId, &'tcx Substs<'tcx>, PolyFnSig<'tcx>), /// A pointer to a function. Written as `fn() -> i32`. - /// FIXME: This is currently also used to represent the callee of a method; - /// see ty::MethodCallee etc. TyFnPtr(PolyFnSig<'tcx>), /// A trait, defined with `trait`. diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 8a374358bb998..04645214ce83e 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -881,17 +881,17 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnconditionalRecursion { -> bool { use rustc::ty::adjustment::*; - // Check for method calls and overloaded operators. - if let Some(m) = cx.tables.method_map.get(&id).cloned() { - if method_call_refers_to_method(cx.tcx, method, m.def_id, m.substs, id) { - return true; - } - } + // Ignore non-expressions. + let expr = if let hir_map::NodeExpr(e) = cx.tcx.hir.get(id) { + e + } else { + return false; + }; // Check for overloaded autoderef method calls. - if let Some(Adjustment { + if let Some(&Adjustment { kind: Adjust::DerefRef { ref autoderefs, .. }, .. - }) = cx.tables.adjustments.get(&id).cloned() { + }) = cx.tables.adjustments.get(&id) { for &overloaded in autoderefs { if let Some(m) = overloaded { if method_call_refers_to_method(cx.tcx, method, m.def_id, m.substs, id) { @@ -901,9 +901,18 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnconditionalRecursion { } } + // Check for method calls and overloaded operators. + if cx.tables.is_method_call(expr) { + let def_id = cx.tables.type_dependent_defs[&id].def_id(); + let substs = cx.tables.node_substs(id); + if method_call_refers_to_method(cx.tcx, method, def_id, substs, id) { + return true; + } + } + // Check for calls to methods via explicit paths (e.g. `T::method()`). - match cx.tcx.hir.get(id) { - hir_map::NodeExpr(&hir::Expr { node: hir::ExprCall(ref callee, _), .. }) => { + match expr.node { + hir::ExprCall(ref callee, _) => { let def = if let hir::ExprPath(ref qpath) = callee.node { cx.tables.qpath_def(qpath, callee.id) } else { diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index c11cd38fe3437..cd540f309b0c2 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -118,7 +118,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { overloaded_lvalue(cx, self, mt.ty, - method, + Some(method), PassArgs::ByRef, expr.to_ref(), vec![]) @@ -244,8 +244,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, // Here comes the interesting stuff: hir::ExprMethodCall(.., ref args) => { // Rewrite a.b(c) into UFCS form like Trait::b(a, c) - let method = cx.tables().method_map[&expr.id]; - let expr = method_callee(cx, expr, method); + let expr = method_callee(cx, expr, None); let args = args.iter() .map(|e| e.to_ref()) .collect(); @@ -257,7 +256,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } hir::ExprCall(ref fun, ref args) => { - if let Some(&method) = cx.tables().method_map.get(&expr.id) { + if cx.tables().is_method_call(expr) { // The callee is something implementing Fn, FnMut, or FnOnce. // Find the actual method implementation being called and // build the appropriate UFCS call expression with the @@ -265,7 +264,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, // rewrite f(u, v) into FnOnce::call_once(f, (u, v)) - let method = method_callee(cx, expr, method); + let method = method_callee(cx, expr, None); let arg_tys = args.iter().map(|e| cx.tables().expr_ty_adjusted(e)); let tupled_args = Expr { @@ -346,7 +345,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } hir::ExprAssignOp(op, ref lhs, ref rhs) => { - if let Some(&method) = cx.tables().method_map.get(&expr.id) { + if cx.tables().is_method_call(expr) { let pass_args = if op.node.is_by_value() { PassArgs::ByValue } else { @@ -354,7 +353,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, }; overloaded_operator(cx, expr, - method, + None, pass_args, lhs.to_ref(), vec![rhs]) @@ -370,7 +369,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, hir::ExprLit(..) => ExprKind::Literal { literal: cx.const_eval_literal(expr) }, hir::ExprBinary(op, ref lhs, ref rhs) => { - if let Some(&method) = cx.tables().method_map.get(&expr.id) { + if cx.tables().is_method_call(expr) { let pass_args = if op.node.is_by_value() { PassArgs::ByValue } else { @@ -378,7 +377,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, }; overloaded_operator(cx, expr, - method, + None, pass_args, lhs.to_ref(), vec![rhs]) @@ -430,11 +429,11 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } hir::ExprIndex(ref lhs, ref index) => { - if let Some(&method) = cx.tables().method_map.get(&expr.id) { + if cx.tables().is_method_call(expr) { overloaded_lvalue(cx, expr, expr_ty, - method, + None, PassArgs::ByValue, lhs.to_ref(), vec![index]) @@ -447,11 +446,11 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } hir::ExprUnary(hir::UnOp::UnDeref, ref arg) => { - if let Some(&method) = cx.tables().method_map.get(&expr.id) { + if cx.tables().is_method_call(expr) { overloaded_lvalue(cx, expr, expr_ty, - method, + None, PassArgs::ByValue, arg.to_ref(), vec![]) @@ -461,10 +460,10 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } hir::ExprUnary(hir::UnOp::UnNot, ref arg) => { - if let Some(&method) = cx.tables().method_map.get(&expr.id) { + if cx.tables().is_method_call(expr) { overloaded_operator(cx, expr, - method, + None, PassArgs::ByValue, arg.to_ref(), vec![]) @@ -477,10 +476,10 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } hir::ExprUnary(hir::UnOp::UnNeg, ref arg) => { - if let Some(&method) = cx.tables().method_map.get(&expr.id) { + if cx.tables().is_method_call(expr) { overloaded_operator(cx, expr, - method, + None, PassArgs::ByValue, arg.to_ref(), vec![]) @@ -699,17 +698,21 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, fn method_callee<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, expr: &hir::Expr, - callee: ty::MethodCallee<'tcx>) + custom_callee: Option>) -> Expr<'tcx> { let (temp_lifetime, was_shrunk) = cx.region_maps.temporary_scope2(expr.id); + let (def_id, substs) = custom_callee.map(|m| (m.def_id, m.substs)).unwrap_or_else(|| { + (cx.tables().type_dependent_defs[&expr.id].def_id(), + cx.tables().node_substs(expr.id)) + }); Expr { temp_lifetime: temp_lifetime, temp_lifetime_was_shrunk: was_shrunk, - ty: cx.tcx.type_of(callee.def_id).subst(cx.tcx, callee.substs), + ty: cx.tcx.type_of(def_id).subst(cx.tcx, substs), span: expr.span, kind: ExprKind::Literal { literal: Literal::Value { - value: ConstVal::Function(callee.def_id, callee.substs), + value: ConstVal::Function(def_id, substs), }, }, } @@ -942,7 +945,7 @@ enum PassArgs { fn overloaded_operator<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, expr: &'tcx hir::Expr, - method: ty::MethodCallee<'tcx>, + custom_callee: Option>, pass_args: PassArgs, receiver: ExprRef<'tcx>, args: Vec<&'tcx P>) @@ -985,7 +988,7 @@ fn overloaded_operator<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } // now create the call itself - let fun = method_callee(cx, expr, method); + let fun = method_callee(cx, expr, custom_callee); ExprKind::Call { ty: fun.ty, fun: fun.to_ref(), @@ -996,7 +999,7 @@ fn overloaded_operator<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, fn overloaded_lvalue<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, expr: &'tcx hir::Expr, lvalue_ty: Ty<'tcx>, - method: ty::MethodCallee<'tcx>, + custom_callee: Option>, pass_args: PassArgs, receiver: ExprRef<'tcx>, args: Vec<&'tcx P>) @@ -1025,7 +1028,7 @@ fn overloaded_lvalue<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, // construct the complete expression `foo()` for the overloaded call, // which will yield the &T type let (temp_lifetime, was_shrunk) = cx.region_maps.temporary_scope2(expr.id); - let ref_kind = overloaded_operator(cx, expr, method, pass_args, receiver, args); + let ref_kind = overloaded_operator(cx, expr, custom_callee, pass_args, receiver, args); let ref_expr = Expr { temp_lifetime: temp_lifetime, temp_lifetime_was_shrunk: was_shrunk, diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index 712f5f7ad3906..f73ae9d42f619 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -283,7 +283,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node match e.node { hir::ExprUnary(..) | hir::ExprBinary(..) | - hir::ExprIndex(..) if v.tables.method_map.contains_key(&e.id) => { + hir::ExprIndex(..) if v.tables.is_method_call(e) => { v.promotable = false; } hir::ExprBox(_) => { @@ -380,9 +380,9 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node } } hir::ExprMethodCall(..) => { - let method = v.tables.method_map[&e.id]; - match v.tcx.associated_item(method.def_id).container { - ty::ImplContainer(_) => v.handle_const_fn_call(method.def_id, node_ty), + let def_id = v.tables.type_dependent_defs[&e.id].def_id(); + match v.tcx.associated_item(def_id).container { + ty::ImplContainer(_) => v.handle_const_fn_call(def_id, node_ty), ty::TraitContainer(_) => v.promotable = false } } diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index d0809f0f6429d..b4d74cfb16084 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -564,7 +564,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { } } ast::ExprKind::MethodCall(..) => { - let method_id = self.tables.method_map[&expr.id].def_id; + let method_id = self.tables.type_dependent_defs[&expr.id].def_id(); let (def_id, decl_id) = match self.tcx.associated_item(method_id).container { ty::ImplContainer(_) => (Some(method_id), None), ty::TraitContainer(_) => (None, Some(method_id)), diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index 5302ba0029192..f8560550da49d 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -308,7 +308,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { TupleArgumentsFlag::TupleArguments, expected); - self.tables.borrow_mut().method_map.insert(call_expr.id, method_callee); + self.write_method_call(call_expr.id, method_callee); output_type } } @@ -363,7 +363,7 @@ impl<'a, 'gcx, 'tcx> DeferredCallResolution<'gcx, 'tcx> { target: method_sig.inputs()[0] }); - fcx.tables.borrow_mut().method_map.insert(self.call_expr.id, method_callee); + fcx.write_method_call(self.call_expr.id, method_callee); } None => { span_bug!(self.call_expr.span, diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 71bcff84cc2d6..52ed664799448 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -475,7 +475,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { { debug!("convert_lvalue_op_to_mutable({:?}, {:?}, {:?}, {:?})", op, expr, base_expr, arg_tys); - if !self.tables.borrow().method_map.contains_key(&expr.id) { + if !self.tables.borrow().is_method_call(expr) { debug!("convert_lvalue_op_to_mutable - builtin, nothing to do"); return } @@ -497,7 +497,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { }; let (_, method) = self.register_infer_ok_obligations(ok); debug!("convert_lvalue_op_to_mutable: method={:?}", method); - self.tables.borrow_mut().method_map.insert(expr.id, method); + self.write_method_call(expr.id, method); // Convert the autoref in the base expr to mutable with the correct // region and mutability. diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 0b0233103ef7b..df5023fb7a68a 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1758,6 +1758,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } + pub fn write_method_call(&self, node_id: ast::NodeId, method: ty::MethodCallee<'tcx>) { + self.tables.borrow_mut().type_dependent_defs.insert(node_id, Def::Method(method.def_id)); + self.write_substs(node_id, method.substs); + } + pub fn write_substs(&self, node_id: ast::NodeId, substs: &'tcx Substs<'tcx>) { if !substs.is_noop() { debug!("write_substs({}, {:?}) in fcx {}", @@ -2238,7 +2243,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { target: method.sig.inputs()[0] }); - self.tables.borrow_mut().method_map.insert(expr.id, method); + self.write_method_call(expr.id, method); (input_ty, self.make_overloaded_lvalue_return_type(method).ty) }); if result.is_some() { @@ -2777,7 +2782,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { expr, rcvr) { Ok(method) => { - self.tables.borrow_mut().method_map.insert(expr.id, method); + self.write_method_call(expr.id, method); Ok(method) } Err(error) => { @@ -3453,7 +3458,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { target: method.sig.inputs()[0] }); oprnd_t = self.make_overloaded_lvalue_return_type(method).ty; - self.tables.borrow_mut().method_map.insert(expr.id, method); + self.write_method_call(expr.id, method); } else { self.type_error_message(expr.span, |actual| { format!("type `{}` cannot be \ @@ -3918,7 +3923,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } // Finish resolving a path in a struct expression or pattern `S::A { .. }` if necessary. - // The newly resolved definition is written into `type_relative_path_defs`. + // The newly resolved definition is written into `type_dependent_defs`. fn finish_resolving_struct_path(&self, qpath: &hir::QPath, path_span: Span, @@ -3943,7 +3948,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ty, def, segment); // Write back the new resolution. - self.tables.borrow_mut().type_relative_path_defs.insert(node_id, def); + self.tables.borrow_mut().type_dependent_defs.insert(node_id, def); (def, ty) } @@ -3951,7 +3956,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } // Resolve associated value path into a base type and associated constant or method definition. - // The newly resolved definition is written into `type_relative_path_defs`. + // The newly resolved definition is written into `type_dependent_defs`. pub fn resolve_ty_and_def_ufcs<'b>(&self, qpath: &'b hir::QPath, node_id: ast::NodeId, @@ -3984,7 +3989,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }; // Write back the new resolution. - self.tables.borrow_mut().type_relative_path_defs.insert(node_id, def); + self.tables.borrow_mut().type_dependent_defs.insert(node_id, def); (def, Some(ty), slice::ref_slice(&**item_segment)) } diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index 267b2b0097866..0c820d2404a50 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -421,7 +421,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }, target: method.sig.inputs()[0] }); - self.tables.borrow_mut().method_map.insert(expr.id, method); + self.write_method_call(expr.id, method); Ok(method.sig.output()) } diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 2fae9d8e70e5c..e1451139d6efc 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -520,14 +520,13 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> { self.type_must_outlive(infer::ExprTypeIsNotInScope(expr_ty, expr.span), expr_ty, expr_region); - let opt_method_callee = self.tables.borrow().method_map.get(&expr.id).cloned(); - let has_method_map = opt_method_callee.is_some(); + let is_method_call = self.tables.borrow().is_method_call(expr); // If we are calling a method (either explicitly or via an // overloaded operator), check that all of the types provided as // arguments for its type parameters are well-formed, and all the regions // provided as arguments outlive the call. - if let Some(callee) = opt_method_callee { + if is_method_call { let origin = match expr.node { hir::ExprMethodCall(..) => infer::ParameterOrigin::MethodCall, @@ -537,7 +536,8 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> { infer::ParameterOrigin::OverloadedOperator }; - self.substs_wf_in_scope(origin, &callee.substs, expr.span, expr_region); + let substs = self.tables.borrow().node_substs(expr.id); + self.substs_wf_in_scope(origin, substs, expr.span, expr_region); // Arguments (sub-expressions) are checked via `constrain_call`, below. } @@ -614,7 +614,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> { } hir::ExprCall(ref callee, ref args) => { - if has_method_map { + if is_method_call { self.constrain_call(expr, Some(&callee), args.iter().map(|e| &*e), false); } else { @@ -634,7 +634,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> { } hir::ExprAssignOp(_, ref lhs, ref rhs) => { - if has_method_map { + if is_method_call { self.constrain_call(expr, Some(&lhs), Some(&**rhs).into_iter(), false); } @@ -642,14 +642,14 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> { intravisit::walk_expr(self, expr); } - hir::ExprIndex(ref lhs, ref rhs) if has_method_map => { + hir::ExprIndex(ref lhs, ref rhs) if is_method_call => { self.constrain_call(expr, Some(&lhs), Some(&**rhs).into_iter(), true); intravisit::walk_expr(self, expr); }, - hir::ExprBinary(op, ref lhs, ref rhs) if has_method_map => { + hir::ExprBinary(op, ref lhs, ref rhs) if is_method_call => { let implicitly_ref_args = !op.node.is_by_value(); // As `expr_method_call`, but the call is via an @@ -674,7 +674,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> { intravisit::walk_expr(self, expr); } - hir::ExprUnary(op, ref lhs) if has_method_map => { + hir::ExprUnary(op, ref lhs) if is_method_call => { let implicitly_ref_args = !op.is_by_value(); // As above. @@ -686,7 +686,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> { hir::ExprUnary(hir::UnDeref, ref base) => { // For *a, the lifetime of a must enclose the deref - if self.tables.borrow().is_method_call(expr.id) { + if self.tables.borrow().is_method_call(expr) { self.constrain_call(expr, Some(base), None::.iter(), true); } diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index dcdfed6cbd888..4db0475a18b24 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -106,7 +106,9 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { let inner_ty = self.fcx.resolve_type_vars_if_possible(&inner_ty); if inner_ty.is_scalar() { - self.fcx.tables.borrow_mut().method_map.remove(&e.id); + let mut tables = self.fcx.tables.borrow_mut(); + tables.type_dependent_defs.remove(&e.id); + tables.node_substs.remove(&e.id); } } hir::ExprBinary(ref op, ref lhs, ref rhs) | @@ -118,7 +120,9 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { let rhs_ty = self.fcx.resolve_type_vars_if_possible(&rhs_ty); if lhs_ty.is_scalar() && rhs_ty.is_scalar() { - self.fcx.tables.borrow_mut().method_map.remove(&e.id); + let mut tables = self.fcx.tables.borrow_mut(); + tables.type_dependent_defs.remove(&e.id); + tables.node_substs.remove(&e.id); // weird but true: the by-ref binops put an // adjustment on the lhs but not the rhs; the @@ -127,11 +131,11 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { match e.node { hir::ExprBinary(..) => { if !op.node.is_by_value() { - self.fcx.tables.borrow_mut().adjustments.remove(&lhs.id); + tables.adjustments.remove(&lhs.id); } }, hir::ExprAssignOp(..) => { - self.fcx.tables.borrow_mut().adjustments.remove(&lhs.id); + tables.adjustments.remove(&lhs.id); }, _ => {}, } @@ -164,7 +168,6 @@ impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> { self.fix_scalar_builtin_expr(e); self.visit_node_id(e.span, e.id); - self.visit_method_map_entry(e.span, e.id); if let hir::ExprClosure(_, _, body, _) = e.node { let body = self.fcx.tcx.hir.body(body); @@ -280,9 +283,9 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { } fn visit_node_id(&mut self, span: Span, node_id: ast::NodeId) { - // Export associated path extensions. - if let Some(def) = self.fcx.tables.borrow_mut().type_relative_path_defs.remove(&node_id) { - self.tables.type_relative_path_defs.insert(node_id, def); + // Export associated path extensions and method resultions. + if let Some(def) = self.fcx.tables.borrow_mut().type_dependent_defs.remove(&node_id) { + self.tables.type_dependent_defs.insert(node_id, def); } // Resolve any borrowings for the node with id `node_id` @@ -358,27 +361,6 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { } } - fn visit_method_map_entry(&mut self, - method_span: Span, - node_id: ast::NodeId) { - // Resolve any method map entry - let new_method = match self.fcx.tables.borrow_mut().method_map.remove(&node_id) { - Some(method) => { - Some(MethodCallee { - def_id: method.def_id, - substs: self.resolve(&method.substs, &method_span), - sig: self.resolve(&method.sig, &method_span), - }) - } - None => None - }; - - //NB(jroesch): We need to match twice to avoid a double borrow which would cause an ICE - if let Some(method) = new_method { - self.tables.method_map.insert(node_id, method); - } - } - fn visit_liberated_fn_sigs(&mut self) { for (&node_id, fn_sig) in self.fcx.tables.borrow().liberated_fn_sigs.iter() { let fn_sig = self.resolve(fn_sig, &node_id); From c0e8fffcbfea1d61695acc143b514419826f5ac8 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Sat, 20 May 2017 17:52:05 +0300 Subject: [PATCH 08/14] rustc: remove unused TypeFolder methods. --- src/librustc/ty/fold.rs | 27 --------------------------- src/librustc/ty/structural_impls.rs | 16 ---------------- src/librustc/ty/subst.rs | 4 ---- 3 files changed, 47 deletions(-) diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs index c17a54f4f69bb..bb13031a2b7c4 100644 --- a/src/librustc/ty/fold.rs +++ b/src/librustc/ty/fold.rs @@ -39,8 +39,6 @@ //! These methods return true to indicate that the visitor has found what it is looking for //! and does not need to visit anything else. -use ty::subst::Substs; -use ty::adjustment; use ty::{self, Binder, Ty, TyCtxt, TypeFlags}; use std::fmt; @@ -138,34 +136,9 @@ pub trait TypeFolder<'gcx: 'tcx, 'tcx> : Sized { t.super_fold_with(self) } - fn fold_mt(&mut self, t: &ty::TypeAndMut<'tcx>) -> ty::TypeAndMut<'tcx> { - t.super_fold_with(self) - } - - fn fold_impl_header(&mut self, imp: &ty::ImplHeader<'tcx>) -> ty::ImplHeader<'tcx> { - imp.super_fold_with(self) - } - - fn fold_substs(&mut self, - substs: &'tcx Substs<'tcx>) - -> &'tcx Substs<'tcx> { - substs.super_fold_with(self) - } - - fn fold_fn_sig(&mut self, - sig: &ty::FnSig<'tcx>) - -> ty::FnSig<'tcx> { - sig.super_fold_with(self) - } - fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { r.super_fold_with(self) } - - fn fold_autoref(&mut self, ar: &adjustment::AutoBorrow<'tcx>) - -> adjustment::AutoBorrow<'tcx> { - ar.super_fold_with(self) - } } pub trait TypeVisitor<'tcx> : Sized { diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 9336e7beae20a..60dbbae90cae3 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -532,10 +532,6 @@ impl<'tcx> TypeFoldable<'tcx> for ty::TypeAndMut<'tcx> { ty::TypeAndMut { ty: self.ty.fold_with(folder), mutbl: self.mutbl } } - fn fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - folder.fold_mt(self) - } - fn super_visit_with>(&self, visitor: &mut V) -> bool { self.ty.visit_with(visitor) } @@ -552,10 +548,6 @@ impl<'tcx> TypeFoldable<'tcx> for ty::FnSig<'tcx> { } } - fn fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - folder.fold_fn_sig(self) - } - fn super_visit_with>(&self, visitor: &mut V) -> bool { self.inputs().iter().any(|i| i.visit_with(visitor)) || self.output().visit_with(visitor) @@ -602,10 +594,6 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ImplHeader<'tcx> { } } - fn fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - folder.fold_impl_header(self) - } - fn super_visit_with>(&self, visitor: &mut V) -> bool { self.self_ty.visit_with(visitor) || self.trait_ref.map(|r| r.visit_with(visitor)).unwrap_or(false) || @@ -653,10 +641,6 @@ impl<'tcx> TypeFoldable<'tcx> for ty::adjustment::AutoBorrow<'tcx> { } } - fn fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - folder.fold_autoref(self) - } - fn super_visit_with>(&self, visitor: &mut V) -> bool { match *self { ty::adjustment::AutoBorrow::Ref(r, _m) => r.visit_with(visitor), diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs index e23003bf772f2..d0d61323392c7 100644 --- a/src/librustc/ty/subst.rs +++ b/src/librustc/ty/subst.rs @@ -320,10 +320,6 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx Substs<'tcx> { } } - fn fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - folder.fold_substs(self) - } - fn super_visit_with>(&self, visitor: &mut V) -> bool { self.iter().any(|t| t.visit_with(visitor)) } From 4a754f224d2ec61268649bc2421b7843b686375b Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Sat, 20 May 2017 20:03:04 +0300 Subject: [PATCH 09/14] rustc: replace autoderefs' use of MethodCallee with OverloadedDeref. --- src/librustc/ich/impls_ty.rs | 2 +- src/librustc/middle/expr_use_visitor.rs | 17 +-- src/librustc/middle/mem_categorization.rs | 15 +-- src/librustc/ty/adjustment.rs | 31 +++++- src/librustc/ty/mod.rs | 12 --- src/librustc/ty/structural_impls.rs | 108 ++++++++++++++++++++ src/librustc_lint/builtin.rs | 10 +- src/librustc_mir/hair/cx/expr.rs | 65 ++++++------ src/librustc_typeck/check/autoderef.rs | 25 +++-- src/librustc_typeck/check/callee.rs | 11 +- src/librustc_typeck/check/method/confirm.rs | 8 +- src/librustc_typeck/check/method/mod.rs | 18 +++- src/librustc_typeck/check/mod.rs | 12 +-- src/librustc_typeck/check/regionck.rs | 42 +++----- src/librustc_typeck/check/writeback.rs | 49 +-------- 15 files changed, 261 insertions(+), 164 deletions(-) diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index e607a6bf74a60..22ef88e0e5a9e 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -110,7 +110,7 @@ impl<'a, 'tcx> HashStable> for ty::adjustment::Ad } impl_stable_hash_for!(struct ty::adjustment::Adjustment<'tcx> { kind, target }); -impl_stable_hash_for!(struct ty::MethodCallee<'tcx> { def_id, substs, sig }); +impl_stable_hash_for!(struct ty::adjustment::OverloadedDeref<'tcx> { region, mutbl, target }); impl_stable_hash_for!(struct ty::UpvarId { var_id, closure_expr_id }); impl_stable_hash_for!(struct ty::UpvarBorrow<'tcx> { kind, region }); diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 340a929331ffa..f75f3a145f557 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -745,23 +745,16 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { fn walk_autoderefs(&mut self, expr: &hir::Expr, mut cmt: mc::cmt<'tcx>, - autoderefs: &[Option>]) + autoderefs: &[Option>]) -> mc::McResult> { debug!("walk_autoderefs expr={:?} autoderefs={:?}", expr, autoderefs); for &overloaded in autoderefs { - if let Some(method) = overloaded { - let self_ty = method.sig.inputs()[0]; - let self_ty = self.mc.infcx.resolve_type_vars_if_possible(&self_ty); - - let (m, r) = match self_ty.sty { - ty::TyRef(r, ref m) => (m.mutbl, r), - _ => span_bug!(expr.span, "bad overloaded deref type {:?}", self_ty) - }; - let bk = ty::BorrowKind::from_mutbl(m); + if let Some(deref) = overloaded { + let bk = ty::BorrowKind::from_mutbl(deref.mutbl); self.delegate.borrow(expr.id, expr.span, cmt.clone(), - r, bk, AutoRef); - cmt = self.mc.cat_overloaded_autoderef(expr, method)?; + deref.region, bk, AutoRef); + cmt = self.mc.cat_overloaded_autoderef(expr, deref)?; } else { cmt = self.mc.cat_deref(expr, cmt, false)?; } diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index f971700b2c86c..68c56177490c5 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -485,8 +485,8 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { debug!("cat_expr: autoderefs={:?}, cmt={:?}", autoderefs, cmt); for &overloaded in autoderefs { - if let Some(method) = overloaded { - cmt = self.cat_overloaded_autoderef(expr, method)?; + if let Some(deref) = overloaded { + cmt = self.cat_overloaded_autoderef(expr, deref)?; } else { cmt = self.cat_deref(expr, cmt, false)?; } @@ -936,12 +936,15 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { pub fn cat_overloaded_autoderef(&self, expr: &hir::Expr, - method: ty::MethodCallee<'tcx>) + deref: adjustment::OverloadedDeref<'tcx>) -> McResult> { - debug!("cat_overloaded_autoderef: method={:?}", method); + debug!("cat_overloaded_autoderef: deref={:?}", deref); - let ref_ty = method.sig.output(); - let ref_ty = self.infcx.resolve_type_vars_if_possible(&ref_ty); + let target = self.infcx.resolve_type_vars_if_possible(&deref.target); + let ref_ty = self.tcx().mk_ref(deref.region, ty::TypeAndMut { + ty: target, + mutbl: deref.mutbl, + }); let base_cmt = self.cat_rvalue_node(expr.id, expr.span, ref_ty); self.cat_deref(expr, base_cmt, false) } diff --git a/src/librustc/ty/adjustment.rs b/src/librustc/ty/adjustment.rs index 629f94609aa37..55f85ef003b1c 100644 --- a/src/librustc/ty/adjustment.rs +++ b/src/librustc/ty/adjustment.rs @@ -8,9 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use ty::{self, Ty, TyCtxt, TypeAndMut}; - use hir; +use hir::def_id::DefId; +use ty::{self, Ty, TyCtxt, TypeAndMut}; +use ty::subst::Substs; #[derive(Clone, RustcEncodable, RustcDecodable)] pub struct Adjustment<'tcx> { @@ -105,7 +106,7 @@ pub enum Adjust<'tcx> { /// ``` DerefRef { /// Step 1. Apply a number of dereferences, producing an lvalue. - autoderefs: Vec>>, + autoderefs: Vec>>, /// Step 2. Optionally produce a pointer/reference from the value. autoref: Option>, @@ -136,6 +137,30 @@ impl<'tcx> Adjustment<'tcx> { } } +/// An overloaded autoderef step, representing a `Deref(Mut)::deref(_mut)` +/// call, with the signature `&'a T -> &'a U` or `&'a mut T -> &'a mut U`. +/// The target type is `U` in both cases, with the region and mutability +/// being those shared by both the receiver and the returned reference. +#[derive(Copy, Clone, PartialEq, Debug, RustcEncodable, RustcDecodable)] +pub struct OverloadedDeref<'tcx> { + pub region: ty::Region<'tcx>, + pub mutbl: hir::Mutability, + pub target: Ty<'tcx>, +} + +impl<'a, 'gcx, 'tcx> OverloadedDeref<'tcx> { + pub fn method_call(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, source: Ty<'tcx>) + -> (DefId, &'tcx Substs<'tcx>) { + let trait_def_id = match self.mutbl { + hir::MutImmutable => tcx.lang_items.deref_trait(), + hir::MutMutable => tcx.lang_items.deref_mut_trait() + }; + let method_def_id = tcx.associated_items(trait_def_id.unwrap()) + .find(|m| m.kind == ty::AssociatedKind::Method).unwrap().def_id; + (method_def_id, tcx.mk_substs_trait(source, &[])) + } +} + #[derive(Copy, Clone, PartialEq, Debug, RustcEncodable, RustcDecodable)] pub enum AutoBorrow<'tcx> { /// Convert from T to &T. diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index a45f85db4c257..259f44d9d1391 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -390,18 +390,6 @@ impl Variance { } } -#[derive(Clone, Copy, Debug, RustcDecodable, RustcEncodable)] -pub struct MethodCallee<'tcx> { - /// Impl method ID, for inherent methods, or trait method ID, otherwise. - pub def_id: DefId, - pub substs: &'tcx Substs<'tcx>, - - /// Instantiated method signature, i.e. it has been substituted, - /// normalized, and has had late-bound lifetimes replaced - /// (with inference variables, during type-checking). - pub sig: FnSig<'tcx>, -} - // Contains information needed to resolve types and (in the future) look up // the types of AST nodes. #[derive(Copy, Clone, PartialEq, Eq, Hash)] diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 60dbbae90cae3..811b383324de3 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -220,6 +220,55 @@ impl<'a, 'tcx> Lift<'tcx> for ty::ClosureSubsts<'a> { } } +impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::Adjustment<'a> { + type Lifted = ty::adjustment::Adjustment<'tcx>; + fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { + tcx.lift(&self.kind).and_then(|kind| { + tcx.lift(&self.target).map(|target| { + ty::adjustment::Adjustment { kind, target } + }) + }) + } +} + +impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::Adjust<'a> { + type Lifted = ty::adjustment::Adjust<'tcx>; + fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { + match *self { + ty::adjustment::Adjust::NeverToAny => + Some(ty::adjustment::Adjust::NeverToAny), + ty::adjustment::Adjust::ReifyFnPointer => + Some(ty::adjustment::Adjust::ReifyFnPointer), + ty::adjustment::Adjust::UnsafeFnPointer => + Some(ty::adjustment::Adjust::UnsafeFnPointer), + ty::adjustment::Adjust::ClosureFnPointer => + Some(ty::adjustment::Adjust::ClosureFnPointer), + ty::adjustment::Adjust::MutToConstPointer => + Some(ty::adjustment::Adjust::MutToConstPointer), + ty::adjustment::Adjust::DerefRef { ref autoderefs, ref autoref, unsize } => { + tcx.lift(autoderefs).and_then(|autoderefs| { + tcx.lift(autoref).map(|autoref| { + ty::adjustment::Adjust::DerefRef { autoderefs, autoref, unsize } + }) + }) + } + } + } +} + +impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::OverloadedDeref<'a> { + type Lifted = ty::adjustment::OverloadedDeref<'tcx>; + fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { + tcx.lift(&(self.region, self.target)).map(|(region, target)| { + ty::adjustment::OverloadedDeref { + region, + mutbl: self.mutbl, + target, + } + }) + } +} + impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::AutoBorrow<'a> { type Lifted = ty::adjustment::AutoBorrow<'tcx>; fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { @@ -631,6 +680,65 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ClosureSubsts<'tcx> { } } +impl<'tcx> TypeFoldable<'tcx> for ty::adjustment::Adjustment<'tcx> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + ty::adjustment::Adjustment { + kind: self.kind.fold_with(folder), + target: self.target.fold_with(folder), + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.kind.visit_with(visitor) || self.target.visit_with(visitor) + } +} + +impl<'tcx> TypeFoldable<'tcx> for ty::adjustment::Adjust<'tcx> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + match *self { + ty::adjustment::Adjust::NeverToAny | + ty::adjustment::Adjust::ReifyFnPointer | + ty::adjustment::Adjust::UnsafeFnPointer | + ty::adjustment::Adjust::ClosureFnPointer | + ty::adjustment::Adjust::MutToConstPointer => self.clone(), + ty::adjustment::Adjust::DerefRef { ref autoderefs, ref autoref, unsize } => { + ty::adjustment::Adjust::DerefRef { + autoderefs: autoderefs.fold_with(folder), + autoref: autoref.fold_with(folder), + unsize, + } + } + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + match *self { + ty::adjustment::Adjust::NeverToAny | + ty::adjustment::Adjust::ReifyFnPointer | + ty::adjustment::Adjust::UnsafeFnPointer | + ty::adjustment::Adjust::ClosureFnPointer | + ty::adjustment::Adjust::MutToConstPointer => false, + ty::adjustment::Adjust::DerefRef { ref autoderefs, ref autoref, unsize: _ } => { + autoderefs.visit_with(visitor) || autoref.visit_with(visitor) + } + } + } +} + +impl<'tcx> TypeFoldable<'tcx> for ty::adjustment::OverloadedDeref<'tcx> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + ty::adjustment::OverloadedDeref { + region: self.region.fold_with(folder), + mutbl: self.mutbl, + target: self.target.fold_with(folder), + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.region.visit_with(visitor) || self.target.visit_with(visitor) + } +} + impl<'tcx> TypeFoldable<'tcx> for ty::adjustment::AutoBorrow<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { match *self { diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 04645214ce83e..b0bfda4a65875 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -892,11 +892,17 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnconditionalRecursion { if let Some(&Adjustment { kind: Adjust::DerefRef { ref autoderefs, .. }, .. }) = cx.tables.adjustments.get(&id) { + let mut source = cx.tables.expr_ty(expr); for &overloaded in autoderefs { - if let Some(m) = overloaded { - if method_call_refers_to_method(cx.tcx, method, m.def_id, m.substs, id) { + if let Some(deref) = overloaded { + let (def_id, substs) = deref.method_call(cx.tcx, source); + if method_call_refers_to_method(cx.tcx, method, def_id, substs, id) { return true; } + source = deref.target; + } else { + source = source.builtin_deref(true, + ty::LvaluePreference::NoPreference).unwrap().ty; } } } diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index cd540f309b0c2..05f6381d93468 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -89,55 +89,56 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { Some((&ty::adjustment::Adjust::DerefRef { ref autoderefs, autoref, unsize }, adjusted_ty)) => { for &overloaded in autoderefs { - let mut ref_ty = expr.ty; - let kind = if let Some(method) = overloaded { - debug!("make_mirror: overloaded autoderef (method={:?})", method); - - ref_ty = method.sig.output(); - let (region, mt) = match ref_ty.sty { - ty::TyRef(region, mt) => (region, mt), - _ => span_bug!(expr.span, "autoderef returned bad type"), - }; + let source = expr.ty; + let target; + let kind = if let Some(deref) = overloaded { + debug!("make_mirror: overloaded autoderef ({:?})", deref); expr = Expr { temp_lifetime: temp_lifetime, temp_lifetime_was_shrunk: was_shrunk, - ty: cx.tcx.mk_ref(region, + ty: cx.tcx.mk_ref(deref.region, ty::TypeAndMut { - ty: expr.ty, - mutbl: mt.mutbl, + ty: source, + mutbl: deref.mutbl, }), span: expr.span, kind: ExprKind::Borrow { - region: region, - borrow_kind: to_borrow_kind(mt.mutbl), + region: deref.region, + borrow_kind: to_borrow_kind(deref.mutbl), arg: expr.to_ref(), }, }; + target = deref.target; + + let call = deref.method_call(cx.tcx, source); overloaded_lvalue(cx, self, - mt.ty, - Some(method), + deref.target, + Some(call), PassArgs::ByRef, expr.to_ref(), vec![]) } else { + match source.builtin_deref(true, + ty::LvaluePreference::NoPreference) { + Some(mt) => { + target = mt.ty; + } + None => { + span_bug!(self.span, "autoderef for {} failed: {}", + self.id, source); + } + }; debug!("make_mirror: built-in autoderef"); ExprKind::Deref { arg: expr.to_ref() } }; - let adjusted_ty = match ref_ty.builtin_deref(true, - ty::LvaluePreference::NoPreference) { - Some(mt) => mt.ty, - None => { - span_bug!(self.span, "autoderef for {} failed: {}", self.id, ref_ty); - } - }; - debug!("make_mirror: autoderef adjusted_ty={:?}", adjusted_ty); + debug!("make_mirror: autoderef target={:?}", target); expr = Expr { temp_lifetime: temp_lifetime, temp_lifetime_was_shrunk: was_shrunk, - ty: adjusted_ty, + ty: target, span: self.span, kind: kind, }; @@ -698,10 +699,10 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, fn method_callee<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, expr: &hir::Expr, - custom_callee: Option>) + custom_callee: Option<(DefId, &'tcx Substs<'tcx>)>) -> Expr<'tcx> { let (temp_lifetime, was_shrunk) = cx.region_maps.temporary_scope2(expr.id); - let (def_id, substs) = custom_callee.map(|m| (m.def_id, m.substs)).unwrap_or_else(|| { + let (def_id, substs) = custom_callee.unwrap_or_else(|| { (cx.tables().type_dependent_defs[&expr.id].def_id(), cx.tables().node_substs(expr.id)) }); @@ -945,7 +946,7 @@ enum PassArgs { fn overloaded_operator<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, expr: &'tcx hir::Expr, - custom_callee: Option>, + custom_callee: Option<(DefId, &'tcx Substs<'tcx>)>, pass_args: PassArgs, receiver: ExprRef<'tcx>, args: Vec<&'tcx P>) @@ -999,7 +1000,7 @@ fn overloaded_operator<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, fn overloaded_lvalue<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, expr: &'tcx hir::Expr, lvalue_ty: Ty<'tcx>, - custom_callee: Option>, + custom_callee: Option<(DefId, &'tcx Substs<'tcx>)>, pass_args: PassArgs, receiver: ExprRef<'tcx>, args: Vec<&'tcx P>) @@ -1016,13 +1017,13 @@ fn overloaded_lvalue<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, // Reconstruct the output assuming it's a reference with the // same region and mutability as the receiver. This holds for // `Deref(Mut)::Deref(_mut)` and `Index(Mut)::index(_mut)`. - let (region, mutbl) = match recv_ty.sty { - ty::TyRef(region, mt) => (region, mt.mutbl), + let (region, mt) = match recv_ty.sty { + ty::TyRef(region, mt) => (region, mt), _ => span_bug!(expr.span, "overloaded_lvalue: receiver is not a reference"), }; let ref_ty = cx.tcx.mk_ref(region, ty::TypeAndMut { ty: lvalue_ty, - mutbl, + mutbl: mt.mutbl, }); // construct the complete expression `foo()` for the overloaded call, diff --git a/src/librustc_typeck/check/autoderef.rs b/src/librustc_typeck/check/autoderef.rs index 098674519b4d8..36671521474a0 100644 --- a/src/librustc_typeck/check/autoderef.rs +++ b/src/librustc_typeck/check/autoderef.rs @@ -11,13 +11,14 @@ use astconv::AstConv; use super::{FnCtxt, LvalueOp}; +use super::method::MethodCallee; use rustc::infer::InferOk; use rustc::traits; use rustc::ty::{self, Ty, TraitRef}; use rustc::ty::{ToPredicate, TypeFoldable}; use rustc::ty::{LvaluePreference, NoPreference}; -use rustc::ty::adjustment::AutoBorrow; +use rustc::ty::adjustment::{AutoBorrow, OverloadedDeref}; use syntax_pos::Span; use syntax::symbol::Symbol; @@ -153,19 +154,27 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> { /// Returns the steps required in adjustments (overloaded deref calls). pub fn adjust_steps(&self, pref: LvaluePreference) - -> Vec>> { + -> Vec>> { self.fcx.register_infer_ok_obligations(self.adjust_steps_as_infer_ok(pref)) } pub fn adjust_steps_as_infer_ok(&self, pref: LvaluePreference) - -> InferOk<'tcx, Vec>>> { + -> InferOk<'tcx, Vec>>> { let mut obligations = vec![]; - let steps: Vec<_> = self.steps.iter().map(|&(ty, kind)| { + let steps: Vec<_> = self.steps.iter().map(|&(source, kind)| { if let AutoderefKind::Overloaded = kind { - self.fcx.try_overloaded_deref(self.span, ty, pref) - .map(|InferOk { value: (_, method), obligations: o }| { + self.fcx.try_overloaded_deref(self.span, source, pref) + .and_then(|InferOk { value: (_, method), obligations: o }| { obligations.extend(o); - method + if let ty::TyRef(region, mt) = method.sig.output().sty { + Some(OverloadedDeref { + region, + mutbl: mt.mutbl, + target: mt.ty + }) + } else { + None + } }) } else { None @@ -206,7 +215,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pref: LvaluePreference) -> Option>, - ty::MethodCallee<'tcx>)>> { + MethodCallee<'tcx>)>> { self.try_overloaded_lvalue_op(span, base_ty, &[], pref, LvalueOp::Deref) } } diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index f8560550da49d..b498d0f80826b 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -10,13 +10,14 @@ use super::{Expectation, FnCtxt, TupleArgumentsFlag}; use super::autoderef::Autoderef; +use super::method::MethodCallee; use hir::def::Def; use hir::def_id::{DefId, LOCAL_CRATE}; use rustc::{infer, traits}; use rustc::ty::{self, TyCtxt, LvaluePreference, Ty}; use rustc::ty::subst::Subst; -use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow}; +use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, OverloadedDeref}; use syntax::abi; use syntax::symbol::Symbol; use syntax_pos::Span; @@ -37,7 +38,7 @@ pub fn check_legal_trait_for_method_call(tcx: TyCtxt, span: Span, trait_id: DefI enum CallStep<'tcx> { Builtin(Ty<'tcx>), DeferredClosure(ty::FnSig<'tcx>), - Overloaded(ty::MethodCallee<'tcx>), + Overloaded(MethodCallee<'tcx>), } impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { @@ -158,7 +159,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { call_expr: &hir::Expr, adjusted_ty: Ty<'tcx>) -> Option<(Option>, - ty::MethodCallee<'tcx>)> { + MethodCallee<'tcx>)> { // Try the options that are least restrictive on the caller first. for &(opt_trait_def_id, method_name) in &[(self.tcx.lang_items.fn_trait(), Symbol::intern("call")), @@ -300,7 +301,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { call_expr: &hir::Expr, arg_exprs: &'gcx [hir::Expr], expected: Expectation<'tcx>, - method_callee: ty::MethodCallee<'tcx>) + method_callee: MethodCallee<'tcx>) -> Ty<'tcx> { let output_type = self.check_method_argument_types(call_expr.span, Ok(method_callee), @@ -318,7 +319,7 @@ pub struct DeferredCallResolution<'gcx: 'tcx, 'tcx> { call_expr: &'gcx hir::Expr, callee_expr: &'gcx hir::Expr, adjusted_ty: Ty<'tcx>, - autoderefs: Vec>>, + autoderefs: Vec>>, fn_sig: ty::FnSig<'tcx>, closure_def_id: DefId, } diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 52ed664799448..ad05a83918907 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use super::probe; +use super::{probe, MethodCallee}; use check::{FnCtxt, LvalueOp, callee}; use hir::def_id::DefId; @@ -45,7 +45,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { unadjusted_self_ty: Ty<'tcx>, pick: probe::Pick<'tcx>, supplied_method_types: Vec>) - -> ty::MethodCallee<'tcx> { + -> MethodCallee<'tcx> { debug!("confirm(unadjusted_self_ty={:?}, pick={:?}, supplied_method_types={:?})", unadjusted_self_ty, pick, @@ -74,7 +74,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { unadjusted_self_ty: Ty<'tcx>, pick: probe::Pick<'tcx>, supplied_method_types: Vec>) - -> ty::MethodCallee<'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); @@ -98,7 +98,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { self.add_obligations(method_ty, all_substs, &method_predicates); // Create the final `MethodCallee`. - let callee = ty::MethodCallee { + let callee = MethodCallee { def_id: pick.item.def_id, substs: all_substs, sig: method_sig, diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index dd58fdbf073ab..688def4356ccc 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -36,6 +36,18 @@ mod suggest; use self::probe::IsSuggestion; +#[derive(Clone, Copy, Debug)] +pub struct MethodCallee<'tcx> { + /// Impl method ID, for inherent methods, or trait method ID, otherwise. + pub def_id: DefId, + pub substs: &'tcx Substs<'tcx>, + + /// Instantiated method signature, i.e. it has been + /// substituted, normalized, and has had late-bound + /// lifetimes replaced with inference variables. + pub sig: ty::FnSig<'tcx>, +} + pub enum MethodError<'tcx> { // Did not find an applicable method, but we did find various near-misses that may work. NoMatch(NoMatchData<'tcx>), @@ -125,7 +137,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { supplied_method_types: Vec>, call_expr: &'gcx hir::Expr, self_expr: &'gcx hir::Expr) - -> Result, MethodError<'tcx>> { + -> Result, MethodError<'tcx>> { debug!("lookup(method_name={}, self_ty={:?}, call_expr={:?}, self_expr={:?})", method_name, self_ty, @@ -172,7 +184,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { opt_input_types: Option<&[ty::Ty<'tcx>]>) -> Option>, - ty::MethodCallee<'tcx>)>> { + MethodCallee<'tcx>)>> { debug!("lookup_in_trait_adjusted(self_ty={:?}, \ m_name={}, trait_def_id={:?})", self_ty, @@ -279,7 +291,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } }; - let callee = ty::MethodCallee { + let callee = MethodCallee { def_id: def_id, substs: trait_ref.substs, sig: fn_sig, diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index df5023fb7a68a..bc76c56599d02 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -81,6 +81,7 @@ use self::autoderef::Autoderef; use self::callee::DeferredCallResolution; use self::coercion::{CoerceMany, DynamicCoerceMany}; pub use self::compare_method::{compare_impl_method, compare_const_impl}; +use self::method::MethodCallee; use self::TupleArgumentsFlag::*; use astconv::AstConv; @@ -95,8 +96,7 @@ use rustc::ty::subst::{Kind, Subst, Substs}; use rustc::traits::{self, FulfillmentContext, ObligationCause, ObligationCauseCode, Reveal}; use rustc::ty::{ParamTy, LvaluePreference, NoPreference, PreferMutLvalue}; use rustc::ty::{self, Ty, TyCtxt, Visibility}; -use rustc::ty::{MethodCallee}; -use rustc::ty::adjustment::{Adjust, Adjustment, AutoBorrow}; +use rustc::ty::adjustment::{Adjust, Adjustment, AutoBorrow, OverloadedDeref}; use rustc::ty::fold::{BottomUpFolder, TypeFoldable}; use rustc::ty::maps::Providers; use rustc::ty::util::{Representability, IntTypeExt}; @@ -1758,7 +1758,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } - pub fn write_method_call(&self, node_id: ast::NodeId, method: ty::MethodCallee<'tcx>) { + pub fn write_method_call(&self, node_id: ast::NodeId, method: MethodCallee<'tcx>) { self.tables.borrow_mut().type_dependent_defs.insert(node_id, Def::Method(method.def_id)); self.write_substs(node_id, method.substs); } @@ -1776,7 +1776,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn apply_autoderef_adjustment(&self, node_id: ast::NodeId, - autoderefs: Vec>>, + autoderefs: Vec>>, adjusted_ty: Ty<'tcx>) { self.apply_adjustment(node_id, Adjustment { kind: Adjust::DerefRef { @@ -2276,7 +2276,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { op: LvalueOp) -> Option>, - ty::MethodCallee<'tcx>)>> + MethodCallee<'tcx>)>> { debug!("try_overloaded_lvalue_op({:?},{:?},{:?},{:?})", span, @@ -2315,7 +2315,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn check_method_argument_types(&self, sp: Span, - method: Result, ()>, + method: Result, ()>, args_no_rcvr: &'gcx [hir::Expr], tuple_arguments: TupleArgumentsFlag, expected: Expectation<'tcx>) diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index e1451139d6efc..7fff0ceb7788c 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -906,7 +906,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { /// dereferenced, the lifetime of the pointer includes the deref expr. fn constrain_autoderefs(&mut self, deref_expr: &hir::Expr, - autoderefs: &[Option>]) + autoderefs: &[Option>]) -> mc::McResult> { debug!("constrain_autoderefs(deref_expr={:?}, autoderefs={:?})", @@ -920,43 +920,35 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { let r_deref_expr = self.tcx.node_scope_region(deref_expr.id); for &overloaded in autoderefs { - if let Some(method) = overloaded { - debug!("constrain_autoderefs: overloaded, method={:?}", method); - - let origin = infer::ParameterOrigin::OverloadedDeref; - self.substs_wf_in_scope(origin, method.substs, deref_expr.span, r_deref_expr); + if let Some(deref) = overloaded { + debug!("constrain_autoderefs: overloaded, {:?}", deref); // Treat overloaded autoderefs as if an AutoBorrow adjustment // was applied on the base type, as that is always the case. - let self_ty = method.sig.inputs()[0]; - let (m, r) = match self_ty.sty { - ty::TyRef(r, ref m) => (m.mutbl, r), - _ => { - span_bug!( - deref_expr.span, - "bad overloaded deref type {:?}", - method.sig) - } - }; - - debug!("constrain_autoderefs: receiver r={:?} m={:?}", - r, m); + let input = self.tcx.mk_ref(deref.region, ty::TypeAndMut { + ty: cmt.ty, + mutbl: deref.mutbl, + }); + let output = self.tcx.mk_ref(deref.region, ty::TypeAndMut { + ty: deref.target, + mutbl: deref.mutbl, + }); debug!("constrain_autoderefs: self_cmt={:?}", cmt); - self.link_region(deref_expr.span, r, - ty::BorrowKind::from_mutbl(m), cmt.clone()); + self.link_region(deref_expr.span, deref.region, + ty::BorrowKind::from_mutbl(deref.mutbl), cmt.clone()); // Specialized version of constrain_call. self.type_must_outlive(infer::CallRcvr(deref_expr.span), - self_ty, r_deref_expr); + input, r_deref_expr); self.type_must_outlive(infer::CallReturn(deref_expr.span), - method.sig.output(), r_deref_expr); + output, r_deref_expr); } { let mc = mc::MemCategorizationContext::new(self, &self.region_maps); - if let Some(method) = overloaded { - cmt = mc.cat_overloaded_autoderef(deref_expr, method)?; + if let Some(deref) = overloaded { + cmt = mc.cat_overloaded_autoderef(deref_expr, deref)?; } else { cmt = mc.cat_deref(deref_expr, cmt, false)?; } diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 4db0475a18b24..0b93db5498099 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -16,8 +16,7 @@ use check::FnCtxt; use rustc::hir; use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; use rustc::infer::{InferCtxt}; -use rustc::ty::{self, Ty, TyCtxt, MethodCallee}; -use rustc::ty::adjustment; +use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::fold::{TypeFolder,TypeFoldable}; use rustc::util::nodemap::DefIdSet; use syntax::ast; @@ -307,54 +306,14 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { } fn visit_adjustments(&mut self, span: Span, node_id: ast::NodeId) { - let adjustments = self.fcx.tables.borrow_mut().adjustments.remove(&node_id); - match adjustments { + let adjustment = self.fcx.tables.borrow_mut().adjustments.remove(&node_id); + match adjustment { None => { debug!("No adjustments for node {}", node_id); } Some(adjustment) => { - let resolved_adjustment = match adjustment.kind { - adjustment::Adjust::NeverToAny => { - adjustment::Adjust::NeverToAny - } - - adjustment::Adjust::ReifyFnPointer => { - adjustment::Adjust::ReifyFnPointer - } - - adjustment::Adjust::MutToConstPointer => { - adjustment::Adjust::MutToConstPointer - } - - adjustment::Adjust::ClosureFnPointer => { - adjustment::Adjust::ClosureFnPointer - } - - adjustment::Adjust::UnsafeFnPointer => { - adjustment::Adjust::UnsafeFnPointer - } - - adjustment::Adjust::DerefRef { autoderefs, autoref, unsize } => { - adjustment::Adjust::DerefRef { - autoderefs: autoderefs.iter().map(|overloaded| { - overloaded.map(|method| { - MethodCallee { - def_id: method.def_id, - substs: self.resolve(&method.substs, &span), - sig: self.resolve(&method.sig, &span), - } - }) - }).collect(), - autoref: self.resolve(&autoref, &span), - unsize: unsize, - } - } - }; - let resolved_adjustment = adjustment::Adjustment { - kind: resolved_adjustment, - target: self.resolve(&adjustment.target, &span) - }; + let resolved_adjustment = self.resolve(&adjustment, &span); debug!("Adjustments for node {}: {:?}", node_id, resolved_adjustment); self.tables.adjustments.insert(node_id, resolved_adjustment); } From 91d603a2a7ad6caed2275da0c7ae21d845ed72d1 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Sat, 20 May 2017 23:52:52 +0300 Subject: [PATCH 10/14] rustc: move autoref and unsize from Adjust::DerefRef to Adjustment. --- src/librustc/ich/impls_ty.rs | 6 +- src/librustc/middle/expr_use_visitor.rs | 29 ++-- src/librustc/middle/mem_categorization.rs | 9 +- src/librustc/ty/adjustment.rs | 169 ++++++++++---------- src/librustc/ty/structural_impls.rs | 35 ++-- src/librustc_lint/builtin.rs | 2 +- src/librustc_lint/unused.rs | 24 ++- src/librustc_mir/hair/cx/expr.rs | 113 ++++++------- src/librustc_passes/consts.rs | 2 +- src/librustc_typeck/check/callee.rs | 16 +- src/librustc_typeck/check/coercion.rs | 116 ++++++++------ src/librustc_typeck/check/method/confirm.rs | 17 +- src/librustc_typeck/check/mod.rs | 40 +++-- src/librustc_typeck/check/op.rs | 8 +- src/librustc_typeck/check/regionck.rs | 8 +- 15 files changed, 290 insertions(+), 304 deletions(-) diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 22ef88e0e5a9e..f0fdb94b81b36 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -100,16 +100,14 @@ impl<'a, 'tcx> HashStable> for ty::adjustment::Ad ty::adjustment::Adjust::UnsafeFnPointer | ty::adjustment::Adjust::ClosureFnPointer | ty::adjustment::Adjust::MutToConstPointer => {} - ty::adjustment::Adjust::DerefRef { ref autoderefs, ref autoref, unsize } => { + ty::adjustment::Adjust::Deref(ref autoderefs) => { autoderefs.hash_stable(hcx, hasher); - autoref.hash_stable(hcx, hasher); - unsize.hash_stable(hcx, hasher); } } } } -impl_stable_hash_for!(struct ty::adjustment::Adjustment<'tcx> { kind, target }); +impl_stable_hash_for!(struct ty::adjustment::Adjustment<'tcx> { kind, autoref, unsize, target }); impl_stable_hash_for!(struct ty::adjustment::OverloadedDeref<'tcx> { region, mutbl, target }); impl_stable_hash_for!(struct ty::UpvarId { var_id, closure_expr_id }); impl_stable_hash_for!(struct ty::UpvarBorrow<'tcx> { kind, region }); diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index f75f3a145f557..9120990777dfa 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -707,9 +707,9 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { let infcx = self.mc.infcx; //NOTE(@jroesch): mixed RefCell borrow causes crash let adj = infcx.tables.borrow().adjustments.get(&expr.id).cloned(); - let cmt_unadjusted = - return_if_err!(self.mc.cat_expr_unadjusted(expr)); + let mut cmt = return_if_err!(self.mc.cat_expr_unadjusted(expr)); if let Some(adjustment) = adj { + debug!("walk_adjustment expr={:?} adj={:?}", expr, adjustment); match adjustment.kind { adjustment::Adjust::NeverToAny | adjustment::Adjust::ReifyFnPointer | @@ -718,23 +718,20 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { adjustment::Adjust::MutToConstPointer => { // Creating a closure/fn-pointer or unsizing consumes // the input and stores it into the resulting rvalue. - debug!("walk_adjustment: trivial adjustment"); - self.delegate_consume(expr.id, expr.span, cmt_unadjusted); + self.delegate_consume(expr.id, expr.span, cmt); + assert!(adjustment.autoref.is_none() && !adjustment.unsize); + return; } - adjustment::Adjust::DerefRef { ref autoderefs, autoref, unsize } => { - debug!("walk_adjustment expr={:?} adj={:?}", expr, adjustment); - - let cmt_derefd = - return_if_err!(self.walk_autoderefs(expr, cmt_unadjusted, autoderefs)); + adjustment::Adjust::Deref(ref autoderefs) => { + cmt = return_if_err!(self.walk_autoderefs(expr, cmt, autoderefs)); + } + } - let cmt_refd = - self.walk_autoref(expr, cmt_derefd, autoref); + cmt = self.walk_autoref(expr, cmt, adjustment.autoref); - if unsize { - // Unsizing consumes the thin pointer and produces a fat one. - self.delegate_consume(expr.id, expr.span, cmt_refd); - } - } + if adjustment.unsize { + // Unsizing consumes the thin pointer and produces a fat one. + self.delegate_consume(expr.id, expr.span, cmt); } } } diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 68c56177490c5..707b52a1a22fa 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -475,11 +475,8 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { Some(adjustment) => { debug!("cat_expr({:?}): {:?}", adjustment, expr); match adjustment.kind { - adjustment::Adjust::DerefRef { - ref autoderefs, - autoref: None, - unsize: false - } => { + adjustment::Adjust::Deref(ref autoderefs) + if adjustment.autoref.is_none() && !adjustment.unsize => { // Equivalent to *expr or something similar. let mut cmt = self.cat_expr_unadjusted(expr)?; debug!("cat_expr: autoderefs={:?}, cmt={:?}", @@ -499,7 +496,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { adjustment::Adjust::UnsafeFnPointer | adjustment::Adjust::ClosureFnPointer | adjustment::Adjust::MutToConstPointer | - adjustment::Adjust::DerefRef {..} => { + adjustment::Adjust::Deref(_) => { // Result is an rvalue. let expr_ty = self.expr_ty_adjusted(expr)?; Ok(self.cat_rvalue_node(expr.id(), expr.span(), expr_ty)) diff --git a/src/librustc/ty/adjustment.rs b/src/librustc/ty/adjustment.rs index 55f85ef003b1c..e2e017e9f519a 100644 --- a/src/librustc/ty/adjustment.rs +++ b/src/librustc/ty/adjustment.rs @@ -13,10 +13,83 @@ use hir::def_id::DefId; use ty::{self, Ty, TyCtxt, TypeAndMut}; use ty::subst::Substs; + +/// Represents coercing a value to a different type of value. +/// +/// We transform values by following the following steps in order: +/// 1. Apply a step of `Adjust` (see its variants for details). +/// 2. If `autoref` is `Some(_)`, then take the address and produce either a +/// `&` or `*` pointer. +/// 3. If `unsize` is `true`, then apply the unsize transformation, +/// which will do things like convert thin pointers to fat +/// pointers, or convert structs containing thin pointers to +/// structs containing fat pointers, or convert between fat +/// pointers. We don't store the details of how the transform is +/// done (in fact, we don't know that, because it might depend on +/// the precise type parameters). We just store the target +/// type. Trans figures out what has to be done at monomorphization +/// time based on the precise source/target type at hand. +/// +/// To make that more concrete, here are some common scenarios: +/// +/// 1. The simplest cases are where the pointer is not adjusted fat vs thin. +/// Here the pointer will be dereferenced N times (where a dereference can +/// happen to raw or borrowed pointers or any smart pointer which implements +/// Deref, including Box<_>). The types of dereferences is given by +/// `autoderefs`. It can then be auto-referenced zero or one times, indicated +/// by `autoref`, to either a raw or borrowed pointer. In these cases unsize is +/// `false`. +/// +/// 2. A thin-to-fat coercon involves unsizing the underlying data. We start +/// with a thin pointer, deref a number of times, unsize the underlying data, +/// then autoref. The 'unsize' phase may change a fixed length array to a +/// dynamically sized one, a concrete object to a trait object, or statically +/// sized struct to a dynamically sized one. E.g., &[i32; 4] -> &[i32] is +/// represented by: +/// +/// ``` +/// Adjustment { +/// kind: Adjust::Deref(vec![None]),// &[i32; 4] -> [i32; 4] +/// autoref: Some(AutoBorrow::Ref), // [i32; 4] -> &[i32; 4] +/// unsize: true, // &[i32; 4] -> &[i32] +/// target: `[i32]`, +/// } +/// ``` +/// +/// Note that for a struct, the 'deep' unsizing of the struct is not recorded. +/// E.g., `struct Foo { x: T }` we can coerce &Foo<[i32; 4]> to &Foo<[i32]> +/// The autoderef and -ref are the same as in the above example, but the type +/// stored in `unsize` is `Foo<[i32]>`, we don't store any further detail about +/// the underlying conversions from `[i32; 4]` to `[i32]`. +/// +/// 3. Coercing a `Box` to `Box` is an interesting special case. In +/// that case, we have the pointer we need coming in, so there are no +/// autoderefs, and no autoref. Instead we just do the `Unsize` transformation. +/// At some point, of course, `Box` should move out of the compiler, in which +/// case this is analogous to transformating a struct. E.g., Box<[i32; 4]> -> +/// Box<[i32]> is represented by: +/// +/// ``` +/// Adjustment { +/// kind: Adjust::Deref(vec![]), +/// autoref: None, +/// unsize: true, +/// target: `Box<[i32]>`, +/// } +/// ``` #[derive(Clone, RustcEncodable, RustcDecodable)] pub struct Adjustment<'tcx> { + /// Step 1. pub kind: Adjust<'tcx>, - pub target: Ty<'tcx> + + /// Step 2. Optionally produce a pointer/reference from the value. + pub autoref: Option>, + + /// Step 3. Unsize a pointer/reference value, e.g. `&[T; n]` to + /// `&[T]`. Note that the source could be a thin or fat pointer. + pub unsize: bool, + + pub target: Ty<'tcx>, } #[derive(Clone, Debug, RustcEncodable, RustcDecodable)] @@ -36,103 +109,25 @@ pub enum Adjust<'tcx> { /// Go from a mut raw pointer to a const raw pointer. MutToConstPointer, - /// Represents coercing a pointer to a different kind of pointer - where 'kind' - /// here means either or both of raw vs borrowed vs unique and fat vs thin. - /// - /// We transform pointers by following the following steps in order: - /// 1. Deref the pointer through `self.autoderefs` steps (may be no steps). - /// 2. If `autoref` is `Some(_)`, then take the address and produce either a - /// `&` or `*` pointer. - /// 3. If `unsize` is `true`, then apply the unsize transformation, - /// which will do things like convert thin pointers to fat - /// pointers, or convert structs containing thin pointers to - /// structs containing fat pointers, or convert between fat - /// pointers. We don't store the details of how the transform is - /// done (in fact, we don't know that, because it might depend on - /// the precise type parameters). We just store the target - /// type. Trans figures out what has to be done at monomorphization - /// time based on the precise source/target type at hand. - /// - /// To make that more concrete, here are some common scenarios: - /// - /// 1. The simplest cases are where the pointer is not adjusted fat vs thin. - /// Here the pointer will be dereferenced N times (where a dereference can - /// happen to raw or borrowed pointers or any smart pointer which implements - /// Deref, including Box<_>). The types of dereferences is given by - /// `autoderefs`. It can then be auto-referenced zero or one times, indicated - /// by `autoref`, to either a raw or borrowed pointer. In these cases unsize is - /// `false`. - /// - /// 2. A thin-to-fat coercon involves unsizing the underlying data. We start - /// with a thin pointer, deref a number of times, unsize the underlying data, - /// then autoref. The 'unsize' phase may change a fixed length array to a - /// dynamically sized one, a concrete object to a trait object, or statically - /// sized struct to a dynamically sized one. E.g., &[i32; 4] -> &[i32] is - /// represented by: - /// - /// ``` - /// Adjustment { - /// kind: Adjust::DerefRef { - /// autoderefs: vec![None], // &[i32; 4] -> [i32; 4] - /// autoref: Some(AutoBorrow::Ref), // [i32; 4] -> &[i32; 4] - /// unsize: true, // &[i32; 4] -> &[i32] - /// }, - /// target: `[i32]`, - /// } - /// ``` - /// - /// Note that for a struct, the 'deep' unsizing of the struct is not recorded. - /// E.g., `struct Foo { x: T }` we can coerce &Foo<[i32; 4]> to &Foo<[i32]> - /// The autoderef and -ref are the same as in the above example, but the type - /// stored in `unsize` is `Foo<[i32]>`, we don't store any further detail about - /// the underlying conversions from `[i32; 4]` to `[i32]`. - /// - /// 3. Coercing a `Box` to `Box` is an interesting special case. In - /// that case, we have the pointer we need coming in, so there are no - /// autoderefs, and no autoref. Instead we just do the `Unsize` transformation. - /// At some point, of course, `Box` should move out of the compiler, in which - /// case this is analogous to transformating a struct. E.g., Box<[i32; 4]> -> - /// Box<[i32]> is represented by: - /// - /// ``` - /// Adjustment { - /// Adjust::DerefRef { - /// autoderefs: vec![], - /// autoref: None, - /// unsize: true, - /// }, - /// target: `Box<[i32]>`, - /// } - /// ``` - DerefRef { - /// Step 1. Apply a number of dereferences, producing an lvalue. - autoderefs: Vec>>, - - /// Step 2. Optionally produce a pointer/reference from the value. - autoref: Option>, - - /// Step 3. Unsize a pointer/reference value, e.g. `&[T; n]` to - /// `&[T]`. Note that the source could be a thin or fat pointer. - unsize: bool, - } + /// Apply a number of dereferences, producing an lvalue, + /// if there are more than 0 dereferences. + Deref(Vec>>), } impl<'tcx> Adjustment<'tcx> { pub fn is_identity(&self) -> bool { + if self.autoref.is_some() || self.unsize { + return false; + } match self.kind { Adjust::NeverToAny => self.target.is_never(), - Adjust::DerefRef { - ref autoderefs, - autoref: None, - unsize: false - } if autoderefs.is_empty() => true, + Adjust::Deref(ref autoderefs) => autoderefs.is_empty(), Adjust::ReifyFnPointer | Adjust::UnsafeFnPointer | Adjust::ClosureFnPointer | - Adjust::MutToConstPointer | - Adjust::DerefRef {..} => false, + Adjust::MutToConstPointer => false, } } } diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 811b383324de3..cd34ebc7650b3 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -224,8 +224,13 @@ impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::Adjustment<'a> { type Lifted = ty::adjustment::Adjustment<'tcx>; fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { tcx.lift(&self.kind).and_then(|kind| { - tcx.lift(&self.target).map(|target| { - ty::adjustment::Adjustment { kind, target } + tcx.lift(&(self.autoref, self.target)).map(|(autoref, target)| { + ty::adjustment::Adjustment { + kind, + autoref, + unsize: self.unsize, + target, + } }) }) } @@ -245,12 +250,8 @@ impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::Adjust<'a> { Some(ty::adjustment::Adjust::ClosureFnPointer), ty::adjustment::Adjust::MutToConstPointer => Some(ty::adjustment::Adjust::MutToConstPointer), - ty::adjustment::Adjust::DerefRef { ref autoderefs, ref autoref, unsize } => { - tcx.lift(autoderefs).and_then(|autoderefs| { - tcx.lift(autoref).map(|autoref| { - ty::adjustment::Adjust::DerefRef { autoderefs, autoref, unsize } - }) - }) + ty::adjustment::Adjust::Deref(ref autoderefs) => { + tcx.lift(autoderefs).map(ty::adjustment::Adjust::Deref) } } } @@ -684,12 +685,16 @@ impl<'tcx> TypeFoldable<'tcx> for ty::adjustment::Adjustment<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { ty::adjustment::Adjustment { kind: self.kind.fold_with(folder), + autoref: self.autoref.fold_with(folder), + unsize: self.unsize, target: self.target.fold_with(folder), } } fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.kind.visit_with(visitor) || self.target.visit_with(visitor) + self.kind.visit_with(visitor) || + self.autoref.visit_with(visitor) || + self.target.visit_with(visitor) } } @@ -701,12 +706,8 @@ impl<'tcx> TypeFoldable<'tcx> for ty::adjustment::Adjust<'tcx> { ty::adjustment::Adjust::UnsafeFnPointer | ty::adjustment::Adjust::ClosureFnPointer | ty::adjustment::Adjust::MutToConstPointer => self.clone(), - ty::adjustment::Adjust::DerefRef { ref autoderefs, ref autoref, unsize } => { - ty::adjustment::Adjust::DerefRef { - autoderefs: autoderefs.fold_with(folder), - autoref: autoref.fold_with(folder), - unsize, - } + ty::adjustment::Adjust::Deref(ref autoderefs) => { + ty::adjustment::Adjust::Deref(autoderefs.fold_with(folder)) } } } @@ -718,8 +719,8 @@ impl<'tcx> TypeFoldable<'tcx> for ty::adjustment::Adjust<'tcx> { ty::adjustment::Adjust::UnsafeFnPointer | ty::adjustment::Adjust::ClosureFnPointer | ty::adjustment::Adjust::MutToConstPointer => false, - ty::adjustment::Adjust::DerefRef { ref autoderefs, ref autoref, unsize: _ } => { - autoderefs.visit_with(visitor) || autoref.visit_with(visitor) + ty::adjustment::Adjust::Deref(ref autoderefs) => { + autoderefs.visit_with(visitor) } } } diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index b0bfda4a65875..e4a8a1267f0c8 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -890,7 +890,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnconditionalRecursion { // Check for overloaded autoderef method calls. if let Some(&Adjustment { - kind: Adjust::DerefRef { ref autoderefs, .. }, .. + kind: Adjust::Deref(ref autoderefs), .. }) = cx.tables.adjustments.get(&id) { let mut source = cx.tables.expr_ty(expr); for &overloaded in autoderefs { diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index 93ff609a280ae..4db27647d427a 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -469,20 +469,18 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedAllocation { } if let Some(adjustment) = cx.tables.adjustments.get(&e.id) { - if let adjustment::Adjust::DerefRef { autoref, .. } = adjustment.kind { - match autoref { - Some(adjustment::AutoBorrow::Ref(_, hir::MutImmutable)) => { - cx.span_lint(UNUSED_ALLOCATION, - e.span, - "unnecessary allocation, use & instead"); - } - Some(adjustment::AutoBorrow::Ref(_, hir::MutMutable)) => { - cx.span_lint(UNUSED_ALLOCATION, - e.span, - "unnecessary allocation, use &mut instead"); - } - _ => (), + match adjustment.autoref { + Some(adjustment::AutoBorrow::Ref(_, hir::MutImmutable)) => { + cx.span_lint(UNUSED_ALLOCATION, + e.span, + "unnecessary allocation, use & instead"); } + Some(adjustment::AutoBorrow::Ref(_, hir::MutMutable)) => { + cx.span_lint(UNUSED_ALLOCATION, + e.span, + "unnecessary allocation, use &mut instead"); + } + _ => (), } } } diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 05f6381d93468..dbf35971fa323 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -86,8 +86,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { kind: ExprKind::Cast { source: expr.to_ref() }, }; } - Some((&ty::adjustment::Adjust::DerefRef { ref autoderefs, autoref, unsize }, - adjusted_ty)) => { + Some((&ty::adjustment::Adjust::Deref(ref autoderefs), _)) => { for &overloaded in autoderefs { let source = expr.ty; let target; @@ -143,64 +142,66 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { kind: kind, }; } + } + } - if let Some(autoref) = autoref { - let adjusted_ty = expr.ty.adjust_for_autoref(cx.tcx, Some(autoref)); - match autoref { - ty::adjustment::AutoBorrow::Ref(r, m) => { - expr = Expr { - temp_lifetime: temp_lifetime, - temp_lifetime_was_shrunk: was_shrunk, - ty: adjusted_ty, - span: self.span, - kind: ExprKind::Borrow { - region: r, - borrow_kind: to_borrow_kind(m), - arg: expr.to_ref(), - }, - }; - } - ty::adjustment::AutoBorrow::RawPtr(m) => { - // Convert this to a suitable `&foo` and - // then an unsafe coercion. Limit the region to be just this - // expression. - let region = ty::ReScope(expr_extent); - let region = cx.tcx.mk_region(region); - expr = Expr { - temp_lifetime: temp_lifetime, - temp_lifetime_was_shrunk: was_shrunk, - ty: cx.tcx.mk_ref(region, - ty::TypeAndMut { - ty: expr.ty, - mutbl: m, - }), - span: self.span, - kind: ExprKind::Borrow { - region: region, - borrow_kind: to_borrow_kind(m), - arg: expr.to_ref(), - }, - }; - expr = Expr { - temp_lifetime: temp_lifetime, - temp_lifetime_was_shrunk: was_shrunk, - ty: adjusted_ty, - span: self.span, - kind: ExprKind::Cast { source: expr.to_ref() }, - }; - } + if let Some(adj) = adj { + if let Some(autoref) = adj.autoref { + let adjusted_ty = expr.ty.adjust_for_autoref(cx.tcx, Some(autoref)); + match autoref { + ty::adjustment::AutoBorrow::Ref(r, m) => { + expr = Expr { + temp_lifetime: temp_lifetime, + temp_lifetime_was_shrunk: was_shrunk, + ty: adjusted_ty, + span: self.span, + kind: ExprKind::Borrow { + region: r, + borrow_kind: to_borrow_kind(m), + arg: expr.to_ref(), + }, + }; + } + ty::adjustment::AutoBorrow::RawPtr(m) => { + // Convert this to a suitable `&foo` and + // then an unsafe coercion. Limit the region to be just this + // expression. + let region = ty::ReScope(expr_extent); + let region = cx.tcx.mk_region(region); + expr = Expr { + temp_lifetime: temp_lifetime, + temp_lifetime_was_shrunk: was_shrunk, + ty: cx.tcx.mk_ref(region, + ty::TypeAndMut { + ty: expr.ty, + mutbl: m, + }), + span: self.span, + kind: ExprKind::Borrow { + region: region, + borrow_kind: to_borrow_kind(m), + arg: expr.to_ref(), + }, + }; + expr = Expr { + temp_lifetime: temp_lifetime, + temp_lifetime_was_shrunk: was_shrunk, + ty: adjusted_ty, + span: self.span, + kind: ExprKind::Cast { source: expr.to_ref() }, + }; } } + } - if unsize { - expr = Expr { - temp_lifetime: temp_lifetime, - temp_lifetime_was_shrunk: was_shrunk, - ty: adjusted_ty, - span: self.span, - kind: ExprKind::Unsize { source: expr.to_ref() }, - }; - } + if adj.unsize { + expr = Expr { + temp_lifetime: temp_lifetime, + temp_lifetime_was_shrunk: was_shrunk, + ty: adj.target, + span: self.span, + kind: ExprKind::Unsize { source: expr.to_ref() }, + }; } } diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index f73ae9d42f619..e7aa74494f9e8 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -449,7 +449,7 @@ fn check_adjustments<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Exp Some(&Adjust::ClosureFnPointer) | Some(&Adjust::MutToConstPointer) => {} - Some(&Adjust::DerefRef { ref autoderefs, .. }) => { + Some(&Adjust::Deref(ref autoderefs)) => { if autoderefs.iter().any(|overloaded| overloaded.is_some()) { v.promotable = false; } diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index b498d0f80826b..579bcda8dc619 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -144,11 +144,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.try_overloaded_call_traits(call_expr, adjusted_ty).map(|(autoref, method)| { let autoderefs = autoderef.adjust_steps(LvaluePreference::NoPreference); self.apply_adjustment(callee_expr.id, Adjustment { - kind: Adjust::DerefRef { - autoderefs, - autoref, - unsize: false - }, + kind: Adjust::Deref(autoderefs), + autoref, + unsize: false, target: method.sig.inputs()[0] }); CallStep::Overloaded(method) @@ -356,11 +354,9 @@ impl<'a, 'gcx, 'tcx> DeferredCallResolution<'gcx, 'tcx> { fcx.demand_eqtype(self.call_expr.span, method_sig.output(), self.fn_sig.output()); fcx.apply_adjustment(self.callee_expr.id, Adjustment { - kind: Adjust::DerefRef { - autoderefs: self.autoderefs, - autoref, - unsize: false - }, + kind: Adjust::Deref(self.autoderefs), + autoref, + unsize: false, target: method_sig.inputs()[0] }); diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 78559e470aee5..dc373610814dd 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -108,23 +108,24 @@ fn coerce_mutbls<'tcx>(from_mutbl: hir::Mutability, } } -fn identity<'tcx>() -> Adjust<'tcx> { - Adjust::DerefRef { - autoderefs: vec![], +fn identity<'tcx>(target: Ty<'tcx>) -> Adjustment<'tcx> { + simple(Adjust::Deref(vec![]))(target) +} + +fn simple<'tcx>(kind: Adjust<'tcx>) -> impl FnOnce(Ty<'tcx>) -> Adjustment<'tcx> { + move |target| Adjustment { + kind, autoref: None, unsize: false, + target } } -fn success<'tcx>(kind: Adjust<'tcx>, - target: Ty<'tcx>, +fn success<'tcx>(adj: Adjustment<'tcx>, obligations: traits::PredicateObligations<'tcx>) -> CoerceResult<'tcx> { Ok(InferOk { - value: Adjustment { - kind, - target - }, + value: adj, obligations }) } @@ -150,10 +151,12 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { } /// Unify two types (using sub or lub) and produce a specific coercion. - fn unify_and(&self, a: Ty<'tcx>, b: Ty<'tcx>, kind: Adjust<'tcx>) - -> CoerceResult<'tcx> { + fn unify_and(&self, a: Ty<'tcx>, b: Ty<'tcx>, f: F) + -> CoerceResult<'tcx> + where F: FnOnce(Ty<'tcx>) -> Adjustment<'tcx> + { self.unify(&a, &b).and_then(|InferOk { value: ty, obligations }| { - success(kind, ty, obligations) + success(f(ty), obligations) }) } @@ -163,7 +166,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { // Just ignore error types. if a.references_error() || b.references_error() { - return success(identity(), b, vec![]); + return success(identity(b), vec![]); } if a.is_never() { @@ -180,9 +183,9 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { // already resolved in some way. let diverging_ty = self.next_diverging_ty_var( TypeVariableOrigin::AdjustmentType(self.cause.span)); - self.unify_and(&b, &diverging_ty, Adjust::NeverToAny) + self.unify_and(&b, &diverging_ty, simple(Adjust::NeverToAny)) } else { - success(Adjust::NeverToAny, b, vec![]) + success(simple(Adjust::NeverToAny)(b), vec![]) }; } @@ -231,7 +234,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { } _ => { // Otherwise, just use unification rules. - self.unify_and(a, b, identity()) + self.unify_and(a, b, identity) } } } @@ -259,7 +262,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { coerce_mutbls(mt_a.mutbl, mt_b.mutbl)?; (r_a, mt_a) } - _ => return self.unify_and(a, b, identity()), + _ => return self.unify_and(a, b, identity), }; let span = self.cause.span; @@ -404,7 +407,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { // `self.x`, but we auto-coerce it to `foo(&mut *self.x)`, // which is a borrow. assert_eq!(mt_b.mutbl, hir::MutImmutable); // can only coerce &T -> &U - return success(identity(), ty, obligations); + return success(identity(ty), obligations); } // Now apply the autoref. We have to extract the region out of @@ -426,11 +429,12 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { autoderefs, autoref); - success(Adjust::DerefRef { - autoderefs, + success(Adjustment { + kind: Adjust::Deref(autoderefs), autoref, unsize: false, - }, ty, obligations) + target: ty + }, obligations) } @@ -471,19 +475,18 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { }; let coerce_source = source.adjust_for_autoref(self.tcx, reborrow); - let adjust = Adjust::DerefRef { - autoderefs: if reborrow.is_some() { vec![None] } else { vec![] }, - autoref: reborrow, - unsize: true, - }; - // Setup either a subtyping or a LUB relationship between // the `CoerceUnsized` target type and the expected type. // We only have the latter, so we use an inference variable // for the former and let type inference do the rest. let origin = TypeVariableOrigin::MiscVariable(self.cause.span); let coerce_target = self.next_ty_var(origin); - let mut coercion = self.unify_and(coerce_target, target, adjust)?; + let mut coercion = self.unify_and(coerce_target, target, |target| Adjustment { + kind: Adjust::Deref(if reborrow.is_some() { vec![None] } else { vec![] }), + autoref: reborrow, + unsize: true, + target + })?; let mut selcx = traits::SelectionContext::new(self); @@ -536,13 +539,16 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { Ok(coercion) } - fn coerce_from_safe_fn(&self, - a: Ty<'tcx>, - fn_ty_a: ty::PolyFnSig<'tcx>, - b: Ty<'tcx>, - to_unsafe: Adjust<'tcx>, - normal: Adjust<'tcx>) - -> CoerceResult<'tcx> { + fn coerce_from_safe_fn(&self, + a: Ty<'tcx>, + fn_ty_a: ty::PolyFnSig<'tcx>, + b: Ty<'tcx>, + to_unsafe: F, + normal: G) + -> CoerceResult<'tcx> + where F: FnOnce(Ty<'tcx>) -> Adjustment<'tcx>, + G: FnOnce(Ty<'tcx>) -> Adjustment<'tcx> + { if let ty::TyFnPtr(fn_ty_b) = b.sty { match (fn_ty_a.unsafety(), fn_ty_b.unsafety()) { (hir::Unsafety::Normal, hir::Unsafety::Unsafe) => { @@ -568,7 +574,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { debug!("coerce_from_fn_pointer(a={:?}, b={:?})", a, b); self.coerce_from_safe_fn(a, fn_ty_a, b, - Adjust::UnsafeFnPointer, identity()) + simple(Adjust::UnsafeFnPointer), identity) } fn coerce_from_fn_item(&self, @@ -587,9 +593,9 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { ty::TyFnPtr(_) => { let a_fn_pointer = self.tcx.mk_fn_ptr(fn_ty_a); self.coerce_from_safe_fn(a_fn_pointer, fn_ty_a, b, - Adjust::ReifyFnPointer, Adjust::ReifyFnPointer) + simple(Adjust::ReifyFnPointer), simple(Adjust::ReifyFnPointer)) } - _ => self.unify_and(a, b, identity()), + _ => self.unify_and(a, b, identity), } } @@ -631,9 +637,9 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { let pointer_ty = self.tcx.mk_fn_ptr(converted_sig); debug!("coerce_closure_to_fn(a={:?}, b={:?}, pty={:?})", a, b, pointer_ty); - self.unify_and(pointer_ty, b, Adjust::ClosureFnPointer) + self.unify_and(pointer_ty, b, simple(Adjust::ClosureFnPointer)) } - _ => self.unify_and(a, b, identity()), + _ => self.unify_and(a, b, identity), } } @@ -648,7 +654,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { ty::TyRef(_, mt) => (true, mt), ty::TyRawPtr(mt) => (false, mt), _ => { - return self.unify_and(a, b, identity()); + return self.unify_and(a, b, identity); } }; @@ -661,17 +667,18 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { // Although references and unsafe ptrs have the same // representation, we still register an Adjust::DerefRef so that // regionck knows that the region for `a` must be valid here. - self.unify_and(a_unsafe, b, if is_ref { - Adjust::DerefRef { - autoderefs: vec![None], + if is_ref { + self.unify_and(a_unsafe, b, |target| Adjustment { + kind: Adjust::Deref(vec![None]), autoref: Some(AutoBorrow::RawPtr(mutbl_b)), unsize: false, - } + target + }) } else if mt_a.mutbl != mutbl_b { - Adjust::MutToConstPointer + self.unify_and(a_unsafe, b, simple(Adjust::MutToConstPointer)) } else { - identity() - }) + self.unify_and(a_unsafe, b, identity) + } } } @@ -776,6 +783,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // `NeverToAny`, so this should always be valid. self.apply_adjustment(expr.id, Adjustment { kind: Adjust::ReifyFnPointer, + autoref: None, + unsize: false, target: fn_ptr }); } @@ -808,11 +817,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // previous expressions, other than noop reborrows (ignoring lifetimes). for expr in exprs { let expr = expr.as_coercion_site(); - let noop = match self.tables.borrow().adjustments.get(&expr.id).map(|adj| &adj.kind) { - Some(&Adjust::DerefRef { - ref autoderefs, + let noop = match self.tables.borrow().adjustments.get(&expr.id) { + Some(&Adjustment { + kind: Adjust::Deref(ref autoderefs), autoref: Some(AutoBorrow::Ref(_, mutbl_adj)), - unsize: false + unsize: false, + target: _ }) if autoderefs.len() == 1 => { match self.node_ty(expr.id).sty { ty::TyRef(_, mt_orig) => { @@ -824,7 +834,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { _ => false, } } - Some(&Adjust::NeverToAny) => true, + Some(&Adjustment { kind: Adjust::NeverToAny, .. }) => true, Some(_) => false, None => true, }; diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index ad05a83918907..bdbc7f677e4cf 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -147,12 +147,10 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { // Write out the final adjustment. self.apply_adjustment(self.self_expr.id, Adjustment { - kind: Adjust::DerefRef { - autoderefs, - autoref, - unsize: pick.unsize.is_some(), - }, - target: target + kind: Adjust::Deref(autoderefs), + autoref, + unsize: pick.unsize.is_some(), + target, }); target @@ -440,7 +438,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { // the correct region. let expr_ty = self.node_ty(expr.id); if let Some(adj) = self.tables.borrow_mut().adjustments.get_mut(&expr.id) { - if let Adjust::DerefRef { ref mut autoderefs, .. } = adj.kind { + if let Adjust::Deref(ref mut autoderefs) = adj.kind { let mut autoderef = self.autoderef(expr.span, expr_ty); autoderef.nth(autoderefs.len()).unwrap_or_else(|| { span_bug!(expr.span, @@ -502,9 +500,8 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { // Convert the autoref in the base expr to mutable with the correct // region and mutability. if let Some(&mut Adjustment { - ref mut target, kind: Adjust::DerefRef { - autoref: Some(AutoBorrow::Ref(ref mut r, ref mut mutbl)), .. - } + ref mut target, + autoref: Some(AutoBorrow::Ref(ref mut r, ref mut mutbl)), .. }) = self.tables.borrow_mut().adjustments.get_mut(&base_expr.id) { debug!("convert_lvalue_op_to_mutable: converting autoref of {:?}", target); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index bc76c56599d02..e6d43f0040362 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1779,11 +1779,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { autoderefs: Vec>>, adjusted_ty: Ty<'tcx>) { self.apply_adjustment(node_id, Adjustment { - kind: Adjust::DerefRef { - autoderefs, - autoref: None, - unsize: false - }, + kind: Adjust::Deref(autoderefs), + autoref: None, + unsize: false, target: adjusted_ty }); } @@ -1799,17 +1797,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { Entry::Vacant(entry) => { entry.insert(adj); }, Entry::Occupied(mut entry) => { debug!(" - composing on top of {:?}", entry.get()); - match (&entry.get().kind, &adj.kind) { + match (entry.get(), &adj) { // Applying any adjustment on top of a NeverToAny // is a valid NeverToAny adjustment, because it can't // be reached. - (&Adjust::NeverToAny, _) => return, - (&Adjust::DerefRef { - autoderefs: ref old, + (&Adjustment { kind: Adjust::NeverToAny, .. }, _) => return, + (&Adjustment { + kind: Adjust::Deref(ref old), autoref: Some(AutoBorrow::Ref(..)), - unsize: false - }, &Adjust::DerefRef { - autoderefs: ref new, .. + unsize: false, .. + }, &Adjustment { + kind: Adjust::Deref(ref new), .. }) if old.len() == 1 && new.len() >= 1 => { // A reborrow has no effect before a dereference. } @@ -2235,11 +2233,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let autoderefs = autoderef.adjust_steps(lvalue_pref); self.apply_adjustment(base_expr.id, Adjustment { - kind: Adjust::DerefRef { - autoderefs, - autoref, - unsize - }, + kind: Adjust::Deref(autoderefs), + autoref, + unsize, target: method.sig.inputs()[0] }); @@ -2651,6 +2647,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { TypeVariableOrigin::AdjustmentType(expr.span)); self.apply_adjustment(expr.id, Adjustment { kind: Adjust::NeverToAny, + autoref: None, + unsize: false, target: adj_ty }); ty = adj_ty; @@ -3450,11 +3448,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { expr.span, oprnd_t, lvalue_pref) { let (autoref, method) = self.register_infer_ok_obligations(ok); self.apply_adjustment(oprnd.id, Adjustment { - kind: Adjust::DerefRef { - autoderefs: vec![], - autoref, - unsize: false - }, + kind: Adjust::Deref(vec![]), + autoref, + unsize: false, target: method.sig.inputs()[0] }); oprnd_t = self.make_overloaded_lvalue_return_type(method).ty; diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index 0c820d2404a50..8d442aae70e3b 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -414,11 +414,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.select_obligations_where_possible(); self.apply_adjustment(lhs_expr.id, Adjustment { - kind: Adjust::DerefRef { - autoderefs: vec![], - autoref, - unsize: false - }, + kind: Adjust::Deref(vec![]), + autoref, + unsize: false, target: method.sig.inputs()[0] }); self.write_method_call(expr.id, method); diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 7fff0ceb7788c..119ae748f85cd 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -546,9 +546,9 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> { if let Some(adjustment) = adjustment { debug!("adjustment={:?}", adjustment); match adjustment.kind { - adjustment::Adjust::DerefRef { ref autoderefs, ref autoref, .. } => { + adjustment::Adjust::Deref(ref autoderefs) => { let cmt = ignore_err!(self.constrain_autoderefs(expr, autoderefs)); - if let Some(ref autoref) = *autoref { + if let Some(ref autoref) = adjustment.autoref { self.link_autoref(expr, cmt, autoref); // Require that the resulting region encompasses @@ -569,7 +569,9 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> { source_ty, bounds.region_bound); } */ - _ => {} + _ => { + assert!(adjustment.autoref.is_none()); + } } // If necessary, constrain destructors in the unadjusted form of this From 194fe695e3af6f03953cbb4ca66f159993f6214d Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Sat, 27 May 2017 10:29:24 +0300 Subject: [PATCH 11/14] rustc: decompose Adjustment into a vector of adjustment steps. --- src/librustc/ich/impls_ty.rs | 14 +- src/librustc/middle/expr_use_visitor.rs | 96 ++----- src/librustc/middle/mem_categorization.rs | 101 ++++---- src/librustc/ty/adjustment.rs | 103 ++------ src/librustc/ty/context.rs | 16 +- src/librustc/ty/structural_impls.rs | 47 ++-- src/librustc_lint/builtin.rs | 21 +- src/librustc_lint/unused.rs | 20 +- src/librustc_mir/hair/cx/expr.rs | 271 ++++++++------------ src/librustc_passes/consts.rs | 26 +- src/librustc_typeck/check/autoderef.rs | 24 +- src/librustc_typeck/check/callee.rs | 73 +++--- src/librustc_typeck/check/coercion.rs | 165 ++++++------ src/librustc_typeck/check/method/confirm.rs | 133 ++++++---- src/librustc_typeck/check/method/mod.rs | 52 ++-- src/librustc_typeck/check/mod.rs | 136 +++++----- src/librustc_typeck/check/op.rs | 98 ++++--- src/librustc_typeck/check/regionck.rs | 128 ++++----- src/librustc_typeck/lib.rs | 2 + 19 files changed, 676 insertions(+), 850 deletions(-) diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index f0fdb94b81b36..899e994302f80 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -99,16 +99,20 @@ impl<'a, 'tcx> HashStable> for ty::adjustment::Ad ty::adjustment::Adjust::ReifyFnPointer | ty::adjustment::Adjust::UnsafeFnPointer | ty::adjustment::Adjust::ClosureFnPointer | - ty::adjustment::Adjust::MutToConstPointer => {} - ty::adjustment::Adjust::Deref(ref autoderefs) => { - autoderefs.hash_stable(hcx, hasher); + ty::adjustment::Adjust::MutToConstPointer | + ty::adjustment::Adjust::Unsize => {} + ty::adjustment::Adjust::Deref(ref overloaded) => { + overloaded.hash_stable(hcx, hasher); + } + ty::adjustment::Adjust::Borrow(ref autoref) => { + autoref.hash_stable(hcx, hasher); } } } } -impl_stable_hash_for!(struct ty::adjustment::Adjustment<'tcx> { kind, autoref, unsize, target }); -impl_stable_hash_for!(struct ty::adjustment::OverloadedDeref<'tcx> { region, mutbl, target }); +impl_stable_hash_for!(struct ty::adjustment::Adjustment<'tcx> { kind, target }); +impl_stable_hash_for!(struct ty::adjustment::OverloadedDeref<'tcx> { region, mutbl }); impl_stable_hash_for!(struct ty::UpvarId { var_id, closure_expr_id }); impl_stable_hash_for!(struct ty::UpvarBorrow<'tcx> { kind, region }); diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 9120990777dfa..55c3049155f4d 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -704,89 +704,55 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { // consumed or borrowed as part of the automatic adjustment // process. fn walk_adjustment(&mut self, expr: &hir::Expr) { - let infcx = self.mc.infcx; //NOTE(@jroesch): mixed RefCell borrow causes crash - let adj = infcx.tables.borrow().adjustments.get(&expr.id).cloned(); + let adjustments = self.mc.infcx.tables.borrow().expr_adjustments(expr).to_vec(); let mut cmt = return_if_err!(self.mc.cat_expr_unadjusted(expr)); - if let Some(adjustment) = adj { + for adjustment in adjustments { debug!("walk_adjustment expr={:?} adj={:?}", expr, adjustment); match adjustment.kind { adjustment::Adjust::NeverToAny | adjustment::Adjust::ReifyFnPointer | adjustment::Adjust::UnsafeFnPointer | adjustment::Adjust::ClosureFnPointer | - adjustment::Adjust::MutToConstPointer => { + adjustment::Adjust::MutToConstPointer | + adjustment::Adjust::Unsize => { // Creating a closure/fn-pointer or unsizing consumes // the input and stores it into the resulting rvalue. - self.delegate_consume(expr.id, expr.span, cmt); - assert!(adjustment.autoref.is_none() && !adjustment.unsize); - return; - } - adjustment::Adjust::Deref(ref autoderefs) => { - cmt = return_if_err!(self.walk_autoderefs(expr, cmt, autoderefs)); + self.delegate_consume(expr.id, expr.span, cmt.clone()); } - } - cmt = self.walk_autoref(expr, cmt, adjustment.autoref); - - if adjustment.unsize { - // Unsizing consumes the thin pointer and produces a fat one. - self.delegate_consume(expr.id, expr.span, cmt); - } - } - } + adjustment::Adjust::Deref(None) => {} + + // Autoderefs for overloaded Deref calls in fact reference + // their receiver. That is, if we have `(*x)` where `x` + // is of type `Rc`, then this in fact is equivalent to + // `x.deref()`. Since `deref()` is declared with `&self`, + // this is an autoref of `x`. + adjustment::Adjust::Deref(Some(ref deref)) => { + let bk = ty::BorrowKind::from_mutbl(deref.mutbl); + self.delegate.borrow(expr.id, expr.span, cmt.clone(), + deref.region, bk, AutoRef); + } - /// Autoderefs for overloaded Deref calls in fact reference their receiver. That is, if we have - /// `(*x)` where `x` is of type `Rc`, then this in fact is equivalent to `x.deref()`. Since - /// `deref()` is declared with `&self`, this is an autoref of `x`. - fn walk_autoderefs(&mut self, - expr: &hir::Expr, - mut cmt: mc::cmt<'tcx>, - autoderefs: &[Option>]) - -> mc::McResult> { - debug!("walk_autoderefs expr={:?} autoderefs={:?}", expr, autoderefs); - - for &overloaded in autoderefs { - if let Some(deref) = overloaded { - let bk = ty::BorrowKind::from_mutbl(deref.mutbl); - self.delegate.borrow(expr.id, expr.span, cmt.clone(), - deref.region, bk, AutoRef); - cmt = self.mc.cat_overloaded_autoderef(expr, deref)?; - } else { - cmt = self.mc.cat_deref(expr, cmt, false)?; + adjustment::Adjust::Borrow(ref autoref) => { + self.walk_autoref(expr, cmt.clone(), autoref); + } } + cmt = return_if_err!(self.mc.cat_expr_adjusted(expr, cmt, &adjustment)); } - Ok(cmt) } - /// Walks the autoref `opt_autoref` applied to the autoderef'd - /// `expr`. `cmt_derefd` is the mem-categorized form of `expr` - /// after all relevant autoderefs have occurred. Because AutoRefs - /// can be recursive, this function is recursive: it first walks - /// deeply all the way down the autoref chain, and then processes - /// the autorefs on the way out. At each point, it returns the - /// `cmt` for the rvalue that will be produced by introduced an - /// autoref. + /// Walks the autoref `autoref` applied to the autoderef'd + /// `expr`. `cmt_base` is the mem-categorized form of `expr` + /// after all relevant autoderefs have occurred. fn walk_autoref(&mut self, expr: &hir::Expr, cmt_base: mc::cmt<'tcx>, - opt_autoref: Option>) - -> mc::cmt<'tcx> - { - debug!("walk_autoref(expr.id={} cmt_derefd={:?} opt_autoref={:?})", + autoref: &adjustment::AutoBorrow<'tcx>) { + debug!("walk_autoref(expr.id={} cmt_base={:?} autoref={:?})", expr.id, cmt_base, - opt_autoref); - - let cmt_base_ty = cmt_base.ty; - - let autoref = match opt_autoref { - Some(ref autoref) => autoref, - None => { - // No AutoRef. - return cmt_base; - } - }; + autoref); match *autoref { adjustment::AutoBorrow::Ref(r, m) => { @@ -816,14 +782,6 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { AutoUnsafe); } } - - // Construct the categorization for the result of the autoref. - // This is always an rvalue, since we are producing a new - // (temporary) indirection. - - let adj_ty = cmt_base_ty.adjust_for_autoref(self.tcx(), opt_autoref); - - self.mc.cat_rvalue_node(expr.id, expr.span, adj_ty) } diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 707b52a1a22fa..53d8eecde5422 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -466,42 +466,62 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { } pub fn cat_expr(&self, expr: &hir::Expr) -> McResult> { - match self.infcx.tables.borrow().adjustments.get(&expr.id) { - None => { - // No adjustments. - self.cat_expr_unadjusted(expr) + // This recursion helper avoids going through *too many* + // adjustments, since *only* non-overloaded deref recurses. + fn helper<'a, 'gcx, 'tcx>(mc: &MemCategorizationContext<'a, 'gcx, 'tcx>, + expr: &hir::Expr, + adjustments: &[adjustment::Adjustment<'tcx>]) + -> McResult> { + match adjustments.split_last() { + None => mc.cat_expr_unadjusted(expr), + Some((adjustment, previous)) => { + mc.cat_expr_adjusted_with(expr, || helper(mc, expr, previous), adjustment) + } } + } - Some(adjustment) => { - debug!("cat_expr({:?}): {:?}", adjustment, expr); - match adjustment.kind { - adjustment::Adjust::Deref(ref autoderefs) - if adjustment.autoref.is_none() && !adjustment.unsize => { - // Equivalent to *expr or something similar. - let mut cmt = self.cat_expr_unadjusted(expr)?; - debug!("cat_expr: autoderefs={:?}, cmt={:?}", - autoderefs, cmt); - for &overloaded in autoderefs { - if let Some(deref) = overloaded { - cmt = self.cat_overloaded_autoderef(expr, deref)?; - } else { - cmt = self.cat_deref(expr, cmt, false)?; - } - } - return Ok(cmt); - } + helper(self, expr, self.infcx.tables.borrow().expr_adjustments(expr)) + } - adjustment::Adjust::NeverToAny | - adjustment::Adjust::ReifyFnPointer | - adjustment::Adjust::UnsafeFnPointer | - adjustment::Adjust::ClosureFnPointer | - adjustment::Adjust::MutToConstPointer | - adjustment::Adjust::Deref(_) => { - // Result is an rvalue. - let expr_ty = self.expr_ty_adjusted(expr)?; - Ok(self.cat_rvalue_node(expr.id(), expr.span(), expr_ty)) - } - } + pub fn cat_expr_adjusted(&self, expr: &hir::Expr, + previous: cmt<'tcx>, + adjustment: &adjustment::Adjustment<'tcx>) + -> McResult> { + self.cat_expr_adjusted_with(expr, || Ok(previous), adjustment) + } + + fn cat_expr_adjusted_with(&self, expr: &hir::Expr, + previous: F, + adjustment: &adjustment::Adjustment<'tcx>) + -> McResult> + where F: FnOnce() -> McResult> + { + debug!("cat_expr_adjusted_with({:?}): {:?}", adjustment, expr); + let target = self.infcx.resolve_type_vars_if_possible(&adjustment.target); + match adjustment.kind { + adjustment::Adjust::Deref(overloaded) => { + // Equivalent to *expr or something similar. + let base = if let Some(deref) = overloaded { + let ref_ty = self.tcx().mk_ref(deref.region, ty::TypeAndMut { + ty: target, + mutbl: deref.mutbl, + }); + self.cat_rvalue_node(expr.id, expr.span, ref_ty) + } else { + previous()? + }; + self.cat_deref(expr, base, false) + } + + adjustment::Adjust::NeverToAny | + adjustment::Adjust::ReifyFnPointer | + adjustment::Adjust::UnsafeFnPointer | + adjustment::Adjust::ClosureFnPointer | + adjustment::Adjust::MutToConstPointer | + adjustment::Adjust::Borrow(_) | + adjustment::Adjust::Unsize => { + // Result is an rvalue. + Ok(self.cat_rvalue_node(expr.id, expr.span, target)) } } } @@ -931,21 +951,6 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { self.cat_deref(expr, base_cmt, implicit) } - pub fn cat_overloaded_autoderef(&self, - expr: &hir::Expr, - deref: adjustment::OverloadedDeref<'tcx>) - -> McResult> { - debug!("cat_overloaded_autoderef: deref={:?}", deref); - - let target = self.infcx.resolve_type_vars_if_possible(&deref.target); - let ref_ty = self.tcx().mk_ref(deref.region, ty::TypeAndMut { - ty: target, - mutbl: deref.mutbl, - }); - let base_cmt = self.cat_rvalue_node(expr.id, expr.span, ref_ty); - self.cat_deref(expr, base_cmt, false) - } - pub fn cat_deref(&self, node: &N, base_cmt: cmt<'tcx>, diff --git a/src/librustc/ty/adjustment.rs b/src/librustc/ty/adjustment.rs index e2e017e9f519a..62d137475f90e 100644 --- a/src/librustc/ty/adjustment.rs +++ b/src/librustc/ty/adjustment.rs @@ -10,29 +10,18 @@ use hir; use hir::def_id::DefId; -use ty::{self, Ty, TyCtxt, TypeAndMut}; +use ty::{self, Ty, TyCtxt}; use ty::subst::Substs; /// Represents coercing a value to a different type of value. /// -/// We transform values by following the following steps in order: -/// 1. Apply a step of `Adjust` (see its variants for details). -/// 2. If `autoref` is `Some(_)`, then take the address and produce either a -/// `&` or `*` pointer. -/// 3. If `unsize` is `true`, then apply the unsize transformation, -/// which will do things like convert thin pointers to fat -/// pointers, or convert structs containing thin pointers to -/// structs containing fat pointers, or convert between fat -/// pointers. We don't store the details of how the transform is -/// done (in fact, we don't know that, because it might depend on -/// the precise type parameters). We just store the target -/// type. Trans figures out what has to be done at monomorphization -/// time based on the precise source/target type at hand. +/// We transform values by following a number of `Adjust` steps in order. +/// See the documentation on variants of `Adjust` for more details. /// -/// To make that more concrete, here are some common scenarios: +/// Here are some common scenarios: /// -/// 1. The simplest cases are where the pointer is not adjusted fat vs thin. +/// 1. The simplest cases are where a pointer is not adjusted fat vs thin. /// Here the pointer will be dereferenced N times (where a dereference can /// happen to raw or borrowed pointers or any smart pointer which implements /// Deref, including Box<_>). The types of dereferences is given by @@ -48,12 +37,9 @@ use ty::subst::Substs; /// represented by: /// /// ``` -/// Adjustment { -/// kind: Adjust::Deref(vec![None]),// &[i32; 4] -> [i32; 4] -/// autoref: Some(AutoBorrow::Ref), // [i32; 4] -> &[i32; 4] -/// unsize: true, // &[i32; 4] -> &[i32] -/// target: `[i32]`, -/// } +/// Deref(None) -> [i32; 4], +/// Borrow(AutoBorrow::Ref) -> &[i32; 4], +/// Unsize -> &[i32], /// ``` /// /// Note that for a struct, the 'deep' unsizing of the struct is not recorded. @@ -67,28 +53,10 @@ use ty::subst::Substs; /// autoderefs, and no autoref. Instead we just do the `Unsize` transformation. /// At some point, of course, `Box` should move out of the compiler, in which /// case this is analogous to transformating a struct. E.g., Box<[i32; 4]> -> -/// Box<[i32]> is represented by: -/// -/// ``` -/// Adjustment { -/// kind: Adjust::Deref(vec![]), -/// autoref: None, -/// unsize: true, -/// target: `Box<[i32]>`, -/// } -/// ``` +/// Box<[i32]> is an `Adjust::Unsize` with the target `Box<[i32]>`. #[derive(Clone, RustcEncodable, RustcDecodable)] pub struct Adjustment<'tcx> { - /// Step 1. pub kind: Adjust<'tcx>, - - /// Step 2. Optionally produce a pointer/reference from the value. - pub autoref: Option>, - - /// Step 3. Unsize a pointer/reference value, e.g. `&[T; n]` to - /// `&[T]`. Note that the source could be a thin or fat pointer. - pub unsize: bool, - pub target: Ty<'tcx>, } @@ -109,27 +77,23 @@ pub enum Adjust<'tcx> { /// Go from a mut raw pointer to a const raw pointer. MutToConstPointer, - /// Apply a number of dereferences, producing an lvalue, - /// if there are more than 0 dereferences. - Deref(Vec>>), -} + /// Dereference once, producing an lvalue. + Deref(Option>), -impl<'tcx> Adjustment<'tcx> { - pub fn is_identity(&self) -> bool { - if self.autoref.is_some() || self.unsize { - return false; - } - match self.kind { - Adjust::NeverToAny => self.target.is_never(), - - Adjust::Deref(ref autoderefs) => autoderefs.is_empty(), - - Adjust::ReifyFnPointer | - Adjust::UnsafeFnPointer | - Adjust::ClosureFnPointer | - Adjust::MutToConstPointer => false, - } - } + /// Take the address and produce either a `&` or `*` pointer. + Borrow(AutoBorrow<'tcx>), + + /// Unsize a pointer/reference value, e.g. `&[T; n]` to + /// `&[T]`. Note that the source could be a thin or fat pointer. + /// This will do things like convert thin pointers to fat + /// pointers, or convert structs containing thin pointers to + /// structs containing fat pointers, or convert between fat + /// pointers. We don't store the details of how the transform is + /// done (in fact, we don't know that, because it might depend on + /// the precise type parameters). We just store the target + /// type. Trans figures out what has to be done at monomorphization + /// time based on the precise source/target type at hand. + Unsize, } /// An overloaded autoderef step, representing a `Deref(Mut)::deref(_mut)` @@ -140,7 +104,6 @@ impl<'tcx> Adjustment<'tcx> { pub struct OverloadedDeref<'tcx> { pub region: ty::Region<'tcx>, pub mutbl: hir::Mutability, - pub target: Ty<'tcx>, } impl<'a, 'gcx, 'tcx> OverloadedDeref<'tcx> { @@ -185,19 +148,3 @@ pub enum CustomCoerceUnsized { /// Records the index of the field being coerced. Struct(usize) } - -impl<'a, 'gcx, 'tcx> ty::TyS<'tcx> { - pub fn adjust_for_autoref(&'tcx self, tcx: TyCtxt<'a, 'gcx, 'tcx>, - autoref: Option>) - -> Ty<'tcx> { - match autoref { - None => self, - Some(AutoBorrow::Ref(r, m)) => { - tcx.mk_ref(r, TypeAndMut { ty: self, mutbl: m }) - } - Some(AutoBorrow::RawPtr(m)) => { - tcx.mk_ptr(TypeAndMut { ty: self, mutbl: m }) - } - } - } -} diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index f0cee2fe2b1ca..c6fb2a5871b05 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -221,7 +221,7 @@ pub struct TypeckTables<'tcx> { /// other items. pub node_substs: NodeMap<&'tcx Substs<'tcx>>, - pub adjustments: NodeMap>, + pub adjustments: NodeMap>>, /// Borrows pub upvar_capture_map: ty::UpvarCaptureMap<'tcx>, @@ -343,16 +343,24 @@ impl<'tcx> TypeckTables<'tcx> { self.node_id_to_type_opt(expr.id) } + pub fn expr_adjustments(&self, expr: &hir::Expr) + -> &[ty::adjustment::Adjustment<'tcx>] { + self.adjustments.get(&expr.id).map_or(&[], |a| &a[..]) + } + /// Returns the type of `expr`, considering any `Adjustment` /// entry recorded for that expression. pub fn expr_ty_adjusted(&self, expr: &hir::Expr) -> Ty<'tcx> { - self.adjustments.get(&expr.id) + self.expr_adjustments(expr) + .last() .map_or_else(|| self.expr_ty(expr), |adj| adj.target) } pub fn expr_ty_adjusted_opt(&self, expr: &hir::Expr) -> Option> { - self.adjustments.get(&expr.id) - .map(|adj| adj.target).or_else(|| self.expr_ty_opt(expr)) + self.expr_adjustments(expr) + .last() + .map(|adj| adj.target) + .or_else(|| self.expr_ty_opt(expr)) } pub fn is_method_call(&self, expr: &hir::Expr) -> bool { diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index cd34ebc7650b3..31412ad1ab222 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -224,13 +224,8 @@ impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::Adjustment<'a> { type Lifted = ty::adjustment::Adjustment<'tcx>; fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { tcx.lift(&self.kind).and_then(|kind| { - tcx.lift(&(self.autoref, self.target)).map(|(autoref, target)| { - ty::adjustment::Adjustment { - kind, - autoref, - unsize: self.unsize, - target, - } + tcx.lift(&self.target).map(|target| { + ty::adjustment::Adjustment { kind, target } }) }) } @@ -250,8 +245,13 @@ impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::Adjust<'a> { Some(ty::adjustment::Adjust::ClosureFnPointer), ty::adjustment::Adjust::MutToConstPointer => Some(ty::adjustment::Adjust::MutToConstPointer), - ty::adjustment::Adjust::Deref(ref autoderefs) => { - tcx.lift(autoderefs).map(ty::adjustment::Adjust::Deref) + ty::adjustment::Adjust::Unsize => + Some(ty::adjustment::Adjust::Unsize), + ty::adjustment::Adjust::Deref(ref overloaded) => { + tcx.lift(overloaded).map(ty::adjustment::Adjust::Deref) + } + ty::adjustment::Adjust::Borrow(ref autoref) => { + tcx.lift(autoref).map(ty::adjustment::Adjust::Borrow) } } } @@ -260,11 +260,10 @@ impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::Adjust<'a> { impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::OverloadedDeref<'a> { type Lifted = ty::adjustment::OverloadedDeref<'tcx>; fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { - tcx.lift(&(self.region, self.target)).map(|(region, target)| { + tcx.lift(&self.region).map(|region| { ty::adjustment::OverloadedDeref { region, mutbl: self.mutbl, - target, } }) } @@ -685,15 +684,12 @@ impl<'tcx> TypeFoldable<'tcx> for ty::adjustment::Adjustment<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { ty::adjustment::Adjustment { kind: self.kind.fold_with(folder), - autoref: self.autoref.fold_with(folder), - unsize: self.unsize, target: self.target.fold_with(folder), } } fn super_visit_with>(&self, visitor: &mut V) -> bool { self.kind.visit_with(visitor) || - self.autoref.visit_with(visitor) || self.target.visit_with(visitor) } } @@ -705,9 +701,13 @@ impl<'tcx> TypeFoldable<'tcx> for ty::adjustment::Adjust<'tcx> { ty::adjustment::Adjust::ReifyFnPointer | ty::adjustment::Adjust::UnsafeFnPointer | ty::adjustment::Adjust::ClosureFnPointer | - ty::adjustment::Adjust::MutToConstPointer => self.clone(), - ty::adjustment::Adjust::Deref(ref autoderefs) => { - ty::adjustment::Adjust::Deref(autoderefs.fold_with(folder)) + ty::adjustment::Adjust::MutToConstPointer | + ty::adjustment::Adjust::Unsize => self.clone(), + ty::adjustment::Adjust::Deref(ref overloaded) => { + ty::adjustment::Adjust::Deref(overloaded.fold_with(folder)) + } + ty::adjustment::Adjust::Borrow(ref autoref) => { + ty::adjustment::Adjust::Borrow(autoref.fold_with(folder)) } } } @@ -718,9 +718,13 @@ impl<'tcx> TypeFoldable<'tcx> for ty::adjustment::Adjust<'tcx> { ty::adjustment::Adjust::ReifyFnPointer | ty::adjustment::Adjust::UnsafeFnPointer | ty::adjustment::Adjust::ClosureFnPointer | - ty::adjustment::Adjust::MutToConstPointer => false, - ty::adjustment::Adjust::Deref(ref autoderefs) => { - autoderefs.visit_with(visitor) + ty::adjustment::Adjust::MutToConstPointer | + ty::adjustment::Adjust::Unsize => false, + ty::adjustment::Adjust::Deref(ref overloaded) => { + overloaded.visit_with(visitor) + } + ty::adjustment::Adjust::Borrow(ref autoref) => { + autoref.visit_with(visitor) } } } @@ -731,12 +735,11 @@ impl<'tcx> TypeFoldable<'tcx> for ty::adjustment::OverloadedDeref<'tcx> { ty::adjustment::OverloadedDeref { region: self.region.fold_with(folder), mutbl: self.mutbl, - target: self.target.fold_with(folder), } } fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.region.visit_with(visitor) || self.target.visit_with(visitor) + self.region.visit_with(visitor) } } diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index e4a8a1267f0c8..12bfb1e02cf6f 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -889,22 +889,15 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnconditionalRecursion { }; // Check for overloaded autoderef method calls. - if let Some(&Adjustment { - kind: Adjust::Deref(ref autoderefs), .. - }) = cx.tables.adjustments.get(&id) { - let mut source = cx.tables.expr_ty(expr); - for &overloaded in autoderefs { - if let Some(deref) = overloaded { - let (def_id, substs) = deref.method_call(cx.tcx, source); - if method_call_refers_to_method(cx.tcx, method, def_id, substs, id) { - return true; - } - source = deref.target; - } else { - source = source.builtin_deref(true, - ty::LvaluePreference::NoPreference).unwrap().ty; + let mut source = cx.tables.expr_ty(expr); + for adjustment in cx.tables.expr_adjustments(expr) { + if let Adjust::Deref(Some(deref)) = adjustment.kind { + let (def_id, substs) = deref.method_call(cx.tcx, source); + if method_call_refers_to_method(cx.tcx, method, def_id, substs, id) { + return true; } } + source = adjustment.target; } // Check for method calls and overloaded operators. diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index 4db27647d427a..0c82679c307d3 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -468,19 +468,13 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedAllocation { _ => return, } - if let Some(adjustment) = cx.tables.adjustments.get(&e.id) { - match adjustment.autoref { - Some(adjustment::AutoBorrow::Ref(_, hir::MutImmutable)) => { - cx.span_lint(UNUSED_ALLOCATION, - e.span, - "unnecessary allocation, use & instead"); - } - Some(adjustment::AutoBorrow::Ref(_, hir::MutMutable)) => { - cx.span_lint(UNUSED_ALLOCATION, - e.span, - "unnecessary allocation, use &mut instead"); - } - _ => (), + for adj in cx.tables.expr_adjustments(e) { + if let adjustment::Adjust::Borrow(adjustment::AutoBorrow::Ref(_, m)) = adj.kind { + let msg = match m { + hir::MutImmutable => "unnecessary allocation, use & instead", + hir::MutMutable => "unnecessary allocation, use &mut instead" + }; + cx.span_lint(UNUSED_ALLOCATION, e.span, msg); } } } diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index dbf35971fa323..6d1509e7e24c7 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -17,6 +17,7 @@ use hair::cx::to_ref::ToRef; use rustc::hir::def::{Def, CtorKind}; use rustc::middle::const_val::ConstVal; use rustc::ty::{self, AdtKind, VariantDef, Ty}; +use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow}; use rustc::ty::cast::CastKind as TyCastKind; use rustc::ty::subst::Subst; use rustc::hir; @@ -32,177 +33,13 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { debug!("Expr::make_mirror(): id={}, span={:?}", self.id, self.span); let mut expr = make_mirror_unadjusted(cx, self); - let adj = cx.tables().adjustments.get(&self.id); - - debug!("make_mirror: unadjusted-expr={:?} applying adjustments={:?}", - expr, - adj); // Now apply adjustments, if any. - match adj.map(|adj| (&adj.kind, adj.target)) { - None => {} - Some((&ty::adjustment::Adjust::ReifyFnPointer, adjusted_ty)) => { - expr = Expr { - temp_lifetime: temp_lifetime, - temp_lifetime_was_shrunk: was_shrunk, - ty: adjusted_ty, - span: self.span, - kind: ExprKind::ReifyFnPointer { source: expr.to_ref() }, - }; - } - Some((&ty::adjustment::Adjust::UnsafeFnPointer, adjusted_ty)) => { - expr = Expr { - temp_lifetime: temp_lifetime, - temp_lifetime_was_shrunk: was_shrunk, - ty: adjusted_ty, - span: self.span, - kind: ExprKind::UnsafeFnPointer { source: expr.to_ref() }, - }; - } - Some((&ty::adjustment::Adjust::ClosureFnPointer, adjusted_ty)) => { - expr = Expr { - temp_lifetime: temp_lifetime, - temp_lifetime_was_shrunk: was_shrunk, - ty: adjusted_ty, - span: self.span, - kind: ExprKind::ClosureFnPointer { source: expr.to_ref() }, - }; - } - Some((&ty::adjustment::Adjust::NeverToAny, adjusted_ty)) => { - expr = Expr { - temp_lifetime: temp_lifetime, - temp_lifetime_was_shrunk: was_shrunk, - ty: adjusted_ty, - span: self.span, - kind: ExprKind::NeverToAny { source: expr.to_ref() }, - }; - } - Some((&ty::adjustment::Adjust::MutToConstPointer, adjusted_ty)) => { - expr = Expr { - temp_lifetime: temp_lifetime, - temp_lifetime_was_shrunk: was_shrunk, - ty: adjusted_ty, - span: self.span, - kind: ExprKind::Cast { source: expr.to_ref() }, - }; - } - Some((&ty::adjustment::Adjust::Deref(ref autoderefs), _)) => { - for &overloaded in autoderefs { - let source = expr.ty; - let target; - let kind = if let Some(deref) = overloaded { - debug!("make_mirror: overloaded autoderef ({:?})", deref); - - expr = Expr { - temp_lifetime: temp_lifetime, - temp_lifetime_was_shrunk: was_shrunk, - ty: cx.tcx.mk_ref(deref.region, - ty::TypeAndMut { - ty: source, - mutbl: deref.mutbl, - }), - span: expr.span, - kind: ExprKind::Borrow { - region: deref.region, - borrow_kind: to_borrow_kind(deref.mutbl), - arg: expr.to_ref(), - }, - }; - - target = deref.target; - - let call = deref.method_call(cx.tcx, source); - overloaded_lvalue(cx, - self, - deref.target, - Some(call), - PassArgs::ByRef, - expr.to_ref(), - vec![]) - } else { - match source.builtin_deref(true, - ty::LvaluePreference::NoPreference) { - Some(mt) => { - target = mt.ty; - } - None => { - span_bug!(self.span, "autoderef for {} failed: {}", - self.id, source); - } - }; - debug!("make_mirror: built-in autoderef"); - ExprKind::Deref { arg: expr.to_ref() } - }; - debug!("make_mirror: autoderef target={:?}", target); - expr = Expr { - temp_lifetime: temp_lifetime, - temp_lifetime_was_shrunk: was_shrunk, - ty: target, - span: self.span, - kind: kind, - }; - } - } - } - - if let Some(adj) = adj { - if let Some(autoref) = adj.autoref { - let adjusted_ty = expr.ty.adjust_for_autoref(cx.tcx, Some(autoref)); - match autoref { - ty::adjustment::AutoBorrow::Ref(r, m) => { - expr = Expr { - temp_lifetime: temp_lifetime, - temp_lifetime_was_shrunk: was_shrunk, - ty: adjusted_ty, - span: self.span, - kind: ExprKind::Borrow { - region: r, - borrow_kind: to_borrow_kind(m), - arg: expr.to_ref(), - }, - }; - } - ty::adjustment::AutoBorrow::RawPtr(m) => { - // Convert this to a suitable `&foo` and - // then an unsafe coercion. Limit the region to be just this - // expression. - let region = ty::ReScope(expr_extent); - let region = cx.tcx.mk_region(region); - expr = Expr { - temp_lifetime: temp_lifetime, - temp_lifetime_was_shrunk: was_shrunk, - ty: cx.tcx.mk_ref(region, - ty::TypeAndMut { - ty: expr.ty, - mutbl: m, - }), - span: self.span, - kind: ExprKind::Borrow { - region: region, - borrow_kind: to_borrow_kind(m), - arg: expr.to_ref(), - }, - }; - expr = Expr { - temp_lifetime: temp_lifetime, - temp_lifetime_was_shrunk: was_shrunk, - ty: adjusted_ty, - span: self.span, - kind: ExprKind::Cast { source: expr.to_ref() }, - }; - } - } - } - - if adj.unsize { - expr = Expr { - temp_lifetime: temp_lifetime, - temp_lifetime_was_shrunk: was_shrunk, - ty: adj.target, - span: self.span, - kind: ExprKind::Unsize { source: expr.to_ref() }, - }; - } + for adjustment in cx.tables().expr_adjustments(self) { + debug!("make_mirror: expr={:?} applying adjustment={:?}", + expr, + adjustment); + expr = apply_adjustment(cx, self, expr, adjustment); } // Next, wrap this up in the expr's scope. @@ -236,6 +73,102 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { } } +fn apply_adjustment<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, + hir_expr: &'tcx hir::Expr, + mut expr: Expr<'tcx>, + adjustment: &Adjustment<'tcx>) + -> Expr<'tcx> { + let Expr { temp_lifetime, temp_lifetime_was_shrunk, span, .. } = expr; + let kind = match adjustment.kind { + Adjust::ReifyFnPointer => { + ExprKind::ReifyFnPointer { source: expr.to_ref() } + } + Adjust::UnsafeFnPointer => { + ExprKind::UnsafeFnPointer { source: expr.to_ref() } + } + Adjust::ClosureFnPointer => { + ExprKind::ClosureFnPointer { source: expr.to_ref() } + } + Adjust::NeverToAny => { + ExprKind::NeverToAny { source: expr.to_ref() } + } + Adjust::MutToConstPointer => { + ExprKind::Cast { source: expr.to_ref() } + } + Adjust::Deref(None) => { + ExprKind::Deref { arg: expr.to_ref() } + } + Adjust::Deref(Some(deref)) => { + let call = deref.method_call(cx.tcx, expr.ty); + + expr = Expr { + temp_lifetime, + temp_lifetime_was_shrunk, + ty: cx.tcx.mk_ref(deref.region, + ty::TypeAndMut { + ty: expr.ty, + mutbl: deref.mutbl, + }), + span, + kind: ExprKind::Borrow { + region: deref.region, + borrow_kind: to_borrow_kind(deref.mutbl), + arg: expr.to_ref(), + }, + }; + + overloaded_lvalue(cx, + hir_expr, + adjustment.target, + Some(call), + PassArgs::ByValue, + expr.to_ref(), + vec![]) + } + Adjust::Borrow(AutoBorrow::Ref(r, m)) => { + ExprKind::Borrow { + region: r, + borrow_kind: to_borrow_kind(m), + arg: expr.to_ref(), + } + } + Adjust::Borrow(AutoBorrow::RawPtr(m)) => { + // Convert this to a suitable `&foo` and + // then an unsafe coercion. Limit the region to be just this + // expression. + let region = ty::ReScope(CodeExtent::Misc(hir_expr.id)); + let region = cx.tcx.mk_region(region); + expr = Expr { + temp_lifetime, + temp_lifetime_was_shrunk, + ty: cx.tcx.mk_ref(region, + ty::TypeAndMut { + ty: expr.ty, + mutbl: m, + }), + span, + kind: ExprKind::Borrow { + region: region, + borrow_kind: to_borrow_kind(m), + arg: expr.to_ref(), + }, + }; + ExprKind::Cast { source: expr.to_ref() } + } + Adjust::Unsize => { + ExprKind::Unsize { source: expr.to_ref() } + } + }; + + Expr { + temp_lifetime, + temp_lifetime_was_shrunk, + ty: adjustment.target, + span, + kind, + } +} + fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, expr: &'tcx hir::Expr) -> Expr<'tcx> { diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index e7aa74494f9e8..fecde3a636cda 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -441,17 +441,21 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node fn check_adjustments<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr) { use rustc::ty::adjustment::*; - match v.tables.adjustments.get(&e.id).map(|adj| &adj.kind) { - None | - Some(&Adjust::NeverToAny) | - Some(&Adjust::ReifyFnPointer) | - Some(&Adjust::UnsafeFnPointer) | - Some(&Adjust::ClosureFnPointer) | - Some(&Adjust::MutToConstPointer) => {} - - Some(&Adjust::Deref(ref autoderefs)) => { - if autoderefs.iter().any(|overloaded| overloaded.is_some()) { - v.promotable = false; + for adjustment in v.tables.expr_adjustments(e) { + match adjustment.kind { + Adjust::NeverToAny | + Adjust::ReifyFnPointer | + Adjust::UnsafeFnPointer | + Adjust::ClosureFnPointer | + Adjust::MutToConstPointer | + Adjust::Borrow(_) | + Adjust::Unsize => {} + + Adjust::Deref(ref overloaded) => { + if overloaded.is_some() { + v.promotable = false; + break; + } } } } diff --git a/src/librustc_typeck/check/autoderef.rs b/src/librustc_typeck/check/autoderef.rs index 36671521474a0..92044737df1ca 100644 --- a/src/librustc_typeck/check/autoderef.rs +++ b/src/librustc_typeck/check/autoderef.rs @@ -18,11 +18,13 @@ use rustc::traits; use rustc::ty::{self, Ty, TraitRef}; use rustc::ty::{ToPredicate, TypeFoldable}; use rustc::ty::{LvaluePreference, NoPreference}; -use rustc::ty::adjustment::{AutoBorrow, OverloadedDeref}; +use rustc::ty::adjustment::{Adjustment, Adjust, OverloadedDeref}; use syntax_pos::Span; use syntax::symbol::Symbol; +use std::iter; + #[derive(Copy, Clone, Debug)] enum AutoderefKind { Builtin, @@ -152,25 +154,26 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> { self.steps.len() } - /// Returns the steps required in adjustments (overloaded deref calls). + /// Returns the adjustment steps. pub fn adjust_steps(&self, pref: LvaluePreference) - -> Vec>> { + -> Vec> { self.fcx.register_infer_ok_obligations(self.adjust_steps_as_infer_ok(pref)) } pub fn adjust_steps_as_infer_ok(&self, pref: LvaluePreference) - -> InferOk<'tcx, Vec>>> { + -> InferOk<'tcx, Vec>> { let mut obligations = vec![]; + let targets = self.steps.iter().skip(1).map(|&(ty, _)| ty) + .chain(iter::once(self.cur_ty)); let steps: Vec<_> = self.steps.iter().map(|&(source, kind)| { if let AutoderefKind::Overloaded = kind { self.fcx.try_overloaded_deref(self.span, source, pref) - .and_then(|InferOk { value: (_, method), obligations: o }| { + .and_then(|InferOk { value: method, obligations: o }| { obligations.extend(o); if let ty::TyRef(region, mt) = method.sig.output().sty { Some(OverloadedDeref { region, mutbl: mt.mutbl, - target: mt.ty }) } else { None @@ -179,6 +182,11 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> { } else { None } + }).zip(targets).map(|(autoderef, target)| { + Adjustment { + kind: Adjust::Deref(autoderef), + target + } }).collect(); InferOk { @@ -213,9 +221,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { span: Span, base_ty: Ty<'tcx>, pref: LvaluePreference) - -> Option>, - MethodCallee<'tcx>)>> { + -> Option>> { self.try_overloaded_lvalue_op(span, base_ty, &[], pref, LvalueOp::Deref) } } diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index 579bcda8dc619..d5ee66a2f0a07 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -17,7 +17,7 @@ use hir::def_id::{DefId, LOCAL_CRATE}; use rustc::{infer, traits}; use rustc::ty::{self, TyCtxt, LvaluePreference, Ty}; use rustc::ty::subst::Subst; -use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, OverloadedDeref}; +use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow}; use syntax::abi; use syntax::symbol::Symbol; use syntax_pos::Span; @@ -96,8 +96,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // If the callee is a bare function or a closure, then we're all set. match adjusted_ty.sty { ty::TyFnDef(..) | ty::TyFnPtr(_) => { - let autoderefs = autoderef.adjust_steps(LvaluePreference::NoPreference); - self.apply_autoderef_adjustment(callee_expr.id, autoderefs, adjusted_ty); + let adjustments = autoderef.adjust_steps(LvaluePreference::NoPreference); + self.apply_adjustments(callee_expr, adjustments); return Some(CallStep::Builtin(adjusted_ty)); } @@ -113,13 +113,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { infer::FnCall, &closure_ty) .0; - let autoderefs = autoderef.adjust_steps(LvaluePreference::NoPreference); + let adjustments = autoderef.adjust_steps(LvaluePreference::NoPreference); self.record_deferred_call_resolution(def_id, DeferredCallResolution { - call_expr: call_expr, - callee_expr: callee_expr, - adjusted_ty: adjusted_ty, - autoderefs: autoderefs, - fn_sig: fn_sig.clone(), + call_expr, + callee_expr, + adjusted_ty, + adjustments, + fn_sig, closure_def_id: def_id, }); return Some(CallStep::DeferredClosure(fn_sig)); @@ -142,13 +142,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } self.try_overloaded_call_traits(call_expr, adjusted_ty).map(|(autoref, method)| { - let autoderefs = autoderef.adjust_steps(LvaluePreference::NoPreference); - self.apply_adjustment(callee_expr.id, Adjustment { - kind: Adjust::Deref(autoderefs), - autoref, - unsize: false, - target: method.sig.inputs()[0] - }); + let mut adjustments = autoderef.adjust_steps(LvaluePreference::NoPreference); + adjustments.extend(autoref); + self.apply_adjustments(callee_expr, adjustments); CallStep::Overloaded(method) }) } @@ -156,25 +152,37 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn try_overloaded_call_traits(&self, call_expr: &hir::Expr, adjusted_ty: Ty<'tcx>) - -> Option<(Option>, + -> Option<(Option>, MethodCallee<'tcx>)> { // Try the options that are least restrictive on the caller first. - for &(opt_trait_def_id, method_name) in - &[(self.tcx.lang_items.fn_trait(), Symbol::intern("call")), - (self.tcx.lang_items.fn_mut_trait(), Symbol::intern("call_mut")), - (self.tcx.lang_items.fn_once_trait(), Symbol::intern("call_once"))] { + for &(opt_trait_def_id, method_name, borrow) in + &[(self.tcx.lang_items.fn_trait(), Symbol::intern("call"), true), + (self.tcx.lang_items.fn_mut_trait(), Symbol::intern("call_mut"), true), + (self.tcx.lang_items.fn_once_trait(), Symbol::intern("call_once"), false)] { let trait_def_id = match opt_trait_def_id { Some(def_id) => def_id, None => continue, }; - match self.lookup_method_in_trait_adjusted(call_expr.span, - method_name, - trait_def_id, - adjusted_ty, - None) { + match self.lookup_method_in_trait(call_expr.span, + method_name, + trait_def_id, + adjusted_ty, + None) { None => continue, - Some(ok) => return Some(self.register_infer_ok_obligations(ok)) + Some(ok) => { + let method = self.register_infer_ok_obligations(ok); + let mut autoref = None; + if borrow { + if let ty::TyRef(region, mt) = method.sig.inputs()[0].sty { + autoref = Some(Adjustment { + kind: Adjust::Borrow(AutoBorrow::Ref(region, mt.mutbl)), + target: method.sig.inputs()[0] + }); + } + } + return Some((autoref, method)); + } } } @@ -317,7 +325,7 @@ pub struct DeferredCallResolution<'gcx: 'tcx, 'tcx> { call_expr: &'gcx hir::Expr, callee_expr: &'gcx hir::Expr, adjusted_ty: Ty<'tcx>, - autoderefs: Vec>>, + adjustments: Vec>, fn_sig: ty::FnSig<'tcx>, closure_def_id: DefId, } @@ -353,12 +361,9 @@ impl<'a, 'gcx, 'tcx> DeferredCallResolution<'gcx, 'tcx> { fcx.demand_eqtype(self.call_expr.span, method_sig.output(), self.fn_sig.output()); - fcx.apply_adjustment(self.callee_expr.id, Adjustment { - kind: Adjust::Deref(self.autoderefs), - autoref, - unsize: false, - target: method_sig.inputs()[0] - }); + let mut adjustments = self.adjustments; + adjustments.extend(autoref); + fcx.apply_adjustments(self.callee_expr, adjustments); fcx.write_method_call(self.call_expr.id, method_callee); } diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index dc373610814dd..a962cdb8f728f 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -95,7 +95,7 @@ impl<'a, 'gcx, 'tcx> Deref for Coerce<'a, 'gcx, 'tcx> { } } -type CoerceResult<'tcx> = InferResult<'tcx, Adjustment<'tcx>>; +type CoerceResult<'tcx> = InferResult<'tcx, (Vec>, Ty<'tcx>)>; fn coerce_mutbls<'tcx>(from_mutbl: hir::Mutability, to_mutbl: hir::Mutability) @@ -108,24 +108,18 @@ fn coerce_mutbls<'tcx>(from_mutbl: hir::Mutability, } } -fn identity<'tcx>(target: Ty<'tcx>) -> Adjustment<'tcx> { - simple(Adjust::Deref(vec![]))(target) -} +fn identity(_: Ty) -> Vec { vec![] } -fn simple<'tcx>(kind: Adjust<'tcx>) -> impl FnOnce(Ty<'tcx>) -> Adjustment<'tcx> { - move |target| Adjustment { - kind, - autoref: None, - unsize: false, - target - } +fn simple<'tcx>(kind: Adjust<'tcx>) -> impl FnOnce(Ty<'tcx>) -> Vec> { + move |target| vec![Adjustment { kind, target }] } -fn success<'tcx>(adj: Adjustment<'tcx>, +fn success<'tcx>(adj: Vec>, + target: Ty<'tcx>, obligations: traits::PredicateObligations<'tcx>) -> CoerceResult<'tcx> { Ok(InferOk { - value: adj, + value: (adj, target), obligations }) } @@ -153,10 +147,10 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { /// Unify two types (using sub or lub) and produce a specific coercion. fn unify_and(&self, a: Ty<'tcx>, b: Ty<'tcx>, f: F) -> CoerceResult<'tcx> - where F: FnOnce(Ty<'tcx>) -> Adjustment<'tcx> + where F: FnOnce(Ty<'tcx>) -> Vec> { self.unify(&a, &b).and_then(|InferOk { value: ty, obligations }| { - success(f(ty), obligations) + success(f(ty), ty, obligations) }) } @@ -166,7 +160,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { // Just ignore error types. if a.references_error() || b.references_error() { - return success(identity(b), vec![]); + return success(vec![], b, vec![]); } if a.is_never() { @@ -185,7 +179,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { TypeVariableOrigin::AdjustmentType(self.cause.span)); self.unify_and(&b, &diverging_ty, simple(Adjust::NeverToAny)) } else { - success(simple(Adjust::NeverToAny)(b), vec![]) + success(simple(Adjust::NeverToAny)(b), b, vec![]) }; } @@ -407,34 +401,31 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { // `self.x`, but we auto-coerce it to `foo(&mut *self.x)`, // which is a borrow. assert_eq!(mt_b.mutbl, hir::MutImmutable); // can only coerce &T -> &U - return success(identity(ty), obligations); + return success(vec![], ty, obligations); } + let pref = LvaluePreference::from_mutbl(mt_b.mutbl); + let InferOk { value: mut adjustments, obligations: o } + = autoderef.adjust_steps_as_infer_ok(pref); + obligations.extend(o); + obligations.extend(autoderef.into_obligations()); + // Now apply the autoref. We have to extract the region out of // the final ref type we got. let r_borrow = match ty.sty { ty::TyRef(r_borrow, _) => r_borrow, _ => span_bug!(span, "expected a ref type, got {:?}", ty), }; - let autoref = Some(AutoBorrow::Ref(r_borrow, mt_b.mutbl)); - - let pref = LvaluePreference::from_mutbl(mt_b.mutbl); - let InferOk { value: autoderefs, obligations: o } - = autoderef.adjust_steps_as_infer_ok(pref); - obligations.extend(o); - obligations.extend(autoderef.into_obligations()); + adjustments.push(Adjustment { + kind: Adjust::Borrow(AutoBorrow::Ref(r_borrow, mt_b.mutbl)), + target: ty + }); - debug!("coerce_borrowed_pointer: succeeded ty={:?} autoderefs={:?} autoref={:?}", + debug!("coerce_borrowed_pointer: succeeded ty={:?} adjustments={:?}", ty, - autoderefs, - autoref); + adjustments); - success(Adjustment { - kind: Adjust::Deref(autoderefs), - autoref, - unsize: false, - target: ty - }, obligations) + success(adjustments, ty, obligations) } @@ -459,21 +450,40 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { // that, at which point we will need extra checks on the target here. // Handle reborrows before selecting `Source: CoerceUnsized`. - let (source, reborrow) = match (&source.sty, &target.sty) { + let reborrow = match (&source.sty, &target.sty) { (&ty::TyRef(_, mt_a), &ty::TyRef(_, mt_b)) => { coerce_mutbls(mt_a.mutbl, mt_b.mutbl)?; let coercion = Coercion(self.cause.span); let r_borrow = self.next_region_var(coercion); - (mt_a.ty, Some(AutoBorrow::Ref(r_borrow, mt_b.mutbl))) + Some((Adjustment { + kind: Adjust::Deref(None), + target: mt_a.ty + }, Adjustment { + kind: Adjust::Borrow(AutoBorrow::Ref(r_borrow, mt_b.mutbl)), + target: self.tcx.mk_ref(r_borrow, ty::TypeAndMut { + mutbl: mt_b.mutbl, + ty: mt_a.ty + }) + })) } (&ty::TyRef(_, mt_a), &ty::TyRawPtr(mt_b)) => { coerce_mutbls(mt_a.mutbl, mt_b.mutbl)?; - (mt_a.ty, Some(AutoBorrow::RawPtr(mt_b.mutbl))) + + Some((Adjustment { + kind: Adjust::Deref(None), + target: mt_a.ty + }, Adjustment { + kind: Adjust::Borrow(AutoBorrow::RawPtr(mt_b.mutbl)), + target: self.tcx.mk_ptr(ty::TypeAndMut { + mutbl: mt_b.mutbl, + ty: mt_a.ty + }) + })) } - _ => (source, None), + _ => None, }; - let coerce_source = source.adjust_for_autoref(self.tcx, reborrow); + let coerce_source = reborrow.as_ref().map_or(source, |&(_, ref r)| r.target); // Setup either a subtyping or a LUB relationship between // the `CoerceUnsized` target type and the expected type. @@ -481,11 +491,17 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { // for the former and let type inference do the rest. let origin = TypeVariableOrigin::MiscVariable(self.cause.span); let coerce_target = self.next_ty_var(origin); - let mut coercion = self.unify_and(coerce_target, target, |target| Adjustment { - kind: Adjust::Deref(if reborrow.is_some() { vec![None] } else { vec![] }), - autoref: reborrow, - unsize: true, - target + let mut coercion = self.unify_and(coerce_target, target, |target| { + let unsize = Adjustment { + kind: Adjust::Unsize, + target + }; + match reborrow { + None => vec![unsize], + Some((ref deref, ref autoref)) => { + vec![deref.clone(), autoref.clone(), unsize] + } + } })?; let mut selcx = traits::SelectionContext::new(self); @@ -546,8 +562,8 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { to_unsafe: F, normal: G) -> CoerceResult<'tcx> - where F: FnOnce(Ty<'tcx>) -> Adjustment<'tcx>, - G: FnOnce(Ty<'tcx>) -> Adjustment<'tcx> + where F: FnOnce(Ty<'tcx>) -> Vec>, + G: FnOnce(Ty<'tcx>) -> Vec> { if let ty::TyFnPtr(fn_ty_b) = b.sty { match (fn_ty_a.unsafety(), fn_ty_b.unsafety()) { @@ -668,11 +684,14 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { // representation, we still register an Adjust::DerefRef so that // regionck knows that the region for `a` must be valid here. if is_ref { - self.unify_and(a_unsafe, b, |target| Adjustment { - kind: Adjust::Deref(vec![None]), - autoref: Some(AutoBorrow::RawPtr(mutbl_b)), - unsize: false, - target + self.unify_and(a_unsafe, b, |target| { + vec![Adjustment { + kind: Adjust::Deref(None), + target: mt_a.ty + }, Adjustment { + kind: Adjust::Borrow(AutoBorrow::RawPtr(mutbl_b)), + target + }] }) } else if mt_a.mutbl != mutbl_b { self.unify_and(a_unsafe, b, simple(Adjust::MutToConstPointer)) @@ -707,12 +726,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let coerce = Coerce::new(self, cause); let ok = self.commit_if_ok(|_| coerce.coerce(source, target))?; - let adjustment = self.register_infer_ok_obligations(ok); - self.apply_adjustment(expr.id, adjustment); - - // We should now have added sufficient adjustments etc to - // ensure that the type of expression, post-adjustment, is - // a subtype of target. + let (adjustments, _) = self.register_infer_ok_obligations(ok); + self.apply_adjustments(expr, adjustments); Ok(target) } @@ -781,12 +796,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { for expr in exprs.iter().map(|e| e.as_coercion_site()).chain(Some(new)) { // The only adjustment that can produce an fn item is // `NeverToAny`, so this should always be valid. - self.apply_adjustment(expr.id, Adjustment { + self.apply_adjustments(expr, vec![Adjustment { kind: Adjust::ReifyFnPointer, - autoref: None, - unsize: false, target: fn_ptr - }); + }]); } return Ok(fn_ptr); } @@ -803,9 +816,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let result = self.commit_if_ok(|_| coerce.coerce(new_ty, prev_ty)); match result { Ok(ok) => { - let adjustment = self.register_infer_ok_obligations(ok); - let target = adjustment.target; - self.apply_adjustment(new.id, adjustment); + let (adjustments, target) = self.register_infer_ok_obligations(ok); + self.apply_adjustments(new, adjustments); return Ok(target); } Err(e) => first_error = Some(e), @@ -817,26 +829,23 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // previous expressions, other than noop reborrows (ignoring lifetimes). for expr in exprs { let expr = expr.as_coercion_site(); - let noop = match self.tables.borrow().adjustments.get(&expr.id) { - Some(&Adjustment { - kind: Adjust::Deref(ref autoderefs), - autoref: Some(AutoBorrow::Ref(_, mutbl_adj)), - unsize: false, - target: _ - }) if autoderefs.len() == 1 => { + let noop = match self.tables.borrow().expr_adjustments(expr) { + &[ + Adjustment { kind: Adjust::Deref(_), .. }, + Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(_, mutbl_adj)), .. } + ] => { match self.node_ty(expr.id).sty { ty::TyRef(_, mt_orig) => { // Reborrow that we can safely ignore, because - // the next adjustment can only be a DerefRef + // the next adjustment can only be a Deref // which will be merged into it. mutbl_adj == mt_orig.mutbl } _ => false, } } - Some(&Adjustment { kind: Adjust::NeverToAny, .. }) => true, - Some(_) => false, - None => true, + &[Adjustment { kind: Adjust::NeverToAny, .. }] | &[] => true, + _ => false, }; if !noop { @@ -860,12 +869,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } Ok(ok) => { - let adjustment = self.register_infer_ok_obligations(ok); + let (adjustments, target) = self.register_infer_ok_obligations(ok); for expr in exprs { let expr = expr.as_coercion_site(); - self.apply_adjustment(expr.id, adjustment.clone()); + self.apply_adjustments(expr, adjustments.clone()); } - Ok(adjustment.target) + Ok(target) } } } diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index bdbc7f677e4cf..34e8d6b95a926 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -15,7 +15,7 @@ use hir::def_id::DefId; use rustc::ty::subst::Substs; use rustc::traits; use rustc::ty::{self, LvaluePreference, NoPreference, PreferMutLvalue, Ty}; -use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow}; +use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, OverloadedDeref}; use rustc::ty::fold::TypeFoldable; use rustc::infer::{self, InferOk}; use syntax_pos::Span; @@ -118,40 +118,49 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { unadjusted_self_ty: Ty<'tcx>, pick: &probe::Pick<'tcx>) -> Ty<'tcx> { - let autoref = if let Some(mutbl) = pick.autoref { + // Commit the autoderefs by calling `autoderef` again, but this + // time writing the results into the various tables. + let mut autoderef = self.autoderef(self.span, unadjusted_self_ty); + let (_, n) = autoderef.nth(pick.autoderefs).unwrap(); + assert_eq!(n, pick.autoderefs); + + let mut adjustments = autoderef.adjust_steps(LvaluePreference::NoPreference); + + let mut target = autoderef.unambiguous_final_ty(); + + if let Some(mutbl) = pick.autoref { let region = self.next_region_var(infer::Autoref(self.span)); - Some(AutoBorrow::Ref(region, mutbl)) + target = self.tcx.mk_ref(region, ty::TypeAndMut { + mutbl, + ty: target + }); + adjustments.push(Adjustment { + kind: Adjust::Borrow(AutoBorrow::Ref(region, mutbl)), + target + }); + + if let Some(unsize_target) = pick.unsize { + target = self.tcx.mk_ref(region, ty::TypeAndMut { + mutbl, + ty: unsize_target + }); + adjustments.push(Adjustment { + kind: Adjust::Unsize, + target + }); + } } else { // No unsizing should be performed without autoref (at // least during method dispach). This is because we // currently only unsize `[T;N]` to `[T]`, and naturally // that must occur being a reference. assert!(pick.unsize.is_none()); - None - }; - - - // Commit the autoderefs by calling `autoderef` again, but this - // time writing the results into the various tables. - let mut autoderef = self.autoderef(self.span, unadjusted_self_ty); - let (autoderefd_ty, n) = autoderef.nth(pick.autoderefs).unwrap(); - assert_eq!(n, pick.autoderefs); - - let autoderefs = autoderef.adjust_steps(LvaluePreference::NoPreference); + } - autoderef.unambiguous_final_ty(); autoderef.finalize(); - let target = pick.unsize.unwrap_or(autoderefd_ty); - let target = target.adjust_for_autoref(self.tcx, autoref); - - // Write out the final adjustment. - self.apply_adjustment(self.self_expr.id, Adjustment { - kind: Adjust::Deref(autoderefs), - autoref, - unsize: pick.unsize.is_some(), - target, - }); + // Write out the final adjustments. + self.apply_adjustments(self.self_expr, adjustments); target } @@ -436,17 +445,22 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { // Fix up the autoderefs. Autorefs can only occur immediately preceding // overloaded lvalue ops, and will be fixed by them in order to get // the correct region. - let expr_ty = self.node_ty(expr.id); - if let Some(adj) = self.tables.borrow_mut().adjustments.get_mut(&expr.id) { - if let Adjust::Deref(ref mut autoderefs) = adj.kind { - let mut autoderef = self.autoderef(expr.span, expr_ty); - autoderef.nth(autoderefs.len()).unwrap_or_else(|| { - span_bug!(expr.span, - "expr was deref-able as {:?} but now isn't?", - autoderefs); - }); - *autoderefs = autoderef.adjust_steps(LvaluePreference::PreferMutLvalue); - autoderef.finalize(); + let mut source = self.node_ty(expr.id); + if let Some(adjustments) = self.tables.borrow_mut().adjustments.get_mut(&expr.id) { + let pref = LvaluePreference::PreferMutLvalue; + for adjustment in adjustments { + if let Adjust::Deref(Some(ref mut deref)) = adjustment.kind { + if let Some(ok) = self.try_overloaded_deref(expr.span, source, pref) { + let method = self.register_infer_ok_obligations(ok); + if let ty::TyRef(region, mt) = method.sig.output().sty { + *deref = OverloadedDeref { + region, + mutbl: mt.mutbl + }; + } + } + } + source = adjustment.target; } } @@ -478,7 +492,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { return } - let base_ty = self.tables.borrow().adjustments.get(&base_expr.id) + let base_ty = self.tables.borrow().expr_adjustments(base_expr).last() .map_or_else(|| self.node_ty(expr.id), |adj| adj.target); let base_ty = self.resolve_type_vars_if_possible(&base_ty); @@ -489,28 +503,43 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { let method = self.try_overloaded_lvalue_op( expr.span, base_ty, arg_tys, PreferMutLvalue, op); - let ok = match method { - Some(method) => method, + let method = match method { + Some(ok) => self.register_infer_ok_obligations(ok), None => return self.tcx.sess.delay_span_bug(expr.span, "re-trying op failed") }; - let (_, method) = self.register_infer_ok_obligations(ok); debug!("convert_lvalue_op_to_mutable: method={:?}", method); self.write_method_call(expr.id, method); + let (region, mutbl) = if let ty::TyRef(r, mt) = method.sig.inputs()[0].sty { + (r, mt.mutbl) + } else { + span_bug!(expr.span, "input to lvalue op is not a ref?"); + }; + // Convert the autoref in the base expr to mutable with the correct // region and mutability. - if let Some(&mut Adjustment { - ref mut target, - autoref: Some(AutoBorrow::Ref(ref mut r, ref mut mutbl)), .. - }) = self.tables.borrow_mut().adjustments.get_mut(&base_expr.id) { - debug!("convert_lvalue_op_to_mutable: converting autoref of {:?}", target); - - *target = method.sig.inputs()[0]; - if let ty::TyRef(r_, mt) = target.sty { - *r = r_; - *mutbl = mt.mutbl; - } else { - span_bug!(expr.span, "input to lvalue op is not a ref?"); + let base_expr_ty = self.node_ty(base_expr.id); + if let Some(adjustments) = self.tables.borrow_mut().adjustments.get_mut(&base_expr.id) { + let mut source = base_expr_ty; + for adjustment in &mut adjustments[..] { + if let Adjust::Borrow(AutoBorrow::Ref(..)) = adjustment.kind { + debug!("convert_lvalue_op_to_mutable: converting autoref {:?}", adjustment); + adjustment.kind = Adjust::Borrow(AutoBorrow::Ref(region, mutbl)); + adjustment.target = self.tcx.mk_ref(region, ty::TypeAndMut { + ty: source, + mutbl + }); + } + source = adjustment.target; + } + + // If we have an autoref followed by unsizing at the end, fix the unsize target. + match adjustments[..] { + [.., Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(..)), .. }, + Adjustment { kind: Adjust::Unsize, ref mut target }] => { + *target = method.sig.inputs()[0]; + } + _ => {} } } } diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index 688def4356ccc..b0ac61d2cc34a 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -16,7 +16,6 @@ use hir::def_id::DefId; use rustc::ty::subst::Substs; use rustc::traits; use rustc::ty::{self, ToPredicate, ToPolyTraitRef, TraitRef, TypeFoldable}; -use rustc::ty::adjustment::AutoBorrow; use rustc::ty::subst::Subst; use rustc::infer::{self, InferOk}; @@ -165,26 +164,22 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { supplied_method_types)) } - /// `lookup_in_trait_adjusted` is used for overloaded operators. + /// `lookup_method_in_trait` is used for overloaded operators. /// It does a very narrow slice of what the normal probe/confirm path does. /// In particular, it doesn't really do any probing: it simply constructs /// an obligation for aparticular trait with the given self-type and checks /// whether that trait is implemented. /// /// FIXME(#18741) -- It seems likely that we can consolidate some of this - /// code with the other method-lookup code. In particular, autoderef on - /// index is basically identical to autoderef with normal probes, except - /// that the test also looks for built-in indexing. Also, the second half of - /// this method is basically the same as confirmation. - pub fn lookup_method_in_trait_adjusted(&self, - span: Span, - m_name: ast::Name, - trait_def_id: DefId, - self_ty: ty::Ty<'tcx>, - opt_input_types: Option<&[ty::Ty<'tcx>]>) - -> Option>, - MethodCallee<'tcx>)>> { + /// code with the other method-lookup code. In particular, the second half + /// of this method is basically the same as confirmation. + pub fn lookup_method_in_trait(&self, + span: Span, + m_name: ast::Name, + trait_def_id: DefId, + self_ty: ty::Ty<'tcx>, + opt_input_types: Option<&[ty::Ty<'tcx>]>) + -> Option>> { debug!("lookup_in_trait_adjusted(self_ty={:?}, \ m_name={}, trait_def_id={:?})", self_ty, @@ -237,8 +232,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // NB: Instantiate late-bound regions first so that // `instantiate_type_scheme` can normalize associated types that // may reference those regions. - let original_method_ty = tcx.type_of(def_id); - let fn_sig = original_method_ty.fn_sig(); + let fn_sig = tcx.type_of(def_id).fn_sig(); let fn_sig = self.replace_late_bound_regions_with_fresh_var(span, infer::FnCall, &fn_sig).0; @@ -249,11 +243,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { value } }; - let method_ty = tcx.mk_fn_def(def_id, substs, ty::Binder(fn_sig)); - - debug!("lookup_in_trait_adjusted: matched method method_ty={:?} obligation={:?}", - method_ty, - obligation); // Register obligations for the parameters. This will include the // `Self` parameter, which in turn has a bound of the main trait, @@ -276,21 +265,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { obligations.extend(traits::predicates_for_generics(cause.clone(), &bounds)); // Also add an obligation for the method type being well-formed. + let method_ty = tcx.mk_fn_ptr(ty::Binder(fn_sig)); + debug!("lookup_in_trait_adjusted: matched method method_ty={:?} obligation={:?}", + method_ty, + obligation); obligations.push(traits::Obligation::new(cause, ty::Predicate::WellFormed(method_ty))); - let autoref = match (&original_method_ty.fn_sig().input(0).skip_binder().sty, - &fn_sig.inputs()[0].sty) { - (&ty::TyRef(..), &ty::TyRef(region, ty::TypeAndMut { mutbl, ty: _ })) => { - // Trait method is fn(&self) or fn(&mut self), need an - // autoref. Pull the region etc out of the type of first argument. - Some(AutoBorrow::Ref(region, mutbl)) - } - _ => { - // Trait method is fn(self), no transformation needed. - None - } - }; - let callee = MethodCallee { def_id: def_id, substs: trait_ref.substs, @@ -301,7 +281,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { Some(InferOk { obligations, - value: (autoref, callee) + value: callee }) } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index e6d43f0040362..813e199f85a75 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -96,7 +96,7 @@ use rustc::ty::subst::{Kind, Subst, Substs}; use rustc::traits::{self, FulfillmentContext, ObligationCause, ObligationCauseCode, Reveal}; use rustc::ty::{ParamTy, LvaluePreference, NoPreference, PreferMutLvalue}; use rustc::ty::{self, Ty, TyCtxt, Visibility}; -use rustc::ty::adjustment::{Adjust, Adjustment, AutoBorrow, OverloadedDeref}; +use rustc::ty::adjustment::{Adjust, Adjustment, AutoBorrow}; use rustc::ty::fold::{BottomUpFolder, TypeFoldable}; use rustc::ty::maps::Providers; use rustc::ty::util::{Representability, IntTypeExt}; @@ -1774,48 +1774,36 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } - pub fn apply_autoderef_adjustment(&self, - node_id: ast::NodeId, - autoderefs: Vec>>, - adjusted_ty: Ty<'tcx>) { - self.apply_adjustment(node_id, Adjustment { - kind: Adjust::Deref(autoderefs), - autoref: None, - unsize: false, - target: adjusted_ty - }); - } - - pub fn apply_adjustment(&self, node_id: ast::NodeId, adj: Adjustment<'tcx>) { - debug!("apply_adjustment(node_id={}, adj={:?})", node_id, adj); + pub fn apply_adjustments(&self, expr: &hir::Expr, adj: Vec>) { + debug!("apply_adjustments(expr={:?}, adj={:?})", expr, adj); - if adj.is_identity() { + if adj.is_empty() { return; } - match self.tables.borrow_mut().adjustments.entry(node_id) { + match self.tables.borrow_mut().adjustments.entry(expr.id) { Entry::Vacant(entry) => { entry.insert(adj); }, Entry::Occupied(mut entry) => { debug!(" - composing on top of {:?}", entry.get()); - match (entry.get(), &adj) { + match (&entry.get()[..], &adj[..]) { // Applying any adjustment on top of a NeverToAny // is a valid NeverToAny adjustment, because it can't // be reached. - (&Adjustment { kind: Adjust::NeverToAny, .. }, _) => return, - (&Adjustment { - kind: Adjust::Deref(ref old), - autoref: Some(AutoBorrow::Ref(..)), - unsize: false, .. - }, &Adjustment { - kind: Adjust::Deref(ref new), .. - }) if old.len() == 1 && new.len() >= 1 => { + (&[Adjustment { kind: Adjust::NeverToAny, .. }], _) => return, + (&[ + Adjustment { kind: Adjust::Deref(_), .. }, + Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(..)), .. }, + ], &[ + Adjustment { kind: Adjust::Deref(_), .. }, + .. // Any following adjustments are allowed. + ]) => { // A reborrow has no effect before a dereference. } // FIXME: currently we never try to compose autoderefs // and ReifyFnPointer/UnsafeFnPointer, but we could. _ => - bug!("while adjusting {}, can't compose {:?} and {:?}", - node_id, entry.get(), adj) + bug!("while adjusting {:?}, can't compose {:?} and {:?}", + expr, entry.get(), adj) }; *entry.get_mut() = adj; } @@ -2189,7 +2177,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { index_ty: Ty<'tcx>) -> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)> { - let mut adjusted_ty = autoderef.unambiguous_final_ty(); + let adjusted_ty = autoderef.unambiguous_final_ty(); debug!("try_index_step(expr={:?}, base_expr={:?}, adjusted_ty={:?}, \ index_ty={:?})", expr, @@ -2202,19 +2190,19 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { match (adjusted_ty.builtin_index(), &index_ty.sty) { (Some(ty), &ty::TyUint(ast::UintTy::Us)) | (Some(ty), &ty::TyInfer(ty::IntVar(_))) => { debug!("try_index_step: success, using built-in indexing"); - let autoderefs = autoderef.adjust_steps(lvalue_pref); - self.apply_autoderef_adjustment( - base_expr.id, autoderefs, adjusted_ty); + let adjustments = autoderef.adjust_steps(lvalue_pref); + self.apply_adjustments(base_expr, adjustments); return Some((self.tcx.types.usize, ty)); } _ => {} } for &unsize in &[false, true] { + let mut self_ty = adjusted_ty; if unsize { // We only unsize arrays here. if let ty::TyArray(element_ty, _) = adjusted_ty.sty { - adjusted_ty = self.tcx.mk_slice(element_ty); + self_ty = self.tcx.mk_slice(element_ty); } else { continue; } @@ -2225,19 +2213,29 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // If some lookup succeeded, install method in table let input_ty = self.next_ty_var(TypeVariableOrigin::AutoDeref(base_expr.span)); let method = self.try_overloaded_lvalue_op( - expr.span, adjusted_ty, &[input_ty], lvalue_pref, LvalueOp::Index); + expr.span, self_ty, &[input_ty], lvalue_pref, LvalueOp::Index); let result = method.map(|ok| { debug!("try_index_step: success, using overloaded indexing"); - let (autoref, method) = self.register_infer_ok_obligations(ok); - - let autoderefs = autoderef.adjust_steps(lvalue_pref); - self.apply_adjustment(base_expr.id, Adjustment { - kind: Adjust::Deref(autoderefs), - autoref, - unsize, - target: method.sig.inputs()[0] - }); + let method = self.register_infer_ok_obligations(ok); + + let mut adjustments = autoderef.adjust_steps(lvalue_pref); + if let ty::TyRef(region, mt) = method.sig.inputs()[0].sty { + adjustments.push(Adjustment { + kind: Adjust::Borrow(AutoBorrow::Ref(region, mt.mutbl)), + target: self.tcx.mk_ref(region, ty::TypeAndMut { + mutbl: mt.mutbl, + ty: adjusted_ty + }) + }); + } + if unsize { + adjustments.push(Adjustment { + kind: Adjust::Unsize, + target: method.sig.inputs()[0] + }); + } + self.apply_adjustments(base_expr, adjustments); self.write_method_call(expr.id, method); (input_ty, self.make_overloaded_lvalue_return_type(method).ty) @@ -2270,9 +2268,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { arg_tys: &[Ty<'tcx>], lvalue_pref: LvaluePreference, op: LvalueOp) - -> Option>, - MethodCallee<'tcx>)>> + -> Option>> { debug!("try_overloaded_lvalue_op({:?},{:?},{:?},{:?})", span, @@ -2284,11 +2280,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let (mut_tr, mut_op) = self.resolve_lvalue_op(op, true); let method = match (lvalue_pref, mut_tr) { (PreferMutLvalue, Some(trait_did)) => { - self.lookup_method_in_trait_adjusted(span, - mut_op, - trait_did, - base_ty, - Some(arg_tys)) + self.lookup_method_in_trait(span, mut_op, trait_did, base_ty, Some(arg_tys)) } _ => None, }; @@ -2297,11 +2289,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let (imm_tr, imm_op) = self.resolve_lvalue_op(op, false); let method = match (method, imm_tr) { (None, Some(trait_did)) => { - self.lookup_method_in_trait_adjusted(span, - imm_op, - trait_did, - base_ty, - Some(arg_tys)) + self.lookup_method_in_trait(span, imm_op, trait_did, base_ty, Some(arg_tys)) } (method, _) => method, }; @@ -2645,12 +2633,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { "expression with never type wound up being adjusted"); let adj_ty = self.next_diverging_ty_var( TypeVariableOrigin::AdjustmentType(expr.span)); - self.apply_adjustment(expr.id, Adjustment { + self.apply_adjustments(expr, vec![Adjustment { kind: Adjust::NeverToAny, - autoref: None, - unsize: false, target: adj_ty - }); + }]); ty = adj_ty; } @@ -2895,8 +2881,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let Some(field) = fields.iter().find(|f| f.name.to_ident() == ident) { let field_ty = self.field_ty(expr.span, field, substs); if field.vis.is_accessible_from(def_scope, self.tcx) { - let autoderefs = autoderef.adjust_steps(lvalue_pref); - self.apply_autoderef_adjustment(base.id, autoderefs, base_t); + let adjustments = autoderef.adjust_steps(lvalue_pref); + self.apply_adjustments(base, adjustments); autoderef.finalize(); self.tcx.check_stability(field.did, expr.id, expr.span); @@ -3029,8 +3015,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }; if let Some(field_ty) = field { - let autoderefs = autoderef.adjust_steps(lvalue_pref); - self.apply_autoderef_adjustment(base.id, autoderefs, base_t); + let adjustments = autoderef.adjust_steps(lvalue_pref); + self.apply_adjustments(base, adjustments); autoderef.finalize(); return field_ty; } @@ -3446,13 +3432,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { oprnd_t = mt.ty; } else if let Some(ok) = self.try_overloaded_deref( expr.span, oprnd_t, lvalue_pref) { - let (autoref, method) = self.register_infer_ok_obligations(ok); - self.apply_adjustment(oprnd.id, Adjustment { - kind: Adjust::Deref(vec![]), - autoref, - unsize: false, - target: method.sig.inputs()[0] - }); + let method = self.register_infer_ok_obligations(ok); + if let ty::TyRef(region, mt) = method.sig.inputs()[0].sty { + self.apply_adjustments(oprnd, vec![Adjustment { + kind: Adjust::Borrow(AutoBorrow::Ref(region, mt.mutbl)), + target: method.sig.inputs()[0] + }]); + } oprnd_t = self.make_overloaded_lvalue_return_type(method).ty; self.write_method_call(expr.id, method); } else { @@ -3466,9 +3452,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { hir::UnNot => { oprnd_t = self.structurally_resolved_type(oprnd.span, oprnd_t); - let result = self.check_user_unop("!", "not", - tcx.lang_items.not_trait(), - expr, &oprnd, oprnd_t, unop); + let result = self.check_user_unop(expr, &oprnd, oprnd_t, unop); // If it's builtin, we can reuse the type, this helps inference. if !(oprnd_t.is_integral() || oprnd_t.sty == ty::TyBool) { oprnd_t = result; @@ -3477,9 +3461,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { hir::UnNeg => { oprnd_t = self.structurally_resolved_type(oprnd.span, oprnd_t); - let result = self.check_user_unop("-", "neg", - tcx.lang_items.neg_trait(), - expr, &oprnd, oprnd_t, unop); + let result = self.check_user_unop(expr, &oprnd, oprnd_t, unop); // If it's builtin, we can reuse the type, this helps inference. if !(oprnd_t.is_integral() || oprnd_t.is_fp()) { oprnd_t = result; diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index 8d442aae70e3b..cbb89355bf952 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -11,13 +11,11 @@ //! Code related to processing overloaded binary and unary operators. use super::FnCtxt; -use hir::def_id::DefId; -use rustc::ty::{Ty, TypeFoldable, PreferMutLvalue, TypeVariants}; +use rustc::ty::{self, Ty, TypeFoldable, PreferMutLvalue, TypeVariants}; use rustc::ty::TypeVariants::{TyStr, TyRef}; -use rustc::ty::adjustment::{Adjustment, Adjust}; +use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow}; use rustc::infer::type_variable::TypeVariableOrigin; use errors; -use syntax::ast; use syntax::symbol::Symbol; use rustc::hir; @@ -175,8 +173,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { lhs_ty, is_assign); - let (name, trait_def_id) = self.name_and_trait_def_id(op, is_assign); - // NB: As we have not yet type-checked the RHS, we don't have the // type at hand. Make a variable to represent it. The whole reason // for this indirection is so that, below, we can check the expr @@ -186,8 +182,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let rhs_ty_var = self.next_ty_var(TypeVariableOrigin::MiscVariable(rhs_expr.span)); let return_ty = self.lookup_op_method(expr, lhs_ty, &[rhs_ty_var], - Symbol::intern(name), trait_def_id, - lhs_expr); + Op::Binary(op, is_assign), lhs_expr); // see `NB` above let rhs_ty = self.check_expr_coercable_to_type(rhs_expr, rhs_ty_var); @@ -216,8 +211,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let TypeVariants::TyRef(_, ref ty_mut) = lhs_ty.sty { if !self.infcx.type_moves_by_default(ty_mut.ty, lhs_expr.span) && self.lookup_op_method(expr, ty_mut.ty, &[rhs_ty], - Symbol::intern(name), trait_def_id, - lhs_expr).is_ok() { + Op::Binary(op, is_assign), lhs_expr).is_ok() { err.note( &format!( "this is a reference to a type that `{}` can be applied \ @@ -303,9 +297,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } pub fn check_user_unop(&self, - op_str: &str, - mname: &str, - trait_did: Option, ex: &'gcx hir::Expr, operand_expr: &'gcx hir::Expr, operand_ty: Ty<'tcx>, @@ -313,28 +304,31 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { -> Ty<'tcx> { assert!(op.is_by_value()); - let mname = Symbol::intern(mname); - match self.lookup_op_method(ex, operand_ty, &[], mname, trait_did, operand_expr) { + match self.lookup_op_method(ex, operand_ty, &[], Op::Unary(op), operand_expr) { Ok(t) => t, Err(()) => { let actual = self.resolve_type_vars_if_possible(&operand_ty); if !actual.references_error() { struct_span_err!(self.tcx.sess, ex.span, E0600, "cannot apply unary operator `{}` to type `{}`", - op_str, actual).emit(); + op.as_str(), actual).emit(); } self.tcx.types.err } } } - fn name_and_trait_def_id(&self, - op: hir::BinOp, - is_assign: IsAssign) - -> (&'static str, Option) { + fn lookup_op_method(&self, + expr: &'gcx hir::Expr, + lhs_ty: Ty<'tcx>, + other_tys: &[Ty<'tcx>], + op: Op, + lhs_expr: &'a hir::Expr) + -> Result,()> + { let lang = &self.tcx.lang_items; - if let IsAssign::Yes = is_assign { + let (opname, trait_did) = if let Op::Binary(op, IsAssign::Yes) = op { match op.node { hir::BiAdd => ("add_assign", lang.add_assign_trait()), hir::BiSub => ("sub_assign", lang.sub_assign_trait()), @@ -355,7 +349,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { op.node.as_str()) } } - } else { + } else if let Op::Binary(op, IsAssign::No) = op { match op.node { hir::BiAdd => ("add", lang.add_trait()), hir::BiSub => ("sub", lang.sub_trait()), @@ -377,18 +371,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { span_bug!(op.span, "&& and || are not overloadable") } } - } - } + } else if let Op::Unary(hir::UnNot) = op { + ("not", lang.not_trait()) + } else if let Op::Unary(hir::UnNeg) = op { + ("neg", lang.neg_trait()) + } else { + bug!("lookup_op_method: op not supported: {:?}", op) + }; - fn lookup_op_method(&self, - expr: &'gcx hir::Expr, - lhs_ty: Ty<'tcx>, - other_tys: &[Ty<'tcx>], - opname: ast::Name, - trait_did: Option, - lhs_expr: &'a hir::Expr) - -> Result,()> - { debug!("lookup_op_method(expr={:?}, lhs_ty={:?}, opname={:?}, \ trait_did={:?}, lhs_expr={:?})", expr, @@ -397,28 +387,30 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { trait_did, lhs_expr); - let method = match trait_did { - Some(trait_did) => { - self.lookup_method_in_trait_adjusted(expr.span, - opname, - trait_did, - lhs_ty, - Some(other_tys)) - } - None => None - }; + let method = trait_did.and_then(|trait_did| { + let opname = Symbol::intern(opname); + self.lookup_method_in_trait(expr.span, opname, trait_did, lhs_ty, Some(other_tys)) + }); match method { Some(ok) => { - let (autoref, method) = self.register_infer_ok_obligations(ok); + let method = self.register_infer_ok_obligations(ok); self.select_obligations_where_possible(); - self.apply_adjustment(lhs_expr.id, Adjustment { - kind: Adjust::Deref(vec![]), - autoref, - unsize: false, - target: method.sig.inputs()[0] - }); + let (lhs_by_ref, _rhs_by_ref) = match op { + Op::Binary(_, IsAssign::Yes) => (true, false), + Op::Binary(op, _) if !op.node.is_by_value() => (true, true), + Op::Binary(..) | Op::Unary(_) => (false, false), + }; + if lhs_by_ref { + if let ty::TyRef(region, mt) = method.sig.inputs()[0].sty { + let autoref = Adjustment { + kind: Adjust::Borrow(AutoBorrow::Ref(region, mt.mutbl)), + target: method.sig.inputs()[0] + }; + self.apply_adjustments(lhs_expr, vec![autoref]); + } + } self.write_method_call(expr.id, method); Ok(method.sig.output()) @@ -493,6 +485,12 @@ enum IsAssign { Yes, } +#[derive(Clone, Copy, Debug)] +enum Op { + Binary(hir::BinOp, IsAssign), + Unary(hir::UnOp), +} + /// Returns true if this is a built-in arithmetic operation (e.g. u32 /// + u32, i16x4 == i16x4) and false if these types would have to be /// overloaded to be legal. There are two reasons that we distinguish diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 119ae748f85cd..e1905c9310649 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -542,61 +542,10 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> { } // Check any autoderefs or autorefs that appear. - let adjustment = self.tables.borrow().adjustments.get(&expr.id).map(|a| a.clone()); - if let Some(adjustment) = adjustment { - debug!("adjustment={:?}", adjustment); - match adjustment.kind { - adjustment::Adjust::Deref(ref autoderefs) => { - let cmt = ignore_err!(self.constrain_autoderefs(expr, autoderefs)); - if let Some(ref autoref) = adjustment.autoref { - self.link_autoref(expr, cmt, autoref); - - // Require that the resulting region encompasses - // the current node. - // - // FIXME(#6268) remove to support nested method calls - self.type_of_node_must_outlive(infer::AutoBorrow(expr.span), - expr.id, expr_region); - } - } - /* - adjustment::AutoObject(_, ref bounds, ..) => { - // Determine if we are casting `expr` to a trait - // instance. If so, we have to be sure that the type - // of the source obeys the new region bound. - let source_ty = self.resolve_node_type(expr.id); - self.type_must_outlive(infer::RelateObjectBound(expr.span), - source_ty, bounds.region_bound); - } - */ - _ => { - assert!(adjustment.autoref.is_none()); - } - } - - // If necessary, constrain destructors in the unadjusted form of this - // expression. - let cmt_result = { - let mc = mc::MemCategorizationContext::new(self, &self.region_maps); - mc.cat_expr_unadjusted(expr) - }; - match cmt_result { - Ok(head_cmt) => { - self.check_safety_of_rvalue_destructor_if_necessary(head_cmt, - expr.span); - } - Err(..) => { - self.tcx.sess.delay_span_bug(expr.span, "cat_expr_unadjusted Errd"); - } - } - } + let cmt_result = self.constrain_adjustments(expr); // If necessary, constrain destructors in this expression. This will be // the adjusted form if there is an adjustment. - let cmt_result = { - let mc = mc::MemCategorizationContext::new(self, &self.region_maps); - mc.cat_expr(expr) - }; match cmt_result { Ok(head_cmt) => { self.check_safety_of_rvalue_destructor_if_necessary(head_cmt, expr.span); @@ -904,26 +853,35 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { } } - /// Invoked on any auto-dereference that occurs. Checks that if this is a region pointer being + /// Invoked on any adjustments that occur. Checks that if this is a region pointer being /// dereferenced, the lifetime of the pointer includes the deref expr. - fn constrain_autoderefs(&mut self, - deref_expr: &hir::Expr, - autoderefs: &[Option>]) - -> mc::McResult> - { - debug!("constrain_autoderefs(deref_expr={:?}, autoderefs={:?})", - deref_expr, - autoderefs); + fn constrain_adjustments(&mut self, expr: &hir::Expr) -> mc::McResult> { + debug!("constrain_adjustments(expr={:?})", expr); let mut cmt = { let mc = mc::MemCategorizationContext::new(self, &self.region_maps); - mc.cat_expr_unadjusted(deref_expr)? + mc.cat_expr_unadjusted(expr)? }; - let r_deref_expr = self.tcx.node_scope_region(deref_expr.id); - for &overloaded in autoderefs { - if let Some(deref) = overloaded { - debug!("constrain_autoderefs: overloaded, {:?}", deref); + //NOTE(@jroesch): mixed RefCell borrow causes crash + let adjustments = self.tables.borrow().expr_adjustments(&expr).to_vec(); + if adjustments.is_empty() { + return Ok(cmt); + } + + debug!("constrain_adjustments: adjustments={:?}", adjustments); + + // If necessary, constrain destructors in the unadjusted form of this + // expression. + self.check_safety_of_rvalue_destructor_if_necessary(cmt.clone(), expr.span); + + let expr_region = self.tcx.node_scope_region(expr.id); + for adjustment in adjustments { + debug!("constrain_adjustments: adjustment={:?}, cmt={:?}", + adjustment, cmt); + + if let adjustment::Adjust::Deref(Some(deref)) = adjustment.kind { + debug!("constrain_adjustments: overloaded deref: {:?}", deref); // Treat overloaded autoderefs as if an AutoBorrow adjustment // was applied on the base type, as that is always the case. @@ -932,33 +890,39 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { mutbl: deref.mutbl, }); let output = self.tcx.mk_ref(deref.region, ty::TypeAndMut { - ty: deref.target, + ty: adjustment.target, mutbl: deref.mutbl, }); - debug!("constrain_autoderefs: self_cmt={:?}", cmt); - self.link_region(deref_expr.span, deref.region, + self.link_region(expr.span, deref.region, ty::BorrowKind::from_mutbl(deref.mutbl), cmt.clone()); // Specialized version of constrain_call. - self.type_must_outlive(infer::CallRcvr(deref_expr.span), - input, r_deref_expr); - self.type_must_outlive(infer::CallReturn(deref_expr.span), - output, r_deref_expr); + self.type_must_outlive(infer::CallRcvr(expr.span), + input, expr_region); + self.type_must_outlive(infer::CallReturn(expr.span), + output, expr_region); + } + + if let adjustment::Adjust::Borrow(ref autoref) = adjustment.kind { + self.link_autoref(expr, cmt.clone(), autoref); + + // Require that the resulting region encompasses + // the current node. + // + // FIXME(#6268) remove to support nested method calls + self.type_of_node_must_outlive(infer::AutoBorrow(expr.span), + expr.id, expr_region); } { let mc = mc::MemCategorizationContext::new(self, &self.region_maps); - if let Some(deref) = overloaded { - cmt = mc.cat_overloaded_autoderef(deref_expr, deref)?; - } else { - cmt = mc.cat_deref(deref_expr, cmt, false)?; - } + cmt = mc.cat_expr_adjusted(expr, cmt, &adjustment)?; } if let Categorization::Deref(_, mc::BorrowedPtr(_, r_ptr)) = cmt.cat { - self.mk_subregion_due_to_dereference(deref_expr.span, - r_deref_expr, r_ptr); + self.mk_subregion_due_to_dereference(expr.span, + expr_region, r_ptr); } } @@ -1029,7 +993,9 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { // is going to fail anyway, so just stop here and let typeck // report errors later on in the writeback phase. let ty0 = self.resolve_node_type(id); - let ty = self.tables.borrow().adjustments.get(&id).map_or(ty0, |adj| adj.target); + let ty = self.tables.borrow().adjustments.get(&id) + .and_then(|adj| adj.last()) + .map_or(ty0, |adj| adj.target); let ty = self.resolve_type(ty); debug!("constrain_regions_in_type_of_node(\ ty={}, ty0={}, id={}, minimum_lifetime={:?})", diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 699b5f330d457..baef48fe7d2cd 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -73,12 +73,14 @@ This API is completely unstable and subject to change. #![allow(non_camel_case_types)] +#![feature(advanced_slice_patterns)] #![feature(box_patterns)] #![feature(box_syntax)] #![feature(conservative_impl_trait)] #![feature(never_type)] #![feature(quote)] #![feature(rustc_diagnostic_macros)] +#![feature(slice_patterns)] #![cfg_attr(stage0, unstable(feature = "rustc_private", issue = "27812"))] #![cfg_attr(stage0, feature(rustc_private))] From 3ce443828be823cac2791d2b8392c33db9320677 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Sun, 28 May 2017 15:04:13 +0300 Subject: [PATCH 12/14] rustc: adjust the RHS of comparison operators instead of assuming autorefs. --- src/librustc/middle/expr_use_visitor.rs | 100 +++--------------- src/librustc_mir/hair/cx/expr.rs | 129 ++++-------------------- src/librustc_typeck/check/mod.rs | 11 +- src/librustc_typeck/check/op.rs | 102 ++++++++++--------- src/librustc_typeck/check/regionck.rs | 83 ++++----------- src/librustc_typeck/check/writeback.rs | 9 +- 6 files changed, 114 insertions(+), 320 deletions(-) diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 55c3049155f4d..bb56439a157fe 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -263,12 +263,6 @@ macro_rules! return_if_err { ) } -/// Whether the elements of an overloaded operation are passed by value or by reference -enum PassArgs { - ByValue, - ByRef, -} - impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { pub fn new(delegate: &'a mut (Delegate<'tcx>+'a), region_maps: &'a RegionMaps, @@ -382,9 +376,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { } hir::ExprUnary(hir::UnDeref, ref base) => { // *base - if !self.walk_overloaded_operator(expr, &base, Vec::new(), PassArgs::ByRef) { - self.select_from_expr(&base); - } + self.select_from_expr(&base); } hir::ExprField(ref base, _) => { // base.f @@ -396,13 +388,8 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { } hir::ExprIndex(ref lhs, ref rhs) => { // lhs[rhs] - if !self.walk_overloaded_operator(expr, - &lhs, - vec![&rhs], - PassArgs::ByValue) { - self.select_from_expr(&lhs); - self.consume_expr(&rhs); - } + self.select_from_expr(&lhs); + self.consume_expr(&rhs); } hir::ExprCall(ref callee, ref args) => { // callee(args) @@ -485,29 +472,13 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { self.walk_block(&blk); } - hir::ExprUnary(op, ref lhs) => { - let pass_args = if op.is_by_value() { - PassArgs::ByValue - } else { - PassArgs::ByRef - }; - - if !self.walk_overloaded_operator(expr, &lhs, Vec::new(), pass_args) { - self.consume_expr(&lhs); - } + hir::ExprUnary(_, ref lhs) => { + self.consume_expr(&lhs); } - hir::ExprBinary(op, ref lhs, ref rhs) => { - let pass_args = if op.node.is_by_value() { - PassArgs::ByValue - } else { - PassArgs::ByRef - }; - - if !self.walk_overloaded_operator(expr, &lhs, vec![&rhs], pass_args) { - self.consume_expr(&lhs); - self.consume_expr(&rhs); - } + hir::ExprBinary(_, ref lhs, ref rhs) => { + self.consume_expr(&lhs); + self.consume_expr(&rhs); } hir::ExprBlock(ref blk) => { @@ -529,14 +500,13 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { self.consume_expr(&base); } - hir::ExprAssignOp(op, ref lhs, ref rhs) => { - // NB All our assignment operations take the RHS by value - assert!(op.node.is_by_value()); - - if !self.walk_overloaded_operator(expr, lhs, vec![rhs], PassArgs::ByValue) { + hir::ExprAssignOp(_, ref lhs, ref rhs) => { + if self.mc.infcx.tables.borrow().is_method_call(expr) { + self.consume_expr(lhs); + } else { self.mutate_expr(expr, &lhs, MutateMode::WriteAndRead); - self.consume_expr(&rhs); } + self.consume_expr(&rhs); } hir::ExprRepeat(ref base, _) => { @@ -784,50 +754,6 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { } } - - // When this returns true, it means that the expression *is* a - // method-call (i.e. via the operator-overload). This true result - // also implies that walk_overloaded_operator already took care of - // recursively processing the input arguments, and thus the caller - // should not do so. - fn walk_overloaded_operator(&mut self, - expr: &hir::Expr, - receiver: &hir::Expr, - rhs: Vec<&hir::Expr>, - pass_args: PassArgs) - -> bool - { - if !self.mc.infcx.tables.borrow().is_method_call(expr) { - return false; - } - - match pass_args { - PassArgs::ByValue => { - self.consume_expr(receiver); - for &arg in &rhs { - self.consume_expr(arg); - } - - return true; - }, - PassArgs::ByRef => {}, - } - - self.walk_expr(receiver); - - // Arguments (but not receivers) to overloaded operator - // methods are implicitly autoref'd which sadly does not use - // adjustments, so we must hardcode the borrow here. - - let r = self.tcx().node_scope_region(expr.id); - let bk = ty::ImmBorrow; - - for &arg in &rhs { - self.borrow_expr(arg, r, bk, OverloadedOperator); - } - return true; - } - fn arm_move_mode(&mut self, discr_cmt: mc::cmt<'tcx>, arm: &hir::Arm) -> TrackMatchMode { let mut mode = Unknown; for pat in &arm.pats { diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 6d1509e7e24c7..2c3f51969267f 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -21,7 +21,6 @@ use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow}; use rustc::ty::cast::CastKind as TyCastKind; use rustc::ty::subst::Subst; use rustc::hir; -use syntax::ptr::P; impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { type Output = Expr<'tcx>; @@ -117,13 +116,7 @@ fn apply_adjustment<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, }, }; - overloaded_lvalue(cx, - hir_expr, - adjustment.target, - Some(call), - PassArgs::ByValue, - expr.to_ref(), - vec![]) + overloaded_lvalue(cx, hir_expr, adjustment.target, Some(call), vec![expr.to_ref()]) } Adjust::Borrow(AutoBorrow::Ref(r, m)) => { ExprKind::Borrow { @@ -281,17 +274,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, hir::ExprAssignOp(op, ref lhs, ref rhs) => { if cx.tables().is_method_call(expr) { - let pass_args = if op.node.is_by_value() { - PassArgs::ByValue - } else { - PassArgs::ByRef - }; - overloaded_operator(cx, - expr, - None, - pass_args, - lhs.to_ref(), - vec![rhs]) + overloaded_operator(cx, expr, vec![lhs.to_ref(), rhs.to_ref()]) } else { ExprKind::AssignOp { op: bin_op(op.node), @@ -305,17 +288,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, hir::ExprBinary(op, ref lhs, ref rhs) => { if cx.tables().is_method_call(expr) { - let pass_args = if op.node.is_by_value() { - PassArgs::ByValue - } else { - PassArgs::ByRef - }; - overloaded_operator(cx, - expr, - None, - pass_args, - lhs.to_ref(), - vec![rhs]) + overloaded_operator(cx, expr, vec![lhs.to_ref(), rhs.to_ref()]) } else { // FIXME overflow match (op.node, cx.constness) { @@ -365,13 +338,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, hir::ExprIndex(ref lhs, ref index) => { if cx.tables().is_method_call(expr) { - overloaded_lvalue(cx, - expr, - expr_ty, - None, - PassArgs::ByValue, - lhs.to_ref(), - vec![index]) + overloaded_lvalue(cx, expr, expr_ty, None, vec![lhs.to_ref(), index.to_ref()]) } else { ExprKind::Index { lhs: lhs.to_ref(), @@ -382,13 +349,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, hir::ExprUnary(hir::UnOp::UnDeref, ref arg) => { if cx.tables().is_method_call(expr) { - overloaded_lvalue(cx, - expr, - expr_ty, - None, - PassArgs::ByValue, - arg.to_ref(), - vec![]) + overloaded_lvalue(cx, expr, expr_ty, None, vec![arg.to_ref()]) } else { ExprKind::Deref { arg: arg.to_ref() } } @@ -396,12 +357,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, hir::ExprUnary(hir::UnOp::UnNot, ref arg) => { if cx.tables().is_method_call(expr) { - overloaded_operator(cx, - expr, - None, - PassArgs::ByValue, - arg.to_ref(), - vec![]) + overloaded_operator(cx, expr, vec![arg.to_ref()]) } else { ExprKind::Unary { op: UnOp::Not, @@ -412,12 +368,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, hir::ExprUnary(hir::UnOp::UnNeg, ref arg) => { if cx.tables().is_method_call(expr) { - overloaded_operator(cx, - expr, - None, - PassArgs::ByValue, - arg.to_ref(), - vec![]) + overloaded_operator(cx, expr, vec![arg.to_ref()]) } else { // FIXME runtime-overflow if let hir::ExprLit(_) = arg.node { @@ -873,61 +824,15 @@ fn bin_op(op: hir::BinOp_) -> BinOp { } } -enum PassArgs { - ByValue, - ByRef, -} - fn overloaded_operator<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, expr: &'tcx hir::Expr, - custom_callee: Option<(DefId, &'tcx Substs<'tcx>)>, - pass_args: PassArgs, - receiver: ExprRef<'tcx>, - args: Vec<&'tcx P>) + args: Vec>) -> ExprKind<'tcx> { - // the receiver has all the adjustments that are needed, so we can - // just push a reference to it - let mut argrefs = vec![receiver]; - - // the arguments, unfortunately, do not, so if this is a ByRef - // operator, we have to gin up the autorefs (but by value is easy) - match pass_args { - PassArgs::ByValue => argrefs.extend(args.iter().map(|arg| arg.to_ref())), - - PassArgs::ByRef => { - let region = cx.tcx.node_scope_region(expr.id); - let (temp_lifetime, was_shrunk) = - cx.region_maps.temporary_scope2(expr.id); - argrefs.extend(args.iter() - .map(|arg| { - let arg_ty = cx.tables().expr_ty_adjusted(arg); - let adjusted_ty = cx.tcx.mk_ref(region, - ty::TypeAndMut { - ty: arg_ty, - mutbl: hir::MutImmutable, - }); - Expr { - temp_lifetime: temp_lifetime, - temp_lifetime_was_shrunk: was_shrunk, - ty: adjusted_ty, - span: expr.span, - kind: ExprKind::Borrow { - region: region, - borrow_kind: BorrowKind::Shared, - arg: arg.to_ref(), - }, - } - .to_ref() - })) - } - } - - // now create the call itself - let fun = method_callee(cx, expr, custom_callee); + let fun = method_callee(cx, expr, None); ExprKind::Call { ty: fun.ty, fun: fun.to_ref(), - args: argrefs, + args, } } @@ -935,15 +840,13 @@ fn overloaded_lvalue<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, expr: &'tcx hir::Expr, lvalue_ty: Ty<'tcx>, custom_callee: Option<(DefId, &'tcx Substs<'tcx>)>, - pass_args: PassArgs, - receiver: ExprRef<'tcx>, - args: Vec<&'tcx P>) + args: Vec>) -> ExprKind<'tcx> { // For an overloaded *x or x[y] expression of type T, the method // call returns an &T and we must add the deref so that the types // line up (this is because `*x` and `x[y]` represent lvalues): - let recv_ty = match receiver { + let recv_ty = match args[0] { ExprRef::Hair(e) => cx.tables().expr_ty_adjusted(e), ExprRef::Mirror(ref e) => e.ty }; @@ -963,13 +866,17 @@ fn overloaded_lvalue<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, // construct the complete expression `foo()` for the overloaded call, // which will yield the &T type let (temp_lifetime, was_shrunk) = cx.region_maps.temporary_scope2(expr.id); - let ref_kind = overloaded_operator(cx, expr, custom_callee, pass_args, receiver, args); + let fun = method_callee(cx, expr, custom_callee); let ref_expr = Expr { temp_lifetime: temp_lifetime, temp_lifetime_was_shrunk: was_shrunk, ty: ref_ty, span: expr.span, - kind: ref_kind, + kind: ExprKind::Call { + ty: fun.ty, + fun: fun.to_ref(), + args, + }, }; // construct and return a deref wrapper `*foo()` diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 813e199f85a75..32c3f5c8a5edd 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3424,10 +3424,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { lvalue_pref); if !oprnd_t.references_error() { + oprnd_t = self.structurally_resolved_type(expr.span, oprnd_t); match unop { hir::UnDeref => { - oprnd_t = self.structurally_resolved_type(expr.span, oprnd_t); - if let Some(mt) = oprnd_t.builtin_deref(true, NoPreference) { oprnd_t = mt.ty; } else if let Some(ok) = self.try_overloaded_deref( @@ -3450,18 +3449,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } hir::UnNot => { - oprnd_t = self.structurally_resolved_type(oprnd.span, - oprnd_t); - let result = self.check_user_unop(expr, &oprnd, oprnd_t, unop); + let result = self.check_user_unop(expr, oprnd_t, unop); // If it's builtin, we can reuse the type, this helps inference. if !(oprnd_t.is_integral() || oprnd_t.sty == ty::TyBool) { oprnd_t = result; } } hir::UnNeg => { - oprnd_t = self.structurally_resolved_type(oprnd.span, - oprnd_t); - let result = self.check_user_unop(expr, &oprnd, oprnd_t, unop); + let result = self.check_user_unop(expr, oprnd_t, unop); // If it's builtin, we can reuse the type, this helps inference. if !(oprnd_t.is_integral() || oprnd_t.is_fp()) { oprnd_t = result; diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index cbb89355bf952..8e5b7a6546973 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -11,11 +11,13 @@ //! Code related to processing overloaded binary and unary operators. use super::FnCtxt; +use super::method::MethodCallee; use rustc::ty::{self, Ty, TypeFoldable, PreferMutLvalue, TypeVariants}; use rustc::ty::TypeVariants::{TyStr, TyRef}; use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow}; use rustc::infer::type_variable::TypeVariableOrigin; use errors; +use syntax_pos::Span; use syntax::symbol::Symbol; use rustc::hir; @@ -181,14 +183,41 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // particularly for things like `String + &String`. let rhs_ty_var = self.next_ty_var(TypeVariableOrigin::MiscVariable(rhs_expr.span)); - let return_ty = self.lookup_op_method(expr, lhs_ty, &[rhs_ty_var], - Op::Binary(op, is_assign), lhs_expr); + let result = self.lookup_op_method(lhs_ty, &[rhs_ty_var], Op::Binary(op, is_assign)); // see `NB` above let rhs_ty = self.check_expr_coercable_to_type(rhs_expr, rhs_ty_var); - let return_ty = match return_ty { - Ok(return_ty) => return_ty, + let return_ty = match result { + Ok(method) => { + let by_ref_binop = !op.node.is_by_value(); + if is_assign == IsAssign::Yes || by_ref_binop { + if let ty::TyRef(region, mt) = method.sig.inputs()[0].sty { + let autoref = Adjustment { + kind: Adjust::Borrow(AutoBorrow::Ref(region, mt.mutbl)), + target: method.sig.inputs()[0] + }; + self.apply_adjustments(lhs_expr, vec![autoref]); + } + } + if by_ref_binop { + if let ty::TyRef(region, mt) = method.sig.inputs()[1].sty { + let autoref = Adjustment { + kind: Adjust::Borrow(AutoBorrow::Ref(region, mt.mutbl)), + target: method.sig.inputs()[1] + }; + // HACK(eddyb) Bypass checks due to reborrows being in + // some cases applied on the RHS, on top of which we need + // to autoref, which is not allowed by apply_adjustments. + // self.apply_adjustments(rhs_expr, vec![autoref]); + self.tables.borrow_mut().adjustments.entry(rhs_expr.id) + .or_insert(vec![]).push(autoref); + } + } + self.write_method_call(expr.id, method); + + method.sig.output() + } Err(()) => { // error types are considered "builtin" if !lhs_ty.references_error() { @@ -210,8 +239,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let TypeVariants::TyRef(_, ref ty_mut) = lhs_ty.sty { if !self.infcx.type_moves_by_default(ty_mut.ty, lhs_expr.span) && - self.lookup_op_method(expr, ty_mut.ty, &[rhs_ty], - Op::Binary(op, is_assign), lhs_expr).is_ok() { + self.lookup_op_method(ty_mut.ty, &[rhs_ty], + Op::Binary(op, is_assign)).is_ok() { err.note( &format!( "this is a reference to a type that `{}` can be applied \ @@ -298,14 +327,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn check_user_unop(&self, ex: &'gcx hir::Expr, - operand_expr: &'gcx hir::Expr, operand_ty: Ty<'tcx>, op: hir::UnOp) -> Ty<'tcx> { assert!(op.is_by_value()); - match self.lookup_op_method(ex, operand_ty, &[], Op::Unary(op), operand_expr) { - Ok(t) => t, + match self.lookup_op_method(operand_ty, &[], Op::Unary(op, ex.span)) { + Ok(method) => { + self.write_method_call(ex.id, method); + method.sig.output() + } Err(()) => { let actual = self.resolve_type_vars_if_possible(&operand_ty); if !actual.references_error() { @@ -318,16 +349,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } - fn lookup_op_method(&self, - expr: &'gcx hir::Expr, - lhs_ty: Ty<'tcx>, - other_tys: &[Ty<'tcx>], - op: Op, - lhs_expr: &'a hir::Expr) - -> Result,()> + fn lookup_op_method(&self, lhs_ty: Ty<'tcx>, other_tys: &[Ty<'tcx>], op: Op) + -> Result, ()> { let lang = &self.tcx.lang_items; + let span = match op { + Op::Binary(op, _) => op.span, + Op::Unary(_, span) => span + }; let (opname, trait_did) = if let Op::Binary(op, IsAssign::Yes) = op { match op.node { hir::BiAdd => ("add_assign", lang.add_assign_trait()), @@ -344,7 +374,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { hir::BiGe | hir::BiGt | hir::BiEq | hir::BiNe | hir::BiAnd | hir::BiOr => { - span_bug!(op.span, + span_bug!(span, "impossible assignment operation: {}=", op.node.as_str()) } @@ -368,28 +398,26 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { hir::BiEq => ("eq", lang.eq_trait()), hir::BiNe => ("ne", lang.eq_trait()), hir::BiAnd | hir::BiOr => { - span_bug!(op.span, "&& and || are not overloadable") + span_bug!(span, "&& and || are not overloadable") } } - } else if let Op::Unary(hir::UnNot) = op { + } else if let Op::Unary(hir::UnNot, _) = op { ("not", lang.not_trait()) - } else if let Op::Unary(hir::UnNeg) = op { + } else if let Op::Unary(hir::UnNeg, _) = op { ("neg", lang.neg_trait()) } else { bug!("lookup_op_method: op not supported: {:?}", op) }; - debug!("lookup_op_method(expr={:?}, lhs_ty={:?}, opname={:?}, \ - trait_did={:?}, lhs_expr={:?})", - expr, + debug!("lookup_op_method(lhs_ty={:?}, op={:?}, opname={:?}, trait_did={:?})", lhs_ty, + op, opname, - trait_did, - lhs_expr); + trait_did); let method = trait_did.and_then(|trait_did| { let opname = Symbol::intern(opname); - self.lookup_method_in_trait(expr.span, opname, trait_did, lhs_ty, Some(other_tys)) + self.lookup_method_in_trait(span, opname, trait_did, lhs_ty, Some(other_tys)) }); match method { @@ -397,23 +425,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let method = self.register_infer_ok_obligations(ok); self.select_obligations_where_possible(); - let (lhs_by_ref, _rhs_by_ref) = match op { - Op::Binary(_, IsAssign::Yes) => (true, false), - Op::Binary(op, _) if !op.node.is_by_value() => (true, true), - Op::Binary(..) | Op::Unary(_) => (false, false), - }; - if lhs_by_ref { - if let ty::TyRef(region, mt) = method.sig.inputs()[0].sty { - let autoref = Adjustment { - kind: Adjust::Borrow(AutoBorrow::Ref(region, mt.mutbl)), - target: method.sig.inputs()[0] - }; - self.apply_adjustments(lhs_expr, vec![autoref]); - } - } - self.write_method_call(expr.id, method); - - Ok(method.sig.output()) + Ok(method) } None => { Err(()) @@ -479,7 +491,7 @@ impl BinOpCategory { } /// Whether the binary operation is an assignment (`a += b`), or not (`a + b`) -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, PartialEq)] enum IsAssign { No, Yes, @@ -488,7 +500,7 @@ enum IsAssign { #[derive(Clone, Copy, Debug)] enum Op { Binary(hir::BinOp, IsAssign), - Unary(hir::UnOp), + Unary(hir::UnOp, Span), } /// Returns true if this is a built-in arithmetic operation (e.g. u32 diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index e1905c9310649..33fbc006e4e1f 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -566,49 +566,38 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> { hir::ExprCall(ref callee, ref args) => { if is_method_call { - self.constrain_call(expr, Some(&callee), - args.iter().map(|e| &*e), false); + self.constrain_call(expr, Some(&callee), args.iter().map(|e| &*e)); } else { self.constrain_callee(callee.id, expr, &callee); - self.constrain_call(expr, None, - args.iter().map(|e| &*e), false); + self.constrain_call(expr, None, args.iter().map(|e| &*e)); } intravisit::walk_expr(self, expr); } hir::ExprMethodCall(.., ref args) => { - self.constrain_call(expr, Some(&args[0]), - args[1..].iter().map(|e| &*e), false); + self.constrain_call(expr, Some(&args[0]), args[1..].iter().map(|e| &*e)); intravisit::walk_expr(self, expr); } hir::ExprAssignOp(_, ref lhs, ref rhs) => { if is_method_call { - self.constrain_call(expr, Some(&lhs), - Some(&**rhs).into_iter(), false); + self.constrain_call(expr, Some(&lhs), Some(&**rhs).into_iter()); } intravisit::walk_expr(self, expr); } hir::ExprIndex(ref lhs, ref rhs) if is_method_call => { - self.constrain_call(expr, Some(&lhs), - Some(&**rhs).into_iter(), true); + self.constrain_call(expr, Some(&lhs), Some(&**rhs).into_iter()); intravisit::walk_expr(self, expr); }, - hir::ExprBinary(op, ref lhs, ref rhs) if is_method_call => { - let implicitly_ref_args = !op.node.is_by_value(); - - // As `expr_method_call`, but the call is via an - // overloaded op. Note that we (sadly) currently use an - // implicit "by ref" sort of passing style here. This - // should be converted to an adjustment! - self.constrain_call(expr, Some(&lhs), - Some(&**rhs).into_iter(), implicitly_ref_args); + hir::ExprBinary(_, ref lhs, ref rhs) if is_method_call => { + // As `ExprMethodCall`, but the call is via an overloaded op. + self.constrain_call(expr, Some(&lhs), Some(&**rhs).into_iter()); intravisit::walk_expr(self, expr); } @@ -625,21 +614,10 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> { intravisit::walk_expr(self, expr); } - hir::ExprUnary(op, ref lhs) if is_method_call => { - let implicitly_ref_args = !op.is_by_value(); - - // As above. - self.constrain_call(expr, Some(&lhs), - None::.iter(), implicitly_ref_args); - - intravisit::walk_expr(self, expr); - } - hir::ExprUnary(hir::UnDeref, ref base) => { // For *a, the lifetime of a must enclose the deref - if self.tables.borrow().is_method_call(expr) { - self.constrain_call(expr, Some(base), - None::.iter(), true); + if is_method_call { + self.constrain_call(expr, Some(base), None::.iter()); } // For overloaded derefs, base_ty is the input to `Deref::deref`, // but it's a reference type uing the same region as the output. @@ -651,6 +629,13 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> { intravisit::walk_expr(self, expr); } + hir::ExprUnary(_, ref lhs) if is_method_call => { + // As above. + self.constrain_call(expr, Some(&lhs), None::.iter()); + + intravisit::walk_expr(self, expr); + } + hir::ExprIndex(ref vec_expr, _) => { // For a[b], the lifetime of a must enclose the deref let vec_type = self.resolve_expr_type_adjusted(&vec_expr); @@ -802,19 +787,15 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { fn constrain_call<'b, I: Iterator>(&mut self, call_expr: &hir::Expr, receiver: Option<&hir::Expr>, - arg_exprs: I, - implicitly_ref_args: bool) { + arg_exprs: I) { //! Invoked on every call site (i.e., normal calls, method calls, //! and overloaded operators). Constrains the regions which appear //! in the type of the function. Also constrains the regions that //! appear in the arguments appropriately. - debug!("constrain_call(call_expr={:?}, \ - receiver={:?}, \ - implicitly_ref_args={})", + debug!("constrain_call(call_expr={:?}, receiver={:?})", call_expr, - receiver, - implicitly_ref_args); + receiver); // `callee_region` is the scope representing the time in which the // call occurs. @@ -832,14 +813,6 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { // valid for at least the lifetime of the function: self.type_of_node_must_outlive(infer::CallArg(arg_expr.span), arg_expr.id, callee_region); - - // unfortunately, there are two means of taking implicit - // references, and we need to propagate constraints as a - // result. modes are going away and the "DerefArgs" code - // should be ported to use adjustments - if implicitly_ref_args { - self.link_by_ref(arg_expr, callee_scope); - } } // as loop above, but for receiver @@ -847,9 +820,6 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { debug!("receiver: {:?}", r); self.type_of_node_must_outlive(infer::CallRcvr(r.span), r.id, callee_region); - if implicitly_ref_args { - self.link_by_ref(&r, callee_scope); - } } } @@ -1111,19 +1081,6 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { } } - /// Computes the guarantor for cases where the `expr` is being passed by implicit reference and - /// must outlive `callee_scope`. - fn link_by_ref(&self, - expr: &hir::Expr, - callee_scope: CodeExtent) { - debug!("link_by_ref(expr={:?}, callee_scope={:?})", - expr, callee_scope); - let mc = mc::MemCategorizationContext::new(self, &self.region_maps); - let expr_cmt = ignore_err!(mc.cat_expr(expr)); - let borrow_region = self.tcx.mk_region(ty::ReScope(callee_scope)); - self.link_region(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 some reference (`&T`, `&str`, etc). fn link_region_from_node_type(&self, diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 0b93db5498099..012fde16d875e 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -123,18 +123,15 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { tables.type_dependent_defs.remove(&e.id); tables.node_substs.remove(&e.id); - // weird but true: the by-ref binops put an - // adjustment on the lhs but not the rhs; the - // adjustment for rhs is kind of baked into the - // system. match e.node { hir::ExprBinary(..) => { if !op.node.is_by_value() { - tables.adjustments.remove(&lhs.id); + tables.adjustments.get_mut(&lhs.id).map(|a| a.pop()); + tables.adjustments.get_mut(&rhs.id).map(|a| a.pop()); } }, hir::ExprAssignOp(..) => { - tables.adjustments.remove(&lhs.id); + tables.adjustments.get_mut(&lhs.id).map(|a| a.pop()); }, _ => {}, } From 58632f3c1ce2a6a9ff3d92e12d912a073b28414d Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Sun, 28 May 2017 18:24:53 +0300 Subject: [PATCH 13/14] tests: fix fallout from empowering unused_allocation in comparisons. --- src/libcollections/tests/binary_heap.rs | 12 ++++++------ src/libstd/sync/mpsc/mod.rs | 20 ++++++++++---------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/libcollections/tests/binary_heap.rs b/src/libcollections/tests/binary_heap.rs index af18cddaddb01..06d585f8ea82f 100644 --- a/src/libcollections/tests/binary_heap.rs +++ b/src/libcollections/tests/binary_heap.rs @@ -134,22 +134,22 @@ fn test_push() { fn test_push_unique() { let mut heap = BinaryHeap::>::from(vec![box 2, box 4, box 9]); assert_eq!(heap.len(), 3); - assert!(*heap.peek().unwrap() == box 9); + assert!(**heap.peek().unwrap() == 9); heap.push(box 11); assert_eq!(heap.len(), 4); - assert!(*heap.peek().unwrap() == box 11); + assert!(**heap.peek().unwrap() == 11); heap.push(box 5); assert_eq!(heap.len(), 5); - assert!(*heap.peek().unwrap() == box 11); + assert!(**heap.peek().unwrap() == 11); heap.push(box 27); assert_eq!(heap.len(), 6); - assert!(*heap.peek().unwrap() == box 27); + assert!(**heap.peek().unwrap() == 27); heap.push(box 3); assert_eq!(heap.len(), 7); - assert!(*heap.peek().unwrap() == box 27); + assert!(**heap.peek().unwrap() == 27); heap.push(box 103); assert_eq!(heap.len(), 8); - assert!(*heap.peek().unwrap() == box 103); + assert!(**heap.peek().unwrap() == 103); } fn check_to_vec(mut data: Vec) { diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs index 69507cada2b4e..3d472adc1fba5 100644 --- a/src/libstd/sync/mpsc/mod.rs +++ b/src/libstd/sync/mpsc/mod.rs @@ -1924,7 +1924,7 @@ mod tests { fn oneshot_single_thread_send_then_recv() { let (tx, rx) = channel::>(); tx.send(box 10).unwrap(); - assert!(rx.recv().unwrap() == box 10); + assert!(*rx.recv().unwrap() == 10); } #[test] @@ -1981,7 +1981,7 @@ mod tests { fn oneshot_multi_task_recv_then_send() { let (tx, rx) = channel::>(); let _t = thread::spawn(move|| { - assert!(rx.recv().unwrap() == box 10); + assert!(*rx.recv().unwrap() == 10); }); tx.send(box 10).unwrap(); @@ -1994,7 +1994,7 @@ mod tests { drop(tx); }); let res = thread::spawn(move|| { - assert!(rx.recv().unwrap() == box 10); + assert!(*rx.recv().unwrap() == 10); }).join(); assert!(res.is_err()); } @@ -2048,7 +2048,7 @@ mod tests { let _t = thread::spawn(move|| { tx.send(box 10).unwrap(); }); - assert!(rx.recv().unwrap() == box 10); + assert!(*rx.recv().unwrap() == 10); } } @@ -2073,7 +2073,7 @@ mod tests { if i == 10 { return } thread::spawn(move|| { - assert!(rx.recv().unwrap() == box i); + assert!(*rx.recv().unwrap() == i); recv(rx, i + 1); }); } @@ -2610,7 +2610,7 @@ mod sync_tests { fn oneshot_single_thread_send_then_recv() { let (tx, rx) = sync_channel::>(1); tx.send(box 10).unwrap(); - assert!(rx.recv().unwrap() == box 10); + assert!(*rx.recv().unwrap() == 10); } #[test] @@ -2682,7 +2682,7 @@ mod sync_tests { fn oneshot_multi_task_recv_then_send() { let (tx, rx) = sync_channel::>(0); let _t = thread::spawn(move|| { - assert!(rx.recv().unwrap() == box 10); + assert!(*rx.recv().unwrap() == 10); }); tx.send(box 10).unwrap(); @@ -2695,7 +2695,7 @@ mod sync_tests { drop(tx); }); let res = thread::spawn(move|| { - assert!(rx.recv().unwrap() == box 10); + assert!(*rx.recv().unwrap() == 10); }).join(); assert!(res.is_err()); } @@ -2749,7 +2749,7 @@ mod sync_tests { let _t = thread::spawn(move|| { tx.send(box 10).unwrap(); }); - assert!(rx.recv().unwrap() == box 10); + assert!(*rx.recv().unwrap() == 10); } } @@ -2774,7 +2774,7 @@ mod sync_tests { if i == 10 { return } thread::spawn(move|| { - assert!(rx.recv().unwrap() == box i); + assert!(*rx.recv().unwrap() == i); recv(rx, i + 1); }); } From 5fb37beecdb7827aada42a2ab4e7e0228d02c13a Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Mon, 29 May 2017 14:55:54 +0300 Subject: [PATCH 14/14] tests: fix fallout from changing the span of binop errors. --- src/test/ui/impl-trait/equality.stderr | 4 +-- src/test/ui/mismatched_types/binops.stderr | 28 +++++++++---------- src/test/ui/span/multiline-span-simple.stderr | 11 ++------ 3 files changed, 19 insertions(+), 24 deletions(-) diff --git a/src/test/ui/impl-trait/equality.stderr b/src/test/ui/impl-trait/equality.stderr index a08e77a2151e2..2206234b77744 100644 --- a/src/test/ui/impl-trait/equality.stderr +++ b/src/test/ui/impl-trait/equality.stderr @@ -8,10 +8,10 @@ error[E0308]: mismatched types found type `u32` error[E0277]: the trait bound `u32: std::ops::Add` is not satisfied - --> $DIR/equality.rs:34:9 + --> $DIR/equality.rs:34:11 | 34 | n + sum_to(n - 1) - | ^^^^^^^^^^^^^^^^^ no implementation for `u32 + impl Foo` + | ^ no implementation for `u32 + impl Foo` | = help: the trait `std::ops::Add` is not implemented for `u32` diff --git a/src/test/ui/mismatched_types/binops.stderr b/src/test/ui/mismatched_types/binops.stderr index d97c78137089e..1faf72cd760b7 100644 --- a/src/test/ui/mismatched_types/binops.stderr +++ b/src/test/ui/mismatched_types/binops.stderr @@ -1,56 +1,56 @@ error[E0277]: the trait bound `{integer}: std::ops::Add>` is not satisfied - --> $DIR/binops.rs:12:5 + --> $DIR/binops.rs:12:7 | 12 | 1 + Some(1); - | ^^^^^^^^^^^ no implementation for `{integer} + std::option::Option<{integer}>` + | ^ no implementation for `{integer} + std::option::Option<{integer}>` | = help: the trait `std::ops::Add>` is not implemented for `{integer}` error[E0277]: the trait bound `usize: std::ops::Sub>` is not satisfied - --> $DIR/binops.rs:13:5 + --> $DIR/binops.rs:13:16 | 13 | 2 as usize - Some(1); - | ^^^^^^^^^^^^^^^^^^^^ no implementation for `usize - std::option::Option<{integer}>` + | ^ no implementation for `usize - std::option::Option<{integer}>` | = help: the trait `std::ops::Sub>` is not implemented for `usize` error[E0277]: the trait bound `{integer}: std::ops::Mul<()>` is not satisfied - --> $DIR/binops.rs:14:5 + --> $DIR/binops.rs:14:7 | 14 | 3 * (); - | ^^^^^^ no implementation for `{integer} * ()` + | ^ no implementation for `{integer} * ()` | = help: the trait `std::ops::Mul<()>` is not implemented for `{integer}` error[E0277]: the trait bound `{integer}: std::ops::Div<&str>` is not satisfied - --> $DIR/binops.rs:15:5 + --> $DIR/binops.rs:15:7 | 15 | 4 / ""; - | ^^^^^^ no implementation for `{integer} / &str` + | ^ no implementation for `{integer} / &str` | = help: the trait `std::ops::Div<&str>` is not implemented for `{integer}` error[E0277]: the trait bound `{integer}: std::cmp::PartialEq` is not satisfied - --> $DIR/binops.rs:16:5 + --> $DIR/binops.rs:16:7 | 16 | 5 < String::new(); - | ^^^^^^^^^^^^^^^^^ can't compare `{integer}` with `std::string::String` + | ^ can't compare `{integer}` with `std::string::String` | = help: the trait `std::cmp::PartialEq` is not implemented for `{integer}` error[E0277]: the trait bound `{integer}: std::cmp::PartialOrd` is not satisfied - --> $DIR/binops.rs:16:5 + --> $DIR/binops.rs:16:7 | 16 | 5 < String::new(); - | ^^^^^^^^^^^^^^^^^ can't compare `{integer}` with `std::string::String` + | ^ can't compare `{integer}` with `std::string::String` | = help: the trait `std::cmp::PartialOrd` is not implemented for `{integer}` error[E0277]: the trait bound `{integer}: std::cmp::PartialEq>` is not satisfied - --> $DIR/binops.rs:17:5 + --> $DIR/binops.rs:17:7 | 17 | 6 == Ok(1); - | ^^^^^^^^^^ can't compare `{integer}` with `std::result::Result<{integer}, _>` + | ^^ can't compare `{integer}` with `std::result::Result<{integer}, _>` | = help: the trait `std::cmp::PartialEq>` is not implemented for `{integer}` diff --git a/src/test/ui/span/multiline-span-simple.stderr b/src/test/ui/span/multiline-span-simple.stderr index 057f8fe6ee274..0224cef8da123 100644 --- a/src/test/ui/span/multiline-span-simple.stderr +++ b/src/test/ui/span/multiline-span-simple.stderr @@ -1,13 +1,8 @@ error[E0277]: the trait bound `u32: std::ops::Add<()>` is not satisfied - --> $DIR/multiline-span-simple.rs:23:9 + --> $DIR/multiline-span-simple.rs:23:18 | -23 | foo(1 as u32 + - | _________^ -24 | | -25 | | bar(x, -26 | | -27 | | y), - | |______________^ no implementation for `u32 + ()` +23 | foo(1 as u32 + + | ^ no implementation for `u32 + ()` | = help: the trait `std::ops::Add<()>` is not implemented for `u32`