From a65ced5d161d31e7e5b097b36bff0f51ec0843bc Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Fri, 19 May 2017 12:46:34 +0300 Subject: [PATCH] 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 2246621f83c..affc84382a5 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 e84265cb60f..c9593e54a86 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 73598d0bb1a..45afc17f339 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 fd8ca332a64..6a74af6eb8a 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 aa729c75796..cc65777bfce 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 722ec6424fe..0fe8865f4a2 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 baa18307510..3d98c2a23dc 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 f7c3bb36da7..cceb4a7b3cc 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 0b2cb1b93f9..2b5bbe0e8a5 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 1b364596a23..0a31905c792 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 6428146525c..eee1f1a9712 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 9b609cac2fc..5cda50b428b 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 {