From 194fe695e3af6f03953cbb4ca66f159993f6214d Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Sat, 27 May 2017 10:29:24 +0300 Subject: [PATCH] rustc: decompose Adjustment into a vector of adjustment steps. --- src/librustc/ich/impls_ty.rs | 14 +- src/librustc/middle/expr_use_visitor.rs | 98 ++----- src/librustc/middle/mem_categorization.rs | 103 ++++---- src/librustc/ty/adjustment.rs | 101 ++------ 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 | 24 +- src/librustc_typeck/check/autoderef.rs | 24 +- src/librustc_typeck/check/callee.rs | 73 +++--- src/librustc_typeck/check/coercion.rs | 171 ++++++------ src/librustc_typeck/check/method/confirm.rs | 131 ++++++---- src/librustc_typeck/check/method/mod.rs | 52 ++-- src/librustc_typeck/check/mod.rs | 134 +++++----- src/librustc_typeck/check/op.rs | 98 ++++--- src/librustc_typeck/check/regionck.rs | 128 ++++----- src/librustc_typeck/lib.rs | 2 + 19 files changed, 677 insertions(+), 851 deletions(-) diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index f0fdb94b81b..899e994302f 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 9120990777d..55c3049155f 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; + self.delegate_consume(expr.id, expr.span, cmt.clone()); } - adjustment::Adjust::Deref(ref autoderefs) => { - cmt = return_if_err!(self.walk_autoderefs(expr, cmt, autoderefs)); + + 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); + } + + adjustment::Adjust::Borrow(ref autoref) => { + self.walk_autoref(expr, cmt.clone(), autoref); } } - - 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); - } + cmt = return_if_err!(self.mc.cat_expr_adjusted(expr, cmt, &adjustment)); } } - /// 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)?; - } - } - 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 707b52a1a22..53d8eecde54 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) + } + } + } + + helper(self, expr, self.infcx.tables.borrow().expr_adjustments(expr)) + } + + 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) } - 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); - } - - 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)) - } - } + 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 e2e017e9f51..62d137475f9 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(), + /// Take the address and produce either a `&` or `*` pointer. + Borrow(AutoBorrow<'tcx>), - Adjust::Deref(ref autoderefs) => autoderefs.is_empty(), - - Adjust::ReifyFnPointer | - Adjust::UnsafeFnPointer | - Adjust::ClosureFnPointer | - Adjust::MutToConstPointer => false, - } - } + /// 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 f0cee2fe2b1..c6fb2a5871b 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 cd34ebc7650..31412ad1ab2 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 e4a8a1267f0..12bfb1e02cf 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 4db27647d42..0c82679c307 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 dbf35971fa3..6d1509e7e24 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 e7aa74494f9..fecde3a636c 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) => {} + 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 => {} - Some(&Adjust::Deref(ref autoderefs)) => { - if autoderefs.iter().any(|overloaded| overloaded.is_some()) { - v.promotable = false; + 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 36671521474..92044737df1 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 579bcda8dc6..d5ee66a2f0a 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 dc373610814..a962cdb8f72 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>) -> Vec> { + move |target| vec![Adjustment { kind, 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>(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()); - - debug!("coerce_borrowed_pointer: succeeded ty={:?} autoderefs={:?} autoref={:?}", - ty, - autoderefs, - autoref); - - success(Adjustment { - kind: Adjust::Deref(autoderefs), - autoref, - unsize: false, + adjustments.push(Adjustment { + kind: Adjust::Borrow(AutoBorrow::Ref(r_borrow, mt_b.mutbl)), target: ty - }, obligations) + }); + + debug!("coerce_borrowed_pointer: succeeded ty={:?} adjustments={:?}", + ty, + adjustments); + + 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 bdbc7f677e4..34e8d6b95a9 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); + 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; + } - *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?"); + // 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 688def4356c..b0ac61d2cc3 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 e6d43f00403..813e199f85a 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_adjustments(&self, expr: &hir::Expr, adj: Vec>) { + debug!("apply_adjustments(expr={:?}, adj={:?})", expr, adj); - pub fn apply_adjustment(&self, node_id: ast::NodeId, adj: Adjustment<'tcx>) { - debug!("apply_adjustment(node_id={}, adj={:?})", node_id, 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 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 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 8d442aae70e..cbb89355bf9 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 119ae748f85..e1905c93106 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 699b5f330d4..baef48fe7d2 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))]