]> git.lizzy.rs Git - rust.git/commitdiff
Refactor usage of Needs in typeck
authorGary Guo <gary@garyguo.net>
Mon, 15 Jun 2020 20:59:09 +0000 (21:59 +0100)
committerGary Guo <gary@garyguo.net>
Mon, 15 Jun 2020 21:09:12 +0000 (22:09 +0100)
src/librustc_typeck/check/autoderef.rs
src/librustc_typeck/check/callee.rs
src/librustc_typeck/check/coercion.rs
src/librustc_typeck/check/expr.rs
src/librustc_typeck/check/method/confirm.rs
src/librustc_typeck/check/mod.rs
src/librustc_typeck/check/op.rs
src/librustc_typeck/check/place_op.rs [new file with mode: 0644]
src/librustc_typeck/check/reconciliation.rs [deleted file]

index 73d4e2b78206d98300bce537efa8f31aebf2df0b..2570025959cb4f7320010f63837a7444209bd402 100644 (file)
@@ -1,5 +1,5 @@
 use super::method::MethodCallee;
-use super::{FnCtxt, Needs, PlaceOp};
+use super::{FnCtxt, PlaceOp};
 
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
@@ -170,14 +170,13 @@ pub fn step_count(&self) -> usize {
     }
 
     /// Returns the adjustment steps.
