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); }