-    pub fn adjust_steps(&self, fcx: &FnCtxt<'a, 'tcx>, needs: Needs) -> Vec<Adjustment<'tcx>> {
-        fcx.register_infer_ok_obligations(self.adjust_steps_as_infer_ok(fcx, needs))
+    pub fn adjust_steps(&self, fcx: &FnCtxt<'a, 'tcx>) -> Vec<Adjustment<'tcx>> {
+        fcx.register_infer_ok_obligations(self.adjust_steps_as_infer_ok(fcx))
     }
 
     pub fn adjust_steps_as_infer_ok(
         &self,
         fcx: &FnCtxt<'a, 'tcx>,
-        needs: Needs,
     ) -> InferOk<'tcx, Vec<Adjustment<'tcx>>> {
         let mut obligations = vec![];
         let targets = self.steps.iter().skip(1).map(|&(ty, _)| ty).chain(iter::once(self.cur_ty));
@@ -186,7 +185,7 @@ pub fn adjust_steps_as_infer_ok(
             .iter()
             .map(|&(source, kind)| {
                 if let AutoderefKind::Overloaded = kind {
-                    fcx.try_overloaded_deref(self.span, source, needs).and_then(
+                    fcx.try_overloaded_deref(self.span, source).and_then(
                         |InferOk { value: method, obligations: o }| {
                             obligations.extend(o);
                             if let ty::Ref(region, _, mutbl) = method.sig.output().kind {
@@ -266,8 +265,7 @@ pub fn try_overloaded_deref(
         &self,
         span: Span,
         base_ty: Ty<'tcx>,
-        needs: Needs,
     ) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
-        self.try_overloaded_place_op(span, base_ty, &[], needs, PlaceOp::Deref)
+        self.try_overloaded_place_op(span, base_ty, &[], PlaceOp::Deref)
     }
 }
index f86b7f07b7fc48b46293dfe4e9877c0c1b5985fb..916fe9afc876a76ac75192e6d212345c78464289 100644 (file)
@@ -1,6 +1,6 @@
 use super::autoderef::Autoderef;
 use super::method::MethodCallee;
-use super::{Expectation, FnCtxt, Needs, TupleArgumentsFlag};
+use super::{Expectation, FnCtxt, TupleArgumentsFlag};
 use crate::type_error_struct;
 
 use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
@@ -115,7 +115,7 @@ fn try_overloaded_call_step(
         // If the callee is a bare function or a closure, then we're all set.
         match adjusted_ty.kind {
             ty::FnDef(..) | ty::FnPtr(_) => {
-                let adjustments = autoderef.adjust_steps(self, Needs::None);
+                let adjustments = autoderef.adjust_steps(self);
                 self.apply_adjustments(callee_expr, adjustments);
                 return Some(CallStep::Builtin(adjusted_ty));
             }
@@ -135,7 +135,7 @@ fn try_overloaded_call_step(
                             &closure_sig,
                         )
                         .0;
-                    let adjustments = autoderef.adjust_steps(self, Needs::None);
+                    let adjustments = autoderef.adjust_steps(self);
                     self.record_deferred_call_resolution(
                         def_id,
                         DeferredCallResolution {
@@ -176,7 +176,7 @@ fn try_overloaded_call_step(
         self.try_overloaded_call_traits(call_expr, adjusted_ty, Some(arg_exprs))
             .or_else(|| self.try_overloaded_call_traits(call_expr, adjusted_ty, None))
             .map(|(autoref, method)| {
-                let mut adjustments = autoderef.adjust_steps(self, Needs::None);
+                let mut adjustments = autoderef.adjust_steps(self);
                 adjustments.extend(autoref);
                 self.apply_adjustments(callee_expr, adjustments);
                 CallStep::Overloaded(method)
index 96c0d98ab0618d7d19f71a9bc69277646d9f74cc..085bb384e124ba69abf9656ee43391acf7ef5eb6 100644 (file)
@@ -51,7 +51,7 @@
 //! we may want to adjust precisely when coercions occur.
 
 use crate::astconv::AstConv;
-use crate::check::{FnCtxt, Needs};
+use crate::check::FnCtxt;
 use rustc_errors::{struct_span_err, DiagnosticBuilder};
 use rustc_hir as hir;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
@@ -421,9 +421,8 @@ fn coerce_borrowed_pointer(
             return success(vec![], ty, obligations);
         }
 
-        let needs = Needs::maybe_mut_place(mutbl_b);
         let InferOk { value: mut adjustments, obligations: o } =
-            autoderef.adjust_steps_as_infer_ok(self, needs);
+            autoderef.adjust_steps_as_infer_ok(self);
         obligations.extend(o);
         obligations.extend(autoderef.into_obligations());
 
index bc3ef73d851ebcdc0258c517ea26f86de9ddda98..c15d747be52998d1b6e9b8b43fb3eaca7382addf 100644 (file)
@@ -29,9 +29,7 @@
 use rustc_infer::infer;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_middle::ty;
-use rustc_middle::ty::adjustment::{
-    Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability,
-};
+use rustc_middle::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase};
 use rustc_middle::ty::Ty;
 use rustc_middle::ty::TypeFoldable;
 use rustc_middle::ty::{AdtKind, Visibility};
@@ -113,12 +111,21 @@ pub(super) fn check_expr_with_hint(
         self.check_expr_with_expectation(expr, ExpectHasType(expected))
     }
 
-    pub(super) fn check_expr_with_expectation(
+    fn check_expr_with_expectation_and_needs(
         &self,
         expr: &'tcx hir::Expr<'tcx>,
         expected: Expectation<'tcx>,
+        needs: Needs,
     ) -> Ty<'tcx> {
-        self.check_expr_with_expectation_and_needs(expr, expected, Needs::None)
+        let ty = self.check_expr_with_expectation(expr, expected);
+
+        // If the expression is used in a place whether mutable place is required
+        // e.g. LHS of assignment, perform the conversion.
+        if let Needs::MutPlace = needs {
+            self.convert_place_derefs_to_mutable(expr);
+        }
+
+        ty
     }
 
     pub(super) fn check_expr(&self, expr: &'tcx hir::Expr<'tcx>) -> Ty<'tcx> {
@@ -143,11 +150,10 @@ pub(super) fn check_expr_with_needs(
     /// Note that inspecting a type's structure *directly* may expose the fact
     /// that there are actually multiple representations for `Error`, so avoid
     /// that when err needs to be handled differently.
-    fn check_expr_with_expectation_and_needs(
+    pub(super) fn check_expr_with_expectation(
         &self,
         expr: &'tcx hir::Expr<'tcx>,
         expected: Expectation<'tcx>,
-        needs: Needs,
     ) -> Ty<'tcx> {
         debug!(">> type-checking: expr={:?} expected={:?}", expr, expected);
 
@@ -171,7 +177,7 @@ fn check_expr_with_expectation_and_needs(
         let old_diverges = self.diverges.replace(Diverges::Maybe);
         let old_has_errors = self.has_errors.replace(false);
 
-        let ty = self.check_expr_kind(expr, expected, needs);
+        let ty = self.check_expr_kind(expr, expected);
 
         // Warn for non-block expressions with diverging children.
         match expr.kind {
@@ -213,9 +219,8 @@ fn check_expr_kind(
         &self,
         expr: &'tcx hir::Expr<'tcx>,
         expected: Expectation<'tcx>,
-        needs: Needs,
     ) -> Ty<'tcx> {
-        debug!("check_expr_kind(expr={:?}, expected={:?}, needs={:?})", expr, expected, needs,);
+        debug!("check_expr_kind(expr={:?}, expected={:?})", expr, expected);
 
         let tcx = self.tcx;
         match expr.kind {
@@ -226,9 +231,7 @@ fn check_expr_kind(
                 self.check_expr_assign(expr, expected, lhs, rhs, span)
             }
             ExprKind::AssignOp(op, ref lhs, ref rhs) => self.check_binop_assign(expr, op, lhs, rhs),
-            ExprKind::Unary(unop, ref oprnd) => {
-                self.check_expr_unary(unop, oprnd, expected, needs, expr)
-            }
+            ExprKind::Unary(unop, ref oprnd) => self.check_expr_unary(unop, oprnd, expected, expr),
             ExprKind::AddrOf(kind, mutbl, ref oprnd) => {
                 self.check_expr_addr_of(kind, mutbl, oprnd, expected, expr)
             }
@@ -264,7 +267,7 @@ fn check_expr_kind(
             ExprKind::Block(ref body, _) => self.check_block_with_expected(&body, expected),
             ExprKind::Call(ref callee, ref args) => self.check_call(expr, &callee, args, expected),
             ExprKind::MethodCall(ref segment, span, ref args, _) => {
-                self.check_method_call(expr, segment, span, args, expected, needs)
+                self.check_method_call(expr, segment, span, args, expected)
             }
             ExprKind::Cast(ref e, ref t) => self.check_expr_cast(e, t, expr),
             ExprKind::Type(ref e, ref t) => {
@@ -281,8 +284,8 @@ fn check_expr_kind(
             ExprKind::Struct(ref qpath, fields, ref base_expr) => {
                 self.check_expr_struct(expr, expected, qpath, fields, base_expr)
             }
-            ExprKind::Field(ref base, field) => self.check_field(expr, needs, &base, field),
-            ExprKind::Index(ref base, ref idx) => self.check_expr_index(base, idx, needs, expr),
+            ExprKind::Field(ref base, field) => self.check_field(expr, &base, field),
+            ExprKind::Index(ref base, ref idx) => self.check_expr_index(base, idx, expr),
             ExprKind::Yield(ref value, ref src) => self.check_expr_yield(value, expr, src),
             hir::ExprKind::Err => tcx.types.err,
         }
@@ -302,7 +305,6 @@ fn check_expr_unary(
         unop: hir::UnOp,
         oprnd: &'tcx hir::Expr<'tcx>,
         expected: Expectation<'tcx>,
-        needs: Needs,
         expr: &'tcx hir::Expr<'tcx>,
     ) -> Ty<'tcx> {
         let tcx = self.tcx;
@@ -310,40 +312,14 @@ fn check_expr_unary(
             hir::UnOp::UnNot | hir::UnOp::UnNeg => expected,
             hir::UnOp::UnDeref => NoExpectation,
         };
-        let needs = match unop {
-            hir::UnOp::UnDeref => needs,
-            _ => Needs::None,
-        };
-        let mut oprnd_t = self.check_expr_with_expectation_and_needs(&oprnd, expected_inner, needs);
+        let mut oprnd_t = self.check_expr_with_expectation(&oprnd, expected_inner);
 
         if !oprnd_t.references_error() {
             oprnd_t = self.structurally_resolved_type(expr.span, oprnd_t);
             match unop {
                 hir::UnOp::UnDeref => {
-                    if let Some(mt) = oprnd_t.builtin_deref(true) {
-                        oprnd_t = mt.ty;
-                    } else if let Some(ok) = self.try_overloaded_deref(expr.span, oprnd_t, needs) {
-                        let method = self.register_infer_ok_obligations(ok);
-                        if let ty::Ref(region, _, mutbl) = method.sig.inputs()[0].kind {
-                            let mutbl = match mutbl {
-                                hir::Mutability::Not => AutoBorrowMutability::Not,
-                                hir::Mutability::Mut => AutoBorrowMutability::Mut {
-                                    // (It shouldn't actually matter for unary ops whether
-                                    // we enable two-phase borrows or not, since a unary
-                                    // op has no additional operands.)
-                                    allow_two_phase_borrow: AllowTwoPhase::No,
-                                },
-                            };
-                            self.apply_adjustments(
-                                oprnd,
-                                vec![Adjustment {
-                                    kind: Adjust::Borrow(AutoBorrow::Ref(region, mutbl)),
-                                    target: method.sig.inputs()[0],
-                                }],
-                            );
-                        }
-                        oprnd_t = self.make_overloaded_place_return_type(method).ty;
-                        self.write_method_call(expr.hir_id, method);
+                    if let Some(ty) = self.lookup_derefing(expr, oprnd, oprnd_t) {
+                        oprnd_t = ty;
                     } else {
                         let mut err = type_error_struct!(
                             tcx.sess,
@@ -405,8 +381,8 @@ fn check_expr_addr_of(
                 _ => NoExpectation,
             }
         });
-        let needs = Needs::maybe_mut_place(mutbl);
-        let ty = self.check_expr_with_expectation_and_needs(&oprnd, hint, needs);
+        let ty =
+            self.check_expr_with_expectation_and_needs(&oprnd, hint, Needs::maybe_mut_place(mutbl));
 
         let tm = ty::TypeAndMut { ty, mutbl };
         match kind {
@@ -861,10 +837,9 @@ fn check_method_call(
         span: Span,
         args: &'tcx [hir::Expr<'tcx>],
         expected: Expectation<'tcx>,
-        needs: Needs,
     ) -> Ty<'tcx> {
         let rcvr = &args[0];
-        let rcvr_t = self.check_expr_with_needs(&rcvr, needs);
+        let rcvr_t = self.check_expr(&rcvr);
         // no need to check for bot/err -- callee does that
         let rcvr_t = self.structurally_resolved_type(args[0].span, rcvr_t);
 
@@ -1443,11 +1418,10 @@ fn name_series_display(&self, names: Vec<Symbol>) -> String {
     fn check_field(
         &self,
         expr: &'tcx hir::Expr<'tcx>,
-        needs: Needs,
         base: &'tcx hir::Expr<'tcx>,
         field: Ident,
     ) -> Ty<'tcx> {
-        let expr_t = self.check_expr_with_needs(base, needs);
+        let expr_t = self.check_expr(base);
         let expr_t = self.structurally_resolved_type(base.span, expr_t);
         let mut private_candidate = None;
         let mut autoderef = self.autoderef(expr.span, expr_t);
@@ -1467,7 +1441,7 @@ fn check_field(
                         // of error recovery.
                         self.write_field_index(expr.hir_id, index);
                         if field.vis.is_accessible_from(def_scope, self.tcx) {
-                            let adjustments = autoderef.adjust_steps(self, needs);
+                            let adjustments = autoderef.adjust_steps(self);
                             self.apply_adjustments(base, adjustments);
                             autoderef.finalize(self);
 
@@ -1482,7 +1456,7 @@ fn check_field(
                     if let Ok(index) = fstr.parse::<usize>() {
                         if fstr == index.to_string() {
                             if let Some(field_ty) = tys.get(index) {
-                                let adjustments = autoderef.adjust_steps(self, needs);
+                                let adjustments = autoderef.adjust_steps(self);
                                 self.apply_adjustments(base, adjustments);
                                 autoderef.finalize(self);
 
@@ -1721,10 +1695,9 @@ fn check_expr_index(
         &self,
         base: &'tcx hir::Expr<'tcx>,
         idx: &'tcx hir::Expr<'tcx>,
-        needs: Needs,
         expr: &'tcx hir::Expr<'tcx>,
     ) -> Ty<'tcx> {
-        let base_t = self.check_expr_with_needs(&base, needs);
+        let base_t = self.check_expr(&base);
         let idx_t = self.check_expr(&idx);
 
         if base_t.references_error() {
@@ -1733,7 +1706,7 @@ fn check_expr_index(
             idx_t
         } else {
             let base_t = self.structurally_resolved_type(base.span, base_t);
-            match self.lookup_indexing(expr, base, base_t, idx_t, needs) {
+            match self.lookup_indexing(expr, base, base_t, idx_t) {
                 Some((index_ty, element_ty)) => {
                     // two-phase not needed because index_ty is never mutable
                     self.demand_coerce(idx, idx_t, index_ty, None, AllowTwoPhase::No);
index c0f1f356ef372afa35ad334df09eca17165d8712..21c359abf0b082cae60710b748d00eb4f2889f46 100644 (file)
@@ -1,7 +1,7 @@
 use super::{probe, MethodCallee};
 
 use crate::astconv::AstConv;
-use crate::check::{callee, FnCtxt, Needs};
+use crate::check::{callee, FnCtxt};
 use crate::hir::def_id::DefId;
 use crate::hir::GenericArg;
 use rustc_hir as hir;
@@ -145,7 +145,7 @@ fn adjust_self_ty(
         };
         assert_eq!(n, pick.autoderefs);
 
-        let mut adjustments = autoderef.adjust_steps(self, Needs::None);
+        let mut adjustments = autoderef.adjust_steps(self);
 
         let mut target = autoderef.unambiguous_final_ty(self);
 
index 82523f843aef91e7b5e97c4bdf2b59de0a6e778a..b1d32213b729e3a70fa5bee71d311a7da5d23293 100644 (file)
@@ -79,7 +79,7 @@
 pub mod method;
 mod op;
 mod pat;
-mod reconciliation;
+mod place_op;
 mod regionck;
 mod upvar;
 mod wfcheck;
 use rustc_middle::hir::map::blocks::FnLikeNode;
 use rustc_middle::mir::interpret::ConstValue;
 use rustc_middle::ty::adjustment::{
-    Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, PointerCast,
+    Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability,
 };
 use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
 use rustc_middle::ty::query::Providers;
 use crate::require_c_abi_if_c_variadic;
 use crate::util::common::indenter;
 
-use self::autoderef::Autoderef;
 use self::callee::DeferredCallResolution;
 use self::coercion::{CoerceMany, DynamicCoerceMany};
 use self::compare_method::{compare_const_impl, compare_impl_method, compare_ty_impl};
@@ -3618,154 +3617,6 @@ fn make_overloaded_place_return_type(
         ret_ty.builtin_deref(true).unwrap()
     }
 
-    fn lookup_indexing(
-        &self,
-        expr: &hir::Expr<'_>,
-        base_expr: &'tcx hir::Expr<'tcx>,
-        base_ty: Ty<'tcx>,
-        idx_ty: Ty<'tcx>,
-        needs: Needs,
-    ) -> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)> {
-        // FIXME(#18741) -- this is almost but not quite the same as the
-        // autoderef that normal method probing does. They could likely be
-        // consolidated.
-
-        let mut autoderef = self.autoderef(base_expr.span, base_ty);
-        let mut result = None;
-        while result.is_none() && autoderef.next().is_some() {
-            result = self.try_index_step(expr, base_expr, &autoderef, needs, idx_ty);
-        }
-        autoderef.finalize(self);
-        result
-    }
-
-    /// To type-check `base_expr[index_expr]`, we progressively autoderef
-    /// (and otherwise adjust) `base_expr`, looking for a type which either
-    /// supports builtin indexing or overloaded indexing.
-    /// This loop implements one step in that search; the autoderef loop
-    /// is implemented by `lookup_indexing`.
-    fn try_index_step(
-        &self,
-        expr: &hir::Expr<'_>,
-        base_expr: &hir::Expr<'_>,
-        autoderef: &Autoderef<'a, 'tcx>,
-        needs: Needs,
-        index_ty: Ty<'tcx>,
-    ) -> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)> {
-        let adjusted_ty = autoderef.unambiguous_final_ty(self);
-        debug!(
-            "try_index_step(expr={:?}, base_expr={:?}, adjusted_ty={:?}, \
-             index_ty={:?})",
-            expr, base_expr, adjusted_ty, index_ty
-        );
-
-        for &unsize in &[false, true] {
-            let mut self_ty = adjusted_ty;
-            if unsize {
-                // We only unsize arrays here.
-                if let ty::Array(element_ty, _) = adjusted_ty.kind {
-                    self_ty = self.tcx.mk_slice(element_ty);
-                } else {
-                    continue;
-                }
-            }
-
-            // If some lookup succeeds, write callee into table and extract index/element
-            // type from the method signature.
-            // If some lookup succeeded, install method in table
-            let input_ty = self.next_ty_var(TypeVariableOrigin {
-                kind: TypeVariableOriginKind::AutoDeref,
-                span: base_expr.span,
-            });
-            let method = self.try_overloaded_place_op(
-                expr.span,
-                self_ty,
-                &[input_ty],
-                needs,
-                PlaceOp::Index,
-            );
-
-            let result = method.map(|ok| {
-                debug!("try_index_step: success, using overloaded indexing");
-                let method = self.register_infer_ok_obligations(ok);
-
-                let mut adjustments = autoderef.adjust_steps(self, needs);
-                if let ty::Ref(region, _, r_mutbl) = method.sig.inputs()[0].kind {
-                    let mutbl = match r_mutbl {
-                        hir::Mutability::Not => AutoBorrowMutability::Not,
-                        hir::Mutability::Mut => AutoBorrowMutability::Mut {
-                            // Indexing can be desugared to a method call,
-                            // so maybe we could use two-phase here.
-                            // See the documentation of AllowTwoPhase for why that's
-                            // not the case today.
-                            allow_two_phase_borrow: AllowTwoPhase::No,
-                        },
-                    };
-                    adjustments.push(Adjustment {
-                        kind: Adjust::Borrow(AutoBorrow::Ref(region, mutbl)),
-                        target: self
-                            .tcx
-                            .mk_ref(region, ty::TypeAndMut { mutbl: r_mutbl, ty: adjusted_ty }),
-                    });
-                }
-                if unsize {
-                    adjustments.push(Adjustment {
-                        kind: Adjust::Pointer(PointerCast::Unsize),
-                        target: method.sig.inputs()[0],
-                    });
-                }
-                self.apply_adjustments(base_expr, adjustments);
-
-                self.write_method_call(expr.hir_id, method);
-                (input_ty, self.make_overloaded_place_return_type(method).ty)
-            });
-            if result.is_some() {
-                return result;
-            }
-        }
-
-        None
-    }
-
-    fn resolve_place_op(&self, op: PlaceOp, is_mut: bool) -> (Option<DefId>, Ident) {
-        let (tr, name) = match (op, is_mut) {
-            (PlaceOp::Deref, false) => (self.tcx.lang_items().deref_trait(), sym::deref),
-            (PlaceOp::Deref, true) => (self.tcx.lang_items().deref_mut_trait(), sym::deref_mut),
-            (PlaceOp::Index, false) => (self.tcx.lang_items().index_trait(), sym::index),
-            (PlaceOp::Index, true) => (self.tcx.lang_items().index_mut_trait(), sym::index_mut),
-        };
-        (tr, Ident::with_dummy_span(name))
-    }
-
-    fn try_overloaded_place_op(
-        &self,
-        span: Span,
-        base_ty: Ty<'tcx>,
-        arg_tys: &[Ty<'tcx>],
-        needs: Needs,
-        op: PlaceOp,
-    ) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
-        debug!("try_overloaded_place_op({:?},{:?},{:?},{:?})", span, base_ty, needs, op);
-
-        // Try Mut first, if needed.
-        let (mut_tr, mut_op) = self.resolve_place_op(op, true);
-        let method = match (needs, mut_tr) {
-            (Needs::MutPlace, Some(trait_did)) => {
-                self.lookup_method_in_trait(span, mut_op, trait_did, base_ty, Some(arg_tys))
-            }
-            _ => None,
-        };
-
-        // Otherwise, fall back to the immutable version.
-        let (imm_tr, imm_op) = self.resolve_place_op(op, false);
-        match (method, imm_tr) {
-            (None, Some(trait_did)) => {
-                self.lookup_method_in_trait(span, imm_op, trait_did, base_ty, Some(arg_tys))
-            }
-            (method, _) => method,
-        }
-    }
-
     fn check_method_argument_types(
         &self,
         sp: Span,
index a3a27dc138be96f11605c2b3d898905673bc3160..41088b0790813e8a45bbfc8b53b395f77d5dc50c 100644 (file)
@@ -1,7 +1,7 @@
 //! Code related to processing overloaded binary and unary operators.
 
 use super::method::MethodCallee;
-use super::{FnCtxt, Needs};
+use super::FnCtxt;
 use rustc_errors::{self, struct_span_err, Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
@@ -165,7 +165,7 @@ fn check_overloaded_binop(
                 // trait matching creating lifetime constraints that are too strict.
                 // e.g., adding `&'a T` and `&'b T`, given `&'x T: Add<&'x T>`, will result
                 // in `&'a T <: &'x T` and `&'b T <: &'x T`, instead of `'a = 'b = 'x`.
-                let lhs_ty = self.check_expr_with_needs(lhs_expr, Needs::None);
+                let lhs_ty = self.check_expr(lhs_expr);
                 let fresh_var = self.next_ty_var(TypeVariableOrigin {
                     kind: TypeVariableOriginKind::MiscVariable,
                     span: lhs_expr.span,
@@ -177,7 +177,7 @@ fn check_overloaded_binop(
                 // equivalence on the LHS of an assign-op like `+=`;
                 // overwritten or mutably-borrowed places cannot be
                 // coerced to a supertype.
-                self.check_expr_with_needs(lhs_expr, Needs::MutPlace)
+                self.check_expr(lhs_expr)
             }
         };
         let lhs_ty = self.resolve_vars_with_obligations(lhs_ty);
diff --git a/src/librustc_typeck/check/place_op.rs b/src/librustc_typeck/check/place_op.rs
new file mode 100644 (file)
index 0000000..ce4b6f8
--- /dev/null
@@ -0,0 +1,334 @@
+use crate::check::autoderef::Autoderef;
+use crate::check::method::MethodCallee;
+use crate::check::{FnCtxt, PlaceOp};
+use rustc_hir as hir;
+use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use rustc_infer::infer::InferOk;
+use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref, PointerCast};
+use rustc_middle::ty::adjustment::{AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
+use rustc_middle::ty::{self, Ty};
+use rustc_span::symbol::{sym, Ident};
+use rustc_span::Span;
+
+impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
+    pub(super) fn lookup_derefing(
+        &self,
+        expr: &hir::Expr<'_>,
+        oprnd: &'tcx hir::Expr<'tcx>,
+        oprnd_ty: Ty<'tcx>,
+    ) -> Option<Ty<'tcx>> {
+        if let Some(mt) = oprnd_ty.builtin_deref(true) {
+            return Some(mt.ty);
+        }
+
+        let ok = self.try_overloaded_deref(expr.span, oprnd_ty)?;
+        let method = self.register_infer_ok_obligations(ok);
+        if let ty::Ref(region, _, hir::Mutability::Not) = method.sig.inputs()[0].kind {
+            self.apply_adjustments(
+                oprnd,
+                vec![Adjustment {
+                    kind: Adjust::Borrow(AutoBorrow::Ref(region, AutoBorrowMutability::Not)),
+                    target: method.sig.inputs()[0],
+                }],
+            );
+        } else {
+            span_bug!(expr.span, "input to deref is not a ref?");
+        }
+        let ty = self.make_overloaded_place_return_type(method).ty;
+        self.write_method_call(expr.hir_id, method);
+        Some(ty)
+    }
+
+    pub(super) fn lookup_indexing(
+        &self,
+        expr: &hir::Expr<'_>,
+        base_expr: &'tcx hir::Expr<'tcx>,
+        base_ty: Ty<'tcx>,
+        idx_ty: Ty<'tcx>,
+    ) -> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)> {
+        // FIXME(#18741) -- this is almost but not quite the same as the
+        // autoderef that normal method probing does. They could likely be
+        // consolidated.
+
+        let mut autoderef = self.autoderef(base_expr.span, base_ty);
+        let mut result = None;
+        while result.is_none() && autoderef.next().is_some() {
+            result = self.try_index_step(expr, base_expr, &autoderef, idx_ty);
+        }
+        autoderef.finalize(self);
+        result
+    }
+
+    /// To type-check `base_expr[index_expr]`, we progressively autoderef
+    /// (and otherwise adjust) `base_expr`, looking for a type which either
+    /// supports builtin indexing or overloaded indexing.
+    /// This loop implements one step in that search; the autoderef loop
+    /// is implemented by `lookup_indexing`.
+    fn try_index_step(
+        &self,
+        expr: &hir::Expr<'_>,
+        base_expr: &hir::Expr<'_>,
+        autoderef: &Autoderef<'a, 'tcx>,
+        index_ty: Ty<'tcx>,
+    ) -> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)> {
+        let adjusted_ty = autoderef.unambiguous_final_ty(self);
+        debug!(
+            "try_index_step(expr={:?}, base_expr={:?}, adjusted_ty={:?}, \
+             index_ty={:?})",
+            expr, base_expr, adjusted_ty, index_ty
+        );
+
+        for &unsize in &[false, true] {
+            let mut self_ty = adjusted_ty;
+            if unsize {
+                // We only unsize arrays here.
+                if let ty::Array(element_ty, _) = adjusted_ty.kind {
+                    self_ty = self.tcx.mk_slice(element_ty);
+                } else {
+                    continue;
+                }
+            }
+
+            // If some lookup succeeds, write callee into table and extract index/element
+            // type from the method signature.
+            // If some lookup succeeded, install method in table
+            let input_ty = self.next_ty_var(TypeVariableOrigin {
+                kind: TypeVariableOriginKind::AutoDeref,
+                span: base_expr.span,
+            });
+            let method =
+                self.try_overloaded_place_op(expr.span, self_ty, &[input_ty], PlaceOp::Index);
+
+            let result = method.map(|ok| {
+                debug!("try_index_step: success, using overloaded indexing");
+                let method = self.register_infer_ok_obligations(ok);
+
+                let mut adjustments = autoderef.adjust_steps(self);
+                if let ty::Ref(region, _, hir::Mutability::Not) = method.sig.inputs()[0].kind {
+                    adjustments.push(Adjustment {
+                        kind: Adjust::Borrow(AutoBorrow::Ref(region, AutoBorrowMutability::Not)),
+                        target: self.tcx.mk_ref(
+                            region,
+                            ty::TypeAndMut { mutbl: hir::Mutability::Not, ty: adjusted_ty },
+                        ),
+                    });
+                } else {
+                    span_bug!(expr.span, "input to index is not a ref?");
+                }
+                if unsize {
+                    adjustments.push(Adjustment {
+                        kind: Adjust::Pointer(PointerCast::Unsize),
+                        target: method.sig.inputs()[0],
+                    });
+                }
+                self.apply_adjustments(base_expr, adjustments);
+
+                self.write_method_call(expr.hir_id, method);
+                (input_ty, self.make_overloaded_place_return_type(method).ty)
+            });
+            if result.is_some() {
+                return result;
+            }
+        }
+
+        None
+    }
+
+    /// Try to resolve an overloaded place op. We only deal with the immutable
+    /// variant here (Deref/Index). In some contexts we would need the mutable
+    /// variant (DerefMut/IndexMut); those would be later converted by
+    /// `convert_place_derefs_to_mutable`.
+    pub(super) fn try_overloaded_place_op(
+        &self,
+        span: Span,
+        base_ty: Ty<'tcx>,
+        arg_tys: &[Ty<'tcx>],
+        op: PlaceOp,
+    ) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
+        debug!("try_overloaded_place_op({:?},{:?},{:?})", span, base_ty, op);
+
+        let (imm_tr, imm_op) = match op {
+            PlaceOp::Deref => (self.tcx.lang_items().deref_trait(), sym::deref),
+            PlaceOp::Index => (self.tcx.lang_items().index_trait(), sym::index),
+        };
+        imm_tr.and_then(|trait_did| {
+            self.lookup_method_in_trait(
+                span,
+                Ident::with_dummy_span(imm_op),
+                trait_did,
+                base_ty,
+                Some(arg_tys),
+            )
+        })
+    }
+
+    fn try_mutable_overloaded_place_op(
+        &self,
+        span: Span,
+        base_ty: Ty<'tcx>,
+        arg_tys: &[Ty<'tcx>],
+        op: PlaceOp,
+    ) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
+        debug!("try_mutable_overloaded_place_op({:?},{:?},{:?})", span, base_ty, op);
+
+        let (mut_tr, mut_op) = match op {
+            PlaceOp::Deref => (self.tcx.lang_items().deref_mut_trait(), sym::deref_mut),
+            PlaceOp::Index => (self.tcx.lang_items().index_mut_trait(), sym::index_mut),
+        };
+        mut_tr.and_then(|trait_did| {
+            self.lookup_method_in_trait(
+                span,
+                Ident::with_dummy_span(mut_op),
+                trait_did,
+                base_ty,
+                Some(arg_tys),
+            )
+        })
+    }
+
+    /// Convert auto-derefs, indices, etc of an expression from `Deref` and `Index`
+    /// into `DerefMut` and `IndexMut` respectively.
+    ///
+    /// This is a second pass of typechecking derefs/indices. We need this we do not
+    /// always know whether a place needs to be mutable or not in the first pass.
+    /// This happens whether there is an implicit mutable reborrow, e.g. when the type
+    /// is used as the receiver of a method call.
+    pub fn convert_place_derefs_to_mutable(&self, expr: &hir::Expr<'_>) {
+        // Gather up expressions we want to munge.
+        let mut exprs = vec![expr];
+
+        loop {
+            match exprs.last().unwrap().kind {
+                hir::ExprKind::Field(ref expr, _)
+                | hir::ExprKind::Index(ref expr, _)
+                | hir::ExprKind::Unary(hir::UnOp::UnDeref, ref expr) => exprs.push(&expr),
+                _ => break,
+            }
+        }
+
+        debug!("convert_place_derefs_to_mutable: exprs={:?}", exprs);
+
+        // Fix up autoderefs and derefs.
+        for (i, &expr) in exprs.iter().rev().enumerate() {
+            debug!("convert_place_derefs_to_mutable: i={} expr={:?}", i, expr);
+
+            // Fix up the autoderefs. Autorefs can only occur immediately preceding
+            // overloaded place ops, and will be fixed by them in order to get
+            // the correct region.
+            let mut source = self.node_ty(expr.hir_id);
+            // Do not mutate adjustments in place, but rather take them,
+            // and replace them after mutating them, to avoid having the
+            // tables borrowed during (`deref_mut`) method resolution.
+            let previous_adjustments =
+                self.tables.borrow_mut().adjustments_mut().remove(expr.hir_id);
+            if let Some(mut adjustments) = previous_adjustments {
+                for adjustment in &mut adjustments {
+                    if let Adjust::Deref(Some(ref mut deref)) = adjustment.kind {
+                        if let Some(ok) = self.try_mutable_overloaded_place_op(
+                            expr.span,
+                            source,
+                            &[],
+                            PlaceOp::Deref,
+                        ) {
+                            let method = self.register_infer_ok_obligations(ok);
+                            if let ty::Ref(region, _, mutbl) = method.sig.output().kind {
+                                *deref = OverloadedDeref { region, mutbl };
+                            }
+                        }
+                    }
+                    source = adjustment.target;
+                }
+                self.tables.borrow_mut().adjustments_mut().insert(expr.hir_id, adjustments);
+            }
+
+            match expr.kind {
+                hir::ExprKind::Index(ref base_expr, ref index_expr) => {
+                    // We need to get the final type in case dereferences were needed for the trait
+                    // to apply (#72002).
+                    let index_expr_ty = self.tables.borrow().expr_ty_adjusted(index_expr);
+                    self.convert_place_op_to_mutable(
+                        PlaceOp::Index,
+                        expr,
+                        base_expr,
+                        &[index_expr_ty],
+                    );
+                }
+                hir::ExprKind::Unary(hir::UnOp::UnDeref, ref base_expr) => {
+                    self.convert_place_op_to_mutable(PlaceOp::Deref, expr, base_expr, &[]);
+                }
+                _ => {}
+            }
+        }
+    }
+
+    fn convert_place_op_to_mutable(
+        &self,
+        op: PlaceOp,
+        expr: &hir::Expr<'_>,
+        base_expr: &hir::Expr<'_>,
+        arg_tys: &[Ty<'tcx>],
+    ) {
+        debug!("convert_place_op_to_mutable({:?}, {:?}, {:?}, {:?})", op, expr, base_expr, arg_tys);
+        if !self.tables.borrow().is_method_call(expr) {
+            debug!("convert_place_op_to_mutable - builtin, nothing to do");
+            return;
+        }
+
+        // Need to deref because overloaded place ops take self by-reference.
+        let base_ty = self
+            .tables
+            .borrow()
+            .expr_ty_adjusted(base_expr)
+            .builtin_deref(false)
+            .expect("place op takes something that is not a ref")
+            .ty;
+
+        let method = self.try_mutable_overloaded_place_op(expr.span, base_ty, arg_tys, op);
+        let method = match method {
+            Some(ok) => self.register_infer_ok_obligations(ok),
+            // Couldn't find the mutable variant of the place op, keep the
+            // current, immutable version.
+            None => return,
+        };
+        debug!("convert_place_op_to_mutable: method={:?}", method);
+        self.write_method_call(expr.hir_id, method);
+
+        let region = if let ty::Ref(r, _, hir::Mutability::Mut) = method.sig.inputs()[0].kind {
+            r
+        } else {
+            span_bug!(expr.span, "input to mutable place op is not a mut ref?");
+        };
+
+        // Convert the autoref in the base expr to mutable with the correct
+        // region and mutability.
+        let base_expr_ty = self.node_ty(base_expr.hir_id);
+        if let Some(adjustments) =
+            self.tables.borrow_mut().adjustments_mut().get_mut(base_expr.hir_id)
+        {
+            let mut source = base_expr_ty;
+            for adjustment in &mut adjustments[..] {
+                if let Adjust::Borrow(AutoBorrow::Ref(..)) = adjustment.kind {
+                    debug!("convert_place_op_to_mutable: converting autoref {:?}", adjustment);
+                    let mutbl = AutoBorrowMutability::Mut {
+                        // Deref/indexing can be desugared to a method call,
+                        // so maybe we could use two-phase here.
+                        // See the documentation of AllowTwoPhase for why that's
+                        // not the case today.
+                        allow_two_phase_borrow: AllowTwoPhase::No,
+                    };
+                    adjustment.kind = Adjust::Borrow(AutoBorrow::Ref(region, mutbl));
+                    adjustment.target =
+                        self.tcx.mk_ref(region, ty::TypeAndMut { ty: source, mutbl: mutbl.into() });
+                }
+                source = adjustment.target;
+            }
+
+            // If we have an autoref followed by unsizing at the end, fix the unsize target.
+            if let [.., Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(..)), .. }, Adjustment { kind: Adjust::Pointer(PointerCast::Unsize), ref mut target }] =
+                adjustments[..]
+            {
+                *target = method.sig.inputs()[0];
+            }
+        }
+    }
+}
diff --git a/src/librustc_typeck/check/reconciliation.rs b/src/librustc_typeck/check/reconciliation.rs
deleted file mode 100644 (file)
index 0a42931..0000000
+++ /dev/null
@@ -1,150 +0,0 @@
-use crate::check::{FnCtxt, Needs, PlaceOp};
-use rustc_hir as hir;
-use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref, PointerCast};
-use rustc_middle::ty::adjustment::{AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
-use rustc_middle::ty::{self, Ty};
-
-impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
-    /// Convert auto-derefs, indices, etc of an expression from `Deref` and `Index`
-    /// into `DerefMut` and `IndexMut` respectively.
-    ///
-    /// This is a second pass of typechecking derefs/indices. We need this we do not
-    /// always know whether a place needs to be mutable or not in the first pass.
-    /// This happens whether there is an implicit mutable reborrow, e.g. when the type
-    /// is used as the receiver of a method call.
-    pub fn convert_place_derefs_to_mutable(&self, expr: &hir::Expr<'_>) {
-        // Gather up expressions we want to munge.
-        let mut exprs = vec![expr];
-
-        loop {
-            match exprs.last().unwrap().kind {
-                hir::ExprKind::Field(ref expr, _)
-                | hir::ExprKind::Index(ref expr, _)
-                | hir::ExprKind::Unary(hir::UnOp::UnDeref, ref expr) => exprs.push(&expr),
-                _ => break,
-            }
-        }
-
-        debug!("convert_place_derefs_to_mutable: exprs={:?}", exprs);
-
-        // Fix up autoderefs and derefs.
-        for (i, &expr) in exprs.iter().rev().enumerate() {
-            debug!("convert_place_derefs_to_mutable: i={} expr={:?}", i, expr);
-
-            // Fix up the autoderefs. Autorefs can only occur immediately preceding
-            // overloaded place ops, and will be fixed by them in order to get
-            // the correct region.
-            let mut source = self.node_ty(expr.hir_id);
-            // Do not mutate adjustments in place, but rather take them,
-            // and replace them after mutating them, to avoid having the
-            // tables borrowed during (`deref_mut`) method resolution.
-            let previous_adjustments =
-                self.tables.borrow_mut().adjustments_mut().remove(expr.hir_id);
-            if let Some(mut adjustments) = previous_adjustments {
-                let needs = Needs::MutPlace;
-                for adjustment in &mut adjustments {
-                    if let Adjust::Deref(Some(ref mut deref)) = adjustment.kind {
-                        if let Some(ok) = self.try_overloaded_deref(expr.span, source, needs) {
-                            let method = self.register_infer_ok_obligations(ok);
-                            if let ty::Ref(region, _, mutbl) = method.sig.output().kind {
-                                *deref = OverloadedDeref { region, mutbl };
-                            }
-                        }
-                    }
-                    source = adjustment.target;
-                }
-                self.tables.borrow_mut().adjustments_mut().insert(expr.hir_id, adjustments);
-            }
-
-            match expr.kind {
-                hir::ExprKind::Index(ref base_expr, ref index_expr) => {
-                    // We need to get the final type in case dereferences were needed for the trait
-                    // to apply (#72002).
-                    let index_expr_ty = self.tables.borrow().expr_ty_adjusted(index_expr);
-                    self.convert_place_op_to_mutable(
-                        PlaceOp::Index,
-                        expr,
-                        base_expr,
-                        &[index_expr_ty],
-                    );
-                }
-                hir::ExprKind::Unary(hir::UnOp::UnDeref, ref base_expr) => {
-                    self.convert_place_op_to_mutable(PlaceOp::Deref, expr, base_expr, &[]);
-                }
-                _ => {}
-            }
-        }
-    }
-
-    fn convert_place_op_to_mutable(
-        &self,
-        op: PlaceOp,
-        expr: &hir::Expr<'_>,
-        base_expr: &hir::Expr<'_>,
-        arg_tys: &[Ty<'tcx>],
-    ) {
-        debug!("convert_place_op_to_mutable({:?}, {:?}, {:?}, {:?})", op, expr, base_expr, arg_tys);
-        if !self.tables.borrow().is_method_call(expr) {
-            debug!("convert_place_op_to_mutable - builtin, nothing to do");
-            return;
-        }
-
-        // Need to deref because overloaded place ops take self by-reference.
-        let base_ty = self
-            .tables
-            .borrow()
-            .expr_ty_adjusted(base_expr)
-            .builtin_deref(false)
-            .expect("place op takes something that is not a ref")
-            .ty;
-
-        let method = self.try_overloaded_place_op(expr.span, base_ty, arg_tys, Needs::MutPlace, op);
-        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"),
-        };
-        debug!("convert_place_op_to_mutable: method={:?}", method);
-        self.write_method_call(expr.hir_id, method);
-
-        let (region, mutbl) = if let ty::Ref(r, _, mutbl) = method.sig.inputs()[0].kind {
-            (r, mutbl)
-        } else {
-            span_bug!(expr.span, "input to place op is not a ref?");
-        };
-
-        // Convert the autoref in the base expr to mutable with the correct
-        // region and mutability.
-        let base_expr_ty = self.node_ty(base_expr.hir_id);
-        if let Some(adjustments) =
-            self.tables.borrow_mut().adjustments_mut().get_mut(base_expr.hir_id)
-        {
-            let mut source = base_expr_ty;
-            for adjustment in &mut adjustments[..] {
-                if let Adjust::Borrow(AutoBorrow::Ref(..)) = adjustment.kind {
-                    debug!("convert_place_op_to_mutable: converting autoref {:?}", adjustment);
-                    let mutbl = match mutbl {
-                        hir::Mutability::Not => AutoBorrowMutability::Not,
-                        hir::Mutability::Mut => AutoBorrowMutability::Mut {
-                            // For initial two-phase borrow
-                            // deployment, conservatively omit
-                            // overloaded operators.
-                            allow_two_phase_borrow: AllowTwoPhase::No,
-                        },
-                    };
-                    adjustment.kind = Adjust::Borrow(AutoBorrow::Ref(region, mutbl));
-                    adjustment.target =
-                        self.tcx.mk_ref(region, ty::TypeAndMut { ty: source, mutbl: mutbl.into() });
-                }
-                source = adjustment.target;
-            }
-
-            // If we have an autoref followed by unsizing at the end, fix the unsize target.
-
-            if let [.., Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(..)), .. }, Adjustment { kind: Adjust::Pointer(PointerCast::Unsize), ref mut target }] =
-                adjustments[..]
-            {
-                *target = method.sig.inputs()[0];
-            }
-        }
-    }
-}