about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2020-09-22 08:11:07 +0000
committerbors <bors@rust-lang.org>2020-09-22 08:11:07 +0000
commitc113030f6b7d10cd27ac7091718e6f48ecf56a63 (patch)
tree45eee5535c8e0c9148e32e941a695ee3ad8ba8c0
parent44ae0b8b2def2a26b82e0a93f8c8c2c523cc3643 (diff)
parentccd218d04ce5124de69716316ff72b9356a00cb8 (diff)
downloadrust-c113030f6b7d10cd27ac7091718e6f48ecf56a63.tar.gz
rust-c113030f6b7d10cd27ac7091718e6f48ecf56a63.zip
Auto merge of #76906 - Nicholas-Baron:shorten_typeck_check, r=oli-obk
Split rustc_typeck::check into separate files

Contributing to #60302.
-rw-r--r--compiler/rustc_typeck/src/check/check.rs1344
-rw-r--r--compiler/rustc_typeck/src/check/diverges.rs78
-rw-r--r--compiler/rustc_typeck/src/check/expectation.rs117
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt.rs3200
-rw-r--r--compiler/rustc_typeck/src/check/gather_locals.rs120
-rw-r--r--compiler/rustc_typeck/src/check/inherited.rs167
-rw-r--r--compiler/rustc_typeck/src/check/mod.rs5036
7 files changed, 5090 insertions, 4972 deletions
diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs
new file mode 100644
index 00000000000..2daa0354acb
--- /dev/null
+++ b/compiler/rustc_typeck/src/check/check.rs
@@ -0,0 +1,1344 @@
+use super::coercion::CoerceMany;
+use super::compare_method::{compare_const_impl, compare_impl_method, compare_ty_impl};
+use super::*;
+
+use rustc_attr as attr;
+use rustc_errors::Applicability;
+use rustc_hir as hir;
+use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE};
+use rustc_hir::lang_items::LangItem;
+use rustc_hir::{ItemKind, Node};
+use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use rustc_infer::infer::RegionVariableOrigin;
+use rustc_middle::ty::fold::TypeFoldable;
+use rustc_middle::ty::subst::GenericArgKind;
+use rustc_middle::ty::util::{Discr, IntTypeExt, Representability};
+use rustc_middle::ty::{self, RegionKind, ToPredicate, Ty, TyCtxt};
+use rustc_session::config::EntryFnType;
+use rustc_span::symbol::sym;
+use rustc_span::{self, MultiSpan, Span};
+use rustc_target::spec::abi::Abi;
+use rustc_trait_selection::traits::{self, ObligationCauseCode};
+
+pub fn check_wf_new(tcx: TyCtxt<'_>) {
+    let visit = wfcheck::CheckTypeWellFormedVisitor::new(tcx);
+    tcx.hir().krate().par_visit_all_item_likes(&visit);
+}
+
+pub(super) fn check_abi(tcx: TyCtxt<'_>, span: Span, abi: Abi) {
+    if !tcx.sess.target.target.is_abi_supported(abi) {
+        struct_span_err!(
+            tcx.sess,
+            span,
+            E0570,
+            "The ABI `{}` is not supported for the current target",
+            abi
+        )
+        .emit()
+    }
+}
+
+/// Helper used for fns and closures. Does the grungy work of checking a function
+/// body and returns the function context used for that purpose, since in the case of a fn item
+/// there is still a bit more to do.
+///
+/// * ...
+/// * inherited: other fields inherited from the enclosing fn (if any)
+pub(super) fn check_fn<'a, 'tcx>(
+    inherited: &'a Inherited<'a, 'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    fn_sig: ty::FnSig<'tcx>,
+    decl: &'tcx hir::FnDecl<'tcx>,
+    fn_id: hir::HirId,
+    body: &'tcx hir::Body<'tcx>,
+    can_be_generator: Option<hir::Movability>,
+) -> (FnCtxt<'a, 'tcx>, Option<GeneratorTypes<'tcx>>) {
+    let mut fn_sig = fn_sig;
+
+    debug!("check_fn(sig={:?}, fn_id={}, param_env={:?})", fn_sig, fn_id, param_env);
+
+    // Create the function context. This is either derived from scratch or,
+    // in the case of closures, based on the outer context.
+    let mut fcx = FnCtxt::new(inherited, param_env, body.value.hir_id);
+    *fcx.ps.borrow_mut() = UnsafetyState::function(fn_sig.unsafety, fn_id);
+
+    let tcx = fcx.tcx;
+    let sess = tcx.sess;
+    let hir = tcx.hir();
+
+    let declared_ret_ty = fn_sig.output();
+
+    let revealed_ret_ty =
+        fcx.instantiate_opaque_types_from_value(fn_id, &declared_ret_ty, decl.output.span());
+    debug!("check_fn: declared_ret_ty: {}, revealed_ret_ty: {}", declared_ret_ty, revealed_ret_ty);
+    fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(revealed_ret_ty)));
+    fcx.ret_type_span = Some(decl.output.span());
+    if let ty::Opaque(..) = declared_ret_ty.kind() {
+        fcx.ret_coercion_impl_trait = Some(declared_ret_ty);
+    }
+    fn_sig = tcx.mk_fn_sig(
+        fn_sig.inputs().iter().cloned(),
+        revealed_ret_ty,
+        fn_sig.c_variadic,
+        fn_sig.unsafety,
+        fn_sig.abi,
+    );
+
+    let span = body.value.span;
+
+    fn_maybe_err(tcx, span, fn_sig.abi);
+
+    if body.generator_kind.is_some() && can_be_generator.is_some() {
+        let yield_ty = fcx
+            .next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span });
+        fcx.require_type_is_sized(yield_ty, span, traits::SizedYieldType);
+
+        // Resume type defaults to `()` if the generator has no argument.
+        let resume_ty = fn_sig.inputs().get(0).copied().unwrap_or_else(|| tcx.mk_unit());
+
+        fcx.resume_yield_tys = Some((resume_ty, yield_ty));
+    }
+
+    let outer_def_id = tcx.closure_base_def_id(hir.local_def_id(fn_id).to_def_id()).expect_local();
+    let outer_hir_id = hir.local_def_id_to_hir_id(outer_def_id);
+    GatherLocalsVisitor::new(&fcx, outer_hir_id).visit_body(body);
+
+    // C-variadic fns also have a `VaList` input that's not listed in `fn_sig`
+    // (as it's created inside the body itself, not passed in from outside).
+    let maybe_va_list = if fn_sig.c_variadic {
+        let span = body.params.last().unwrap().span;
+        let va_list_did = tcx.require_lang_item(LangItem::VaList, Some(span));
+        let region = fcx.next_region_var(RegionVariableOrigin::MiscVariable(span));
+
+        Some(tcx.type_of(va_list_did).subst(tcx, &[region.into()]))
+    } else {
+        None
+    };
+
+    // Add formal parameters.
+    let inputs_hir = hir.fn_decl_by_hir_id(fn_id).map(|decl| &decl.inputs);
+    let inputs_fn = fn_sig.inputs().iter().copied();
+    for (idx, (param_ty, param)) in inputs_fn.chain(maybe_va_list).zip(body.params).enumerate() {
+        // Check the pattern.
+        let ty_span = try { inputs_hir?.get(idx)?.span };
+        fcx.check_pat_top(&param.pat, param_ty, ty_span, false);
+
+        // Check that argument is Sized.
+        // The check for a non-trivial pattern is a hack to avoid duplicate warnings
+        // for simple cases like `fn foo(x: Trait)`,
+        // where we would error once on the parameter as a whole, and once on the binding `x`.
+        if param.pat.simple_ident().is_none() && !tcx.features().unsized_locals {
+            fcx.require_type_is_sized(param_ty, param.pat.span, traits::SizedArgumentType(ty_span));
+        }
+
+        fcx.write_ty(param.hir_id, param_ty);
+    }
+
+    inherited.typeck_results.borrow_mut().liberated_fn_sigs_mut().insert(fn_id, fn_sig);
+
+    fcx.in_tail_expr = true;
+    if let ty::Dynamic(..) = declared_ret_ty.kind() {
+        // FIXME: We need to verify that the return type is `Sized` after the return expression has
+        // been evaluated so that we have types available for all the nodes being returned, but that
+        // requires the coerced evaluated type to be stored. Moving `check_return_expr` before this
+        // causes unsized errors caused by the `declared_ret_ty` to point at the return expression,
+        // while keeping the current ordering we will ignore the tail expression's type because we
+        // don't know it yet. We can't do `check_expr_kind` while keeping `check_return_expr`
+        // because we will trigger "unreachable expression" lints unconditionally.
+        // Because of all of this, we perform a crude check to know whether the simplest `!Sized`
+        // case that a newcomer might make, returning a bare trait, and in that case we populate
+        // the tail expression's type so that the suggestion will be correct, but ignore all other
+        // possible cases.
+        fcx.check_expr(&body.value);
+        fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType);
+        tcx.sess.delay_span_bug(decl.output.span(), "`!Sized` return type");
+    } else {
+        fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType);
+        fcx.check_return_expr(&body.value);
+    }
+    fcx.in_tail_expr = false;
+
+    // We insert the deferred_generator_interiors entry after visiting the body.
+    // This ensures that all nested generators appear before the entry of this generator.
+    // resolve_generator_interiors relies on this property.
+    let gen_ty = if let (Some(_), Some(gen_kind)) = (can_be_generator, body.generator_kind) {
+        let interior = fcx
+            .next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::MiscVariable, span });
+        fcx.deferred_generator_interiors.borrow_mut().push((body.id(), interior, gen_kind));
+
+        let (resume_ty, yield_ty) = fcx.resume_yield_tys.unwrap();
+        Some(GeneratorTypes {
+            resume_ty,
+            yield_ty,
+            interior,
+            movability: can_be_generator.unwrap(),
+        })
+    } else {
+        None
+    };
+
+    // Finalize the return check by taking the LUB of the return types
+    // we saw and assigning it to the expected return type. This isn't
+    // really expected to fail, since the coercions would have failed
+    // earlier when trying to find a LUB.
+    //
+    // However, the behavior around `!` is sort of complex. In the
+    // event that the `actual_return_ty` comes back as `!`, that
+    // indicates that the fn either does not return or "returns" only
+    // values of type `!`. In this case, if there is an expected
+    // return type that is *not* `!`, that should be ok. But if the
+    // return type is being inferred, we want to "fallback" to `!`:
+    //
+    //     let x = move || panic!();
+    //
+    // To allow for that, I am creating a type variable with diverging
+    // fallback. This was deemed ever so slightly better than unifying
+    // the return value with `!` because it allows for the caller to
+    // make more assumptions about the return type (e.g., they could do
+    //
+    //     let y: Option<u32> = Some(x());
+    //
+    // which would then cause this return type to become `u32`, not
+    // `!`).
+    let coercion = fcx.ret_coercion.take().unwrap().into_inner();
+    let mut actual_return_ty = coercion.complete(&fcx);
+    if actual_return_ty.is_never() {
+        actual_return_ty = fcx.next_diverging_ty_var(TypeVariableOrigin {
+            kind: TypeVariableOriginKind::DivergingFn,
+            span,
+        });
+    }
+    fcx.demand_suptype(span, revealed_ret_ty, actual_return_ty);
+
+    // Check that the main return type implements the termination trait.
+    if let Some(term_id) = tcx.lang_items().termination() {
+        if let Some((def_id, EntryFnType::Main)) = tcx.entry_fn(LOCAL_CRATE) {
+            let main_id = hir.local_def_id_to_hir_id(def_id);
+            if main_id == fn_id {
+                let substs = tcx.mk_substs_trait(declared_ret_ty, &[]);
+                let trait_ref = ty::TraitRef::new(term_id, substs);
+                let return_ty_span = decl.output.span();
+                let cause = traits::ObligationCause::new(
+                    return_ty_span,
+                    fn_id,
+                    ObligationCauseCode::MainFunctionType,
+                );
+
+                inherited.register_predicate(traits::Obligation::new(
+                    cause,
+                    param_env,
+                    trait_ref.without_const().to_predicate(tcx),
+                ));
+            }
+        }
+    }
+
+    // Check that a function marked as `#[panic_handler]` has signature `fn(&PanicInfo) -> !`
+    if let Some(panic_impl_did) = tcx.lang_items().panic_impl() {
+        if panic_impl_did == hir.local_def_id(fn_id).to_def_id() {
+            if let Some(panic_info_did) = tcx.lang_items().panic_info() {
+                if *declared_ret_ty.kind() != ty::Never {
+                    sess.span_err(decl.output.span(), "return type should be `!`");
+                }
+
+                let inputs = fn_sig.inputs();
+                let span = hir.span(fn_id);
+                if inputs.len() == 1 {
+                    let arg_is_panic_info = match *inputs[0].kind() {
+                        ty::Ref(region, ty, mutbl) => match *ty.kind() {
+                            ty::Adt(ref adt, _) => {
+                                adt.did == panic_info_did
+                                    && mutbl == hir::Mutability::Not
+                                    && *region != RegionKind::ReStatic
+                            }
+                            _ => false,
+                        },
+                        _ => false,
+                    };
+
+                    if !arg_is_panic_info {
+                        sess.span_err(decl.inputs[0].span, "argument should be `&PanicInfo`");
+                    }
+
+                    if let Node::Item(item) = hir.get(fn_id) {
+                        if let ItemKind::Fn(_, ref generics, _) = item.kind {
+                            if !generics.params.is_empty() {
+                                sess.span_err(span, "should have no type parameters");
+                            }
+                        }
+                    }
+                } else {
+                    let span = sess.source_map().guess_head_span(span);
+                    sess.span_err(span, "function should have one argument");
+                }
+            } else {
+                sess.err("language item required, but not found: `panic_info`");
+            }
+        }
+    }
+
+    // Check that a function marked as `#[alloc_error_handler]` has signature `fn(Layout) -> !`
+    if let Some(alloc_error_handler_did) = tcx.lang_items().oom() {
+        if alloc_error_handler_did == hir.local_def_id(fn_id).to_def_id() {
+            if let Some(alloc_layout_did) = tcx.lang_items().alloc_layout() {
+                if *declared_ret_ty.kind() != ty::Never {
+                    sess.span_err(decl.output.span(), "return type should be `!`");
+                }
+
+                let inputs = fn_sig.inputs();
+                let span = hir.span(fn_id);
+                if inputs.len() == 1 {
+                    let arg_is_alloc_layout = match inputs[0].kind() {
+                        ty::Adt(ref adt, _) => adt.did == alloc_layout_did,
+                        _ => false,
+                    };
+
+                    if !arg_is_alloc_layout {
+                        sess.span_err(decl.inputs[0].span, "argument should be `Layout`");
+                    }
+
+                    if let Node::Item(item) = hir.get(fn_id) {
+                        if let ItemKind::Fn(_, ref generics, _) = item.kind {
+                            if !generics.params.is_empty() {
+                                sess.span_err(
+                                    span,
+                                    "`#[alloc_error_handler]` function should have no type \
+                                     parameters",
+                                );
+                            }
+                        }
+                    }
+                } else {
+                    let span = sess.source_map().guess_head_span(span);
+                    sess.span_err(span, "function should have one argument");
+                }
+            } else {
+                sess.err("language item required, but not found: `alloc_layout`");
+            }
+        }
+    }
+
+    (fcx, gen_ty)
+}
+
+pub(super) fn check_struct(tcx: TyCtxt<'_>, id: hir::HirId, span: Span) {
+    let def_id = tcx.hir().local_def_id(id);
+    let def = tcx.adt_def(def_id);
+    def.destructor(tcx); // force the destructor to be evaluated
+    check_representable(tcx, span, def_id);
+
+    if def.repr.simd() {
+        check_simd(tcx, span, def_id);
+    }
+
+    check_transparent(tcx, span, def);
+    check_packed(tcx, span, def);
+}
+
+pub(super) fn check_union(tcx: TyCtxt<'_>, id: hir::HirId, span: Span) {
+    let def_id = tcx.hir().local_def_id(id);
+    let def = tcx.adt_def(def_id);
+    def.destructor(tcx); // force the destructor to be evaluated
+    check_representable(tcx, span, def_id);
+    check_transparent(tcx, span, def);
+    check_union_fields(tcx, span, def_id);
+    check_packed(tcx, span, def);
+}
+
+/// When the `#![feature(untagged_unions)]` gate is active,
+/// check that the fields of the `union` does not contain fields that need dropping.
+pub(super) fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> bool {
+    let item_type = tcx.type_of(item_def_id);
+    if let ty::Adt(def, substs) = item_type.kind() {
+        assert!(def.is_union());
+        let fields = &def.non_enum_variant().fields;
+        let param_env = tcx.param_env(item_def_id);
+        for field in fields {
+            let field_ty = field.ty(tcx, substs);
+            // We are currently checking the type this field came from, so it must be local.
+            let field_span = tcx.hir().span_if_local(field.did).unwrap();
+            if field_ty.needs_drop(tcx, param_env) {
+                struct_span_err!(
+                    tcx.sess,
+                    field_span,
+                    E0740,
+                    "unions may not contain fields that need dropping"
+                )
+                .span_note(field_span, "`std::mem::ManuallyDrop` can be used to wrap the type")
+                .emit();
+                return false;
+            }
+        }
+    } else {
+        span_bug!(span, "unions must be ty::Adt, but got {:?}", item_type.kind());
+    }
+    true
+}
+
+/// Checks that an opaque type does not contain cycles and does not use `Self` or `T::Foo`
+/// projections that would result in "inheriting lifetimes".
+pub(super) fn check_opaque<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    def_id: LocalDefId,
+    substs: SubstsRef<'tcx>,
+    span: Span,
+    origin: &hir::OpaqueTyOrigin,
+) {
+    check_opaque_for_inheriting_lifetimes(tcx, def_id, span);
+    check_opaque_for_cycles(tcx, def_id, substs, span, origin);
+}
+
+/// Checks that an opaque type does not use `Self` or `T::Foo` projections that would result
+/// in "inheriting lifetimes".
+pub(super) fn check_opaque_for_inheriting_lifetimes(
+    tcx: TyCtxt<'tcx>,
+    def_id: LocalDefId,
+    span: Span,
+) {
+    let item = tcx.hir().expect_item(tcx.hir().local_def_id_to_hir_id(def_id));
+    debug!(
+        "check_opaque_for_inheriting_lifetimes: def_id={:?} span={:?} item={:?}",
+        def_id, span, item
+    );
+
+    #[derive(Debug)]
+    struct ProhibitOpaqueVisitor<'tcx> {
+        opaque_identity_ty: Ty<'tcx>,
+        generics: &'tcx ty::Generics,
+        ty: Option<Ty<'tcx>>,
+    };
+
+    impl<'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueVisitor<'tcx> {
+        fn visit_ty(&mut self, t: Ty<'tcx>) -> bool {
+            debug!("check_opaque_for_inheriting_lifetimes: (visit_ty) t={:?}", t);
+            if t != self.opaque_identity_ty && t.super_visit_with(self) {
+                self.ty = Some(t);
+                return true;
+            }
+            false
+        }
+
+        fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool {
+            debug!("check_opaque_for_inheriting_lifetimes: (visit_region) r={:?}", r);
+            if let RegionKind::ReEarlyBound(ty::EarlyBoundRegion { index, .. }) = r {
+                return *index < self.generics.parent_count as u32;
+            }
+
+            r.super_visit_with(self)
+        }
+
+        fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> bool {
+            if let ty::ConstKind::Unevaluated(..) = c.val {
+                // FIXME(#72219) We currenctly don't detect lifetimes within substs
+                // which would violate this check. Even though the particular substitution is not used
+                // within the const, this should still be fixed.
+                return false;
+            }
+            c.super_visit_with(self)
+        }
+    }
+
+    if let ItemKind::OpaqueTy(hir::OpaqueTy {
+        origin: hir::OpaqueTyOrigin::AsyncFn | hir::OpaqueTyOrigin::FnReturn,
+        ..
+    }) = item.kind
+    {
+        let mut visitor = ProhibitOpaqueVisitor {
+            opaque_identity_ty: tcx.mk_opaque(
+                def_id.to_def_id(),
+                InternalSubsts::identity_for_item(tcx, def_id.to_def_id()),
+            ),
+            generics: tcx.generics_of(def_id),
+            ty: None,
+        };
+        let prohibit_opaque = tcx
+            .predicates_of(def_id)
+            .predicates
+            .iter()
+            .any(|(predicate, _)| predicate.visit_with(&mut visitor));
+        debug!(
+            "check_opaque_for_inheriting_lifetimes: prohibit_opaque={:?}, visitor={:?}",
+            prohibit_opaque, visitor
+        );
+
+        if prohibit_opaque {
+            let is_async = match item.kind {
+                ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => match origin {
+                    hir::OpaqueTyOrigin::AsyncFn => true,
+                    _ => false,
+                },
+                _ => unreachable!(),
+            };
+
+            let mut err = struct_span_err!(
+                tcx.sess,
+                span,
+                E0760,
+                "`{}` return type cannot contain a projection or `Self` that references lifetimes from \
+             a parent scope",
+                if is_async { "async fn" } else { "impl Trait" },
+            );
+
+            if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(span) {
+                if snippet == "Self" {
+                    if let Some(ty) = visitor.ty {
+                        err.span_suggestion(
+                            span,
+                            "consider spelling out the type instead",
+                            format!("{:?}", ty),
+                            Applicability::MaybeIncorrect,
+                        );
+                    }
+                }
+            }
+            err.emit();
+        }
+    }
+}
+
+/// Checks that an opaque type does not contain cycles.
+pub(super) fn check_opaque_for_cycles<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    def_id: LocalDefId,
+    substs: SubstsRef<'tcx>,
+    span: Span,
+    origin: &hir::OpaqueTyOrigin,
+) {
+    if let Err(partially_expanded_type) = tcx.try_expand_impl_trait_type(def_id.to_def_id(), substs)
+    {
+        match origin {
+            hir::OpaqueTyOrigin::AsyncFn => async_opaque_type_cycle_error(tcx, span),
+            hir::OpaqueTyOrigin::Binding => {
+                binding_opaque_type_cycle_error(tcx, def_id, span, partially_expanded_type)
+            }
+            _ => opaque_type_cycle_error(tcx, def_id, span),
+        }
+    }
+}
+
+pub fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, it: &'tcx hir::Item<'tcx>) {
+    debug!(
+        "check_item_type(it.hir_id={}, it.name={})",
+        it.hir_id,
+        tcx.def_path_str(tcx.hir().local_def_id(it.hir_id).to_def_id())
+    );
+    let _indenter = indenter();
+    match it.kind {
+        // Consts can play a role in type-checking, so they are included here.
+        hir::ItemKind::Static(..) => {
+            let def_id = tcx.hir().local_def_id(it.hir_id);
+            tcx.ensure().typeck(def_id);
+            maybe_check_static_with_link_section(tcx, def_id, it.span);
+        }
+        hir::ItemKind::Const(..) => {
+            tcx.ensure().typeck(tcx.hir().local_def_id(it.hir_id));
+        }
+        hir::ItemKind::Enum(ref enum_definition, _) => {
+            check_enum(tcx, it.span, &enum_definition.variants, it.hir_id);
+        }
+        hir::ItemKind::Fn(..) => {} // entirely within check_item_body
+        hir::ItemKind::Impl { ref items, .. } => {
+            debug!("ItemKind::Impl {} with id {}", it.ident, it.hir_id);
+            let impl_def_id = tcx.hir().local_def_id(it.hir_id);
+            if let Some(impl_trait_ref) = tcx.impl_trait_ref(impl_def_id) {
+                check_impl_items_against_trait(tcx, it.span, impl_def_id, impl_trait_ref, items);
+                let trait_def_id = impl_trait_ref.def_id;
+                check_on_unimplemented(tcx, trait_def_id, it);
+            }
+        }
+        hir::ItemKind::Trait(_, _, _, _, ref items) => {
+            let def_id = tcx.hir().local_def_id(it.hir_id);
+            check_on_unimplemented(tcx, def_id.to_def_id(), it);
+
+            for item in items.iter() {
+                let item = tcx.hir().trait_item(item.id);
+                if let hir::TraitItemKind::Fn(sig, _) = &item.kind {
+                    let abi = sig.header.abi;
+                    fn_maybe_err(tcx, item.ident.span, abi);
+                }
+            }
+        }
+        hir::ItemKind::Struct(..) => {
+            check_struct(tcx, it.hir_id, it.span);
+        }
+        hir::ItemKind::Union(..) => {
+            check_union(tcx, it.hir_id, it.span);
+        }
+        hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => {
+            // HACK(jynelson): trying to infer the type of `impl trait` breaks documenting
+            // `async-std` (and `pub async fn` in general).
+            // Since rustdoc doesn't care about the concrete type behind `impl Trait`, just don't look at it!
+            // See https://github.com/rust-lang/rust/issues/75100
+            if !tcx.sess.opts.actually_rustdoc {
+                let def_id = tcx.hir().local_def_id(it.hir_id);
+
+                let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
+                check_opaque(tcx, def_id, substs, it.span, &origin);
+            }
+        }
+        hir::ItemKind::TyAlias(..) => {
+            let def_id = tcx.hir().local_def_id(it.hir_id);
+            let pty_ty = tcx.type_of(def_id);
+            let generics = tcx.generics_of(def_id);
+            check_type_params_are_used(tcx, &generics, pty_ty);
+        }
+        hir::ItemKind::ForeignMod(ref m) => {
+            check_abi(tcx, it.span, m.abi);
+
+            if m.abi == Abi::RustIntrinsic {
+                for item in m.items {
+                    intrinsic::check_intrinsic_type(tcx, item);
+                }
+            } else if m.abi == Abi::PlatformIntrinsic {
+                for item in m.items {
+                    intrinsic::check_platform_intrinsic_type(tcx, item);
+                }
+            } else {
+                for item in m.items {
+                    let generics = tcx.generics_of(tcx.hir().local_def_id(item.hir_id));
+                    let own_counts = generics.own_counts();
+                    if generics.params.len() - own_counts.lifetimes != 0 {
+                        let (kinds, kinds_pl, egs) = match (own_counts.types, own_counts.consts) {
+                            (_, 0) => ("type", "types", Some("u32")),
+                            // We don't specify an example value, because we can't generate
+                            // a valid value for any type.
+                            (0, _) => ("const", "consts", None),
+                            _ => ("type or const", "types or consts", None),
+                        };
+                        struct_span_err!(
+                            tcx.sess,
+                            item.span,
+                            E0044,
+                            "foreign items may not have {} parameters",
+                            kinds,
+                        )
+                        .span_label(item.span, &format!("can't have {} parameters", kinds))
+                        .help(
+                            // FIXME: once we start storing spans for type arguments, turn this
+                            // into a suggestion.
+                            &format!(
+                                "replace the {} parameters with concrete {}{}",
+                                kinds,
+                                kinds_pl,
+                                egs.map(|egs| format!(" like `{}`", egs)).unwrap_or_default(),
+                            ),
+                        )
+                        .emit();
+                    }
+
+                    if let hir::ForeignItemKind::Fn(ref fn_decl, _, _) = item.kind {
+                        require_c_abi_if_c_variadic(tcx, fn_decl, m.abi, item.span);
+                    }
+                }
+            }
+        }
+        _ => { /* nothing to do */ }
+    }
+}
+
+pub(super) fn check_on_unimplemented(tcx: TyCtxt<'_>, trait_def_id: DefId, item: &hir::Item<'_>) {
+    let item_def_id = tcx.hir().local_def_id(item.hir_id);
+    // an error would be reported if this fails.
+    let _ = traits::OnUnimplementedDirective::of_item(tcx, trait_def_id, item_def_id.to_def_id());
+}
+
+pub(super) fn check_specialization_validity<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    trait_def: &ty::TraitDef,
+    trait_item: &ty::AssocItem,
+    impl_id: DefId,
+    impl_item: &hir::ImplItem<'_>,
+) {
+    let kind = match impl_item.kind {
+        hir::ImplItemKind::Const(..) => ty::AssocKind::Const,
+        hir::ImplItemKind::Fn(..) => ty::AssocKind::Fn,
+        hir::ImplItemKind::TyAlias(_) => ty::AssocKind::Type,
+    };
+
+    let ancestors = match trait_def.ancestors(tcx, impl_id) {
+        Ok(ancestors) => ancestors,
+        Err(_) => return,
+    };
+    let mut ancestor_impls = ancestors
+        .skip(1)
+        .filter_map(|parent| {
+            if parent.is_from_trait() {
+                None
+            } else {
+                Some((parent, parent.item(tcx, trait_item.ident, kind, trait_def.def_id)))
+            }
+        })
+        .peekable();
+
+    if ancestor_impls.peek().is_none() {
+        // No parent, nothing to specialize.
+        return;
+    }
+
+    let opt_result = ancestor_impls.find_map(|(parent_impl, parent_item)| {
+        match parent_item {
+            // Parent impl exists, and contains the parent item we're trying to specialize, but
+            // doesn't mark it `default`.
+            Some(parent_item) if traits::impl_item_is_final(tcx, &parent_item) => {
+                Some(Err(parent_impl.def_id()))
+            }
+
+            // Parent impl contains item and makes it specializable.
+            Some(_) => Some(Ok(())),
+
+            // Parent impl doesn't mention the item. This means it's inherited from the
+            // grandparent. In that case, if parent is a `default impl`, inherited items use the
+            // "defaultness" from the grandparent, else they are final.
+            None => {
+                if tcx.impl_defaultness(parent_impl.def_id()).is_default() {
+                    None
+                } else {
+                    Some(Err(parent_impl.def_id()))
+                }
+            }
+        }
+    });
+
+    // If `opt_result` is `None`, we have only encountered `default impl`s that don't contain the
+    // item. This is allowed, the item isn't actually getting specialized here.
+    let result = opt_result.unwrap_or(Ok(()));
+
+    if let Err(parent_impl) = result {
+        report_forbidden_specialization(tcx, impl_item, parent_impl);
+    }
+}
+
+pub(super) fn check_impl_items_against_trait<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    full_impl_span: Span,
+    impl_id: LocalDefId,
+    impl_trait_ref: ty::TraitRef<'tcx>,
+    impl_item_refs: &[hir::ImplItemRef<'_>],
+) {
+    let impl_span = tcx.sess.source_map().guess_head_span(full_impl_span);
+
+    // If the trait reference itself is erroneous (so the compilation is going
+    // to fail), skip checking the items here -- the `impl_item` table in `tcx`
+    // isn't populated for such impls.
+    if impl_trait_ref.references_error() {
+        return;
+    }
+
+    // Negative impls are not expected to have any items
+    match tcx.impl_polarity(impl_id) {
+        ty::ImplPolarity::Reservation | ty::ImplPolarity::Positive => {}
+        ty::ImplPolarity::Negative => {
+            if let [first_item_ref, ..] = impl_item_refs {
+                let first_item_span = tcx.hir().impl_item(first_item_ref.id).span;
+                struct_span_err!(
+                    tcx.sess,
+                    first_item_span,
+                    E0749,
+                    "negative impls cannot have any items"
+                )
+                .emit();
+            }
+            return;
+        }
+    }
+
+    // Locate trait definition and items
+    let trait_def = tcx.trait_def(impl_trait_ref.def_id);
+
+    let impl_items = || impl_item_refs.iter().map(|iiref| tcx.hir().impl_item(iiref.id));
+
+    // Check existing impl methods to see if they are both present in trait
+    // and compatible with trait signature
+    for impl_item in impl_items() {
+        let namespace = impl_item.kind.namespace();
+        let ty_impl_item = tcx.associated_item(tcx.hir().local_def_id(impl_item.hir_id));
+        let ty_trait_item = tcx
+            .associated_items(impl_trait_ref.def_id)
+            .find_by_name_and_namespace(tcx, ty_impl_item.ident, namespace, impl_trait_ref.def_id)
+            .or_else(|| {
+                // Not compatible, but needed for the error message
+                tcx.associated_items(impl_trait_ref.def_id)
+                    .filter_by_name(tcx, ty_impl_item.ident, impl_trait_ref.def_id)
+                    .next()
+            });
+
+        // Check that impl definition matches trait definition
+        if let Some(ty_trait_item) = ty_trait_item {
+            match impl_item.kind {
+                hir::ImplItemKind::Const(..) => {
+                    // Find associated const definition.
+                    if ty_trait_item.kind == ty::AssocKind::Const {
+                        compare_const_impl(
+                            tcx,
+                            &ty_impl_item,
+                            impl_item.span,
+                            &ty_trait_item,
+                            impl_trait_ref,
+                        );
+                    } else {
+                        let mut err = struct_span_err!(
+                            tcx.sess,
+                            impl_item.span,
+                            E0323,
+                            "item `{}` is an associated const, \
+                             which doesn't match its trait `{}`",
+                            ty_impl_item.ident,
+                            impl_trait_ref.print_only_trait_path()
+                        );
+                        err.span_label(impl_item.span, "does not match trait");
+                        // We can only get the spans from local trait definition
+                        // Same for E0324 and E0325
+                        if let Some(trait_span) = tcx.hir().span_if_local(ty_trait_item.def_id) {
+                            err.span_label(trait_span, "item in trait");
+                        }
+                        err.emit()
+                    }
+                }
+                hir::ImplItemKind::Fn(..) => {
+                    let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id);
+                    if ty_trait_item.kind == ty::AssocKind::Fn {
+                        compare_impl_method(
+                            tcx,
+                            &ty_impl_item,
+                            impl_item.span,
+                            &ty_trait_item,
+                            impl_trait_ref,
+                            opt_trait_span,
+                        );
+                    } else {
+                        let mut err = struct_span_err!(
+                            tcx.sess,
+                            impl_item.span,
+                            E0324,
+                            "item `{}` is an associated method, \
+                             which doesn't match its trait `{}`",
+                            ty_impl_item.ident,
+                            impl_trait_ref.print_only_trait_path()
+                        );
+                        err.span_label(impl_item.span, "does not match trait");
+                        if let Some(trait_span) = opt_trait_span {
+                            err.span_label(trait_span, "item in trait");
+                        }
+                        err.emit()
+                    }
+                }
+                hir::ImplItemKind::TyAlias(_) => {
+                    let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id);
+                    if ty_trait_item.kind == ty::AssocKind::Type {
+                        compare_ty_impl(
+                            tcx,
+                            &ty_impl_item,
+                            impl_item.span,
+                            &ty_trait_item,
+                            impl_trait_ref,
+                            opt_trait_span,
+                        );
+                    } else {
+                        let mut err = struct_span_err!(
+                            tcx.sess,
+                            impl_item.span,
+                            E0325,
+                            "item `{}` is an associated type, \
+                             which doesn't match its trait `{}`",
+                            ty_impl_item.ident,
+                            impl_trait_ref.print_only_trait_path()
+                        );
+                        err.span_label(impl_item.span, "does not match trait");
+                        if let Some(trait_span) = opt_trait_span {
+                            err.span_label(trait_span, "item in trait");
+                        }
+                        err.emit()
+                    }
+                }
+            }
+
+            check_specialization_validity(
+                tcx,
+                trait_def,
+                &ty_trait_item,
+                impl_id.to_def_id(),
+                impl_item,
+            );
+        }
+    }
+
+    // Check for missing items from trait
+    let mut missing_items = Vec::new();
+    if let Ok(ancestors) = trait_def.ancestors(tcx, impl_id.to_def_id()) {
+        for trait_item in tcx.associated_items(impl_trait_ref.def_id).in_definition_order() {
+            let is_implemented = ancestors
+                .leaf_def(tcx, trait_item.ident, trait_item.kind)
+                .map(|node_item| !node_item.defining_node.is_from_trait())
+                .unwrap_or(false);
+
+            if !is_implemented && tcx.impl_defaultness(impl_id).is_final() {
+                if !trait_item.defaultness.has_value() {
+                    missing_items.push(*trait_item);
+                }
+            }
+        }
+    }
+
+    if !missing_items.is_empty() {
+        missing_items_err(tcx, impl_span, &missing_items, full_impl_span);
+    }
+}
+
+/// Checks whether a type can be represented in memory. In particular, it
+/// identifies types that contain themselves without indirection through a
+/// pointer, which would mean their size is unbounded.
+pub(super) fn check_representable(tcx: TyCtxt<'_>, sp: Span, item_def_id: LocalDefId) -> bool {
+    let rty = tcx.type_of(item_def_id);
+
+    // Check that it is possible to represent this type. This call identifies
+    // (1) types that contain themselves and (2) types that contain a different
+    // recursive type. It is only necessary to throw an error on those that
+    // contain themselves. For case 2, there must be an inner type that will be
+    // caught by case 1.
+    match rty.is_representable(tcx, sp) {
+        Representability::SelfRecursive(spans) => {
+            recursive_type_with_infinite_size_error(tcx, item_def_id.to_def_id(), spans);
+            return false;
+        }
+        Representability::Representable | Representability::ContainsRecursive => (),
+    }
+    true
+}
+
+pub fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) {
+    let t = tcx.type_of(def_id);
+    if let ty::Adt(def, substs) = t.kind() {
+        if def.is_struct() {
+            let fields = &def.non_enum_variant().fields;
+            if fields.is_empty() {
+                struct_span_err!(tcx.sess, sp, E0075, "SIMD vector cannot be empty").emit();
+                return;
+            }
+            let e = fields[0].ty(tcx, substs);
+            if !fields.iter().all(|f| f.ty(tcx, substs) == e) {
+                struct_span_err!(tcx.sess, sp, E0076, "SIMD vector should be homogeneous")
+                    .span_label(sp, "SIMD elements must have the same type")
+                    .emit();
+                return;
+            }
+            match e.kind() {
+                ty::Param(_) => { /* struct<T>(T, T, T, T) is ok */ }
+                _ if e.is_machine() => { /* struct(u8, u8, u8, u8) is ok */ }
+                _ => {
+                    struct_span_err!(
+                        tcx.sess,
+                        sp,
+                        E0077,
+                        "SIMD vector element type should be machine type"
+                    )
+                    .emit();
+                    return;
+                }
+            }
+        }
+    }
+}
+
+pub(super) fn check_packed(tcx: TyCtxt<'_>, sp: Span, def: &ty::AdtDef) {
+    let repr = def.repr;
+    if repr.packed() {
+        for attr in tcx.get_attrs(def.did).iter() {
+            for r in attr::find_repr_attrs(&tcx.sess, attr) {
+                if let attr::ReprPacked(pack) = r {
+                    if let Some(repr_pack) = repr.pack {
+                        if pack as u64 != repr_pack.bytes() {
+                            struct_span_err!(
+                                tcx.sess,
+                                sp,
+                                E0634,
+                                "type has conflicting packed representation hints"
+                            )
+                            .emit();
+                        }
+                    }
+                }
+            }
+        }
+        if repr.align.is_some() {
+            struct_span_err!(
+                tcx.sess,
+                sp,
+                E0587,
+                "type has conflicting packed and align representation hints"
+            )
+            .emit();
+        } else {
+            if let Some(def_spans) = check_packed_inner(tcx, def.did, &mut vec![]) {
+                let mut err = struct_span_err!(
+                    tcx.sess,
+                    sp,
+                    E0588,
+                    "packed type cannot transitively contain a `#[repr(align)]` type"
+                );
+
+                err.span_note(
+                    tcx.def_span(def_spans[0].0),
+                    &format!(
+                        "`{}` has a `#[repr(align)]` attribute",
+                        tcx.item_name(def_spans[0].0)
+                    ),
+                );
+
+                if def_spans.len() > 2 {
+                    let mut first = true;
+                    for (adt_def, span) in def_spans.iter().skip(1).rev() {
+                        let ident = tcx.item_name(*adt_def);
+                        err.span_note(
+                            *span,
+                            &if first {
+                                format!(
+                                    "`{}` contains a field of type `{}`",
+                                    tcx.type_of(def.did),
+                                    ident
+                                )
+                            } else {
+                                format!("...which contains a field of type `{}`", ident)
+                            },
+                        );
+                        first = false;
+                    }
+                }
+
+                err.emit();
+            }
+        }
+    }
+}
+
+pub(super) fn check_packed_inner(
+    tcx: TyCtxt<'_>,
+    def_id: DefId,
+    stack: &mut Vec<DefId>,
+) -> Option<Vec<(DefId, Span)>> {
+    if let ty::Adt(def, substs) = tcx.type_of(def_id).kind() {
+        if def.is_struct() || def.is_union() {
+            if def.repr.align.is_some() {
+                return Some(vec![(def.did, DUMMY_SP)]);
+            }
+
+            stack.push(def_id);
+            for field in &def.non_enum_variant().fields {
+                if let ty::Adt(def, _) = field.ty(tcx, substs).kind() {
+                    if !stack.contains(&def.did) {
+                        if let Some(mut defs) = check_packed_inner(tcx, def.did, stack) {
+                            defs.push((def.did, field.ident.span));
+                            return Some(defs);
+                        }
+                    }
+                }
+            }
+            stack.pop();
+        }
+    }
+
+    None
+}
+
+pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, adt: &'tcx ty::AdtDef) {
+    if !adt.repr.transparent() {
+        return;
+    }
+    let sp = tcx.sess.source_map().guess_head_span(sp);
+
+    if adt.is_union() && !tcx.features().transparent_unions {
+        feature_err(
+            &tcx.sess.parse_sess,
+            sym::transparent_unions,
+            sp,
+            "transparent unions are unstable",
+        )
+        .emit();
+    }
+
+    if adt.variants.len() != 1 {
+        bad_variant_count(tcx, adt, sp, adt.did);
+        if adt.variants.is_empty() {
+            // Don't bother checking the fields. No variants (and thus no fields) exist.
+            return;
+        }
+    }
+
+    // For each field, figure out if it's known to be a ZST and align(1)
+    let field_infos = adt.all_fields().map(|field| {
+        let ty = field.ty(tcx, InternalSubsts::identity_for_item(tcx, field.did));
+        let param_env = tcx.param_env(field.did);
+        let layout = tcx.layout_of(param_env.and(ty));
+        // We are currently checking the type this field came from, so it must be local
+        let span = tcx.hir().span_if_local(field.did).unwrap();
+        let zst = layout.map(|layout| layout.is_zst()).unwrap_or(false);
+        let align1 = layout.map(|layout| layout.align.abi.bytes() == 1).unwrap_or(false);
+        (span, zst, align1)
+    });
+
+    let non_zst_fields =
+        field_infos.clone().filter_map(|(span, zst, _align1)| if !zst { Some(span) } else { None });
+    let non_zst_count = non_zst_fields.clone().count();
+    if non_zst_count != 1 {
+        bad_non_zero_sized_fields(tcx, adt, non_zst_count, non_zst_fields, sp);
+    }
+    for (span, zst, align1) in field_infos {
+        if zst && !align1 {
+            struct_span_err!(
+                tcx.sess,
+                span,
+                E0691,
+                "zero-sized field in transparent {} has alignment larger than 1",
+                adt.descr(),
+            )
+            .span_label(span, "has alignment larger than 1")
+            .emit();
+        }
+    }
+}
+
+#[allow(trivial_numeric_casts)]
+pub fn check_enum<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    sp: Span,
+    vs: &'tcx [hir::Variant<'tcx>],
+    id: hir::HirId,
+) {
+    let def_id = tcx.hir().local_def_id(id);
+    let def = tcx.adt_def(def_id);
+    def.destructor(tcx); // force the destructor to be evaluated
+
+    if vs.is_empty() {
+        let attributes = tcx.get_attrs(def_id.to_def_id());
+        if let Some(attr) = tcx.sess.find_by_name(&attributes, sym::repr) {
+            struct_span_err!(
+                tcx.sess,
+                attr.span,
+                E0084,
+                "unsupported representation for zero-variant enum"
+            )
+            .span_label(sp, "zero-variant enum")
+            .emit();
+        }
+    }
+
+    let repr_type_ty = def.repr.discr_type().to_ty(tcx);
+    if repr_type_ty == tcx.types.i128 || repr_type_ty == tcx.types.u128 {
+        if !tcx.features().repr128 {
+            feature_err(
+                &tcx.sess.parse_sess,
+                sym::repr128,
+                sp,
+                "repr with 128-bit type is unstable",
+            )
+            .emit();
+        }
+    }
+
+    for v in vs {
+        if let Some(ref e) = v.disr_expr {
+            tcx.ensure().typeck(tcx.hir().local_def_id(e.hir_id));
+        }
+    }
+
+    if tcx.adt_def(def_id).repr.int.is_none() && tcx.features().arbitrary_enum_discriminant {
+        let is_unit = |var: &hir::Variant<'_>| match var.data {
+            hir::VariantData::Unit(..) => true,
+            _ => false,
+        };
+
+        let has_disr = |var: &hir::Variant<'_>| var.disr_expr.is_some();
+        let has_non_units = vs.iter().any(|var| !is_unit(var));
+        let disr_units = vs.iter().any(|var| is_unit(&var) && has_disr(&var));
+        let disr_non_unit = vs.iter().any(|var| !is_unit(&var) && has_disr(&var));
+
+        if disr_non_unit || (disr_units && has_non_units) {
+            let mut err =
+                struct_span_err!(tcx.sess, sp, E0732, "`#[repr(inttype)]` must be specified");
+            err.emit();
+        }
+    }
+
+    let mut disr_vals: Vec<Discr<'tcx>> = Vec::with_capacity(vs.len());
+    for ((_, discr), v) in def.discriminants(tcx).zip(vs) {
+        // Check for duplicate discriminant values
+        if let Some(i) = disr_vals.iter().position(|&x| x.val == discr.val) {
+            let variant_did = def.variants[VariantIdx::new(i)].def_id;
+            let variant_i_hir_id = tcx.hir().local_def_id_to_hir_id(variant_did.expect_local());
+            let variant_i = tcx.hir().expect_variant(variant_i_hir_id);
+            let i_span = match variant_i.disr_expr {
+                Some(ref expr) => tcx.hir().span(expr.hir_id),
+                None => tcx.hir().span(variant_i_hir_id),
+            };
+            let span = match v.disr_expr {
+                Some(ref expr) => tcx.hir().span(expr.hir_id),
+                None => v.span,
+            };
+            struct_span_err!(
+                tcx.sess,
+                span,
+                E0081,
+                "discriminant value `{}` already exists",
+                disr_vals[i]
+            )
+            .span_label(i_span, format!("first use of `{}`", disr_vals[i]))
+            .span_label(span, format!("enum already has `{}`", disr_vals[i]))
+            .emit();
+        }
+        disr_vals.push(discr);
+    }
+
+    check_representable(tcx, sp, def_id);
+    check_transparent(tcx, sp, def);
+}
+
+pub(super) fn check_type_params_are_used<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    generics: &ty::Generics,
+    ty: Ty<'tcx>,
+) {
+    debug!("check_type_params_are_used(generics={:?}, ty={:?})", generics, ty);
+
+    assert_eq!(generics.parent, None);
+
+    if generics.own_counts().types == 0 {
+        return;
+    }
+
+    let mut params_used = BitSet::new_empty(generics.params.len());
+
+    if ty.references_error() {
+        // If there is already another error, do not emit
+        // an error for not using a type parameter.
+        assert!(tcx.sess.has_errors());
+        return;
+    }
+
+    for leaf in ty.walk() {
+        if let GenericArgKind::Type(leaf_ty) = leaf.unpack() {
+            if let ty::Param(param) = leaf_ty.kind() {
+                debug!("found use of ty param {:?}", param);
+                params_used.insert(param.index);
+            }
+        }
+    }
+
+    for param in &generics.params {
+        if !params_used.contains(param.index) {
+            if let ty::GenericParamDefKind::Type { .. } = param.kind {
+                let span = tcx.def_span(param.def_id);
+                struct_span_err!(
+                    tcx.sess,
+                    span,
+                    E0091,
+                    "type parameter `{}` is unused",
+                    param.name,
+                )
+                .span_label(span, "unused type parameter")
+                .emit();
+            }
+        }
+    }
+}
+
+pub(super) fn check_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
+    tcx.hir().visit_item_likes_in_module(module_def_id, &mut CheckItemTypesVisitor { tcx });
+}
+
+pub(super) fn check_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) {
+    wfcheck::check_item_well_formed(tcx, def_id);
+}
+
+pub(super) fn check_trait_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) {
+    wfcheck::check_trait_item(tcx, def_id);
+}
+
+pub(super) fn check_impl_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) {
+    wfcheck::check_impl_item(tcx, def_id);
+}
+
+fn async_opaque_type_cycle_error(tcx: TyCtxt<'tcx>, span: Span) {
+    struct_span_err!(tcx.sess, span, E0733, "recursion in an `async fn` requires boxing")
+        .span_label(span, "recursive `async fn`")
+        .note("a recursive `async fn` must be rewritten to return a boxed `dyn Future`")
+        .emit();
+}
+
+/// Emit an error for recursive opaque types.
+///
+/// If this is a return `impl Trait`, find the item's return expressions and point at them. For
+/// direct recursion this is enough, but for indirect recursion also point at the last intermediary
+/// `impl Trait`.
+///
+/// If all the return expressions evaluate to `!`, then we explain that the error will go away
+/// after changing it. This can happen when a user uses `panic!()` or similar as a placeholder.
+fn opaque_type_cycle_error(tcx: TyCtxt<'tcx>, def_id: LocalDefId, span: Span) {
+    let mut err = struct_span_err!(tcx.sess, span, E0720, "cannot resolve opaque type");
+
+    let mut label = false;
+    if let Some((hir_id, visitor)) = get_owner_return_paths(tcx, def_id) {
+        let typeck_results = tcx.typeck(tcx.hir().local_def_id(hir_id));
+        if visitor
+            .returns
+            .iter()
+            .filter_map(|expr| typeck_results.node_type_opt(expr.hir_id))
+            .all(|ty| matches!(ty.kind(), ty::Never))
+        {
+            let spans = visitor
+                .returns
+                .iter()
+                .filter(|expr| typeck_results.node_type_opt(expr.hir_id).is_some())
+                .map(|expr| expr.span)
+                .collect::<Vec<Span>>();
+            let span_len = spans.len();
+            if span_len == 1 {
+                err.span_label(spans[0], "this returned value is of `!` type");
+            } else {
+                let mut multispan: MultiSpan = spans.clone().into();
+                for span in spans {
+                    multispan
+                        .push_span_label(span, "this returned value is of `!` type".to_string());
+                }
+                err.span_note(multispan, "these returned values have a concrete \"never\" type");
+            }
+            err.help("this error will resolve once the item's body returns a concrete type");
+        } else {
+            let mut seen = FxHashSet::default();
+            seen.insert(span);
+            err.span_label(span, "recursive opaque type");
+            label = true;
+            for (sp, ty) in visitor
+                .returns
+                .iter()
+                .filter_map(|e| typeck_results.node_type_opt(e.hir_id).map(|t| (e.span, t)))
+                .filter(|(_, ty)| !matches!(ty.kind(), ty::Never))
+            {
+                struct VisitTypes(Vec<DefId>);
+                impl<'tcx> ty::fold::TypeVisitor<'tcx> for VisitTypes {
+                    fn visit_ty(&mut self, t: Ty<'tcx>) -> bool {
+                        match *t.kind() {
+                            ty::Opaque(def, _) => {
+                                self.0.push(def);
+                                false
+                            }
+                            _ => t.super_visit_with(self),
+                        }
+                    }
+                }
+                let mut visitor = VisitTypes(vec![]);
+                ty.visit_with(&mut visitor);
+                for def_id in visitor.0 {
+                    let ty_span = tcx.def_span(def_id);
+                    if !seen.contains(&ty_span) {
+                        err.span_label(ty_span, &format!("returning this opaque type `{}`", ty));
+                        seen.insert(ty_span);
+                    }
+                    err.span_label(sp, &format!("returning here with type `{}`", ty));
+                }
+            }
+        }
+    }
+    if !label {
+        err.span_label(span, "cannot resolve opaque type");
+    }
+    err.emit();
+}
diff --git a/compiler/rustc_typeck/src/check/diverges.rs b/compiler/rustc_typeck/src/check/diverges.rs
new file mode 100644
index 00000000000..963a93a95c2
--- /dev/null
+++ b/compiler/rustc_typeck/src/check/diverges.rs
@@ -0,0 +1,78 @@
+use rustc_span::source_map::DUMMY_SP;
+use rustc_span::{self, Span};
+use std::{cmp, ops};
+
+/// Tracks whether executing a node may exit normally (versus
+/// return/break/panic, which "diverge", leaving dead code in their
+/// wake). Tracked semi-automatically (through type variables marked
+/// as diverging), with some manual adjustments for control-flow
+/// primitives (approximating a CFG).
+#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
+pub enum Diverges {
+    /// Potentially unknown, some cases converge,
+    /// others require a CFG to determine them.
+    Maybe,
+
+    /// Definitely known to diverge and therefore
+    /// not reach the next sibling or its parent.
+    Always {
+        /// The `Span` points to the expression
+        /// that caused us to diverge
+        /// (e.g. `return`, `break`, etc).
+        span: Span,
+        /// In some cases (e.g. a `match` expression
+        /// where all arms diverge), we may be
+        /// able to provide a more informative
+        /// message to the user.
+        /// If this is `None`, a default message
+        /// will be generated, which is suitable
+        /// for most cases.
+        custom_note: Option<&'static str>,
+    },
+
+    /// Same as `Always` but with a reachability
+    /// warning already emitted.
+    WarnedAlways,
+}
+
+// Convenience impls for combining `Diverges`.
+
+impl ops::BitAnd for Diverges {
+    type Output = Self;
+    fn bitand(self, other: Self) -> Self {
+        cmp::min(self, other)
+    }
+}
+
+impl ops::BitOr for Diverges {
+    type Output = Self;
+    fn bitor(self, other: Self) -> Self {
+        cmp::max(self, other)
+    }
+}
+
+impl ops::BitAndAssign for Diverges {
+    fn bitand_assign(&mut self, other: Self) {
+        *self = *self & other;
+    }
+}
+
+impl ops::BitOrAssign for Diverges {
+    fn bitor_assign(&mut self, other: Self) {
+        *self = *self | other;
+    }
+}
+
+impl Diverges {
+    /// Creates a `Diverges::Always` with the provided `span` and the default note message.
+    pub(super) fn always(span: Span) -> Diverges {
+        Diverges::Always { span, custom_note: None }
+    }
+
+    pub(super) fn is_always(self) -> bool {
+        // Enum comparison ignores the
+        // contents of fields, so we just
+        // fill them in with garbage here.
+        self >= Diverges::Always { span: DUMMY_SP, custom_note: None }
+    }
+}
diff --git a/compiler/rustc_typeck/src/check/expectation.rs b/compiler/rustc_typeck/src/check/expectation.rs
new file mode 100644
index 00000000000..fd6fe1406c8
--- /dev/null
+++ b/compiler/rustc_typeck/src/check/expectation.rs
@@ -0,0 +1,117 @@
+use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use rustc_middle::ty::{self, Ty};
+use rustc_span::{self, Span};
+
+use super::Expectation::*;
+use super::FnCtxt;
+
+/// When type-checking an expression, we propagate downward
+/// whatever type hint we are able in the form of an `Expectation`.
+#[derive(Copy, Clone, Debug)]
+pub enum Expectation<'tcx> {
+    /// We know nothing about what type this expression should have.
+    NoExpectation,
+
+    /// This expression should have the type given (or some subtype).
+    ExpectHasType(Ty<'tcx>),
+
+    /// This expression will be cast to the `Ty`.
+    ExpectCastableToType(Ty<'tcx>),
+
+    /// This rvalue expression will be wrapped in `&` or `Box` and coerced
+    /// to `&Ty` or `Box<Ty>`, respectively. `Ty` is `[A]` or `Trait`.
+    ExpectRvalueLikeUnsized(Ty<'tcx>),
+}
+
+impl<'a, 'tcx> Expectation<'tcx> {
+    // Disregard "castable to" expectations because they
+    // can lead us astray. Consider for example `if cond
+    // {22} else {c} as u8` -- if we propagate the
+    // "castable to u8" constraint to 22, it will pick the
+    // type 22u8, which is overly constrained (c might not
+    // be a u8). In effect, the problem is that the
+    // "castable to" expectation is not the tightest thing
+    // we can say, so we want to drop it in this case.
+    // The tightest thing we can say is "must unify with
+    // else branch". Note that in the case of a "has type"
+    // constraint, this limitation does not hold.
+
+    // If the expected type is just a type variable, then don't use
+    // an expected type. Otherwise, we might write parts of the type
+    // when checking the 'then' block which are incompatible with the
+    // 'else' branch.
+    pub(super) fn adjust_for_branches(&self, fcx: &FnCtxt<'a, 'tcx>) -> Expectation<'tcx> {
+        match *self {
+            ExpectHasType(ety) => {
+                let ety = fcx.shallow_resolve(ety);
+                if !ety.is_ty_var() { ExpectHasType(ety) } else { NoExpectation }
+            }
+            ExpectRvalueLikeUnsized(ety) => ExpectRvalueLikeUnsized(ety),
+            _ => NoExpectation,
+        }
+    }
+
+    /// Provides an expectation for an rvalue expression given an *optional*
+    /// hint, which is not required for type safety (the resulting type might
+    /// be checked higher up, as is the case with `&expr` and `box expr`), but
+    /// is useful in determining the concrete type.
+    ///
+    /// The primary use case is where the expected type is a fat pointer,
+    /// like `&[isize]`. For example, consider the following statement:
+    ///
+    ///    let x: &[isize] = &[1, 2, 3];
+    ///
+    /// In this case, the expected type for the `&[1, 2, 3]` expression is
+    /// `&[isize]`. If however we were to say that `[1, 2, 3]` has the
+    /// expectation `ExpectHasType([isize])`, that would be too strong --
+    /// `[1, 2, 3]` does not have the type `[isize]` but rather `[isize; 3]`.
+    /// It is only the `&[1, 2, 3]` expression as a whole that can be coerced
+    /// to the type `&[isize]`. Therefore, we propagate this more limited hint,
+    /// which still is useful, because it informs integer literals and the like.
+    /// See the test case `test/ui/coerce-expect-unsized.rs` and #20169
+    /// for examples of where this comes up,.
+    pub(super) fn rvalue_hint(fcx: &FnCtxt<'a, 'tcx>, ty: Ty<'tcx>) -> Expectation<'tcx> {
+        match fcx.tcx.struct_tail_without_normalization(ty).kind() {
+            ty::Slice(_) | ty::Str | ty::Dynamic(..) => ExpectRvalueLikeUnsized(ty),
+            _ => ExpectHasType(ty),
+        }
+    }
+
+    // Resolves `expected` by a single level if it is a variable. If
+    // there is no expected type or resolution is not possible (e.g.,
+    // no constraints yet present), just returns `None`.
+    fn resolve(self, fcx: &FnCtxt<'a, 'tcx>) -> Expectation<'tcx> {
+        match self {
+            NoExpectation => NoExpectation,
+            ExpectCastableToType(t) => ExpectCastableToType(fcx.resolve_vars_if_possible(&t)),
+            ExpectHasType(t) => ExpectHasType(fcx.resolve_vars_if_possible(&t)),
+            ExpectRvalueLikeUnsized(t) => ExpectRvalueLikeUnsized(fcx.resolve_vars_if_possible(&t)),
+        }
+    }
+
+    pub(super) fn to_option(self, fcx: &FnCtxt<'a, 'tcx>) -> Option<Ty<'tcx>> {
+        match self.resolve(fcx) {
+            NoExpectation => None,
+            ExpectCastableToType(ty) | ExpectHasType(ty) | ExpectRvalueLikeUnsized(ty) => Some(ty),
+        }
+    }
+
+    /// It sometimes happens that we want to turn an expectation into
+    /// a **hard constraint** (i.e., something that must be satisfied
+    /// for the program to type-check). `only_has_type` will return
+    /// such a constraint, if it exists.
+    pub(super) fn only_has_type(self, fcx: &FnCtxt<'a, 'tcx>) -> Option<Ty<'tcx>> {
+        match self.resolve(fcx) {
+            ExpectHasType(ty) => Some(ty),
+            NoExpectation | ExpectCastableToType(_) | ExpectRvalueLikeUnsized(_) => None,
+        }
+    }
+
+    /// Like `only_has_type`, but instead of returning `None` if no
+    /// hard constraint exists, creates a fresh type variable.
+    pub(super) fn coercion_target_type(self, fcx: &FnCtxt<'a, 'tcx>, span: Span) -> Ty<'tcx> {
+        self.only_has_type(fcx).unwrap_or_else(|| {
+            fcx.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::MiscVariable, span })
+        })
+    }
+}
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt.rs b/compiler/rustc_typeck/src/check/fn_ctxt.rs
new file mode 100644
index 00000000000..a03b8064b59
--- /dev/null
+++ b/compiler/rustc_typeck/src/check/fn_ctxt.rs
@@ -0,0 +1,3200 @@
+// ignore-tidy-filelength
+// FIXME: This file seems to have too much functionality wrapped into it,
+// leading to it being too long.
+// Splitting this file may involve abstracting functionality into other files.
+
+use super::callee::{self, DeferredCallResolution};
+use super::coercion::{CoerceMany, DynamicCoerceMany};
+use super::method::{self, MethodCallee, SelfSource};
+use super::Expectation::*;
+use super::TupleArgumentsFlag::*;
+use super::{
+    potentially_plural_count, struct_span_err, BreakableCtxt, Diverges, EnclosingBreakables,
+    Expectation, FallbackMode, Inherited, LocalTy, Needs, TupleArgumentsFlag, UnsafetyState,
+};
+use crate::astconv::{
+    AstConv, ExplicitLateBound, GenericArgCountMismatch, GenericArgCountResult, PathSeg,
+};
+
+use rustc_ast as ast;
+use rustc_ast::util::parser::ExprPrecedence;
+use rustc_data_structures::captures::Captures;
+use rustc_data_structures::fx::FxHashSet;
+use rustc_errors::ErrorReported;
+use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticId};
+use rustc_hir as hir;
+use rustc_hir::def::{CtorOf, DefKind, Res};
+use rustc_hir::def_id::DefId;
+use rustc_hir::lang_items::LangItem;
+use rustc_hir::{ExprKind, GenericArg, ItemKind, Node, QPath};
+use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse};
+use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282;
+use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use rustc_infer::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
+use rustc_infer::infer::{self, InferOk, InferResult};
+use rustc_middle::hir::map::blocks::FnLikeNode;
+use rustc_middle::ty::adjustment::{
+    Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability,
+};
+use rustc_middle::ty::fold::TypeFoldable;
+use rustc_middle::ty::subst::{
+    self, GenericArgKind, InternalSubsts, Subst, SubstsRef, UserSelfTy, UserSubsts,
+};
+use rustc_middle::ty::{
+    self, AdtKind, CanonicalUserType, Const, DefIdTree, GenericParamDefKind, ToPolyTraitRef,
+    ToPredicate, Ty, TyCtxt, UserType,
+};
+use rustc_session::{lint, Session};
+use rustc_span::hygiene::DesugaringKind;
+use rustc_span::source_map::{original_sp, DUMMY_SP};
+use rustc_span::symbol::{kw, sym, Ident};
+use rustc_span::{self, BytePos, MultiSpan, Span};
+use rustc_trait_selection::infer::InferCtxtExt as _;
+use rustc_trait_selection::opaque_types::InferCtxtExt as _;
+use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
+use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
+use rustc_trait_selection::traits::{
+    self, ObligationCause, ObligationCauseCode, TraitEngine, TraitEngineExt,
+};
+
+use std::cell::{Cell, RefCell};
+use std::collections::hash_map::Entry;
+use std::iter;
+use std::mem::replace;
+use std::ops::Deref;
+use std::slice;
+
+pub struct FnCtxt<'a, 'tcx> {
+    pub(super) body_id: hir::HirId,
+
+    /// The parameter environment used for proving trait obligations
+    /// in this function. This can change when we descend into
+    /// closures (as they bring new things into scope), hence it is
+    /// not part of `Inherited` (as of the time of this writing,
+    /// closures do not yet change the environment, but they will
+    /// eventually).
+    pub(super) param_env: ty::ParamEnv<'tcx>,
+
+    /// Number of errors that had been reported when we started
+    /// checking this function. On exit, if we find that *more* errors
+    /// have been reported, we will skip regionck and other work that
+    /// expects the types within the function to be consistent.
+    // FIXME(matthewjasper) This should not exist, and it's not correct
+    // if type checking is run in parallel.
+    err_count_on_creation: usize,
+
+    /// If `Some`, this stores coercion information for returned
+    /// expressions. If `None`, this is in a context where return is
+    /// inappropriate, such as a const expression.
+    ///
+    /// This is a `RefCell<DynamicCoerceMany>`, which means that we
+    /// can track all the return expressions and then use them to
+    /// compute a useful coercion from the set, similar to a match
+    /// expression or other branching context. You can use methods
+    /// like `expected_ty` to access the declared return type (if
+    /// any).
+    pub(super) ret_coercion: Option<RefCell<DynamicCoerceMany<'tcx>>>,
+
+    pub(super) ret_coercion_impl_trait: Option<Ty<'tcx>>,
+
+    pub(super) ret_type_span: Option<Span>,
+
+    /// Used exclusively to reduce cost of advanced evaluation used for
+    /// more helpful diagnostics.
+    pub(super) in_tail_expr: bool,
+
+    /// First span of a return site that we find. Used in error messages.
+    pub(super) ret_coercion_span: RefCell<Option<Span>>,
+
+    pub(super) resume_yield_tys: Option<(Ty<'tcx>, Ty<'tcx>)>,
+
+    pub(super) ps: RefCell<UnsafetyState>,
+
+    /// Whether the last checked node generates a divergence (e.g.,
+    /// `return` will set this to `Always`). In general, when entering
+    /// an expression or other node in the tree, the initial value
+    /// indicates whether prior parts of the containing expression may
+    /// have diverged. It is then typically set to `Maybe` (and the
+    /// old value remembered) for processing the subparts of the
+    /// current expression. As each subpart is processed, they may set
+    /// the flag to `Always`, etc. Finally, at the end, we take the
+    /// result and "union" it with the original value, so that when we
+    /// return the flag indicates if any subpart of the parent
+    /// expression (up to and including this part) has diverged. So,
+    /// if you read it after evaluating a subexpression `X`, the value
+    /// you get indicates whether any subexpression that was
+    /// evaluating up to and including `X` diverged.
+    ///
+    /// We currently use this flag only for diagnostic purposes:
+    ///
+    /// - To warn about unreachable code: if, after processing a
+    ///   sub-expression but before we have applied the effects of the
+    ///   current node, we see that the flag is set to `Always`, we
+    ///   can issue a warning. This corresponds to something like
+    ///   `foo(return)`; we warn on the `foo()` expression. (We then
+    ///   update the flag to `WarnedAlways` to suppress duplicate
+    ///   reports.) Similarly, if we traverse to a fresh statement (or
+    ///   tail expression) from a `Always` setting, we will issue a
+    ///   warning. This corresponds to something like `{return;
+    ///   foo();}` or `{return; 22}`, where we would warn on the
+    ///   `foo()` or `22`.
+    ///
+    /// An expression represents dead code if, after checking it,
+    /// the diverges flag is set to something other than `Maybe`.
+    pub(super) diverges: Cell<Diverges>,
+
+    /// Whether any child nodes have any type errors.
+    pub(super) has_errors: Cell<bool>,
+
+    pub(super) enclosing_breakables: RefCell<EnclosingBreakables<'tcx>>,
+
+    pub(super) inh: &'a Inherited<'a, 'tcx>,
+}
+
+impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
+    pub fn new(
+        inh: &'a Inherited<'a, 'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
+        body_id: hir::HirId,
+    ) -> FnCtxt<'a, 'tcx> {
+        FnCtxt {
+            body_id,
+            param_env,
+            err_count_on_creation: inh.tcx.sess.err_count(),
+            ret_coercion: None,
+            ret_coercion_impl_trait: None,
+            ret_type_span: None,
+            in_tail_expr: false,
+            ret_coercion_span: RefCell::new(None),
+            resume_yield_tys: None,
+            ps: RefCell::new(UnsafetyState::function(hir::Unsafety::Normal, hir::CRATE_HIR_ID)),
+            diverges: Cell::new(Diverges::Maybe),
+            has_errors: Cell::new(false),
+            enclosing_breakables: RefCell::new(EnclosingBreakables {
+                stack: Vec::new(),
+                by_id: Default::default(),
+            }),
+            inh,
+        }
+    }
+
+    pub fn sess(&self) -> &Session {
+        &self.tcx.sess
+    }
+
+    pub fn errors_reported_since_creation(&self) -> bool {
+        self.tcx.sess.err_count() > self.err_count_on_creation
+    }
+
+    /// Produces warning on the given node, if the current point in the
+    /// function is unreachable, and there hasn't been another warning.
+    pub(super) fn warn_if_unreachable(&self, id: hir::HirId, span: Span, kind: &str) {
+        // FIXME: Combine these two 'if' expressions into one once
+        // let chains are implemented
+        if let Diverges::Always { span: orig_span, custom_note } = self.diverges.get() {
+            // If span arose from a desugaring of `if` or `while`, then it is the condition itself,
+            // which diverges, that we are about to lint on. This gives suboptimal diagnostics.
+            // Instead, stop here so that the `if`- or `while`-expression's block is linted instead.
+            if !span.is_desugaring(DesugaringKind::CondTemporary)
+                && !span.is_desugaring(DesugaringKind::Async)
+                && !orig_span.is_desugaring(DesugaringKind::Await)
+            {
+                self.diverges.set(Diverges::WarnedAlways);
+
+                debug!("warn_if_unreachable: id={:?} span={:?} kind={}", id, span, kind);
+
+                self.tcx().struct_span_lint_hir(lint::builtin::UNREACHABLE_CODE, id, span, |lint| {
+                    let msg = format!("unreachable {}", kind);
+                    lint.build(&msg)
+                        .span_label(span, &msg)
+                        .span_label(
+                            orig_span,
+                            custom_note
+                                .unwrap_or("any code following this expression is unreachable"),
+                        )
+                        .emit();
+                })
+            }
+        }
+    }
+
+    pub fn cause(&self, span: Span, code: ObligationCauseCode<'tcx>) -> ObligationCause<'tcx> {
+        ObligationCause::new(span, self.body_id, code)
+    }
+
+    pub fn misc(&self, span: Span) -> ObligationCause<'tcx> {
+        self.cause(span, ObligationCauseCode::MiscObligation)
+    }
+
+    /// Resolves type and const variables in `ty` if possible. Unlike the infcx
+    /// version (resolve_vars_if_possible), this version will
+    /// also select obligations if it seems useful, in an effort
+    /// to get more type information.
+    pub(super) fn resolve_vars_with_obligations(&self, mut ty: Ty<'tcx>) -> Ty<'tcx> {
+        debug!("resolve_vars_with_obligations(ty={:?})", ty);
+
+        // No Infer()? Nothing needs doing.
+        if !ty.has_infer_types_or_consts() {
+            debug!("resolve_vars_with_obligations: ty={:?}", ty);
+            return ty;
+        }
+
+        // If `ty` is a type variable, see whether we already know what it is.
+        ty = self.resolve_vars_if_possible(&ty);
+        if !ty.has_infer_types_or_consts() {
+            debug!("resolve_vars_with_obligations: ty={:?}", ty);
+            return ty;
+        }
+
+        // If not, try resolving pending obligations as much as
+        // possible. This can help substantially when there are
+        // indirect dependencies that don't seem worth tracking
+        // precisely.
+        self.select_obligations_where_possible(false, |_| {});
+        ty = self.resolve_vars_if_possible(&ty);
+
+        debug!("resolve_vars_with_obligations: ty={:?}", ty);
+        ty
+    }
+
+    pub(super) fn record_deferred_call_resolution(
+        &self,
+        closure_def_id: DefId,
+        r: DeferredCallResolution<'tcx>,
+    ) {
+        let mut deferred_call_resolutions = self.deferred_call_resolutions.borrow_mut();
+        deferred_call_resolutions.entry(closure_def_id).or_default().push(r);
+    }
+
+    pub(super) fn remove_deferred_call_resolutions(
+        &self,
+        closure_def_id: DefId,
+    ) -> Vec<DeferredCallResolution<'tcx>> {
+        let mut deferred_call_resolutions = self.deferred_call_resolutions.borrow_mut();
+        deferred_call_resolutions.remove(&closure_def_id).unwrap_or(vec![])
+    }
+
+    pub fn tag(&self) -> String {
+        format!("{:p}", self)
+    }
+
+    pub fn local_ty(&self, span: Span, nid: hir::HirId) -> LocalTy<'tcx> {
+        self.locals.borrow().get(&nid).cloned().unwrap_or_else(|| {
+            span_bug!(span, "no type for local variable {}", self.tcx.hir().node_to_string(nid))
+        })
+    }
+
+    #[inline]
+    pub fn write_ty(&self, id: hir::HirId, ty: Ty<'tcx>) {
+        debug!(
+            "write_ty({:?}, {:?}) in fcx {}",
+            id,
+            self.resolve_vars_if_possible(&ty),
+            self.tag()
+        );
+        self.typeck_results.borrow_mut().node_types_mut().insert(id, ty);
+
+        if ty.references_error() {
+            self.has_errors.set(true);
+            self.set_tainted_by_errors();
+        }
+    }
+
+    pub fn write_field_index(&self, hir_id: hir::HirId, index: usize) {
+        self.typeck_results.borrow_mut().field_indices_mut().insert(hir_id, index);
+    }
+
+    fn write_resolution(&self, hir_id: hir::HirId, r: Result<(DefKind, DefId), ErrorReported>) {
+        self.typeck_results.borrow_mut().type_dependent_defs_mut().insert(hir_id, r);
+    }
+
+    pub fn write_method_call(&self, hir_id: hir::HirId, method: MethodCallee<'tcx>) {
+        debug!("write_method_call(hir_id={:?}, method={:?})", hir_id, method);
+        self.write_resolution(hir_id, Ok((DefKind::AssocFn, method.def_id)));
+        self.write_substs(hir_id, method.substs);
+
+        // When the method is confirmed, the `method.substs` includes
+        // parameters from not just the method, but also the impl of
+        // the method -- in particular, the `Self` type will be fully
+        // resolved. However, those are not something that the "user
+        // specified" -- i.e., those types come from the inferred type
+        // of the receiver, not something the user wrote. So when we
+        // create the user-substs, we want to replace those earlier
+        // types with just the types that the user actually wrote --
+        // that is, those that appear on the *method itself*.
+        //
+        // As an example, if the user wrote something like
+        // `foo.bar::<u32>(...)` -- the `Self` type here will be the
+        // type of `foo` (possibly adjusted), but we don't want to
+        // include that. We want just the `[_, u32]` part.
+        if !method.substs.is_noop() {
+            let method_generics = self.tcx.generics_of(method.def_id);
+            if !method_generics.params.is_empty() {
+                let user_type_annotation = self.infcx.probe(|_| {
+                    let user_substs = UserSubsts {
+                        substs: InternalSubsts::for_item(self.tcx, method.def_id, |param, _| {
+                            let i = param.index as usize;
+                            if i < method_generics.parent_count {
+                                self.infcx.var_for_def(DUMMY_SP, param)
+                            } else {
+                                method.substs[i]
+                            }
+                        }),
+                        user_self_ty: None, // not relevant here
+                    };
+
+                    self.infcx.canonicalize_user_type_annotation(&UserType::TypeOf(
+                        method.def_id,
+                        user_substs,
+                    ))
+                });
+
+                debug!("write_method_call: user_type_annotation={:?}", user_type_annotation);
+                self.write_user_type_annotation(hir_id, user_type_annotation);
+            }
+        }
+    }
+
+    pub fn write_substs(&self, node_id: hir::HirId, substs: SubstsRef<'tcx>) {
+        if !substs.is_noop() {
+            debug!("write_substs({:?}, {:?}) in fcx {}", node_id, substs, self.tag());
+
+            self.typeck_results.borrow_mut().node_substs_mut().insert(node_id, substs);
+        }
+    }
+
+    /// Given the substs that we just converted from the HIR, try to
+    /// canonicalize them and store them as user-given substitutions
+    /// (i.e., substitutions that must be respected by the NLL check).
+    ///
+    /// This should be invoked **before any unifications have
+    /// occurred**, so that annotations like `Vec<_>` are preserved
+    /// properly.
+    pub fn write_user_type_annotation_from_substs(
+        &self,
+        hir_id: hir::HirId,
+        def_id: DefId,
+        substs: SubstsRef<'tcx>,
+        user_self_ty: Option<UserSelfTy<'tcx>>,
+    ) {
+        debug!(
+            "write_user_type_annotation_from_substs: hir_id={:?} def_id={:?} substs={:?} \
+             user_self_ty={:?} in fcx {}",
+            hir_id,
+            def_id,
+            substs,
+            user_self_ty,
+            self.tag(),
+        );
+
+        if Self::can_contain_user_lifetime_bounds((substs, user_self_ty)) {
+            let canonicalized = self.infcx.canonicalize_user_type_annotation(&UserType::TypeOf(
+                def_id,
+                UserSubsts { substs, user_self_ty },
+            ));
+            debug!("write_user_type_annotation_from_substs: canonicalized={:?}", canonicalized);
+            self.write_user_type_annotation(hir_id, canonicalized);
+        }
+    }
+
+    pub fn write_user_type_annotation(
+        &self,
+        hir_id: hir::HirId,
+        canonical_user_type_annotation: CanonicalUserType<'tcx>,
+    ) {
+        debug!(
+            "write_user_type_annotation: hir_id={:?} canonical_user_type_annotation={:?} tag={}",
+            hir_id,
+            canonical_user_type_annotation,
+            self.tag(),
+        );
+
+        if !canonical_user_type_annotation.is_identity() {
+            self.typeck_results
+                .borrow_mut()
+                .user_provided_types_mut()
+                .insert(hir_id, canonical_user_type_annotation);
+        } else {
+            debug!("write_user_type_annotation: skipping identity substs");
+        }
+    }
+
+    pub fn apply_adjustments(&self, expr: &hir::Expr<'_>, adj: Vec<Adjustment<'tcx>>) {
+        debug!("apply_adjustments(expr={:?}, adj={:?})", expr, adj);
+
+        if adj.is_empty() {
+            return;
+        }
+
+        let autoborrow_mut = adj.iter().any(|adj| {
+            matches!(adj, &Adjustment {
+                kind: Adjust::Borrow(AutoBorrow::Ref(_, AutoBorrowMutability::Mut { .. })),
+                ..
+            })
+        });
+
+        match self.typeck_results.borrow_mut().adjustments_mut().entry(expr.hir_id) {
+            Entry::Vacant(entry) => {
+                entry.insert(adj);
+            }
+            Entry::Occupied(mut entry) => {
+                debug!(" - composing on top of {:?}", entry.get());
+                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(_), .. },
+                        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 {:?}",
+                             expr, entry.get(), adj)
+                };
+                *entry.get_mut() = adj;
+            }
+        }
+
+        // If there is an mutable auto-borrow, it is equivalent to `&mut <expr>`.
+        // In this case implicit use of `Deref` and `Index` within `<expr>` should
+        // instead be `DerefMut` and `IndexMut`, so fix those up.
+        if autoborrow_mut {
+            self.convert_place_derefs_to_mutable(expr);
+        }
+    }
+
+    /// Basically whenever we are converting from a type scheme into
+    /// the fn body space, we always want to normalize associated
+    /// types as well. This function combines the two.
+    fn instantiate_type_scheme<T>(&self, span: Span, substs: SubstsRef<'tcx>, value: &T) -> T
+    where
+        T: TypeFoldable<'tcx>,
+    {
+        let value = value.subst(self.tcx, substs);
+        let result = self.normalize_associated_types_in(span, &value);
+        debug!("instantiate_type_scheme(value={:?}, substs={:?}) = {:?}", value, substs, result);
+        result
+    }
+
+    /// As `instantiate_type_scheme`, but for the bounds found in a
+    /// generic type scheme.
+    fn instantiate_bounds(
+        &self,
+        span: Span,
+        def_id: DefId,
+        substs: SubstsRef<'tcx>,
+    ) -> (ty::InstantiatedPredicates<'tcx>, Vec<Span>) {
+        let bounds = self.tcx.predicates_of(def_id);
+        let spans: Vec<Span> = bounds.predicates.iter().map(|(_, span)| *span).collect();
+        let result = bounds.instantiate(self.tcx, substs);
+        let result = self.normalize_associated_types_in(span, &result);
+        debug!(
+            "instantiate_bounds(bounds={:?}, substs={:?}) = {:?}, {:?}",
+            bounds, substs, result, spans,
+        );
+        (result, spans)
+    }
+
+    /// Replaces the opaque types from the given value with type variables,
+    /// and records the `OpaqueTypeMap` for later use during writeback. See
+    /// `InferCtxt::instantiate_opaque_types` for more details.
+    pub(super) fn instantiate_opaque_types_from_value<T: TypeFoldable<'tcx>>(
+        &self,
+        parent_id: hir::HirId,
+        value: &T,
+        value_span: Span,
+    ) -> T {
+        let parent_def_id = self.tcx.hir().local_def_id(parent_id);
+        debug!(
+            "instantiate_opaque_types_from_value(parent_def_id={:?}, value={:?})",
+            parent_def_id, value
+        );
+
+        let (value, opaque_type_map) =
+            self.register_infer_ok_obligations(self.instantiate_opaque_types(
+                parent_def_id,
+                self.body_id,
+                self.param_env,
+                value,
+                value_span,
+            ));
+
+        let mut opaque_types = self.opaque_types.borrow_mut();
+        let mut opaque_types_vars = self.opaque_types_vars.borrow_mut();
+        for (ty, decl) in opaque_type_map {
+            let _ = opaque_types.insert(ty, decl);
+            let _ = opaque_types_vars.insert(decl.concrete_ty, decl.opaque_type);
+        }
+
+        value
+    }
+
+    pub(super) fn normalize_associated_types_in<T>(&self, span: Span, value: &T) -> T
+    where
+        T: TypeFoldable<'tcx>,
+    {
+        self.inh.normalize_associated_types_in(span, self.body_id, self.param_env, value)
+    }
+
+    pub(super) fn normalize_associated_types_in_as_infer_ok<T>(
+        &self,
+        span: Span,
+        value: &T,
+    ) -> InferOk<'tcx, T>
+    where
+        T: TypeFoldable<'tcx>,
+    {
+        self.inh.partially_normalize_associated_types_in(span, self.body_id, self.param_env, value)
+    }
+
+    pub fn require_type_meets(
+        &self,
+        ty: Ty<'tcx>,
+        span: Span,
+        code: traits::ObligationCauseCode<'tcx>,
+        def_id: DefId,
+    ) {
+        self.register_bound(ty, def_id, traits::ObligationCause::new(span, self.body_id, code));
+    }
+
+    pub fn require_type_is_sized(
+        &self,
+        ty: Ty<'tcx>,
+        span: Span,
+        code: traits::ObligationCauseCode<'tcx>,
+    ) {
+        if !ty.references_error() {
+            let lang_item = self.tcx.require_lang_item(LangItem::Sized, None);
+            self.require_type_meets(ty, span, code, lang_item);
+        }
+    }
+
+    pub fn require_type_is_sized_deferred(
+        &self,
+        ty: Ty<'tcx>,
+        span: Span,
+        code: traits::ObligationCauseCode<'tcx>,
+    ) {
+        if !ty.references_error() {
+            self.deferred_sized_obligations.borrow_mut().push((ty, span, code));
+        }
+    }
+
+    pub fn register_bound(
+        &self,
+        ty: Ty<'tcx>,
+        def_id: DefId,
+        cause: traits::ObligationCause<'tcx>,
+    ) {
+        if !ty.references_error() {
+            self.fulfillment_cx.borrow_mut().register_bound(
+                self,
+                self.param_env,
+                ty,
+                def_id,
+                cause,
+            );
+        }
+    }
+
+    pub fn to_ty(&self, ast_t: &hir::Ty<'_>) -> Ty<'tcx> {
+        let t = AstConv::ast_ty_to_ty(self, ast_t);
+        self.register_wf_obligation(t.into(), ast_t.span, traits::MiscObligation);
+        t
+    }
+
+    pub fn to_ty_saving_user_provided_ty(&self, ast_ty: &hir::Ty<'_>) -> Ty<'tcx> {
+        let ty = self.to_ty(ast_ty);
+        debug!("to_ty_saving_user_provided_ty: ty={:?}", ty);
+
+        if Self::can_contain_user_lifetime_bounds(ty) {
+            let c_ty = self.infcx.canonicalize_response(&UserType::Ty(ty));
+            debug!("to_ty_saving_user_provided_ty: c_ty={:?}", c_ty);
+            self.typeck_results.borrow_mut().user_provided_types_mut().insert(ast_ty.hir_id, c_ty);
+        }
+
+        ty
+    }
+
+    pub fn to_const(&self, ast_c: &hir::AnonConst) -> &'tcx ty::Const<'tcx> {
+        let const_def_id = self.tcx.hir().local_def_id(ast_c.hir_id);
+        let c = ty::Const::from_anon_const(self.tcx, const_def_id);
+        self.register_wf_obligation(
+            c.into(),
+            self.tcx.hir().span(ast_c.hir_id),
+            ObligationCauseCode::MiscObligation,
+        );
+        c
+    }
+
+    pub fn const_arg_to_const(
+        &self,
+        ast_c: &hir::AnonConst,
+        param_def_id: DefId,
+    ) -> &'tcx ty::Const<'tcx> {
+        let const_def = ty::WithOptConstParam {
+            did: self.tcx.hir().local_def_id(ast_c.hir_id),
+            const_param_did: Some(param_def_id),
+        };
+        let c = ty::Const::from_opt_const_arg_anon_const(self.tcx, const_def);
+        self.register_wf_obligation(
+            c.into(),
+            self.tcx.hir().span(ast_c.hir_id),
+            ObligationCauseCode::MiscObligation,
+        );
+        c
+    }
+
+    // If the type given by the user has free regions, save it for later, since
+    // NLL would like to enforce those. Also pass in types that involve
+    // projections, since those can resolve to `'static` bounds (modulo #54940,
+    // which hopefully will be fixed by the time you see this comment, dear
+    // reader, although I have my doubts). Also pass in types with inference
+    // types, because they may be repeated. Other sorts of things are already
+    // sufficiently enforced with erased regions. =)
+    fn can_contain_user_lifetime_bounds<T>(t: T) -> bool
+    where
+        T: TypeFoldable<'tcx>,
+    {
+        t.has_free_regions() || t.has_projections() || t.has_infer_types()
+    }
+
+    pub fn node_ty(&self, id: hir::HirId) -> Ty<'tcx> {
+        match self.typeck_results.borrow().node_types().get(id) {
+            Some(&t) => t,
+            None if self.is_tainted_by_errors() => self.tcx.ty_error(),
+            None => {
+                bug!(
+                    "no type for node {}: {} in fcx {}",
+                    id,
+                    self.tcx.hir().node_to_string(id),
+                    self.tag()
+                );
+            }
+        }
+    }
+
+    /// Registers an obligation for checking later, during regionck, that `arg` is well-formed.
+    pub fn register_wf_obligation(
+        &self,
+        arg: subst::GenericArg<'tcx>,
+        span: Span,
+        code: traits::ObligationCauseCode<'tcx>,
+    ) {
+        // WF obligations never themselves fail, so no real need to give a detailed cause:
+        let cause = traits::ObligationCause::new(span, self.body_id, code);
+        self.register_predicate(traits::Obligation::new(
+            cause,
+            self.param_env,
+            ty::PredicateAtom::WellFormed(arg).to_predicate(self.tcx),
+        ));
+    }
+
+    /// Registers obligations that all `substs` are well-formed.
+    pub fn add_wf_bounds(&self, substs: SubstsRef<'tcx>, expr: &hir::Expr<'_>) {
+        for arg in substs.iter().filter(|arg| {
+            matches!(arg.unpack(), GenericArgKind::Type(..) | GenericArgKind::Const(..))
+        }) {
+            self.register_wf_obligation(arg, expr.span, traits::MiscObligation);
+        }
+    }
+
+    /// Given a fully substituted set of bounds (`generic_bounds`), and the values with which each
+    /// type/region parameter was instantiated (`substs`), creates and registers suitable
+    /// trait/region obligations.
+    ///
+    /// For example, if there is a function:
+    ///
+    /// ```
+    /// fn foo<'a,T:'a>(...)
+    /// ```
+    ///
+    /// and a reference:
+    ///
+    /// ```
+    /// let f = foo;
+    /// ```
+    ///
+    /// Then we will create a fresh region variable `'$0` and a fresh type variable `$1` for `'a`
+    /// and `T`. This routine will add a region obligation `$1:'$0` and register it locally.
+    pub fn add_obligations_for_parameters(
+        &self,
+        cause: traits::ObligationCause<'tcx>,
+        predicates: ty::InstantiatedPredicates<'tcx>,
+    ) {
+        assert!(!predicates.has_escaping_bound_vars());
+
+        debug!("add_obligations_for_parameters(predicates={:?})", predicates);
+
+        for obligation in traits::predicates_for_generics(cause, self.param_env, predicates) {
+            self.register_predicate(obligation);
+        }
+    }
+
+    // FIXME(arielb1): use this instead of field.ty everywhere
+    // Only for fields! Returns <none> for methods>
+    // Indifferent to privacy flags
+    pub fn field_ty(
+        &self,
+        span: Span,
+        field: &'tcx ty::FieldDef,
+        substs: SubstsRef<'tcx>,
+    ) -> Ty<'tcx> {
+        self.normalize_associated_types_in(span, &field.ty(self.tcx, substs))
+    }
+
+    pub(super) fn check_casts(&self) {
+        let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut();
+        for cast in deferred_cast_checks.drain(..) {
+            cast.check(self);
+        }
+    }
+
+    pub(super) fn resolve_generator_interiors(&self, def_id: DefId) {
+        let mut generators = self.deferred_generator_interiors.borrow_mut();
+        for (body_id, interior, kind) in generators.drain(..) {
+            self.select_obligations_where_possible(false, |_| {});
+            super::generator_interior::resolve_interior(self, def_id, body_id, interior, kind);
+        }
+    }
+
+    // Tries to apply a fallback to `ty` if it is an unsolved variable.
+    //
+    // - Unconstrained ints are replaced with `i32`.
+    //
+    // - Unconstrained floats are replaced with with `f64`.
+    //
+    // - Non-numerics get replaced with `!` when `#![feature(never_type_fallback)]`
+    //   is enabled. Otherwise, they are replaced with `()`.
+    //
+    // Fallback becomes very dubious if we have encountered type-checking errors.
+    // In that case, fallback to Error.
+    // The return value indicates whether fallback has occurred.
+    pub(super) fn fallback_if_possible(&self, ty: Ty<'tcx>, mode: FallbackMode) -> bool {
+        use rustc_middle::ty::error::UnconstrainedNumeric::Neither;
+        use rustc_middle::ty::error::UnconstrainedNumeric::{UnconstrainedFloat, UnconstrainedInt};
+
+        assert!(ty.is_ty_infer());
+        let fallback = match self.type_is_unconstrained_numeric(ty) {
+            _ if self.is_tainted_by_errors() => self.tcx().ty_error(),
+            UnconstrainedInt => self.tcx.types.i32,
+            UnconstrainedFloat => self.tcx.types.f64,
+            Neither if self.type_var_diverges(ty) => self.tcx.mk_diverging_default(),
+            Neither => {
+                // This type variable was created from the instantiation of an opaque
+                // type. The fact that we're attempting to perform fallback for it
+                // means that the function neither constrained it to a concrete
+                // type, nor to the opaque type itself.
+                //
+                // For example, in this code:
+                //
+                //```
+                // type MyType = impl Copy;
+                // fn defining_use() -> MyType { true }
+                // fn other_use() -> MyType { defining_use() }
+                // ```
+                //
+                // `defining_use` will constrain the instantiated inference
+                // variable to `bool`, while `other_use` will constrain
+                // the instantiated inference variable to `MyType`.
+                //
+                // When we process opaque types during writeback, we
+                // will handle cases like `other_use`, and not count
+                // them as defining usages
+                //
+                // However, we also need to handle cases like this:
+                //
+                // ```rust
+                // pub type Foo = impl Copy;
+                // fn produce() -> Option<Foo> {
+                //     None
+                //  }
+                //  ```
+                //
+                // In the above snippet, the inference variable created by
+                // instantiating `Option<Foo>` will be completely unconstrained.
+                // We treat this as a non-defining use by making the inference
+                // variable fall back to the opaque type itself.
+                if let FallbackMode::All = mode {
+                    if let Some(opaque_ty) = self.opaque_types_vars.borrow().get(ty) {
+                        debug!(
+                            "fallback_if_possible: falling back opaque type var {:?} to {:?}",
+                            ty, opaque_ty
+                        );
+                        *opaque_ty
+                    } else {
+                        return false;
+                    }
+                } else {
+                    return false;
+                }
+            }
+        };
+        debug!("fallback_if_possible: defaulting `{:?}` to `{:?}`", ty, fallback);
+        self.demand_eqtype(rustc_span::DUMMY_SP, ty, fallback);
+        true
+    }
+
+    pub(super) fn select_all_obligations_or_error(&self) {
+        debug!("select_all_obligations_or_error");
+        if let Err(errors) = self.fulfillment_cx.borrow_mut().select_all_or_error(&self) {
+            self.report_fulfillment_errors(&errors, self.inh.body_id, false);
+        }
+    }
+
+    /// Select as many obligations as we can at present.
+    pub(super) fn select_obligations_where_possible(
+        &self,
+        fallback_has_occurred: bool,
+        mutate_fullfillment_errors: impl Fn(&mut Vec<traits::FulfillmentError<'tcx>>),
+    ) {
+        let result = self.fulfillment_cx.borrow_mut().select_where_possible(self);
+        if let Err(mut errors) = result {
+            mutate_fullfillment_errors(&mut errors);
+            self.report_fulfillment_errors(&errors, self.inh.body_id, fallback_has_occurred);
+        }
+    }
+
+    /// For the overloaded place expressions (`*x`, `x[3]`), the trait
+    /// returns a type of `&T`, but the actual type we assign to the
+    /// *expression* is `T`. So this function just peels off the return
+    /// type by one layer to yield `T`.
+    pub(super) fn make_overloaded_place_return_type(
+        &self,
+        method: MethodCallee<'tcx>,
+    ) -> ty::TypeAndMut<'tcx> {
+        // extract method return type, which will be &T;
+        let ret_ty = method.sig.output();
+
+        // method returns &T, but the type as visible to user is T, so deref
+        ret_ty.builtin_deref(true).unwrap()
+    }
+
+    pub(super) fn check_method_argument_types(
+        &self,
+        sp: Span,
+        expr: &'tcx hir::Expr<'tcx>,
+        method: Result<MethodCallee<'tcx>, ()>,
+        args_no_rcvr: &'tcx [hir::Expr<'tcx>],
+        tuple_arguments: TupleArgumentsFlag,
+        expected: Expectation<'tcx>,
+    ) -> Ty<'tcx> {
+        let has_error = match method {
+            Ok(method) => method.substs.references_error() || method.sig.references_error(),
+            Err(_) => true,
+        };
+        if has_error {
+            let err_inputs = self.err_args(args_no_rcvr.len());
+
+            let err_inputs = match tuple_arguments {
+                DontTupleArguments => err_inputs,
+                TupleArguments => vec![self.tcx.intern_tup(&err_inputs[..])],
+            };
+
+            self.check_argument_types(
+                sp,
+                expr,
+                &err_inputs[..],
+                &[],
+                args_no_rcvr,
+                false,
+                tuple_arguments,
+                None,
+            );
+            return self.tcx.ty_error();
+        }
+
+        let method = method.unwrap();
+        // HACK(eddyb) ignore self in the definition (see above).
+        let expected_arg_tys = self.expected_inputs_for_expected_output(
+            sp,
+            expected,
+            method.sig.output(),
+            &method.sig.inputs()[1..],
+        );
+        self.check_argument_types(
+            sp,
+            expr,
+            &method.sig.inputs()[1..],
+            &expected_arg_tys[..],
+            args_no_rcvr,
+            method.sig.c_variadic,
+            tuple_arguments,
+            self.tcx.hir().span_if_local(method.def_id),
+        );
+        method.sig.output()
+    }
+
+    fn self_type_matches_expected_vid(
+        &self,
+        trait_ref: ty::PolyTraitRef<'tcx>,
+        expected_vid: ty::TyVid,
+    ) -> bool {
+        let self_ty = self.shallow_resolve(trait_ref.skip_binder().self_ty());
+        debug!(
+            "self_type_matches_expected_vid(trait_ref={:?}, self_ty={:?}, expected_vid={:?})",
+            trait_ref, self_ty, expected_vid
+        );
+        match *self_ty.kind() {
+            ty::Infer(ty::TyVar(found_vid)) => {
+                // FIXME: consider using `sub_root_var` here so we
+                // can see through subtyping.
+                let found_vid = self.root_var(found_vid);
+                debug!("self_type_matches_expected_vid - found_vid={:?}", found_vid);
+                expected_vid == found_vid
+            }
+            _ => false,
+        }
+    }
+
+    pub(super) fn obligations_for_self_ty<'b>(
+        &'b self,
+        self_ty: ty::TyVid,
+    ) -> impl Iterator<Item = (ty::PolyTraitRef<'tcx>, traits::PredicateObligation<'tcx>)>
+    + Captures<'tcx>
+    + 'b {
+        // FIXME: consider using `sub_root_var` here so we
+        // can see through subtyping.
+        let ty_var_root = self.root_var(self_ty);
+        debug!(
+            "obligations_for_self_ty: self_ty={:?} ty_var_root={:?} pending_obligations={:?}",
+            self_ty,
+            ty_var_root,
+            self.fulfillment_cx.borrow().pending_obligations()
+        );
+
+        self.fulfillment_cx
+            .borrow()
+            .pending_obligations()
+            .into_iter()
+            .filter_map(move |obligation| {
+                match obligation.predicate.skip_binders() {
+                    ty::PredicateAtom::Projection(data) => {
+                        Some((ty::Binder::bind(data).to_poly_trait_ref(self.tcx), obligation))
+                    }
+                    ty::PredicateAtom::Trait(data, _) => {
+                        Some((ty::Binder::bind(data).to_poly_trait_ref(), obligation))
+                    }
+                    ty::PredicateAtom::Subtype(..) => None,
+                    ty::PredicateAtom::RegionOutlives(..) => None,
+                    ty::PredicateAtom::TypeOutlives(..) => None,
+                    ty::PredicateAtom::WellFormed(..) => None,
+                    ty::PredicateAtom::ObjectSafe(..) => None,
+                    ty::PredicateAtom::ConstEvaluatable(..) => None,
+                    ty::PredicateAtom::ConstEquate(..) => None,
+                    // N.B., this predicate is created by breaking down a
+                    // `ClosureType: FnFoo()` predicate, where
+                    // `ClosureType` represents some `Closure`. It can't
+                    // possibly be referring to the current closure,
+                    // because we haven't produced the `Closure` for
+                    // this closure yet; this is exactly why the other
+                    // code is looking for a self type of a unresolved
+                    // inference variable.
+                    ty::PredicateAtom::ClosureKind(..) => None,
+                    ty::PredicateAtom::TypeWellFormedFromEnv(..) => None,
+                }
+            })
+            .filter(move |(tr, _)| self.self_type_matches_expected_vid(*tr, ty_var_root))
+    }
+
+    pub(super) fn type_var_is_sized(&self, self_ty: ty::TyVid) -> bool {
+        self.obligations_for_self_ty(self_ty)
+            .any(|(tr, _)| Some(tr.def_id()) == self.tcx.lang_items().sized_trait())
+    }
+
+    /// Generic function that factors out common logic from function calls,
+    /// method calls and overloaded operators.
+    pub(super) fn check_argument_types(
+        &self,
+        sp: Span,
+        expr: &'tcx hir::Expr<'tcx>,
+        fn_inputs: &[Ty<'tcx>],
+        expected_arg_tys: &[Ty<'tcx>],
+        args: &'tcx [hir::Expr<'tcx>],
+        c_variadic: bool,
+        tuple_arguments: TupleArgumentsFlag,
+        def_span: Option<Span>,
+    ) {
+        let tcx = self.tcx;
+        // Grab the argument types, supplying fresh type variables
+        // if the wrong number of arguments were supplied
+        let supplied_arg_count = if tuple_arguments == DontTupleArguments { args.len() } else { 1 };
+
+        // All the input types from the fn signature must outlive the call
+        // so as to validate implied bounds.
+        for (&fn_input_ty, arg_expr) in fn_inputs.iter().zip(args.iter()) {
+            self.register_wf_obligation(fn_input_ty.into(), arg_expr.span, traits::MiscObligation);
+        }
+
+        let expected_arg_count = fn_inputs.len();
+
+        let param_count_error = |expected_count: usize,
+                                 arg_count: usize,
+                                 error_code: &str,
+                                 c_variadic: bool,
+                                 sugg_unit: bool| {
+            let (span, start_span, args) = match &expr.kind {
+                hir::ExprKind::Call(hir::Expr { span, .. }, args) => (*span, *span, &args[..]),
+                hir::ExprKind::MethodCall(path_segment, span, args, _) => (
+                    *span,
+                    // `sp` doesn't point at the whole `foo.bar()`, only at `bar`.
+                    path_segment
+                        .args
+                        .and_then(|args| args.args.iter().last())
+                        // Account for `foo.bar::<T>()`.
+                        .map(|arg| {
+                            // Skip the closing `>`.
+                            tcx.sess
+                                .source_map()
+                                .next_point(tcx.sess.source_map().next_point(arg.span()))
+                        })
+                        .unwrap_or(*span),
+                    &args[1..], // Skip the receiver.
+                ),
+                k => span_bug!(sp, "checking argument types on a non-call: `{:?}`", k),
+            };
+            let arg_spans = if args.is_empty() {
+                // foo()
+                // ^^^-- supplied 0 arguments
+                // |
+                // expected 2 arguments
+                vec![tcx.sess.source_map().next_point(start_span).with_hi(sp.hi())]
+            } else {
+                // foo(1, 2, 3)
+                // ^^^ -  -  - supplied 3 arguments
+                // |
+                // expected 2 arguments
+                args.iter().map(|arg| arg.span).collect::<Vec<Span>>()
+            };
+
+            let mut err = tcx.sess.struct_span_err_with_code(
+                span,
+                &format!(
+                    "this function takes {}{} but {} {} supplied",
+                    if c_variadic { "at least " } else { "" },
+                    potentially_plural_count(expected_count, "argument"),
+                    potentially_plural_count(arg_count, "argument"),
+                    if arg_count == 1 { "was" } else { "were" }
+                ),
+                DiagnosticId::Error(error_code.to_owned()),
+            );
+            let label = format!("supplied {}", potentially_plural_count(arg_count, "argument"));
+            for (i, span) in arg_spans.into_iter().enumerate() {
+                err.span_label(
+                    span,
+                    if arg_count == 0 || i + 1 == arg_count { &label } else { "" },
+                );
+            }
+
+            if let Some(def_s) = def_span.map(|sp| tcx.sess.source_map().guess_head_span(sp)) {
+                err.span_label(def_s, "defined here");
+            }
+            if sugg_unit {
+                let sugg_span = tcx.sess.source_map().end_point(expr.span);
+                // remove closing `)` from the span
+                let sugg_span = sugg_span.shrink_to_lo();
+                err.span_suggestion(
+                    sugg_span,
+                    "expected the unit value `()`; create it with empty parentheses",
+                    String::from("()"),
+                    Applicability::MachineApplicable,
+                );
+            } else {
+                err.span_label(
+                    span,
+                    format!(
+                        "expected {}{}",
+                        if c_variadic { "at least " } else { "" },
+                        potentially_plural_count(expected_count, "argument")
+                    ),
+                );
+            }
+            err.emit();
+        };
+
+        let mut expected_arg_tys = expected_arg_tys.to_vec();
+
+        let formal_tys = if tuple_arguments == TupleArguments {
+            let tuple_type = self.structurally_resolved_type(sp, fn_inputs[0]);
+            match tuple_type.kind() {
+                ty::Tuple(arg_types) if arg_types.len() != args.len() => {
+                    param_count_error(arg_types.len(), args.len(), "E0057", false, false);
+                    expected_arg_tys = vec![];
+                    self.err_args(args.len())
+                }
+                ty::Tuple(arg_types) => {
+                    expected_arg_tys = match expected_arg_tys.get(0) {
+                        Some(&ty) => match ty.kind() {
+                            ty::Tuple(ref tys) => tys.iter().map(|k| k.expect_ty()).collect(),
+                            _ => vec![],
+                        },
+                        None => vec![],
+                    };
+                    arg_types.iter().map(|k| k.expect_ty()).collect()
+                }
+                _ => {
+                    struct_span_err!(
+                        tcx.sess,
+                        sp,
+                        E0059,
+                        "cannot use call notation; the first type parameter \
+                         for the function trait is neither a tuple nor unit"
+                    )
+                    .emit();
+                    expected_arg_tys = vec![];
+                    self.err_args(args.len())
+                }
+            }
+        } else if expected_arg_count == supplied_arg_count {
+            fn_inputs.to_vec()
+        } else if c_variadic {
+            if supplied_arg_count >= expected_arg_count {
+                fn_inputs.to_vec()
+            } else {
+                param_count_error(expected_arg_count, supplied_arg_count, "E0060", true, false);
+                expected_arg_tys = vec![];
+                self.err_args(supplied_arg_count)
+            }
+        } else {
+            // is the missing argument of type `()`?
+            let sugg_unit = if expected_arg_tys.len() == 1 && supplied_arg_count == 0 {
+                self.resolve_vars_if_possible(&expected_arg_tys[0]).is_unit()
+            } else if fn_inputs.len() == 1 && supplied_arg_count == 0 {
+                self.resolve_vars_if_possible(&fn_inputs[0]).is_unit()
+            } else {
+                false
+            };
+            param_count_error(expected_arg_count, supplied_arg_count, "E0061", false, sugg_unit);
+
+            expected_arg_tys = vec![];
+            self.err_args(supplied_arg_count)
+        };
+
+        debug!(
+            "check_argument_types: formal_tys={:?}",
+            formal_tys.iter().map(|t| self.ty_to_string(*t)).collect::<Vec<String>>()
+        );
+
+        // If there is no expectation, expect formal_tys.
+        let expected_arg_tys =
+            if !expected_arg_tys.is_empty() { expected_arg_tys } else { formal_tys.clone() };
+
+        let mut final_arg_types: Vec<(usize, Ty<'_>, Ty<'_>)> = vec![];
+
+        // Check the arguments.
+        // We do this in a pretty awful way: first we type-check any arguments
+        // that are not closures, then we type-check the closures. This is so
+        // that we have more information about the types of arguments when we
+        // type-check the functions. This isn't really the right way to do this.
+        for &check_closures in &[false, true] {
+            debug!("check_closures={}", check_closures);
+
+            // More awful hacks: before we check argument types, try to do
+            // an "opportunistic" trait resolution of any trait bounds on
+            // the call. This helps coercions.
+            if check_closures {
+                self.select_obligations_where_possible(false, |errors| {
+                    self.point_at_type_arg_instead_of_call_if_possible(errors, expr);
+                    self.point_at_arg_instead_of_call_if_possible(
+                        errors,
+                        &final_arg_types[..],
+                        sp,
+                        &args,
+                    );
+                })
+            }
+
+            // For C-variadic functions, we don't have a declared type for all of
+            // the arguments hence we only do our usual type checking with
+            // the arguments who's types we do know.
+            let t = if c_variadic {
+                expected_arg_count
+            } else if tuple_arguments == TupleArguments {
+                args.len()
+            } else {
+                supplied_arg_count
+            };
+            for (i, arg) in args.iter().take(t).enumerate() {
+                // Warn only for the first loop (the "no closures" one).
+                // Closure arguments themselves can't be diverging, but
+                // a previous argument can, e.g., `foo(panic!(), || {})`.
+                if !check_closures {
+                    self.warn_if_unreachable(arg.hir_id, arg.span, "expression");
+                }
+
+                let is_closure = match arg.kind {
+                    ExprKind::Closure(..) => true,
+                    _ => false,
+                };
+
+                if is_closure != check_closures {
+                    continue;
+                }
+
+                debug!("checking the argument");
+                let formal_ty = formal_tys[i];
+
+                // The special-cased logic below has three functions:
+                // 1. Provide as good of an expected type as possible.
+                let expected = Expectation::rvalue_hint(self, expected_arg_tys[i]);
+
+                let checked_ty = self.check_expr_with_expectation(&arg, expected);
+
+                // 2. Coerce to the most detailed type that could be coerced
+                //    to, which is `expected_ty` if `rvalue_hint` returns an
+                //    `ExpectHasType(expected_ty)`, or the `formal_ty` otherwise.
+                let coerce_ty = expected.only_has_type(self).unwrap_or(formal_ty);
+                // We're processing function arguments so we definitely want to use
+                // two-phase borrows.
+                self.demand_coerce(&arg, checked_ty, coerce_ty, None, AllowTwoPhase::Yes);
+                final_arg_types.push((i, checked_ty, coerce_ty));
+
+                // 3. Relate the expected type and the formal one,
+                //    if the expected type was used for the coercion.
+                self.demand_suptype(arg.span, formal_ty, coerce_ty);
+            }
+        }
+
+        // We also need to make sure we at least write the ty of the other
+        // arguments which we skipped above.
+        if c_variadic {
+            fn variadic_error<'tcx>(s: &Session, span: Span, t: Ty<'tcx>, cast_ty: &str) {
+                use crate::structured_errors::{StructuredDiagnostic, VariadicError};
+                VariadicError::new(s, span, t, cast_ty).diagnostic().emit();
+            }
+
+            for arg in args.iter().skip(expected_arg_count) {
+                let arg_ty = self.check_expr(&arg);
+
+                // There are a few types which get autopromoted when passed via varargs
+                // in C but we just error out instead and require explicit casts.
+                let arg_ty = self.structurally_resolved_type(arg.span, arg_ty);
+                match arg_ty.kind() {
+                    ty::Float(ast::FloatTy::F32) => {
+                        variadic_error(tcx.sess, arg.span, arg_ty, "c_double");
+                    }
+                    ty::Int(ast::IntTy::I8 | ast::IntTy::I16) | ty::Bool => {
+                        variadic_error(tcx.sess, arg.span, arg_ty, "c_int");
+                    }
+                    ty::Uint(ast::UintTy::U8 | ast::UintTy::U16) => {
+                        variadic_error(tcx.sess, arg.span, arg_ty, "c_uint");
+                    }
+                    ty::FnDef(..) => {
+                        let ptr_ty = self.tcx.mk_fn_ptr(arg_ty.fn_sig(self.tcx));
+                        let ptr_ty = self.resolve_vars_if_possible(&ptr_ty);
+                        variadic_error(tcx.sess, arg.span, arg_ty, &ptr_ty.to_string());
+                    }
+                    _ => {}
+                }
+            }
+        }
+    }
+
+    pub(super) fn err_args(&self, len: usize) -> Vec<Ty<'tcx>> {
+        vec![self.tcx.ty_error(); len]
+    }
+
+    /// Given a vec of evaluated `FulfillmentError`s and an `fn` call argument expressions, we walk
+    /// the checked and coerced types for each argument to see if any of the `FulfillmentError`s
+    /// reference a type argument. The reason to walk also the checked type is that the coerced type
+    /// can be not easily comparable with predicate type (because of coercion). If the types match
+    /// for either checked or coerced type, and there's only *one* argument that does, we point at
+    /// the corresponding argument's expression span instead of the `fn` call path span.
+    fn point_at_arg_instead_of_call_if_possible(
+        &self,
+        errors: &mut Vec<traits::FulfillmentError<'tcx>>,
+        final_arg_types: &[(usize, Ty<'tcx>, Ty<'tcx>)],
+        call_sp: Span,
+        args: &'tcx [hir::Expr<'tcx>],
+    ) {
+        // We *do not* do this for desugared call spans to keep good diagnostics when involving
+        // the `?` operator.
+        if call_sp.desugaring_kind().is_some() {
+            return;
+        }
+
+        for error in errors {
+            // Only if the cause is somewhere inside the expression we want try to point at arg.
+            // Otherwise, it means that the cause is somewhere else and we should not change
+            // anything because we can break the correct span.
+            if !call_sp.contains(error.obligation.cause.span) {
+                continue;
+            }
+
+            if let ty::PredicateAtom::Trait(predicate, _) =
+                error.obligation.predicate.skip_binders()
+            {
+                // Collect the argument position for all arguments that could have caused this
+                // `FulfillmentError`.
+                let mut referenced_in = final_arg_types
+                    .iter()
+                    .map(|&(i, checked_ty, _)| (i, checked_ty))
+                    .chain(final_arg_types.iter().map(|&(i, _, coerced_ty)| (i, coerced_ty)))
+                    .flat_map(|(i, ty)| {
+                        let ty = self.resolve_vars_if_possible(&ty);
+                        // We walk the argument type because the argument's type could have
+                        // been `Option<T>`, but the `FulfillmentError` references `T`.
+                        if ty.walk().any(|arg| arg == predicate.self_ty().into()) {
+                            Some(i)
+                        } else {
+                            None
+                        }
+                    })
+                    .collect::<Vec<usize>>();
+
+                // Both checked and coerced types could have matched, thus we need to remove
+                // duplicates.
+
+                // We sort primitive type usize here and can use unstable sort
+                referenced_in.sort_unstable();
+                referenced_in.dedup();
+
+                if let (Some(ref_in), None) = (referenced_in.pop(), referenced_in.pop()) {
+                    // We make sure that only *one* argument matches the obligation failure
+                    // and we assign the obligation's span to its expression's.
+                    error.obligation.cause.make_mut().span = args[ref_in].span;
+                    error.points_at_arg_span = true;
+                }
+            }
+        }
+    }
+
+    /// Given a vec of evaluated `FulfillmentError`s and an `fn` call expression, we walk the
+    /// `PathSegment`s and resolve their type parameters to see if any of the `FulfillmentError`s
+    /// were caused by them. If they were, we point at the corresponding type argument's span
+    /// instead of the `fn` call path span.
+    fn point_at_type_arg_instead_of_call_if_possible(
+        &self,
+        errors: &mut Vec<traits::FulfillmentError<'tcx>>,
+        call_expr: &'tcx hir::Expr<'tcx>,
+    ) {
+        if let hir::ExprKind::Call(path, _) = &call_expr.kind {
+            if let hir::ExprKind::Path(qpath) = &path.kind {
+                if let hir::QPath::Resolved(_, path) = &qpath {
+                    for error in errors {
+                        if let ty::PredicateAtom::Trait(predicate, _) =
+                            error.obligation.predicate.skip_binders()
+                        {
+                            // If any of the type arguments in this path segment caused the
+                            // `FullfillmentError`, point at its span (#61860).
+                            for arg in path
+                                .segments
+                                .iter()
+                                .filter_map(|seg| seg.args.as_ref())
+                                .flat_map(|a| a.args.iter())
+                            {
+                                if let hir::GenericArg::Type(hir_ty) = &arg {
+                                    if let hir::TyKind::Path(hir::QPath::TypeRelative(..)) =
+                                        &hir_ty.kind
+                                    {
+                                        // Avoid ICE with associated types. As this is best
+                                        // effort only, it's ok to ignore the case. It
+                                        // would trigger in `is_send::<T::AssocType>();`
+                                        // from `typeck-default-trait-impl-assoc-type.rs`.
+                                    } else {
+                                        let ty = AstConv::ast_ty_to_ty(self, hir_ty);
+                                        let ty = self.resolve_vars_if_possible(&ty);
+                                        if ty == predicate.self_ty() {
+                                            error.obligation.cause.make_mut().span = hir_ty.span;
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    // AST fragment checking
+    pub(super) fn check_lit(&self, lit: &hir::Lit, expected: Expectation<'tcx>) -> Ty<'tcx> {
+        let tcx = self.tcx;
+
+        match lit.node {
+            ast::LitKind::Str(..) => tcx.mk_static_str(),
+            ast::LitKind::ByteStr(ref v) => {
+                tcx.mk_imm_ref(tcx.lifetimes.re_static, tcx.mk_array(tcx.types.u8, v.len() as u64))
+            }
+            ast::LitKind::Byte(_) => tcx.types.u8,
+            ast::LitKind::Char(_) => tcx.types.char,
+            ast::LitKind::Int(_, ast::LitIntType::Signed(t)) => tcx.mk_mach_int(t),
+            ast::LitKind::Int(_, ast::LitIntType::Unsigned(t)) => tcx.mk_mach_uint(t),
+            ast::LitKind::Int(_, ast::LitIntType::Unsuffixed) => {
+                let opt_ty = expected.to_option(self).and_then(|ty| match ty.kind() {
+                    ty::Int(_) | ty::Uint(_) => Some(ty),
+                    ty::Char => Some(tcx.types.u8),
+                    ty::RawPtr(..) => Some(tcx.types.usize),
+                    ty::FnDef(..) | ty::FnPtr(_) => Some(tcx.types.usize),
+                    _ => None,
+                });
+                opt_ty.unwrap_or_else(|| self.next_int_var())
+            }
+            ast::LitKind::Float(_, ast::LitFloatType::Suffixed(t)) => tcx.mk_mach_float(t),
+            ast::LitKind::Float(_, ast::LitFloatType::Unsuffixed) => {
+                let opt_ty = expected.to_option(self).and_then(|ty| match ty.kind() {
+                    ty::Float(_) => Some(ty),
+                    _ => None,
+                });
+                opt_ty.unwrap_or_else(|| self.next_float_var())
+            }
+            ast::LitKind::Bool(_) => tcx.types.bool,
+            ast::LitKind::Err(_) => tcx.ty_error(),
+        }
+    }
+
+    /// Unifies the output type with the expected type early, for more coercions
+    /// and forward type information on the input expressions.
+    pub(super) fn expected_inputs_for_expected_output(
+        &self,
+        call_span: Span,
+        expected_ret: Expectation<'tcx>,
+        formal_ret: Ty<'tcx>,
+        formal_args: &[Ty<'tcx>],
+    ) -> Vec<Ty<'tcx>> {
+        let formal_ret = self.resolve_vars_with_obligations(formal_ret);
+        let ret_ty = match expected_ret.only_has_type(self) {
+            Some(ret) => ret,
+            None => return Vec::new(),
+        };
+        let expect_args = self
+            .fudge_inference_if_ok(|| {
+                // Attempt to apply a subtyping relationship between the formal
+                // return type (likely containing type variables if the function
+                // is polymorphic) and the expected return type.
+                // No argument expectations are produced if unification fails.
+                let origin = self.misc(call_span);
+                let ures = self.at(&origin, self.param_env).sup(ret_ty, &formal_ret);
+
+                // FIXME(#27336) can't use ? here, Try::from_error doesn't default
+                // to identity so the resulting type is not constrained.
+                match ures {
+                    Ok(ok) => {
+                        // Process any obligations locally as much as
+                        // we can.  We don't care if some things turn
+                        // out unconstrained or ambiguous, as we're
+                        // just trying to get hints here.
+                        self.save_and_restore_in_snapshot_flag(|_| {
+                            let mut fulfill = TraitEngine::new(self.tcx);
+                            for obligation in ok.obligations {
+                                fulfill.register_predicate_obligation(self, obligation);
+                            }
+                            fulfill.select_where_possible(self)
+                        })
+                        .map_err(|_| ())?;
+                    }
+                    Err(_) => return Err(()),
+                }
+
+                // Record all the argument types, with the substitutions
+                // produced from the above subtyping unification.
+                Ok(formal_args.iter().map(|ty| self.resolve_vars_if_possible(ty)).collect())
+            })
+            .unwrap_or_default();
+        debug!(
+            "expected_inputs_for_expected_output(formal={:?} -> {:?}, expected={:?} -> {:?})",
+            formal_args, formal_ret, expect_args, expected_ret
+        );
+        expect_args
+    }
+
+    pub fn check_struct_path(
+        &self,
+        qpath: &QPath<'_>,
+        hir_id: hir::HirId,
+    ) -> Option<(&'tcx ty::VariantDef, Ty<'tcx>)> {
+        let path_span = qpath.qself_span();
+        let (def, ty) = self.finish_resolving_struct_path(qpath, path_span, hir_id);
+        let variant = match def {
+            Res::Err => {
+                self.set_tainted_by_errors();
+                return None;
+            }
+            Res::Def(DefKind::Variant, _) => match ty.kind() {
+                ty::Adt(adt, substs) => Some((adt.variant_of_res(def), adt.did, substs)),
+                _ => bug!("unexpected type: {:?}", ty),
+            },
+            Res::Def(DefKind::Struct | DefKind::Union | DefKind::TyAlias | DefKind::AssocTy, _)
+            | Res::SelfTy(..) => match ty.kind() {
+                ty::Adt(adt, substs) if !adt.is_enum() => {
+                    Some((adt.non_enum_variant(), adt.did, substs))
+                }
+                _ => None,
+            },
+            _ => bug!("unexpected definition: {:?}", def),
+        };
+
+        if let Some((variant, did, substs)) = variant {
+            debug!("check_struct_path: did={:?} substs={:?}", did, substs);
+            self.write_user_type_annotation_from_substs(hir_id, did, substs, None);
+
+            // Check bounds on type arguments used in the path.
+            let (bounds, _) = self.instantiate_bounds(path_span, did, substs);
+            let cause =
+                traits::ObligationCause::new(path_span, self.body_id, traits::ItemObligation(did));
+            self.add_obligations_for_parameters(cause, bounds);
+
+            Some((variant, ty))
+        } else {
+            struct_span_err!(
+                self.tcx.sess,
+                path_span,
+                E0071,
+                "expected struct, variant or union type, found {}",
+                ty.sort_string(self.tcx)
+            )
+            .span_label(path_span, "not a struct")
+            .emit();
+            None
+        }
+    }
+
+    // Finish resolving a path in a struct expression or pattern `S::A { .. }` if necessary.
+    // The newly resolved definition is written into `type_dependent_defs`.
+    fn finish_resolving_struct_path(
+        &self,
+        qpath: &QPath<'_>,
+        path_span: Span,
+        hir_id: hir::HirId,
+    ) -> (Res, Ty<'tcx>) {
+        match *qpath {
+            QPath::Resolved(ref maybe_qself, ref path) => {
+                let self_ty = maybe_qself.as_ref().map(|qself| self.to_ty(qself));
+                let ty = AstConv::res_to_ty(self, self_ty, path, true);
+                (path.res, ty)
+            }
+            QPath::TypeRelative(ref qself, ref segment) => {
+                let ty = self.to_ty(qself);
+
+                let res = if let hir::TyKind::Path(QPath::Resolved(_, ref path)) = qself.kind {
+                    path.res
+                } else {
+                    Res::Err
+                };
+                let result =
+                    AstConv::associated_path_to_ty(self, hir_id, path_span, ty, res, segment, true);
+                let ty = result.map(|(ty, _, _)| ty).unwrap_or_else(|_| self.tcx().ty_error());
+                let result = result.map(|(_, kind, def_id)| (kind, def_id));
+
+                // Write back the new resolution.
+                self.write_resolution(hir_id, result);
+
+                (result.map(|(kind, def_id)| Res::Def(kind, def_id)).unwrap_or(Res::Err), ty)
+            }
+            QPath::LangItem(lang_item, span) => {
+                self.resolve_lang_item_path(lang_item, span, hir_id)
+            }
+        }
+    }
+
+    pub(super) fn resolve_lang_item_path(
+        &self,
+        lang_item: hir::LangItem,
+        span: Span,
+        hir_id: hir::HirId,
+    ) -> (Res, Ty<'tcx>) {
+        let def_id = self.tcx.require_lang_item(lang_item, Some(span));
+        let def_kind = self.tcx.def_kind(def_id);
+
+        let item_ty = if let DefKind::Variant = def_kind {
+            self.tcx.type_of(self.tcx.parent(def_id).expect("variant w/out parent"))
+        } else {
+            self.tcx.type_of(def_id)
+        };
+        let substs = self.infcx.fresh_substs_for_item(span, def_id);
+        let ty = item_ty.subst(self.tcx, substs);
+
+        self.write_resolution(hir_id, Ok((def_kind, def_id)));
+        self.add_required_obligations(span, def_id, &substs);
+        (Res::Def(def_kind, def_id), ty)
+    }
+
+    /// Resolves an associated value path into a base type and associated constant, or method
+    /// resolution. The newly resolved definition is written into `type_dependent_defs`.
+    pub fn resolve_ty_and_res_ufcs<'b>(
+        &self,
+        qpath: &'b QPath<'b>,
+        hir_id: hir::HirId,
+        span: Span,
+    ) -> (Res, Option<Ty<'tcx>>, &'b [hir::PathSegment<'b>]) {
+        debug!("resolve_ty_and_res_ufcs: qpath={:?} hir_id={:?} span={:?}", qpath, hir_id, span);
+        let (ty, qself, item_segment) = match *qpath {
+            QPath::Resolved(ref opt_qself, ref path) => {
+                return (
+                    path.res,
+                    opt_qself.as_ref().map(|qself| self.to_ty(qself)),
+                    &path.segments[..],
+                );
+            }
+            QPath::TypeRelative(ref qself, ref segment) => (self.to_ty(qself), qself, segment),
+            QPath::LangItem(..) => bug!("`resolve_ty_and_res_ufcs` called on `LangItem`"),
+        };
+        if let Some(&cached_result) = self.typeck_results.borrow().type_dependent_defs().get(hir_id)
+        {
+            // Return directly on cache hit. This is useful to avoid doubly reporting
+            // errors with default match binding modes. See #44614.
+            let def =
+                cached_result.map(|(kind, def_id)| Res::Def(kind, def_id)).unwrap_or(Res::Err);
+            return (def, Some(ty), slice::from_ref(&**item_segment));
+        }
+        let item_name = item_segment.ident;
+        let result = self.resolve_ufcs(span, item_name, ty, hir_id).or_else(|error| {
+            let result = match error {
+                method::MethodError::PrivateMatch(kind, def_id, _) => Ok((kind, def_id)),
+                _ => Err(ErrorReported),
+            };
+            if item_name.name != kw::Invalid {
+                if let Some(mut e) = self.report_method_error(
+                    span,
+                    ty,
+                    item_name,
+                    SelfSource::QPath(qself),
+                    error,
+                    None,
+                ) {
+                    e.emit();
+                }
+            }
+            result
+        });
+
+        // Write back the new resolution.
+        self.write_resolution(hir_id, result);
+        (
+            result.map(|(kind, def_id)| Res::Def(kind, def_id)).unwrap_or(Res::Err),
+            Some(ty),
+            slice::from_ref(&**item_segment),
+        )
+    }
+
+    pub fn check_decl_initializer(
+        &self,
+        local: &'tcx hir::Local<'tcx>,
+        init: &'tcx hir::Expr<'tcx>,
+    ) -> Ty<'tcx> {
+        // FIXME(tschottdorf): `contains_explicit_ref_binding()` must be removed
+        // for #42640 (default match binding modes).
+        //
+        // See #44848.
+        let ref_bindings = local.pat.contains_explicit_ref_binding();
+
+        let local_ty = self.local_ty(init.span, local.hir_id).revealed_ty;
+        if let Some(m) = ref_bindings {
+            // Somewhat subtle: if we have a `ref` binding in the pattern,
+            // we want to avoid introducing coercions for the RHS. This is
+            // both because it helps preserve sanity and, in the case of
+            // ref mut, for soundness (issue #23116). In particular, in
+            // the latter case, we need to be clear that the type of the
+            // referent for the reference that results is *equal to* the
+            // type of the place it is referencing, and not some
+            // supertype thereof.
+            let init_ty = self.check_expr_with_needs(init, Needs::maybe_mut_place(m));
+            self.demand_eqtype(init.span, local_ty, init_ty);
+            init_ty
+        } else {
+            self.check_expr_coercable_to_type(init, local_ty, None)
+        }
+    }
+
+    /// Type check a `let` statement.
+    pub fn check_decl_local(&self, local: &'tcx hir::Local<'tcx>) {
+        // Determine and write the type which we'll check the pattern against.
+        let ty = self.local_ty(local.span, local.hir_id).decl_ty;
+        self.write_ty(local.hir_id, ty);
+
+        // Type check the initializer.
+        if let Some(ref init) = local.init {
+            let init_ty = self.check_decl_initializer(local, &init);
+            self.overwrite_local_ty_if_err(local, ty, init_ty);
+        }
+
+        // Does the expected pattern type originate from an expression and what is the span?
+        let (origin_expr, ty_span) = match (local.ty, local.init) {
+            (Some(ty), _) => (false, Some(ty.span)), // Bias towards the explicit user type.
+            (_, Some(init)) => (true, Some(init.span)), // No explicit type; so use the scrutinee.
+            _ => (false, None), // We have `let $pat;`, so the expected type is unconstrained.
+        };
+
+        // Type check the pattern. Override if necessary to avoid knock-on errors.
+        self.check_pat_top(&local.pat, ty, ty_span, origin_expr);
+        let pat_ty = self.node_ty(local.pat.hir_id);
+        self.overwrite_local_ty_if_err(local, ty, pat_ty);
+    }
+
+    fn overwrite_local_ty_if_err(
+        &self,
+        local: &'tcx hir::Local<'tcx>,
+        decl_ty: Ty<'tcx>,
+        ty: Ty<'tcx>,
+    ) {
+        if ty.references_error() {
+            // Override the types everywhere with `err()` to avoid knock on errors.
+            self.write_ty(local.hir_id, ty);
+            self.write_ty(local.pat.hir_id, ty);
+            let local_ty = LocalTy { decl_ty, revealed_ty: ty };
+            self.locals.borrow_mut().insert(local.hir_id, local_ty);
+            self.locals.borrow_mut().insert(local.pat.hir_id, local_ty);
+        }
+    }
+
+    pub(super) fn suggest_semicolon_at_end(&self, span: Span, err: &mut DiagnosticBuilder<'_>) {
+        err.span_suggestion_short(
+            span.shrink_to_hi(),
+            "consider using a semicolon here",
+            ";".to_string(),
+            Applicability::MachineApplicable,
+        );
+    }
+
+    pub fn check_stmt(&self, stmt: &'tcx hir::Stmt<'tcx>) {
+        // Don't do all the complex logic below for `DeclItem`.
+        match stmt.kind {
+            hir::StmtKind::Item(..) => return,
+            hir::StmtKind::Local(..) | hir::StmtKind::Expr(..) | hir::StmtKind::Semi(..) => {}
+        }
+
+        self.warn_if_unreachable(stmt.hir_id, stmt.span, "statement");
+
+        // Hide the outer diverging and `has_errors` flags.
+        let old_diverges = self.diverges.replace(Diverges::Maybe);
+        let old_has_errors = self.has_errors.replace(false);
+
+        match stmt.kind {
+            hir::StmtKind::Local(ref l) => {
+                self.check_decl_local(&l);
+            }
+            // Ignore for now.
+            hir::StmtKind::Item(_) => {}
+            hir::StmtKind::Expr(ref expr) => {
+                // Check with expected type of `()`.
+                self.check_expr_has_type_or_error(&expr, self.tcx.mk_unit(), |err| {
+                    self.suggest_semicolon_at_end(expr.span, err);
+                });
+            }
+            hir::StmtKind::Semi(ref expr) => {
+                self.check_expr(&expr);
+            }
+        }
+
+        // Combine the diverging and `has_error` flags.
+        self.diverges.set(self.diverges.get() | old_diverges);
+        self.has_errors.set(self.has_errors.get() | old_has_errors);
+    }
+
+    pub fn check_block_no_value(&self, blk: &'tcx hir::Block<'tcx>) {
+        let unit = self.tcx.mk_unit();
+        let ty = self.check_block_with_expected(blk, ExpectHasType(unit));
+
+        // if the block produces a `!` value, that can always be
+        // (effectively) coerced to unit.
+        if !ty.is_never() {
+            self.demand_suptype(blk.span, unit, ty);
+        }
+    }
+
+    /// If `expr` is a `match` expression that has only one non-`!` arm, use that arm's tail
+    /// expression's `Span`, otherwise return `expr.span`. This is done to give better errors
+    /// when given code like the following:
+    /// ```text
+    /// if false { return 0i32; } else { 1u32 }
+    /// //                               ^^^^ point at this instead of the whole `if` expression
+    /// ```
+    fn get_expr_coercion_span(&self, expr: &hir::Expr<'_>) -> rustc_span::Span {
+        if let hir::ExprKind::Match(_, arms, _) = &expr.kind {
+            let arm_spans: Vec<Span> = arms
+                .iter()
+                .filter_map(|arm| {
+                    self.in_progress_typeck_results
+                        .and_then(|typeck_results| {
+                            typeck_results.borrow().node_type_opt(arm.body.hir_id)
+                        })
+                        .and_then(|arm_ty| {
+                            if arm_ty.is_never() {
+                                None
+                            } else {
+                                Some(match &arm.body.kind {
+                                    // Point at the tail expression when possible.
+                                    hir::ExprKind::Block(block, _) => {
+                                        block.expr.as_ref().map(|e| e.span).unwrap_or(block.span)
+                                    }
+                                    _ => arm.body.span,
+                                })
+                            }
+                        })
+                })
+                .collect();
+            if arm_spans.len() == 1 {
+                return arm_spans[0];
+            }
+        }
+        expr.span
+    }
+
+    pub(super) fn check_block_with_expected(
+        &self,
+        blk: &'tcx hir::Block<'tcx>,
+        expected: Expectation<'tcx>,
+    ) -> Ty<'tcx> {
+        let prev = {
+            let mut fcx_ps = self.ps.borrow_mut();
+            let unsafety_state = fcx_ps.recurse(blk);
+            replace(&mut *fcx_ps, unsafety_state)
+        };
+
+        // In some cases, blocks have just one exit, but other blocks
+        // can be targeted by multiple breaks. This can happen both
+        // with labeled blocks as well as when we desugar
+        // a `try { ... }` expression.
+        //
+        // Example 1:
+        //
+        //    'a: { if true { break 'a Err(()); } Ok(()) }
+        //
+        // Here we would wind up with two coercions, one from
+        // `Err(())` and the other from the tail expression
+        // `Ok(())`. If the tail expression is omitted, that's a
+        // "forced unit" -- unless the block diverges, in which
+        // case we can ignore the tail expression (e.g., `'a: {
+        // break 'a 22; }` would not force the type of the block
+        // to be `()`).
+        let tail_expr = blk.expr.as_ref();
+        let coerce_to_ty = expected.coercion_target_type(self, blk.span);
+        let coerce = if blk.targeted_by_break {
+            CoerceMany::new(coerce_to_ty)
+        } else {
+            let tail_expr: &[&hir::Expr<'_>] = match tail_expr {
+                Some(e) => slice::from_ref(e),
+                None => &[],
+            };
+            CoerceMany::with_coercion_sites(coerce_to_ty, tail_expr)
+        };
+
+        let prev_diverges = self.diverges.get();
+        let ctxt = BreakableCtxt { coerce: Some(coerce), may_break: false };
+
+        let (ctxt, ()) = self.with_breakable_ctxt(blk.hir_id, ctxt, || {
+            for s in blk.stmts {
+                self.check_stmt(s);
+            }
+
+            // check the tail expression **without** holding the
+            // `enclosing_breakables` lock below.
+            let tail_expr_ty = tail_expr.map(|t| self.check_expr_with_expectation(t, expected));
+
+            let mut enclosing_breakables = self.enclosing_breakables.borrow_mut();
+            let ctxt = enclosing_breakables.find_breakable(blk.hir_id);
+            let coerce = ctxt.coerce.as_mut().unwrap();
+            if let Some(tail_expr_ty) = tail_expr_ty {
+                let tail_expr = tail_expr.unwrap();
+                let span = self.get_expr_coercion_span(tail_expr);
+                let cause = self.cause(span, ObligationCauseCode::BlockTailExpression(blk.hir_id));
+                coerce.coerce(self, &cause, tail_expr, tail_expr_ty);
+            } else {
+                // Subtle: if there is no explicit tail expression,
+                // that is typically equivalent to a tail expression
+                // of `()` -- except if the block diverges. In that
+                // case, there is no value supplied from the tail
+                // expression (assuming there are no other breaks,
+                // this implies that the type of the block will be
+                // `!`).
+                //
+                // #41425 -- label the implicit `()` as being the
+                // "found type" here, rather than the "expected type".
+                if !self.diverges.get().is_always() {
+                    // #50009 -- Do not point at the entire fn block span, point at the return type
+                    // span, as it is the cause of the requirement, and
+                    // `consider_hint_about_removing_semicolon` will point at the last expression
+                    // if it were a relevant part of the error. This improves usability in editors
+                    // that highlight errors inline.
+                    let mut sp = blk.span;
+                    let mut fn_span = None;
+                    if let Some((decl, ident)) = self.get_parent_fn_decl(blk.hir_id) {
+                        let ret_sp = decl.output.span();
+                        if let Some(block_sp) = self.parent_item_span(blk.hir_id) {
+                            // HACK: on some cases (`ui/liveness/liveness-issue-2163.rs`) the
+                            // output would otherwise be incorrect and even misleading. Make sure
+                            // the span we're aiming at correspond to a `fn` body.
+                            if block_sp == blk.span {
+                                sp = ret_sp;
+                                fn_span = Some(ident.span);
+                            }
+                        }
+                    }
+                    coerce.coerce_forced_unit(
+                        self,
+                        &self.misc(sp),
+                        &mut |err| {
+                            if let Some(expected_ty) = expected.only_has_type(self) {
+                                self.consider_hint_about_removing_semicolon(blk, expected_ty, err);
+                            }
+                            if let Some(fn_span) = fn_span {
+                                err.span_label(
+                                    fn_span,
+                                    "implicitly returns `()` as its body has no tail or `return` \
+                                     expression",
+                                );
+                            }
+                        },
+                        false,
+                    );
+                }
+            }
+        });
+
+        if ctxt.may_break {
+            // If we can break from the block, then the block's exit is always reachable
+            // (... as long as the entry is reachable) - regardless of the tail of the block.
+            self.diverges.set(prev_diverges);
+        }
+
+        let mut ty = ctxt.coerce.unwrap().complete(self);
+
+        if self.has_errors.get() || ty.references_error() {
+            ty = self.tcx.ty_error()
+        }
+
+        self.write_ty(blk.hir_id, ty);
+
+        *self.ps.borrow_mut() = prev;
+        ty
+    }
+
+    fn parent_item_span(&self, id: hir::HirId) -> Option<Span> {
+        let node = self.tcx.hir().get(self.tcx.hir().get_parent_item(id));
+        match node {
+            Node::Item(&hir::Item { kind: hir::ItemKind::Fn(_, _, body_id), .. })
+            | Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(_, body_id), .. }) => {
+                let body = self.tcx.hir().body(body_id);
+                if let ExprKind::Block(block, _) = &body.value.kind {
+                    return Some(block.span);
+                }
+            }
+            _ => {}
+        }
+        None
+    }
+
+    /// Given a function block's `HirId`, returns its `FnDecl` if it exists, or `None` otherwise.
+    fn get_parent_fn_decl(&self, blk_id: hir::HirId) -> Option<(&'tcx hir::FnDecl<'tcx>, Ident)> {
+        let parent = self.tcx.hir().get(self.tcx.hir().get_parent_item(blk_id));
+        self.get_node_fn_decl(parent).map(|(fn_decl, ident, _)| (fn_decl, ident))
+    }
+
+    /// Given a function `Node`, return its `FnDecl` if it exists, or `None` otherwise.
+    pub(super) fn get_node_fn_decl(
+        &self,
+        node: Node<'tcx>,
+    ) -> Option<(&'tcx hir::FnDecl<'tcx>, Ident, bool)> {
+        match node {
+            Node::Item(&hir::Item { ident, kind: hir::ItemKind::Fn(ref sig, ..), .. }) => {
+                // This is less than ideal, it will not suggest a return type span on any
+                // method called `main`, regardless of whether it is actually the entry point,
+                // but it will still present it as the reason for the expected type.
+                Some((&sig.decl, ident, ident.name != sym::main))
+            }
+            Node::TraitItem(&hir::TraitItem {
+                ident,
+                kind: hir::TraitItemKind::Fn(ref sig, ..),
+                ..
+            }) => Some((&sig.decl, ident, true)),
+            Node::ImplItem(&hir::ImplItem {
+                ident,
+                kind: hir::ImplItemKind::Fn(ref sig, ..),
+                ..
+            }) => Some((&sig.decl, ident, false)),
+            _ => None,
+        }
+    }
+
+    /// Given a `HirId`, return the `FnDecl` of the method it is enclosed by and whether a
+    /// suggestion can be made, `None` otherwise.
+    pub fn get_fn_decl(&self, blk_id: hir::HirId) -> Option<(&'tcx hir::FnDecl<'tcx>, bool)> {
+        // Get enclosing Fn, if it is a function or a trait method, unless there's a `loop` or
+        // `while` before reaching it, as block tail returns are not available in them.
+        self.tcx.hir().get_return_block(blk_id).and_then(|blk_id| {
+            let parent = self.tcx.hir().get(blk_id);
+            self.get_node_fn_decl(parent).map(|(fn_decl, _, is_main)| (fn_decl, is_main))
+        })
+    }
+
+    /// On implicit return expressions with mismatched types, provides the following suggestions:
+    ///
+    /// - Points out the method's return type as the reason for the expected type.
+    /// - Possible missing semicolon.
+    /// - Possible missing return type if the return type is the default, and not `fn main()`.
+    pub fn suggest_mismatched_types_on_tail(
+        &self,
+        err: &mut DiagnosticBuilder<'_>,
+        expr: &'tcx hir::Expr<'tcx>,
+        expected: Ty<'tcx>,
+        found: Ty<'tcx>,
+        cause_span: Span,
+        blk_id: hir::HirId,
+    ) -> bool {
+        let expr = expr.peel_drop_temps();
+        self.suggest_missing_semicolon(err, expr, expected, cause_span);
+        let mut pointing_at_return_type = false;
+        if let Some((fn_decl, can_suggest)) = self.get_fn_decl(blk_id) {
+            pointing_at_return_type =
+                self.suggest_missing_return_type(err, &fn_decl, expected, found, can_suggest);
+        }
+        pointing_at_return_type
+    }
+
+    /// When encountering an fn-like ctor that needs to unify with a value, check whether calling
+    /// the ctor would successfully solve the type mismatch and if so, suggest it:
+    /// ```
+    /// fn foo(x: usize) -> usize { x }
+    /// let x: usize = foo;  // suggest calling the `foo` function: `foo(42)`
+    /// ```
+    fn suggest_fn_call(
+        &self,
+        err: &mut DiagnosticBuilder<'_>,
+        expr: &hir::Expr<'_>,
+        expected: Ty<'tcx>,
+        found: Ty<'tcx>,
+    ) -> bool {
+        let hir = self.tcx.hir();
+        let (def_id, sig) = match *found.kind() {
+            ty::FnDef(def_id, _) => (def_id, found.fn_sig(self.tcx)),
+            ty::Closure(def_id, substs) => (def_id, substs.as_closure().sig()),
+            _ => return false,
+        };
+
+        let sig = self.replace_bound_vars_with_fresh_vars(expr.span, infer::FnCall, &sig).0;
+        let sig = self.normalize_associated_types_in(expr.span, &sig);
+        if self.can_coerce(sig.output(), expected) {
+            let (mut sugg_call, applicability) = if sig.inputs().is_empty() {
+                (String::new(), Applicability::MachineApplicable)
+            } else {
+                ("...".to_string(), Applicability::HasPlaceholders)
+            };
+            let mut msg = "call this function";
+            match hir.get_if_local(def_id) {
+                Some(
+                    Node::Item(hir::Item { kind: ItemKind::Fn(.., body_id), .. })
+                    | Node::ImplItem(hir::ImplItem {
+                        kind: hir::ImplItemKind::Fn(_, body_id), ..
+                    })
+                    | Node::TraitItem(hir::TraitItem {
+                        kind: hir::TraitItemKind::Fn(.., hir::TraitFn::Provided(body_id)),
+                        ..
+                    }),
+                ) => {
+                    let body = hir.body(*body_id);
+                    sugg_call = body
+                        .params
+                        .iter()
+                        .map(|param| match &param.pat.kind {
+                            hir::PatKind::Binding(_, _, ident, None)
+                                if ident.name != kw::SelfLower =>
+                            {
+                                ident.to_string()
+                            }
+                            _ => "_".to_string(),
+                        })
+                        .collect::<Vec<_>>()
+                        .join(", ");
+                }
+                Some(Node::Expr(hir::Expr {
+                    kind: ExprKind::Closure(_, _, body_id, _, _),
+                    span: full_closure_span,
+                    ..
+                })) => {
+                    if *full_closure_span == expr.span {
+                        return false;
+                    }
+                    msg = "call this closure";
+                    let body = hir.body(*body_id);
+                    sugg_call = body
+                        .params
+                        .iter()
+                        .map(|param| match &param.pat.kind {
+                            hir::PatKind::Binding(_, _, ident, None)
+                                if ident.name != kw::SelfLower =>
+                            {
+                                ident.to_string()
+                            }
+                            _ => "_".to_string(),
+                        })
+                        .collect::<Vec<_>>()
+                        .join(", ");
+                }
+                Some(Node::Ctor(hir::VariantData::Tuple(fields, _))) => {
+                    sugg_call = fields.iter().map(|_| "_").collect::<Vec<_>>().join(", ");
+                    match def_id.as_local().map(|def_id| hir.def_kind(def_id)) {
+                        Some(DefKind::Ctor(hir::def::CtorOf::Variant, _)) => {
+                            msg = "instantiate this tuple variant";
+                        }
+                        Some(DefKind::Ctor(CtorOf::Struct, _)) => {
+                            msg = "instantiate this tuple struct";
+                        }
+                        _ => {}
+                    }
+                }
+                Some(Node::ForeignItem(hir::ForeignItem {
+                    kind: hir::ForeignItemKind::Fn(_, idents, _),
+                    ..
+                })) => {
+                    sugg_call = idents
+                        .iter()
+                        .map(|ident| {
+                            if ident.name != kw::SelfLower {
+                                ident.to_string()
+                            } else {
+                                "_".to_string()
+                            }
+                        })
+                        .collect::<Vec<_>>()
+                        .join(", ")
+                }
+                Some(Node::TraitItem(hir::TraitItem {
+                    kind: hir::TraitItemKind::Fn(.., hir::TraitFn::Required(idents)),
+                    ..
+                })) => {
+                    sugg_call = idents
+                        .iter()
+                        .map(|ident| {
+                            if ident.name != kw::SelfLower {
+                                ident.to_string()
+                            } else {
+                                "_".to_string()
+                            }
+                        })
+                        .collect::<Vec<_>>()
+                        .join(", ")
+                }
+                _ => {}
+            }
+            err.span_suggestion_verbose(
+                expr.span.shrink_to_hi(),
+                &format!("use parentheses to {}", msg),
+                format!("({})", sugg_call),
+                applicability,
+            );
+            return true;
+        }
+        false
+    }
+
+    pub fn suggest_deref_ref_or_into(
+        &self,
+        err: &mut DiagnosticBuilder<'_>,
+        expr: &hir::Expr<'_>,
+        expected: Ty<'tcx>,
+        found: Ty<'tcx>,
+        expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
+    ) {
+        if let Some((sp, msg, suggestion, applicability)) = self.check_ref(expr, found, expected) {
+            err.span_suggestion(sp, msg, suggestion, applicability);
+        } else if let (ty::FnDef(def_id, ..), true) =
+            (&found.kind(), self.suggest_fn_call(err, expr, expected, found))
+        {
+            if let Some(sp) = self.tcx.hir().span_if_local(*def_id) {
+                let sp = self.sess().source_map().guess_head_span(sp);
+                err.span_label(sp, &format!("{} defined here", found));
+            }
+        } else if !self.check_for_cast(err, expr, found, expected, expected_ty_expr) {
+            let is_struct_pat_shorthand_field =
+                self.is_hir_id_from_struct_pattern_shorthand_field(expr.hir_id, expr.span);
+            let methods = self.get_conversion_methods(expr.span, expected, found, expr.hir_id);
+            if let Ok(expr_text) = self.sess().source_map().span_to_snippet(expr.span) {
+                let mut suggestions = iter::repeat(&expr_text)
+                    .zip(methods.iter())
+                    .filter_map(|(receiver, method)| {
+                        let method_call = format!(".{}()", method.ident);
+                        if receiver.ends_with(&method_call) {
+                            None // do not suggest code that is already there (#53348)
+                        } else {
+                            let method_call_list = [".to_vec()", ".to_string()"];
+                            let sugg = if receiver.ends_with(".clone()")
+                                && method_call_list.contains(&method_call.as_str())
+                            {
+                                let max_len = receiver.rfind('.').unwrap();
+                                format!("{}{}", &receiver[..max_len], method_call)
+                            } else {
+                                if expr.precedence().order() < ExprPrecedence::MethodCall.order() {
+                                    format!("({}){}", receiver, method_call)
+                                } else {
+                                    format!("{}{}", receiver, method_call)
+                                }
+                            };
+                            Some(if is_struct_pat_shorthand_field {
+                                format!("{}: {}", receiver, sugg)
+                            } else {
+                                sugg
+                            })
+                        }
+                    })
+                    .peekable();
+                if suggestions.peek().is_some() {
+                    err.span_suggestions(
+                        expr.span,
+                        "try using a conversion method",
+                        suggestions,
+                        Applicability::MaybeIncorrect,
+                    );
+                }
+            }
+        }
+    }
+
+    /// When encountering the expected boxed value allocated in the stack, suggest allocating it
+    /// in the heap by calling `Box::new()`.
+    pub(super) fn suggest_boxing_when_appropriate(
+        &self,
+        err: &mut DiagnosticBuilder<'_>,
+        expr: &hir::Expr<'_>,
+        expected: Ty<'tcx>,
+        found: Ty<'tcx>,
+    ) {
+        if self.tcx.hir().is_inside_const_context(expr.hir_id) {
+            // Do not suggest `Box::new` in const context.
+            return;
+        }
+        if !expected.is_box() || found.is_box() {
+            return;
+        }
+        let boxed_found = self.tcx.mk_box(found);
+        if let (true, Ok(snippet)) = (
+            self.can_coerce(boxed_found, expected),
+            self.sess().source_map().span_to_snippet(expr.span),
+        ) {
+            err.span_suggestion(
+                expr.span,
+                "store this in the heap by calling `Box::new`",
+                format!("Box::new({})", snippet),
+                Applicability::MachineApplicable,
+            );
+            err.note(
+                "for more on the distinction between the stack and the heap, read \
+                 https://doc.rust-lang.org/book/ch15-01-box.html, \
+                 https://doc.rust-lang.org/rust-by-example/std/box.html, and \
+                 https://doc.rust-lang.org/std/boxed/index.html",
+            );
+        }
+    }
+
+    pub(super) fn note_internal_mutation_in_method(
+        &self,
+        err: &mut DiagnosticBuilder<'_>,
+        expr: &hir::Expr<'_>,
+        expected: Ty<'tcx>,
+        found: Ty<'tcx>,
+    ) {
+        if found != self.tcx.types.unit {
+            return;
+        }
+        if let ExprKind::MethodCall(path_segment, _, [rcvr, ..], _) = expr.kind {
+            if self
+                .typeck_results
+                .borrow()
+                .expr_ty_adjusted_opt(rcvr)
+                .map_or(true, |ty| expected.peel_refs() != ty.peel_refs())
+            {
+                return;
+            }
+            let mut sp = MultiSpan::from_span(path_segment.ident.span);
+            sp.push_span_label(
+                path_segment.ident.span,
+                format!(
+                    "this call modifies {} in-place",
+                    match rcvr.kind {
+                        ExprKind::Path(QPath::Resolved(
+                            None,
+                            hir::Path { segments: [segment], .. },
+                        )) => format!("`{}`", segment.ident),
+                        _ => "its receiver".to_string(),
+                    }
+                ),
+            );
+            sp.push_span_label(
+                rcvr.span,
+                "you probably want to use this value after calling the method...".to_string(),
+            );
+            err.span_note(
+                sp,
+                &format!("method `{}` modifies its receiver in-place", path_segment.ident),
+            );
+            err.note(&format!("...instead of the `()` output of method `{}`", path_segment.ident));
+        }
+    }
+
+    /// When encountering an `impl Future` where `BoxFuture` is expected, suggest `Box::pin`.
+    pub(super) fn suggest_calling_boxed_future_when_appropriate(
+        &self,
+        err: &mut DiagnosticBuilder<'_>,
+        expr: &hir::Expr<'_>,
+        expected: Ty<'tcx>,
+        found: Ty<'tcx>,
+    ) -> bool {
+        // Handle #68197.
+
+        if self.tcx.hir().is_inside_const_context(expr.hir_id) {
+            // Do not suggest `Box::new` in const context.
+            return false;
+        }
+        let pin_did = self.tcx.lang_items().pin_type();
+        match expected.kind() {
+            ty::Adt(def, _) if Some(def.did) != pin_did => return false,
+            // This guards the `unwrap` and `mk_box` below.
+            _ if pin_did.is_none() || self.tcx.lang_items().owned_box().is_none() => return false,
+            _ => {}
+        }
+        let boxed_found = self.tcx.mk_box(found);
+        let new_found = self.tcx.mk_lang_item(boxed_found, LangItem::Pin).unwrap();
+        if let (true, Ok(snippet)) = (
+            self.can_coerce(new_found, expected),
+            self.sess().source_map().span_to_snippet(expr.span),
+        ) {
+            match found.kind() {
+                ty::Adt(def, _) if def.is_box() => {
+                    err.help("use `Box::pin`");
+                }
+                _ => {
+                    err.span_suggestion(
+                        expr.span,
+                        "you need to pin and box this expression",
+                        format!("Box::pin({})", snippet),
+                        Applicability::MachineApplicable,
+                    );
+                }
+            }
+            true
+        } else {
+            false
+        }
+    }
+
+    /// A common error is to forget to add a semicolon at the end of a block, e.g.,
+    ///
+    /// ```
+    /// fn foo() {
+    ///     bar_that_returns_u32()
+    /// }
+    /// ```
+    ///
+    /// This routine checks if the return expression in a block would make sense on its own as a
+    /// statement and the return type has been left as default or has been specified as `()`. If so,
+    /// it suggests adding a semicolon.
+    fn suggest_missing_semicolon(
+        &self,
+        err: &mut DiagnosticBuilder<'_>,
+        expression: &'tcx hir::Expr<'tcx>,
+        expected: Ty<'tcx>,
+        cause_span: Span,
+    ) {
+        if expected.is_unit() {
+            // `BlockTailExpression` only relevant if the tail expr would be
+            // useful on its own.
+            match expression.kind {
+                ExprKind::Call(..)
+                | ExprKind::MethodCall(..)
+                | ExprKind::Loop(..)
+                | ExprKind::Match(..)
+                | ExprKind::Block(..) => {
+                    err.span_suggestion(
+                        cause_span.shrink_to_hi(),
+                        "try adding a semicolon",
+                        ";".to_string(),
+                        Applicability::MachineApplicable,
+                    );
+                }
+                _ => (),
+            }
+        }
+    }
+
+    /// A possible error is to forget to add a return type that is needed:
+    ///
+    /// ```
+    /// fn foo() {
+    ///     bar_that_returns_u32()
+    /// }
+    /// ```
+    ///
+    /// This routine checks if the return type is left as default, the method is not part of an
+    /// `impl` block and that it isn't the `main` method. If so, it suggests setting the return
+    /// type.
+    pub(super) fn suggest_missing_return_type(
+        &self,
+        err: &mut DiagnosticBuilder<'_>,
+        fn_decl: &hir::FnDecl<'_>,
+        expected: Ty<'tcx>,
+        found: Ty<'tcx>,
+        can_suggest: bool,
+    ) -> bool {
+        // Only suggest changing the return type for methods that
+        // haven't set a return type at all (and aren't `fn main()` or an impl).
+        match (&fn_decl.output, found.is_suggestable(), can_suggest, expected.is_unit()) {
+            (&hir::FnRetTy::DefaultReturn(span), true, true, true) => {
+                err.span_suggestion(
+                    span,
+                    "try adding a return type",
+                    format!("-> {} ", self.resolve_vars_with_obligations(found)),
+                    Applicability::MachineApplicable,
+                );
+                true
+            }
+            (&hir::FnRetTy::DefaultReturn(span), false, true, true) => {
+                err.span_label(span, "possibly return type missing here?");
+                true
+            }
+            (&hir::FnRetTy::DefaultReturn(span), _, false, true) => {
+                // `fn main()` must return `()`, do not suggest changing return type
+                err.span_label(span, "expected `()` because of default return type");
+                true
+            }
+            // expectation was caused by something else, not the default return
+            (&hir::FnRetTy::DefaultReturn(_), _, _, false) => false,
+            (&hir::FnRetTy::Return(ref ty), _, _, _) => {
+                // Only point to return type if the expected type is the return type, as if they
+                // are not, the expectation must have been caused by something else.
+                debug!("suggest_missing_return_type: return type {:?} node {:?}", ty, ty.kind);
+                let sp = ty.span;
+                let ty = AstConv::ast_ty_to_ty(self, ty);
+                debug!("suggest_missing_return_type: return type {:?}", ty);
+                debug!("suggest_missing_return_type: expected type {:?}", ty);
+                if ty.kind() == expected.kind() {
+                    err.span_label(sp, format!("expected `{}` because of return type", expected));
+                    return true;
+                }
+                false
+            }
+        }
+    }
+
+    /// A possible error is to forget to add `.await` when using futures:
+    ///
+    /// ```
+    /// async fn make_u32() -> u32 {
+    ///     22
+    /// }
+    ///
+    /// fn take_u32(x: u32) {}
+    ///
+    /// async fn foo() {
+    ///     let x = make_u32();
+    ///     take_u32(x);
+    /// }
+    /// ```
+    ///
+    /// This routine checks if the found type `T` implements `Future<Output=U>` where `U` is the
+    /// expected type. If this is the case, and we are inside of an async body, it suggests adding
+    /// `.await` to the tail of the expression.
+    pub(super) fn suggest_missing_await(
+        &self,
+        err: &mut DiagnosticBuilder<'_>,
+        expr: &hir::Expr<'_>,
+        expected: Ty<'tcx>,
+        found: Ty<'tcx>,
+    ) {
+        debug!("suggest_missing_await: expr={:?} expected={:?}, found={:?}", expr, expected, found);
+        // `.await` is not permitted outside of `async` bodies, so don't bother to suggest if the
+        // body isn't `async`.
+        let item_id = self.tcx().hir().get_parent_node(self.body_id);
+        if let Some(body_id) = self.tcx().hir().maybe_body_owned_by(item_id) {
+            let body = self.tcx().hir().body(body_id);
+            if let Some(hir::GeneratorKind::Async(_)) = body.generator_kind {
+                let sp = expr.span;
+                // Check for `Future` implementations by constructing a predicate to
+                // prove: `<T as Future>::Output == U`
+                let future_trait = self.tcx.require_lang_item(LangItem::Future, Some(sp));
+                let item_def_id = self
+                    .tcx
+                    .associated_items(future_trait)
+                    .in_definition_order()
+                    .next()
+                    .unwrap()
+                    .def_id;
+                // `<T as Future>::Output`
+                let projection_ty = ty::ProjectionTy {
+                    // `T`
+                    substs: self
+                        .tcx
+                        .mk_substs_trait(found, self.fresh_substs_for_item(sp, item_def_id)),
+                    // `Future::Output`
+                    item_def_id,
+                };
+
+                let predicate = ty::PredicateAtom::Projection(ty::ProjectionPredicate {
+                    projection_ty,
+                    ty: expected,
+                })
+                .potentially_quantified(self.tcx, ty::PredicateKind::ForAll);
+                let obligation = traits::Obligation::new(self.misc(sp), self.param_env, predicate);
+
+                debug!("suggest_missing_await: trying obligation {:?}", obligation);
+
+                if self.infcx.predicate_may_hold(&obligation) {
+                    debug!("suggest_missing_await: obligation held: {:?}", obligation);
+                    if let Ok(code) = self.sess().source_map().span_to_snippet(sp) {
+                        err.span_suggestion(
+                            sp,
+                            "consider using `.await` here",
+                            format!("{}.await", code),
+                            Applicability::MaybeIncorrect,
+                        );
+                    } else {
+                        debug!("suggest_missing_await: no snippet for {:?}", sp);
+                    }
+                } else {
+                    debug!("suggest_missing_await: obligation did not hold: {:?}", obligation)
+                }
+            }
+        }
+    }
+
+    pub(super) fn suggest_missing_parentheses(
+        &self,
+        err: &mut DiagnosticBuilder<'_>,
+        expr: &hir::Expr<'_>,
+    ) {
+        let sp = self.tcx.sess.source_map().start_point(expr.span);
+        if let Some(sp) = self.tcx.sess.parse_sess.ambiguous_block_expr_parse.borrow().get(&sp) {
+            // `{ 42 } &&x` (#61475) or `{ 42 } && if x { 1 } else { 0 }`
+            self.tcx.sess.parse_sess.expr_parentheses_needed(err, *sp, None);
+        }
+    }
+
+    pub(super) fn note_need_for_fn_pointer(
+        &self,
+        err: &mut DiagnosticBuilder<'_>,
+        expected: Ty<'tcx>,
+        found: Ty<'tcx>,
+    ) {
+        let (sig, did, substs) = match (&expected.kind(), &found.kind()) {
+            (ty::FnDef(did1, substs1), ty::FnDef(did2, substs2)) => {
+                let sig1 = self.tcx.fn_sig(*did1).subst(self.tcx, substs1);
+                let sig2 = self.tcx.fn_sig(*did2).subst(self.tcx, substs2);
+                if sig1 != sig2 {
+                    return;
+                }
+                err.note(
+                    "different `fn` items always have unique types, even if their signatures are \
+                     the same",
+                );
+                (sig1, *did1, substs1)
+            }
+            (ty::FnDef(did, substs), ty::FnPtr(sig2)) => {
+                let sig1 = self.tcx.fn_sig(*did).subst(self.tcx, substs);
+                if sig1 != *sig2 {
+                    return;
+                }
+                (sig1, *did, substs)
+            }
+            _ => return,
+        };
+        err.help(&format!("change the expected type to be function pointer `{}`", sig));
+        err.help(&format!(
+            "if the expected type is due to type inference, cast the expected `fn` to a function \
+             pointer: `{} as {}`",
+            self.tcx.def_path_str_with_substs(did, substs),
+            sig
+        ));
+    }
+
+    /// A common error is to add an extra semicolon:
+    ///
+    /// ```
+    /// fn foo() -> usize {
+    ///     22;
+    /// }
+    /// ```
+    ///
+    /// This routine checks if the final statement in a block is an
+    /// expression with an explicit semicolon whose type is compatible
+    /// with `expected_ty`. If so, it suggests removing the semicolon.
+    fn consider_hint_about_removing_semicolon(
+        &self,
+        blk: &'tcx hir::Block<'tcx>,
+        expected_ty: Ty<'tcx>,
+        err: &mut DiagnosticBuilder<'_>,
+    ) {
+        if let Some(span_semi) = self.could_remove_semicolon(blk, expected_ty) {
+            err.span_suggestion(
+                span_semi,
+                "consider removing this semicolon",
+                String::new(),
+                Applicability::MachineApplicable,
+            );
+        }
+    }
+
+    pub(super) fn could_remove_semicolon(
+        &self,
+        blk: &'tcx hir::Block<'tcx>,
+        expected_ty: Ty<'tcx>,
+    ) -> Option<Span> {
+        // Be helpful when the user wrote `{... expr;}` and
+        // taking the `;` off is enough to fix the error.
+        let last_stmt = blk.stmts.last()?;
+        let last_expr = match last_stmt.kind {
+            hir::StmtKind::Semi(ref e) => e,
+            _ => return None,
+        };
+        let last_expr_ty = self.node_ty(last_expr.hir_id);
+        if matches!(last_expr_ty.kind(), ty::Error(_))
+            || self.can_sub(self.param_env, last_expr_ty, expected_ty).is_err()
+        {
+            return None;
+        }
+        let original_span = original_sp(last_stmt.span, blk.span);
+        Some(original_span.with_lo(original_span.hi() - BytePos(1)))
+    }
+
+    // Instantiates the given path, which must refer to an item with the given
+    // number of type parameters and type.
+    pub fn instantiate_value_path(
+        &self,
+        segments: &[hir::PathSegment<'_>],
+        self_ty: Option<Ty<'tcx>>,
+        res: Res,
+        span: Span,
+        hir_id: hir::HirId,
+    ) -> (Ty<'tcx>, Res) {
+        debug!(
+            "instantiate_value_path(segments={:?}, self_ty={:?}, res={:?}, hir_id={})",
+            segments, self_ty, res, hir_id,
+        );
+
+        let tcx = self.tcx;
+
+        let path_segs = match res {
+            Res::Local(_) | Res::SelfCtor(_) => vec![],
+            Res::Def(kind, def_id) => {
+                AstConv::def_ids_for_value_path_segments(self, segments, self_ty, kind, def_id)
+            }
+            _ => bug!("instantiate_value_path on {:?}", res),
+        };
+
+        let mut user_self_ty = None;
+        let mut is_alias_variant_ctor = false;
+        match res {
+            Res::Def(DefKind::Ctor(CtorOf::Variant, _), _) => {
+                if let Some(self_ty) = self_ty {
+                    let adt_def = self_ty.ty_adt_def().unwrap();
+                    user_self_ty = Some(UserSelfTy { impl_def_id: adt_def.did, self_ty });
+                    is_alias_variant_ctor = true;
+                }
+            }
+            Res::Def(DefKind::AssocFn | DefKind::AssocConst, def_id) => {
+                let container = tcx.associated_item(def_id).container;
+                debug!("instantiate_value_path: def_id={:?} container={:?}", def_id, container);
+                match container {
+                    ty::TraitContainer(trait_did) => {
+                        callee::check_legal_trait_for_method_call(tcx, span, None, trait_did)
+                    }
+                    ty::ImplContainer(impl_def_id) => {
+                        if segments.len() == 1 {
+                            // `<T>::assoc` will end up here, and so
+                            // can `T::assoc`. It this came from an
+                            // inherent impl, we need to record the
+                            // `T` for posterity (see `UserSelfTy` for
+                            // details).
+                            let self_ty = self_ty.expect("UFCS sugared assoc missing Self");
+                            user_self_ty = Some(UserSelfTy { impl_def_id, self_ty });
+                        }
+                    }
+                }
+            }
+            _ => {}
+        }
+
+        // Now that we have categorized what space the parameters for each
+        // segment belong to, let's sort out the parameters that the user
+        // provided (if any) into their appropriate spaces. We'll also report
+        // errors if type parameters are provided in an inappropriate place.
+
+        let generic_segs: FxHashSet<_> = path_segs.iter().map(|PathSeg(_, index)| index).collect();
+        let generics_has_err = AstConv::prohibit_generics(
+            self,
+            segments.iter().enumerate().filter_map(|(index, seg)| {
+                if !generic_segs.contains(&index) || is_alias_variant_ctor {
+                    Some(seg)
+                } else {
+                    None
+                }
+            }),
+        );
+
+        if let Res::Local(hid) = res {
+            let ty = self.local_ty(span, hid).decl_ty;
+            let ty = self.normalize_associated_types_in(span, &ty);
+            self.write_ty(hir_id, ty);
+            return (ty, res);
+        }
+
+        if generics_has_err {
+            // Don't try to infer type parameters when prohibited generic arguments were given.
+            user_self_ty = None;
+        }
+
+        // Now we have to compare the types that the user *actually*
+        // provided against the types that were *expected*. If the user
+        // did not provide any types, then we want to substitute inference
+        // variables. If the user provided some types, we may still need
+        // to add defaults. If the user provided *too many* types, that's
+        // a problem.
+
+        let mut infer_args_for_err = FxHashSet::default();
+        for &PathSeg(def_id, index) in &path_segs {
+            let seg = &segments[index];
+            let generics = tcx.generics_of(def_id);
+            // Argument-position `impl Trait` is treated as a normal generic
+            // parameter internally, but we don't allow users to specify the
+            // parameter's value explicitly, so we have to do some error-
+            // checking here.
+            if let GenericArgCountResult {
+                correct: Err(GenericArgCountMismatch { reported: Some(ErrorReported), .. }),
+                ..
+            } = AstConv::check_generic_arg_count_for_call(
+                tcx, span, &generics, &seg, false, // `is_method_call`
+            ) {
+                infer_args_for_err.insert(index);
+                self.set_tainted_by_errors(); // See issue #53251.
+            }
+        }
+
+        let has_self = path_segs
+            .last()
+            .map(|PathSeg(def_id, _)| tcx.generics_of(*def_id).has_self)
+            .unwrap_or(false);
+
+        let (res, self_ctor_substs) = if let Res::SelfCtor(impl_def_id) = res {
+            let ty = self.normalize_ty(span, tcx.at(span).type_of(impl_def_id));
+            match *ty.kind() {
+                ty::Adt(adt_def, substs) if adt_def.has_ctor() => {
+                    let variant = adt_def.non_enum_variant();
+                    let ctor_def_id = variant.ctor_def_id.unwrap();
+                    (
+                        Res::Def(DefKind::Ctor(CtorOf::Struct, variant.ctor_kind), ctor_def_id),
+                        Some(substs),
+                    )
+                }
+                _ => {
+                    let mut err = tcx.sess.struct_span_err(
+                        span,
+                        "the `Self` constructor can only be used with tuple or unit structs",
+                    );
+                    if let Some(adt_def) = ty.ty_adt_def() {
+                        match adt_def.adt_kind() {
+                            AdtKind::Enum => {
+                                err.help("did you mean to use one of the enum's variants?");
+                            }
+                            AdtKind::Struct | AdtKind::Union => {
+                                err.span_suggestion(
+                                    span,
+                                    "use curly brackets",
+                                    String::from("Self { /* fields */ }"),
+                                    Applicability::HasPlaceholders,
+                                );
+                            }
+                        }
+                    }
+                    err.emit();
+
+                    return (tcx.ty_error(), res);
+                }
+            }
+        } else {
+            (res, None)
+        };
+        let def_id = res.def_id();
+
+        // The things we are substituting into the type should not contain
+        // escaping late-bound regions, and nor should the base type scheme.
+        let ty = tcx.type_of(def_id);
+
+        let arg_count = GenericArgCountResult {
+            explicit_late_bound: ExplicitLateBound::No,
+            correct: if infer_args_for_err.is_empty() {
+                Ok(())
+            } else {
+                Err(GenericArgCountMismatch::default())
+            },
+        };
+
+        let substs = self_ctor_substs.unwrap_or_else(|| {
+            AstConv::create_substs_for_generic_args(
+                tcx,
+                def_id,
+                &[][..],
+                has_self,
+                self_ty,
+                arg_count,
+                // Provide the generic args, and whether types should be inferred.
+                |def_id| {
+                    if let Some(&PathSeg(_, index)) =
+                        path_segs.iter().find(|&PathSeg(did, _)| *did == def_id)
+                    {
+                        // If we've encountered an `impl Trait`-related error, we're just
+                        // going to infer the arguments for better error messages.
+                        if !infer_args_for_err.contains(&index) {
+                            // Check whether the user has provided generic arguments.
+                            if let Some(ref data) = segments[index].args {
+                                return (Some(data), segments[index].infer_args);
+                            }
+                        }
+                        return (None, segments[index].infer_args);
+                    }
+
+                    (None, true)
+                },
+                // Provide substitutions for parameters for which (valid) arguments have been provided.
+                |param, arg| match (&param.kind, arg) {
+                    (GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => {
+                        AstConv::ast_region_to_region(self, lt, Some(param)).into()
+                    }
+                    (GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => {
+                        self.to_ty(ty).into()
+                    }
+                    (GenericParamDefKind::Const, GenericArg::Const(ct)) => {
+                        self.const_arg_to_const(&ct.value, param.def_id).into()
+                    }
+                    _ => unreachable!(),
+                },
+                // Provide substitutions for parameters for which arguments are inferred.
+                |substs, param, infer_args| {
+                    match param.kind {
+                        GenericParamDefKind::Lifetime => {
+                            self.re_infer(Some(param), span).unwrap().into()
+                        }
+                        GenericParamDefKind::Type { has_default, .. } => {
+                            if !infer_args && has_default {
+                                // If we have a default, then we it doesn't matter that we're not
+                                // inferring the type arguments: we provide the default where any
+                                // is missing.
+                                let default = tcx.type_of(param.def_id);
+                                self.normalize_ty(
+                                    span,
+                                    default.subst_spanned(tcx, substs.unwrap(), Some(span)),
+                                )
+                                .into()
+                            } else {
+                                // If no type arguments were provided, we have to infer them.
+                                // This case also occurs as a result of some malformed input, e.g.
+                                // a lifetime argument being given instead of a type parameter.
+                                // Using inference instead of `Error` gives better error messages.
+                                self.var_for_def(span, param)
+                            }
+                        }
+                        GenericParamDefKind::Const => {
+                            // FIXME(const_generics:defaults)
+                            // No const parameters were provided, we have to infer them.
+                            self.var_for_def(span, param)
+                        }
+                    }
+                },
+            )
+        });
+        assert!(!substs.has_escaping_bound_vars());
+        assert!(!ty.has_escaping_bound_vars());
+
+        // First, store the "user substs" for later.
+        self.write_user_type_annotation_from_substs(hir_id, def_id, substs, user_self_ty);
+
+        self.add_required_obligations(span, def_id, &substs);
+
+        // Substitute the values for the type parameters into the type of
+        // the referenced item.
+        let ty_substituted = self.instantiate_type_scheme(span, &substs, &ty);
+
+        if let Some(UserSelfTy { impl_def_id, self_ty }) = user_self_ty {
+            // In the case of `Foo<T>::method` and `<Foo<T>>::method`, if `method`
+            // is inherent, there is no `Self` parameter; instead, the impl needs
+            // type parameters, which we can infer by unifying the provided `Self`
+            // with the substituted impl type.
+            // This also occurs for an enum variant on a type alias.
+            let ty = tcx.type_of(impl_def_id);
+
+            let impl_ty = self.instantiate_type_scheme(span, &substs, &ty);
+            match self.at(&self.misc(span), self.param_env).sup(impl_ty, self_ty) {
+                Ok(ok) => self.register_infer_ok_obligations(ok),
+                Err(_) => {
+                    self.tcx.sess.delay_span_bug(
+                        span,
+                        &format!(
+                        "instantiate_value_path: (UFCS) {:?} was a subtype of {:?} but now is not?",
+                        self_ty,
+                        impl_ty,
+                    ),
+                    );
+                }
+            }
+        }
+
+        self.check_rustc_args_require_const(def_id, hir_id, span);
+
+        debug!("instantiate_value_path: type of {:?} is {:?}", hir_id, ty_substituted);
+        self.write_substs(hir_id, substs);
+
+        (ty_substituted, res)
+    }
+
+    /// Add all the obligations that are required, substituting and normalized appropriately.
+    fn add_required_obligations(&self, span: Span, def_id: DefId, substs: &SubstsRef<'tcx>) {
+        let (bounds, spans) = self.instantiate_bounds(span, def_id, &substs);
+
+        for (i, mut obligation) in traits::predicates_for_generics(
+            traits::ObligationCause::new(span, self.body_id, traits::ItemObligation(def_id)),
+            self.param_env,
+            bounds,
+        )
+        .enumerate()
+        {
+            // This makes the error point at the bound, but we want to point at the argument
+            if let Some(span) = spans.get(i) {
+                obligation.cause.make_mut().code = traits::BindingObligation(def_id, *span);
+            }
+            self.register_predicate(obligation);
+        }
+    }
+
+    fn check_rustc_args_require_const(&self, def_id: DefId, hir_id: hir::HirId, span: Span) {
+        // We're only interested in functions tagged with
+        // #[rustc_args_required_const], so ignore anything that's not.
+        if !self.tcx.has_attr(def_id, sym::rustc_args_required_const) {
+            return;
+        }
+
+        // If our calling expression is indeed the function itself, we're good!
+        // If not, generate an error that this can only be called directly.
+        if let Node::Expr(expr) = self.tcx.hir().get(self.tcx.hir().get_parent_node(hir_id)) {
+            if let ExprKind::Call(ref callee, ..) = expr.kind {
+                if callee.hir_id == hir_id {
+                    return;
+                }
+            }
+        }
+
+        self.tcx.sess.span_err(
+            span,
+            "this function can only be invoked directly, not through a function pointer",
+        );
+    }
+
+    /// Resolves `typ` by a single level if `typ` is a type variable.
+    /// If no resolution is possible, then an error is reported.
+    /// Numeric inference variables may be left unresolved.
+    pub fn structurally_resolved_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
+        let ty = self.resolve_vars_with_obligations(ty);
+        if !ty.is_ty_var() {
+            ty
+        } else {
+            if !self.is_tainted_by_errors() {
+                self.need_type_info_err((**self).body_id, sp, ty, E0282)
+                    .note("type must be known at this point")
+                    .emit();
+            }
+            let err = self.tcx.ty_error();
+            self.demand_suptype(sp, err, ty);
+            err
+        }
+    }
+
+    pub(super) fn with_breakable_ctxt<F: FnOnce() -> R, R>(
+        &self,
+        id: hir::HirId,
+        ctxt: BreakableCtxt<'tcx>,
+        f: F,
+    ) -> (BreakableCtxt<'tcx>, R) {
+        let index;
+        {
+            let mut enclosing_breakables = self.enclosing_breakables.borrow_mut();
+            index = enclosing_breakables.stack.len();
+            enclosing_breakables.by_id.insert(id, index);
+            enclosing_breakables.stack.push(ctxt);
+        }
+        let result = f();
+        let ctxt = {
+            let mut enclosing_breakables = self.enclosing_breakables.borrow_mut();
+            debug_assert!(enclosing_breakables.stack.len() == index + 1);
+            enclosing_breakables.by_id.remove(&id).expect("missing breakable context");
+            enclosing_breakables.stack.pop().expect("missing breakable context")
+        };
+        (ctxt, result)
+    }
+
+    /// Instantiate a QueryResponse in a probe context, without a
+    /// good ObligationCause.
+    pub(super) fn probe_instantiate_query_response(
+        &self,
+        span: Span,
+        original_values: &OriginalQueryValues<'tcx>,
+        query_result: &Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>,
+    ) -> InferResult<'tcx, Ty<'tcx>> {
+        self.instantiate_query_response_and_region_obligations(
+            &traits::ObligationCause::misc(span, self.body_id),
+            self.param_env,
+            original_values,
+            query_result,
+        )
+    }
+
+    /// Returns `true` if an expression is contained inside the LHS of an assignment expression.
+    pub(super) fn expr_in_place(&self, mut expr_id: hir::HirId) -> bool {
+        let mut contained_in_place = false;
+
+        while let hir::Node::Expr(parent_expr) =
+            self.tcx.hir().get(self.tcx.hir().get_parent_node(expr_id))
+        {
+            match &parent_expr.kind {
+                hir::ExprKind::Assign(lhs, ..) | hir::ExprKind::AssignOp(_, lhs, ..) => {
+                    if lhs.hir_id == expr_id {
+                        contained_in_place = true;
+                        break;
+                    }
+                }
+                _ => (),
+            }
+            expr_id = parent_expr.hir_id;
+        }
+
+        contained_in_place
+    }
+}
+impl<'a, 'tcx> Deref for FnCtxt<'a, 'tcx> {
+    type Target = Inherited<'a, 'tcx>;
+    fn deref(&self) -> &Self::Target {
+        &self.inh
+    }
+}
+
+impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
+    fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
+
+    fn item_def_id(&self) -> Option<DefId> {
+        None
+    }
+
+    fn default_constness_for_trait_bounds(&self) -> hir::Constness {
+        // FIXME: refactor this into a method
+        let node = self.tcx.hir().get(self.body_id);
+        if let Some(fn_like) = FnLikeNode::from_node(node) {
+            fn_like.constness()
+        } else {
+            hir::Constness::NotConst
+        }
+    }
+
+    fn get_type_parameter_bounds(&self, _: Span, def_id: DefId) -> ty::GenericPredicates<'tcx> {
+        let tcx = self.tcx;
+        let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
+        let item_id = tcx.hir().ty_param_owner(hir_id);
+        let item_def_id = tcx.hir().local_def_id(item_id);
+        let generics = tcx.generics_of(item_def_id);
+        let index = generics.param_def_id_to_index[&def_id];
+        ty::GenericPredicates {
+            parent: None,
+            predicates: tcx.arena.alloc_from_iter(
+                self.param_env.caller_bounds().iter().filter_map(|predicate| {
+                    match predicate.skip_binders() {
+                        ty::PredicateAtom::Trait(data, _) if data.self_ty().is_param(index) => {
+                            // HACK(eddyb) should get the original `Span`.
+                            let span = tcx.def_span(def_id);
+                            Some((predicate, span))
+                        }
+                        _ => None,
+                    }
+                }),
+            ),
+        }
+    }
+
+    fn re_infer(&self, def: Option<&ty::GenericParamDef>, span: Span) -> Option<ty::Region<'tcx>> {
+        let v = match def {
+            Some(def) => infer::EarlyBoundRegion(span, def.name),
+            None => infer::MiscVariable(span),
+        };
+        Some(self.next_region_var(v))
+    }
+
+    fn allow_ty_infer(&self) -> bool {
+        true
+    }
+
+    fn ty_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> {
+        if let Some(param) = param {
+            if let GenericArgKind::Type(ty) = self.var_for_def(span, param).unpack() {
+                return ty;
+            }
+            unreachable!()
+        } else {
+            self.next_ty_var(TypeVariableOrigin {
+                kind: TypeVariableOriginKind::TypeInference,
+                span,
+            })
+        }
+    }
+
+    fn ct_infer(
+        &self,
+        ty: Ty<'tcx>,
+        param: Option<&ty::GenericParamDef>,
+        span: Span,
+    ) -> &'tcx Const<'tcx> {
+        if let Some(param) = param {
+            if let GenericArgKind::Const(ct) = self.var_for_def(span, param).unpack() {
+                return ct;
+            }
+            unreachable!()
+        } else {
+            self.next_const_var(
+                ty,
+                ConstVariableOrigin { kind: ConstVariableOriginKind::ConstInference, span },
+            )
+        }
+    }
+
+    fn projected_ty_from_poly_trait_ref(
+        &self,
+        span: Span,
+        item_def_id: DefId,
+        item_segment: &hir::PathSegment<'_>,
+        poly_trait_ref: ty::PolyTraitRef<'tcx>,
+    ) -> Ty<'tcx> {
+        let (trait_ref, _) = self.replace_bound_vars_with_fresh_vars(
+            span,
+            infer::LateBoundRegionConversionTime::AssocTypeProjection(item_def_id),
+            &poly_trait_ref,
+        );
+
+        let item_substs = <dyn AstConv<'tcx>>::create_substs_for_associated_item(
+            self,
+            self.tcx,
+            span,
+            item_def_id,
+            item_segment,
+            trait_ref.substs,
+        );
+
+        self.tcx().mk_projection(item_def_id, item_substs)
+    }
+
+    fn normalize_ty(&self, span: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
+        if ty.has_escaping_bound_vars() {
+            ty // FIXME: normalization and escaping regions
+        } else {
+            self.normalize_associated_types_in(span, &ty)
+        }
+    }
+
+    fn set_tainted_by_errors(&self) {
+        self.infcx.set_tainted_by_errors()
+    }
+
+    fn record_ty(&self, hir_id: hir::HirId, ty: Ty<'tcx>, _span: Span) {
+        self.write_ty(hir_id, ty)
+    }
+}
diff --git a/compiler/rustc_typeck/src/check/gather_locals.rs b/compiler/rustc_typeck/src/check/gather_locals.rs
new file mode 100644
index 00000000000..1d505cfa698
--- /dev/null
+++ b/compiler/rustc_typeck/src/check/gather_locals.rs
@@ -0,0 +1,120 @@
+use crate::check::{FnCtxt, LocalTy, UserType};
+use rustc_hir as hir;
+use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc_hir::PatKind;
+use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use rustc_middle::ty::Ty;
+use rustc_span::Span;
+use rustc_trait_selection::traits;
+
+pub(super) struct GatherLocalsVisitor<'a, 'tcx> {
+    fcx: &'a FnCtxt<'a, 'tcx>,
+    parent_id: hir::HirId,
+}
+
+impl<'a, 'tcx> GatherLocalsVisitor<'a, 'tcx> {
+    pub(super) fn new(fcx: &'a FnCtxt<'a, 'tcx>, parent_id: hir::HirId) -> Self {
+        Self { fcx, parent_id }
+    }
+
+    fn assign(&mut self, span: Span, nid: hir::HirId, ty_opt: Option<LocalTy<'tcx>>) -> Ty<'tcx> {
+        match ty_opt {
+            None => {
+                // Infer the variable's type.
+                let var_ty = self.fcx.next_ty_var(TypeVariableOrigin {
+                    kind: TypeVariableOriginKind::TypeInference,
+                    span,
+                });
+                self.fcx
+                    .locals
+                    .borrow_mut()
+                    .insert(nid, LocalTy { decl_ty: var_ty, revealed_ty: var_ty });
+                var_ty
+            }
+            Some(typ) => {
+                // Take type that the user specified.
+                self.fcx.locals.borrow_mut().insert(nid, typ);
+                typ.revealed_ty
+            }
+        }
+    }
+}
+
+impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> {
+    type Map = intravisit::ErasedMap<'tcx>;
+
+    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
+        NestedVisitorMap::None
+    }
+
+    // Add explicitly-declared locals.
+    fn visit_local(&mut self, local: &'tcx hir::Local<'tcx>) {
+        let local_ty = match local.ty {
+            Some(ref ty) => {
+                let o_ty = self.fcx.to_ty(&ty);
+
+                let revealed_ty = if self.fcx.tcx.features().impl_trait_in_bindings {
+                    self.fcx.instantiate_opaque_types_from_value(self.parent_id, &o_ty, ty.span)
+                } else {
+                    o_ty
+                };
+
+                let c_ty = self
+                    .fcx
+                    .inh
+                    .infcx
+                    .canonicalize_user_type_annotation(&UserType::Ty(revealed_ty));
+                debug!(
+                    "visit_local: ty.hir_id={:?} o_ty={:?} revealed_ty={:?} c_ty={:?}",
+                    ty.hir_id, o_ty, revealed_ty, c_ty
+                );
+                self.fcx
+                    .typeck_results
+                    .borrow_mut()
+                    .user_provided_types_mut()
+                    .insert(ty.hir_id, c_ty);
+
+                Some(LocalTy { decl_ty: o_ty, revealed_ty })
+            }
+            None => None,
+        };
+        self.assign(local.span, local.hir_id, local_ty);
+
+        debug!(
+            "local variable {:?} is assigned type {}",
+            local.pat,
+            self.fcx.ty_to_string(&*self.fcx.locals.borrow().get(&local.hir_id).unwrap().decl_ty)
+        );
+        intravisit::walk_local(self, local);
+    }
+
+    // Add pattern bindings.
+    fn visit_pat(&mut self, p: &'tcx hir::Pat<'tcx>) {
+        if let PatKind::Binding(_, _, ident, _) = p.kind {
+            let var_ty = self.assign(p.span, p.hir_id, None);
+
+            if !self.fcx.tcx.features().unsized_locals {
+                self.fcx.require_type_is_sized(var_ty, p.span, traits::VariableType(p.hir_id));
+            }
+
+            debug!(
+                "pattern binding {} is assigned to {} with type {:?}",
+                ident,
+                self.fcx.ty_to_string(&*self.fcx.locals.borrow().get(&p.hir_id).unwrap().decl_ty),
+                var_ty
+            );
+        }
+        intravisit::walk_pat(self, p);
+    }
+
+    // Don't descend into the bodies of nested closures.
+    fn visit_fn(
+        &mut self,
+        _: intravisit::FnKind<'tcx>,
+        _: &'tcx hir::FnDecl<'tcx>,
+        _: hir::BodyId,
+        _: Span,
+        _: hir::HirId,
+    ) {
+    }
+}
diff --git a/compiler/rustc_typeck/src/check/inherited.rs b/compiler/rustc_typeck/src/check/inherited.rs
new file mode 100644
index 00000000000..7e580485c3d
--- /dev/null
+++ b/compiler/rustc_typeck/src/check/inherited.rs
@@ -0,0 +1,167 @@
+use super::callee::DeferredCallResolution;
+use super::MaybeInProgressTables;
+
+use rustc_data_structures::fx::FxHashMap;
+use rustc_hir as hir;
+use rustc_hir::def_id::{DefIdMap, LocalDefId};
+use rustc_hir::HirIdMap;
+use rustc_infer::infer;
+use rustc_infer::infer::{InferCtxt, InferOk, TyCtxtInferExt};
+use rustc_middle::ty::fold::TypeFoldable;
+use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_span::{self, Span};
+use rustc_trait_selection::infer::InferCtxtExt as _;
+use rustc_trait_selection::opaque_types::OpaqueTypeDecl;
+use rustc_trait_selection::traits::{self, TraitEngine, TraitEngineExt};
+
+use std::cell::RefCell;
+use std::ops::Deref;
+
+/// Closures defined within the function. For example:
+///
+///     fn foo() {
+///         bar(move|| { ... })
+///     }
+///
+/// Here, the function `foo()` and the closure passed to
+/// `bar()` will each have their own `FnCtxt`, but they will
+/// share the inherited fields.
+pub struct Inherited<'a, 'tcx> {
+    pub(super) infcx: InferCtxt<'a, 'tcx>,
+
+    pub(super) typeck_results: super::MaybeInProgressTables<'a, 'tcx>,
+
+    pub(super) locals: RefCell<HirIdMap<super::LocalTy<'tcx>>>,
+
+    pub(super) fulfillment_cx: RefCell<Box<dyn TraitEngine<'tcx>>>,
+
+    // Some additional `Sized` obligations badly affect type inference.
+    // These obligations are added in a later stage of typeck.
+    pub(super) deferred_sized_obligations:
+        RefCell<Vec<(Ty<'tcx>, Span, traits::ObligationCauseCode<'tcx>)>>,
+
+    // When we process a call like `c()` where `c` is a closure type,
+    // we may not have decided yet whether `c` is a `Fn`, `FnMut`, or
+    // `FnOnce` closure. In that case, we defer full resolution of the
+    // call until upvar inference can kick in and make the
+    // decision. We keep these deferred resolutions grouped by the
+    // def-id of the closure, so that once we decide, we can easily go
+    // back and process them.
+    pub(super) deferred_call_resolutions: RefCell<DefIdMap<Vec<DeferredCallResolution<'tcx>>>>,
+
+    pub(super) deferred_cast_checks: RefCell<Vec<super::cast::CastCheck<'tcx>>>,
+
+    pub(super) deferred_generator_interiors:
+        RefCell<Vec<(hir::BodyId, Ty<'tcx>, hir::GeneratorKind)>>,
+
+    // Opaque types found in explicit return types and their
+    // associated fresh inference variable. Writeback resolves these
+    // variables to get the concrete type, which can be used to
+    // 'de-opaque' OpaqueTypeDecl, after typeck is done with all functions.
+    pub(super) opaque_types: RefCell<DefIdMap<OpaqueTypeDecl<'tcx>>>,
+
+    /// A map from inference variables created from opaque
+    /// type instantiations (`ty::Infer`) to the actual opaque
+    /// type (`ty::Opaque`). Used during fallback to map unconstrained
+    /// opaque type inference variables to their corresponding
+    /// opaque type.
+    pub(super) opaque_types_vars: RefCell<FxHashMap<Ty<'tcx>, Ty<'tcx>>>,
+
+    pub(super) body_id: Option<hir::BodyId>,
+}
+
+impl<'a, 'tcx> Deref for Inherited<'a, 'tcx> {
+    type Target = InferCtxt<'a, 'tcx>;
+    fn deref(&self) -> &Self::Target {
+        &self.infcx
+    }
+}
+
+/// Helper type of a temporary returned by `Inherited::build(...)`.
+/// Necessary because we can't write the following bound:
+/// `F: for<'b, 'tcx> where 'tcx FnOnce(Inherited<'b, 'tcx>)`.
+pub struct InheritedBuilder<'tcx> {
+    infcx: infer::InferCtxtBuilder<'tcx>,
+    def_id: LocalDefId,
+}
+
+impl Inherited<'_, 'tcx> {
+    pub fn build(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> InheritedBuilder<'tcx> {
+        let hir_owner = tcx.hir().local_def_id_to_hir_id(def_id).owner;
+
+        InheritedBuilder {
+            infcx: tcx.infer_ctxt().with_fresh_in_progress_typeck_results(hir_owner),
+            def_id,
+        }
+    }
+}
+
+impl<'tcx> InheritedBuilder<'tcx> {
+    pub fn enter<F, R>(&mut self, f: F) -> R
+    where
+        F: for<'a> FnOnce(Inherited<'a, 'tcx>) -> R,
+    {
+        let def_id = self.def_id;
+        self.infcx.enter(|infcx| f(Inherited::new(infcx, def_id)))
+    }
+}
+
+impl Inherited<'a, 'tcx> {
+    pub(super) fn new(infcx: InferCtxt<'a, 'tcx>, def_id: LocalDefId) -> Self {
+        let tcx = infcx.tcx;
+        let item_id = tcx.hir().local_def_id_to_hir_id(def_id);
+        let body_id = tcx.hir().maybe_body_owned_by(item_id);
+
+        Inherited {
+            typeck_results: MaybeInProgressTables {
+                maybe_typeck_results: infcx.in_progress_typeck_results,
+            },
+            infcx,
+            fulfillment_cx: RefCell::new(TraitEngine::new(tcx)),
+            locals: RefCell::new(Default::default()),
+            deferred_sized_obligations: RefCell::new(Vec::new()),
+            deferred_call_resolutions: RefCell::new(Default::default()),
+            deferred_cast_checks: RefCell::new(Vec::new()),
+            deferred_generator_interiors: RefCell::new(Vec::new()),
+            opaque_types: RefCell::new(Default::default()),
+            opaque_types_vars: RefCell::new(Default::default()),
+            body_id,
+        }
+    }
+
+    pub(super) fn register_predicate(&self, obligation: traits::PredicateObligation<'tcx>) {
+        debug!("register_predicate({:?})", obligation);
+        if obligation.has_escaping_bound_vars() {
+            span_bug!(obligation.cause.span, "escaping bound vars in predicate {:?}", obligation);
+        }
+        self.fulfillment_cx.borrow_mut().register_predicate_obligation(self, obligation);
+    }
+
+    pub(super) fn register_predicates<I>(&self, obligations: I)
+    where
+        I: IntoIterator<Item = traits::PredicateObligation<'tcx>>,
+    {
+        for obligation in obligations {
+            self.register_predicate(obligation);
+        }
+    }
+
+    pub(super) fn register_infer_ok_obligations<T>(&self, infer_ok: InferOk<'tcx, T>) -> T {
+        self.register_predicates(infer_ok.obligations);
+        infer_ok.value
+    }
+
+    pub(super) fn normalize_associated_types_in<T>(
+        &self,
+        span: Span,
+        body_id: hir::HirId,
+        param_env: ty::ParamEnv<'tcx>,
+        value: &T,
+    ) -> T
+    where
+        T: TypeFoldable<'tcx>,
+    {
+        let ok = self.partially_normalize_associated_types_in(span, body_id, param_env, value);
+        self.register_infer_ok_obligations(ok)
+    }
+}
diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs
index e84cc3c9b86..04d4d8171d4 100644
--- a/compiler/rustc_typeck/src/check/mod.rs
+++ b/compiler/rustc_typeck/src/check/mod.rs
@@ -1,5 +1,3 @@
-// ignore-tidy-filelength
-
 /*!
 
 # typeck: check phase
@@ -68,13 +66,19 @@ pub mod _match;
 mod autoderef;
 mod callee;
 pub mod cast;
+mod check;
 mod closure;
 pub mod coercion;
 mod compare_method;
 pub mod demand;
+mod diverges;
 pub mod dropck;
+mod expectation;
 mod expr;
+mod fn_ctxt;
+mod gather_locals;
 mod generator_interior;
+mod inherited;
 pub mod intrinsic;
 pub mod method;
 mod op;
@@ -85,80 +89,53 @@ mod upvar;
 mod wfcheck;
 pub mod writeback;
 
-use crate::astconv::{
-    AstConv, ExplicitLateBound, GenericArgCountMismatch, GenericArgCountResult, PathSeg,
+use check::{
+    check_abi, check_fn, check_impl_item_well_formed, check_item_well_formed, check_mod_item_types,
+    check_trait_item_well_formed,
 };
-use rustc_ast as ast;
-use rustc_ast::util::parser::ExprPrecedence;
-use rustc_attr as attr;
-use rustc_data_structures::captures::Captures;
+pub use check::{check_item_type, check_wf_new};
+pub use diverges::Diverges;
+pub use expectation::Expectation;
+pub use fn_ctxt::FnCtxt;
+pub use inherited::{Inherited, InheritedBuilder};
+
+use crate::astconv::AstConv;
+use crate::check::gather_locals::GatherLocalsVisitor;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_errors::ErrorReported;
-use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, DiagnosticId};
+use rustc_errors::{pluralize, struct_span_err, Applicability};
 use rustc_hir as hir;
-use rustc_hir::def::{CtorOf, DefKind, Res};
-use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LOCAL_CRATE};
-use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc_hir::def::Res;
+use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
+use rustc_hir::intravisit::Visitor;
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
-use rustc_hir::lang_items::LangItem;
-use rustc_hir::{ExprKind, GenericArg, HirIdMap, ItemKind, Node, PatKind, QPath};
+use rustc_hir::{HirIdMap, Node};
 use rustc_index::bit_set::BitSet;
 use rustc_index::vec::Idx;
-use rustc_infer::infer;
-use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse};
-use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282;
-use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use rustc_infer::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
-use rustc_infer::infer::{InferCtxt, InferOk, InferResult, RegionVariableOrigin, TyCtxtInferExt};
-use rustc_middle::hir::map::blocks::FnLikeNode;
-use rustc_middle::ty::adjustment::{
-    Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability,
-};
 use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
 use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::subst::{self, InternalSubsts, Subst, SubstsRef};
-use rustc_middle::ty::subst::{GenericArgKind, UserSelfTy, UserSubsts};
-use rustc_middle::ty::util::{Discr, IntTypeExt, Representability};
+use rustc_middle::ty::subst::GenericArgKind;
+use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef};
 use rustc_middle::ty::WithConstness;
-use rustc_middle::ty::{self, AdtKind, CanonicalUserType, Const, DefIdTree, GenericParamDefKind};
-use rustc_middle::ty::{RegionKind, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, UserType};
-use rustc_session::config::{self, EntryFnType};
-use rustc_session::lint;
+use rustc_middle::ty::{self, RegionKind, Ty, TyCtxt, UserType};
+use rustc_session::config;
 use rustc_session::parse::feature_err;
 use rustc_session::Session;
-use rustc_span::hygiene::DesugaringKind;
-use rustc_span::source_map::{original_sp, DUMMY_SP};
-use rustc_span::symbol::{kw, sym, Ident};
+use rustc_span::source_map::DUMMY_SP;
+use rustc_span::symbol::{kw, Ident};
 use rustc_span::{self, BytePos, MultiSpan, Span};
 use rustc_target::abi::VariantIdx;
 use rustc_target::spec::abi::Abi;
-use rustc_trait_selection::infer::InferCtxtExt as _;
-use rustc_trait_selection::opaque_types::{InferCtxtExt as _, OpaqueTypeDecl};
+use rustc_trait_selection::traits;
 use rustc_trait_selection::traits::error_reporting::recursive_type_with_infinite_size_error;
 use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor;
-use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
-use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
-use rustc_trait_selection::traits::{
-    self, ObligationCause, ObligationCauseCode, TraitEngine, TraitEngineExt,
-};
 
-use std::cell::{Cell, Ref, RefCell, RefMut};
-use std::cmp;
-use std::collections::hash_map::Entry;
-use std::iter;
-use std::mem::replace;
-use std::ops::{self, Deref};
-use std::slice;
+use std::cell::{Ref, RefCell, RefMut};
 
 use crate::require_c_abi_if_c_variadic;
 use crate::util::common::indenter;
 
-use self::callee::DeferredCallResolution;
-use self::coercion::{CoerceMany, DynamicCoerceMany};
-use self::compare_method::{compare_const_impl, compare_impl_method, compare_ty_impl};
-use self::method::{MethodCallee, SelfSource};
+use self::coercion::DynamicCoerceMany;
 pub use self::Expectation::*;
-use self::TupleArgumentsFlag::*;
 
 #[macro_export]
 macro_rules! type_error_struct {
@@ -178,201 +155,6 @@ pub struct LocalTy<'tcx> {
     revealed_ty: Ty<'tcx>,
 }
 
-/// A wrapper for `InferCtxt`'s `in_progress_typeck_results` field.
-#[derive(Copy, Clone)]
-struct MaybeInProgressTables<'a, 'tcx> {
-    maybe_typeck_results: Option<&'a RefCell<ty::TypeckResults<'tcx>>>,
-}
-
-impl<'a, 'tcx> MaybeInProgressTables<'a, 'tcx> {
-    fn borrow(self) -> Ref<'a, ty::TypeckResults<'tcx>> {
-        match self.maybe_typeck_results {
-            Some(typeck_results) => typeck_results.borrow(),
-            None => bug!(
-                "MaybeInProgressTables: inh/fcx.typeck_results.borrow() with no typeck results"
-            ),
-        }
-    }
-
-    fn borrow_mut(self) -> RefMut<'a, ty::TypeckResults<'tcx>> {
-        match self.maybe_typeck_results {
-            Some(typeck_results) => typeck_results.borrow_mut(),
-            None => bug!(
-                "MaybeInProgressTables: inh/fcx.typeck_results.borrow_mut() with no typeck results"
-            ),
-        }
-    }
-}
-
-/// Closures defined within the function. For example:
-///
-///     fn foo() {
-///         bar(move|| { ... })
-///     }
-///
-/// Here, the function `foo()` and the closure passed to
-/// `bar()` will each have their own `FnCtxt`, but they will
-/// share the inherited fields.
-pub struct Inherited<'a, 'tcx> {
-    infcx: InferCtxt<'a, 'tcx>,
-
-    typeck_results: MaybeInProgressTables<'a, 'tcx>,
-
-    locals: RefCell<HirIdMap<LocalTy<'tcx>>>,
-
-    fulfillment_cx: RefCell<Box<dyn TraitEngine<'tcx>>>,
-
-    // Some additional `Sized` obligations badly affect type inference.
-    // These obligations are added in a later stage of typeck.
-    deferred_sized_obligations: RefCell<Vec<(Ty<'tcx>, Span, traits::ObligationCauseCode<'tcx>)>>,
-
-    // When we process a call like `c()` where `c` is a closure type,
-    // we may not have decided yet whether `c` is a `Fn`, `FnMut`, or
-    // `FnOnce` closure. In that case, we defer full resolution of the
-    // call until upvar inference can kick in and make the
-    // decision. We keep these deferred resolutions grouped by the
-    // def-id of the closure, so that once we decide, we can easily go
-    // back and process them.
-    deferred_call_resolutions: RefCell<DefIdMap<Vec<DeferredCallResolution<'tcx>>>>,
-
-    deferred_cast_checks: RefCell<Vec<cast::CastCheck<'tcx>>>,
-
-    deferred_generator_interiors: RefCell<Vec<(hir::BodyId, Ty<'tcx>, hir::GeneratorKind)>>,
-
-    // Opaque types found in explicit return types and their
-    // associated fresh inference variable. Writeback resolves these
-    // variables to get the concrete type, which can be used to
-    // 'de-opaque' OpaqueTypeDecl, after typeck is done with all functions.
-    opaque_types: RefCell<DefIdMap<OpaqueTypeDecl<'tcx>>>,
-
-    /// A map from inference variables created from opaque
-    /// type instantiations (`ty::Infer`) to the actual opaque
-    /// type (`ty::Opaque`). Used during fallback to map unconstrained
-    /// opaque type inference variables to their corresponding
-    /// opaque type.
-    opaque_types_vars: RefCell<FxHashMap<Ty<'tcx>, Ty<'tcx>>>,
-
-    body_id: Option<hir::BodyId>,
-}
-
-impl<'a, 'tcx> Deref for Inherited<'a, 'tcx> {
-    type Target = InferCtxt<'a, 'tcx>;
-    fn deref(&self) -> &Self::Target {
-        &self.infcx
-    }
-}
-
-/// When type-checking an expression, we propagate downward
-/// whatever type hint we are able in the form of an `Expectation`.
-#[derive(Copy, Clone, Debug)]
-pub enum Expectation<'tcx> {
-    /// We know nothing about what type this expression should have.
-    NoExpectation,
-
-    /// This expression should have the type given (or some subtype).
-    ExpectHasType(Ty<'tcx>),
-
-    /// This expression will be cast to the `Ty`.
-    ExpectCastableToType(Ty<'tcx>),
-
-    /// This rvalue expression will be wrapped in `&` or `Box` and coerced
-    /// to `&Ty` or `Box<Ty>`, respectively. `Ty` is `[A]` or `Trait`.
-    ExpectRvalueLikeUnsized(Ty<'tcx>),
-}
-
-impl<'a, 'tcx> Expectation<'tcx> {
-    // Disregard "castable to" expectations because they
-    // can lead us astray. Consider for example `if cond
-    // {22} else {c} as u8` -- if we propagate the
-    // "castable to u8" constraint to 22, it will pick the
-    // type 22u8, which is overly constrained (c might not
-    // be a u8). In effect, the problem is that the
-    // "castable to" expectation is not the tightest thing
-    // we can say, so we want to drop it in this case.
-    // The tightest thing we can say is "must unify with
-    // else branch". Note that in the case of a "has type"
-    // constraint, this limitation does not hold.
-
-    // If the expected type is just a type variable, then don't use
-    // an expected type. Otherwise, we might write parts of the type
-    // when checking the 'then' block which are incompatible with the
-    // 'else' branch.
-    fn adjust_for_branches(&self, fcx: &FnCtxt<'a, 'tcx>) -> Expectation<'tcx> {
-        match *self {
-            ExpectHasType(ety) => {
-                let ety = fcx.shallow_resolve(ety);
-                if !ety.is_ty_var() { ExpectHasType(ety) } else { NoExpectation }
-            }
-            ExpectRvalueLikeUnsized(ety) => ExpectRvalueLikeUnsized(ety),
-            _ => NoExpectation,
-        }
-    }
-
-    /// Provides an expectation for an rvalue expression given an *optional*
-    /// hint, which is not required for type safety (the resulting type might
-    /// be checked higher up, as is the case with `&expr` and `box expr`), but
-    /// is useful in determining the concrete type.
-    ///
-    /// The primary use case is where the expected type is a fat pointer,
-    /// like `&[isize]`. For example, consider the following statement:
-    ///
-    ///    let x: &[isize] = &[1, 2, 3];
-    ///
-    /// In this case, the expected type for the `&[1, 2, 3]` expression is
-    /// `&[isize]`. If however we were to say that `[1, 2, 3]` has the
-    /// expectation `ExpectHasType([isize])`, that would be too strong --
-    /// `[1, 2, 3]` does not have the type `[isize]` but rather `[isize; 3]`.
-    /// It is only the `&[1, 2, 3]` expression as a whole that can be coerced
-    /// to the type `&[isize]`. Therefore, we propagate this more limited hint,
-    /// which still is useful, because it informs integer literals and the like.
-    /// See the test case `test/ui/coerce-expect-unsized.rs` and #20169
-    /// for examples of where this comes up,.
-    fn rvalue_hint(fcx: &FnCtxt<'a, 'tcx>, ty: Ty<'tcx>) -> Expectation<'tcx> {
-        match fcx.tcx.struct_tail_without_normalization(ty).kind() {
-            ty::Slice(_) | ty::Str | ty::Dynamic(..) => ExpectRvalueLikeUnsized(ty),
-            _ => ExpectHasType(ty),
-        }
-    }
-
-    // Resolves `expected` by a single level if it is a variable. If
-    // there is no expected type or resolution is not possible (e.g.,
-    // no constraints yet present), just returns `None`.
-    fn resolve(self, fcx: &FnCtxt<'a, 'tcx>) -> Expectation<'tcx> {
-        match self {
-            NoExpectation => NoExpectation,
-            ExpectCastableToType(t) => ExpectCastableToType(fcx.resolve_vars_if_possible(&t)),
-            ExpectHasType(t) => ExpectHasType(fcx.resolve_vars_if_possible(&t)),
-            ExpectRvalueLikeUnsized(t) => ExpectRvalueLikeUnsized(fcx.resolve_vars_if_possible(&t)),
-        }
-    }
-
-    fn to_option(self, fcx: &FnCtxt<'a, 'tcx>) -> Option<Ty<'tcx>> {
-        match self.resolve(fcx) {
-            NoExpectation => None,
-            ExpectCastableToType(ty) | ExpectHasType(ty) | ExpectRvalueLikeUnsized(ty) => Some(ty),
-        }
-    }
-
-    /// It sometimes happens that we want to turn an expectation into
-    /// a **hard constraint** (i.e., something that must be satisfied
-    /// for the program to type-check). `only_has_type` will return
-    /// such a constraint, if it exists.
-    fn only_has_type(self, fcx: &FnCtxt<'a, 'tcx>) -> Option<Ty<'tcx>> {
-        match self.resolve(fcx) {
-            ExpectHasType(ty) => Some(ty),
-            NoExpectation | ExpectCastableToType(_) | ExpectRvalueLikeUnsized(_) => None,
-        }
-    }
-
-    /// Like `only_has_type`, but instead of returning `None` if no
-    /// hard constraint exists, creates a fresh type variable.
-    fn coercion_target_type(self, fcx: &FnCtxt<'a, 'tcx>, span: Span) -> Ty<'tcx> {
-        self.only_has_type(fcx).unwrap_or_else(|| {
-            fcx.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::MiscVariable, span })
-        })
-    }
-}
-
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
 pub enum Needs {
     MutPlace,
@@ -435,81 +217,6 @@ pub enum PlaceOp {
     Index,
 }
 
-/// Tracks whether executing a node may exit normally (versus
-/// return/break/panic, which "diverge", leaving dead code in their
-/// wake). Tracked semi-automatically (through type variables marked
-/// as diverging), with some manual adjustments for control-flow
-/// primitives (approximating a CFG).
-#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
-pub enum Diverges {
-    /// Potentially unknown, some cases converge,
-    /// others require a CFG to determine them.
-    Maybe,
-
-    /// Definitely known to diverge and therefore
-    /// not reach the next sibling or its parent.
-    Always {
-        /// The `Span` points to the expression
-        /// that caused us to diverge
-        /// (e.g. `return`, `break`, etc).
-        span: Span,
-        /// In some cases (e.g. a `match` expression
-        /// where all arms diverge), we may be
-        /// able to provide a more informative
-        /// message to the user.
-        /// If this is `None`, a default message
-        /// will be generated, which is suitable
-        /// for most cases.
-        custom_note: Option<&'static str>,
-    },
-
-    /// Same as `Always` but with a reachability
-    /// warning already emitted.
-    WarnedAlways,
-}
-
-// Convenience impls for combining `Diverges`.
-
-impl ops::BitAnd for Diverges {
-    type Output = Self;
-    fn bitand(self, other: Self) -> Self {
-        cmp::min(self, other)
-    }
-}
-
-impl ops::BitOr for Diverges {
-    type Output = Self;
-    fn bitor(self, other: Self) -> Self {
-        cmp::max(self, other)
-    }
-}
-
-impl ops::BitAndAssign for Diverges {
-    fn bitand_assign(&mut self, other: Self) {
-        *self = *self & other;
-    }
-}
-
-impl ops::BitOrAssign for Diverges {
-    fn bitor_assign(&mut self, other: Self) {
-        *self = *self | other;
-    }
-}
-
-impl Diverges {
-    /// Creates a `Diverges::Always` with the provided `span` and the default note message.
-    fn always(span: Span) -> Diverges {
-        Diverges::Always { span, custom_note: None }
-    }
-
-    fn is_always(self) -> bool {
-        // Enum comparison ignores the
-        // contents of fields, so we just
-        // fill them in with garbage here.
-        self >= Diverges::Always { span: DUMMY_SP, custom_note: None }
-    }
-}
-
 pub struct BreakableCtxt<'tcx> {
     may_break: bool,
 
@@ -538,229 +245,6 @@ impl<'tcx> EnclosingBreakables<'tcx> {
     }
 }
 
-pub struct FnCtxt<'a, 'tcx> {
-    body_id: hir::HirId,
-
-    /// The parameter environment used for proving trait obligations
-    /// in this function. This can change when we descend into
-    /// closures (as they bring new things into scope), hence it is
-    /// not part of `Inherited` (as of the time of this writing,
-    /// closures do not yet change the environment, but they will
-    /// eventually).
-    param_env: ty::ParamEnv<'tcx>,
-
-    /// Number of errors that had been reported when we started
-    /// checking this function. On exit, if we find that *more* errors
-    /// have been reported, we will skip regionck and other work that
-    /// expects the types within the function to be consistent.
-    // FIXME(matthewjasper) This should not exist, and it's not correct
-    // if type checking is run in parallel.
-    err_count_on_creation: usize,
-
-    /// If `Some`, this stores coercion information for returned
-    /// expressions. If `None`, this is in a context where return is
-    /// inappropriate, such as a const expression.
-    ///
-    /// This is a `RefCell<DynamicCoerceMany>`, which means that we
-    /// can track all the return expressions and then use them to
-    /// compute a useful coercion from the set, similar to a match
-    /// expression or other branching context. You can use methods
-    /// like `expected_ty` to access the declared return type (if
-    /// any).
-    ret_coercion: Option<RefCell<DynamicCoerceMany<'tcx>>>,
-
-    ret_coercion_impl_trait: Option<Ty<'tcx>>,
-
-    ret_type_span: Option<Span>,
-
-    /// Used exclusively to reduce cost of advanced evaluation used for
-    /// more helpful diagnostics.
-    in_tail_expr: bool,
-
-    /// First span of a return site that we find. Used in error messages.
-    ret_coercion_span: RefCell<Option<Span>>,
-
-    resume_yield_tys: Option<(Ty<'tcx>, Ty<'tcx>)>,
-
-    ps: RefCell<UnsafetyState>,
-
-    /// Whether the last checked node generates a divergence (e.g.,
-    /// `return` will set this to `Always`). In general, when entering
-    /// an expression or other node in the tree, the initial value
-    /// indicates whether prior parts of the containing expression may
-    /// have diverged. It is then typically set to `Maybe` (and the
-    /// old value remembered) for processing the subparts of the
-    /// current expression. As each subpart is processed, they may set
-    /// the flag to `Always`, etc. Finally, at the end, we take the
-    /// result and "union" it with the original value, so that when we
-    /// return the flag indicates if any subpart of the parent
-    /// expression (up to and including this part) has diverged. So,
-    /// if you read it after evaluating a subexpression `X`, the value
-    /// you get indicates whether any subexpression that was
-    /// evaluating up to and including `X` diverged.
-    ///
-    /// We currently use this flag only for diagnostic purposes:
-    ///
-    /// - To warn about unreachable code: if, after processing a
-    ///   sub-expression but before we have applied the effects of the
-    ///   current node, we see that the flag is set to `Always`, we
-    ///   can issue a warning. This corresponds to something like
-    ///   `foo(return)`; we warn on the `foo()` expression. (We then
-    ///   update the flag to `WarnedAlways` to suppress duplicate
-    ///   reports.) Similarly, if we traverse to a fresh statement (or
-    ///   tail expression) from a `Always` setting, we will issue a
-    ///   warning. This corresponds to something like `{return;
-    ///   foo();}` or `{return; 22}`, where we would warn on the
-    ///   `foo()` or `22`.
-    ///
-    /// An expression represents dead code if, after checking it,
-    /// the diverges flag is set to something other than `Maybe`.
-    diverges: Cell<Diverges>,
-
-    /// Whether any child nodes have any type errors.
-    has_errors: Cell<bool>,
-
-    enclosing_breakables: RefCell<EnclosingBreakables<'tcx>>,
-
-    inh: &'a Inherited<'a, 'tcx>,
-}
-
-impl<'a, 'tcx> Deref for FnCtxt<'a, 'tcx> {
-    type Target = Inherited<'a, 'tcx>;
-    fn deref(&self) -> &Self::Target {
-        &self.inh
-    }
-}
-
-/// Helper type of a temporary returned by `Inherited::build(...)`.
-/// Necessary because we can't write the following bound:
-/// `F: for<'b, 'tcx> where 'tcx FnOnce(Inherited<'b, 'tcx>)`.
-pub struct InheritedBuilder<'tcx> {
-    infcx: infer::InferCtxtBuilder<'tcx>,
-    def_id: LocalDefId,
-}
-
-impl Inherited<'_, 'tcx> {
-    pub fn build(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> InheritedBuilder<'tcx> {
-        let hir_owner = tcx.hir().local_def_id_to_hir_id(def_id).owner;
-
-        InheritedBuilder {
-            infcx: tcx.infer_ctxt().with_fresh_in_progress_typeck_results(hir_owner),
-            def_id,
-        }
-    }
-}
-
-impl<'tcx> InheritedBuilder<'tcx> {
-    pub fn enter<F, R>(&mut self, f: F) -> R
-    where
-        F: for<'a> FnOnce(Inherited<'a, 'tcx>) -> R,
-    {
-        let def_id = self.def_id;
-        self.infcx.enter(|infcx| f(Inherited::new(infcx, def_id)))
-    }
-}
-
-impl Inherited<'a, 'tcx> {
-    fn new(infcx: InferCtxt<'a, 'tcx>, def_id: LocalDefId) -> Self {
-        let tcx = infcx.tcx;
-        let item_id = tcx.hir().local_def_id_to_hir_id(def_id);
-        let body_id = tcx.hir().maybe_body_owned_by(item_id);
-
-        Inherited {
-            typeck_results: MaybeInProgressTables {
-                maybe_typeck_results: infcx.in_progress_typeck_results,
-            },
-            infcx,
-            fulfillment_cx: RefCell::new(TraitEngine::new(tcx)),
-            locals: RefCell::new(Default::default()),
-            deferred_sized_obligations: RefCell::new(Vec::new()),
-            deferred_call_resolutions: RefCell::new(Default::default()),
-            deferred_cast_checks: RefCell::new(Vec::new()),
-            deferred_generator_interiors: RefCell::new(Vec::new()),
-            opaque_types: RefCell::new(Default::default()),
-            opaque_types_vars: RefCell::new(Default::default()),
-            body_id,
-        }
-    }
-
-    fn register_predicate(&self, obligation: traits::PredicateObligation<'tcx>) {
-        debug!("register_predicate({:?})", obligation);
-        if obligation.has_escaping_bound_vars() {
-            span_bug!(obligation.cause.span, "escaping bound vars in predicate {:?}", obligation);
-        }
-        self.fulfillment_cx.borrow_mut().register_predicate_obligation(self, obligation);
-    }
-
-    fn register_predicates<I>(&self, obligations: I)
-    where
-        I: IntoIterator<Item = traits::PredicateObligation<'tcx>>,
-    {
-        for obligation in obligations {
-            self.register_predicate(obligation);
-        }
-    }
-
-    fn register_infer_ok_obligations<T>(&self, infer_ok: InferOk<'tcx, T>) -> T {
-        self.register_predicates(infer_ok.obligations);
-        infer_ok.value
-    }
-
-    fn normalize_associated_types_in<T>(
-        &self,
-        span: Span,
-        body_id: hir::HirId,
-        param_env: ty::ParamEnv<'tcx>,
-        value: &T,
-    ) -> T
-    where
-        T: TypeFoldable<'tcx>,
-    {
-        let ok = self.partially_normalize_associated_types_in(span, body_id, param_env, value);
-        self.register_infer_ok_obligations(ok)
-    }
-}
-
-struct CheckItemTypesVisitor<'tcx> {
-    tcx: TyCtxt<'tcx>,
-}
-
-impl ItemLikeVisitor<'tcx> for CheckItemTypesVisitor<'tcx> {
-    fn visit_item(&mut self, i: &'tcx hir::Item<'tcx>) {
-        check_item_type(self.tcx, i);
-    }
-    fn visit_trait_item(&mut self, _: &'tcx hir::TraitItem<'tcx>) {}
-    fn visit_impl_item(&mut self, _: &'tcx hir::ImplItem<'tcx>) {}
-}
-
-pub fn check_wf_new(tcx: TyCtxt<'_>) {
-    let visit = wfcheck::CheckTypeWellFormedVisitor::new(tcx);
-    tcx.hir().krate().par_visit_all_item_likes(&visit);
-}
-
-fn check_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
-    tcx.hir().visit_item_likes_in_module(module_def_id, &mut CheckItemTypesVisitor { tcx });
-}
-
-fn typeck_item_bodies(tcx: TyCtxt<'_>, crate_num: CrateNum) {
-    debug_assert!(crate_num == LOCAL_CRATE);
-    tcx.par_body_owners(|body_owner_def_id| {
-        tcx.ensure().typeck(body_owner_def_id);
-    });
-}
-
-fn check_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) {
-    wfcheck::check_item_well_formed(tcx, def_id);
-}
-
-fn check_trait_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) {
-    wfcheck::check_trait_item(tcx, def_id);
-}
-
-fn check_impl_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) {
-    wfcheck::check_impl_item(tcx, def_id);
-}
-
 pub fn provide(providers: &mut Providers) {
     method::provide(providers);
     *providers = Providers {
@@ -1055,7 +539,7 @@ fn typeck_with_fallback<'tcx>(
             };
 
             // Gather locals in statics (because of block expressions).
-            GatherLocalsVisitor { fcx: &fcx, parent_id: id }.visit_body(body);
+            GatherLocalsVisitor::new(&fcx, id).visit_body(body);
 
             fcx.check_expr_coercable_to_type(&body.value, revealed_ty, None);
 
@@ -1142,127 +626,6 @@ fn typeck_with_fallback<'tcx>(
     typeck_results
 }
 
-fn check_abi(tcx: TyCtxt<'_>, span: Span, abi: Abi) {
-    if !tcx.sess.target.target.is_abi_supported(abi) {
-        struct_span_err!(
-            tcx.sess,
-            span,
-            E0570,
-            "The ABI `{}` is not supported for the current target",
-            abi
-        )
-        .emit()
-    }
-}
-
-struct GatherLocalsVisitor<'a, 'tcx> {
-    fcx: &'a FnCtxt<'a, 'tcx>,
-    parent_id: hir::HirId,
-}
-
-impl<'a, 'tcx> GatherLocalsVisitor<'a, 'tcx> {
-    fn assign(&mut self, span: Span, nid: hir::HirId, ty_opt: Option<LocalTy<'tcx>>) -> Ty<'tcx> {
-        match ty_opt {
-            None => {
-                // Infer the variable's type.
-                let var_ty = self.fcx.next_ty_var(TypeVariableOrigin {
-                    kind: TypeVariableOriginKind::TypeInference,
-                    span,
-                });
-                self.fcx
-                    .locals
-                    .borrow_mut()
-                    .insert(nid, LocalTy { decl_ty: var_ty, revealed_ty: var_ty });
-                var_ty
-            }
-            Some(typ) => {
-                // Take type that the user specified.
-                self.fcx.locals.borrow_mut().insert(nid, typ);
-                typ.revealed_ty
-            }
-        }
-    }
-}
-
-impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> {
-    type Map = intravisit::ErasedMap<'tcx>;
-
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::None
-    }
-
-    // Add explicitly-declared locals.
-    fn visit_local(&mut self, local: &'tcx hir::Local<'tcx>) {
-        let local_ty = match local.ty {
-            Some(ref ty) => {
-                let o_ty = self.fcx.to_ty(&ty);
-
-                let revealed_ty = if self.fcx.tcx.features().impl_trait_in_bindings {
-                    self.fcx.instantiate_opaque_types_from_value(self.parent_id, &o_ty, ty.span)
-                } else {
-                    o_ty
-                };
-
-                let c_ty = self
-                    .fcx
-                    .inh
-                    .infcx
-                    .canonicalize_user_type_annotation(&UserType::Ty(revealed_ty));
-                debug!(
-                    "visit_local: ty.hir_id={:?} o_ty={:?} revealed_ty={:?} c_ty={:?}",
-                    ty.hir_id, o_ty, revealed_ty, c_ty
-                );
-                self.fcx
-                    .typeck_results
-                    .borrow_mut()
-                    .user_provided_types_mut()
-                    .insert(ty.hir_id, c_ty);
-
-                Some(LocalTy { decl_ty: o_ty, revealed_ty })
-            }
-            None => None,
-        };
-        self.assign(local.span, local.hir_id, local_ty);
-
-        debug!(
-            "local variable {:?} is assigned type {}",
-            local.pat,
-            self.fcx.ty_to_string(&*self.fcx.locals.borrow().get(&local.hir_id).unwrap().decl_ty)
-        );
-        intravisit::walk_local(self, local);
-    }
-
-    // Add pattern bindings.
-    fn visit_pat(&mut self, p: &'tcx hir::Pat<'tcx>) {
-        if let PatKind::Binding(_, _, ident, _) = p.kind {
-            let var_ty = self.assign(p.span, p.hir_id, None);
-
-            if !self.fcx.tcx.features().unsized_locals {
-                self.fcx.require_type_is_sized(var_ty, p.span, traits::VariableType(p.hir_id));
-            }
-
-            debug!(
-                "pattern binding {} is assigned to {} with type {:?}",
-                ident,
-                self.fcx.ty_to_string(&*self.fcx.locals.borrow().get(&p.hir_id).unwrap().decl_ty),
-                var_ty
-            );
-        }
-        intravisit::walk_pat(self, p);
-    }
-
-    // Don't descend into the bodies of nested closures.
-    fn visit_fn(
-        &mut self,
-        _: intravisit::FnKind<'tcx>,
-        _: &'tcx hir::FnDecl<'tcx>,
-        _: hir::BodyId,
-        _: Span,
-        _: hir::HirId,
-    ) {
-    }
-}
-
 /// When `check_fn` is invoked on a generator (i.e., a body that
 /// includes yield), it returns back some information about the yield
 /// points.
@@ -1280,460 +643,6 @@ struct GeneratorTypes<'tcx> {
     movability: hir::Movability,
 }
 
-/// Helper used for fns and closures. Does the grungy work of checking a function
-/// body and returns the function context used for that purpose, since in the case of a fn item
-/// there is still a bit more to do.
-///
-/// * ...
-/// * inherited: other fields inherited from the enclosing fn (if any)
-fn check_fn<'a, 'tcx>(
-    inherited: &'a Inherited<'a, 'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
-    fn_sig: ty::FnSig<'tcx>,
-    decl: &'tcx hir::FnDecl<'tcx>,
-    fn_id: hir::HirId,
-    body: &'tcx hir::Body<'tcx>,
-    can_be_generator: Option<hir::Movability>,
-) -> (FnCtxt<'a, 'tcx>, Option<GeneratorTypes<'tcx>>) {
-    let mut fn_sig = fn_sig;
-
-    debug!("check_fn(sig={:?}, fn_id={}, param_env={:?})", fn_sig, fn_id, param_env);
-
-    // Create the function context. This is either derived from scratch or,
-    // in the case of closures, based on the outer context.
-    let mut fcx = FnCtxt::new(inherited, param_env, body.value.hir_id);
-    *fcx.ps.borrow_mut() = UnsafetyState::function(fn_sig.unsafety, fn_id);
-
-    let tcx = fcx.tcx;
-    let sess = tcx.sess;
-    let hir = tcx.hir();
-
-    let declared_ret_ty = fn_sig.output();
-
-    let revealed_ret_ty =
-        fcx.instantiate_opaque_types_from_value(fn_id, &declared_ret_ty, decl.output.span());
-    debug!("check_fn: declared_ret_ty: {}, revealed_ret_ty: {}", declared_ret_ty, revealed_ret_ty);
-    fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(revealed_ret_ty)));
-    fcx.ret_type_span = Some(decl.output.span());
-    if let ty::Opaque(..) = declared_ret_ty.kind() {
-        fcx.ret_coercion_impl_trait = Some(declared_ret_ty);
-    }
-    fn_sig = tcx.mk_fn_sig(
-        fn_sig.inputs().iter().cloned(),
-        revealed_ret_ty,
-        fn_sig.c_variadic,
-        fn_sig.unsafety,
-        fn_sig.abi,
-    );
-
-    let span = body.value.span;
-
-    fn_maybe_err(tcx, span, fn_sig.abi);
-
-    if body.generator_kind.is_some() && can_be_generator.is_some() {
-        let yield_ty = fcx
-            .next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span });
-        fcx.require_type_is_sized(yield_ty, span, traits::SizedYieldType);
-
-        // Resume type defaults to `()` if the generator has no argument.
-        let resume_ty = fn_sig.inputs().get(0).copied().unwrap_or_else(|| tcx.mk_unit());
-
-        fcx.resume_yield_tys = Some((resume_ty, yield_ty));
-    }
-
-    let outer_def_id = tcx.closure_base_def_id(hir.local_def_id(fn_id).to_def_id()).expect_local();
-    let outer_hir_id = hir.local_def_id_to_hir_id(outer_def_id);
-    GatherLocalsVisitor { fcx: &fcx, parent_id: outer_hir_id }.visit_body(body);
-
-    // C-variadic fns also have a `VaList` input that's not listed in `fn_sig`
-    // (as it's created inside the body itself, not passed in from outside).
-    let maybe_va_list = if fn_sig.c_variadic {
-        let span = body.params.last().unwrap().span;
-        let va_list_did = tcx.require_lang_item(LangItem::VaList, Some(span));
-        let region = fcx.next_region_var(RegionVariableOrigin::MiscVariable(span));
-
-        Some(tcx.type_of(va_list_did).subst(tcx, &[region.into()]))
-    } else {
-        None
-    };
-
-    // Add formal parameters.
-    let inputs_hir = hir.fn_decl_by_hir_id(fn_id).map(|decl| &decl.inputs);
-    let inputs_fn = fn_sig.inputs().iter().copied();
-    for (idx, (param_ty, param)) in inputs_fn.chain(maybe_va_list).zip(body.params).enumerate() {
-        // Check the pattern.
-        let ty_span = try { inputs_hir?.get(idx)?.span };
-        fcx.check_pat_top(&param.pat, param_ty, ty_span, false);
-
-        // Check that argument is Sized.
-        // The check for a non-trivial pattern is a hack to avoid duplicate warnings
-        // for simple cases like `fn foo(x: Trait)`,
-        // where we would error once on the parameter as a whole, and once on the binding `x`.
-        if param.pat.simple_ident().is_none() && !tcx.features().unsized_locals {
-            fcx.require_type_is_sized(param_ty, param.pat.span, traits::SizedArgumentType(ty_span));
-        }
-
-        fcx.write_ty(param.hir_id, param_ty);
-    }
-
-    inherited.typeck_results.borrow_mut().liberated_fn_sigs_mut().insert(fn_id, fn_sig);
-
-    fcx.in_tail_expr = true;
-    if let ty::Dynamic(..) = declared_ret_ty.kind() {
-        // FIXME: We need to verify that the return type is `Sized` after the return expression has
-        // been evaluated so that we have types available for all the nodes being returned, but that
-        // requires the coerced evaluated type to be stored. Moving `check_return_expr` before this
-        // causes unsized errors caused by the `declared_ret_ty` to point at the return expression,
-        // while keeping the current ordering we will ignore the tail expression's type because we
-        // don't know it yet. We can't do `check_expr_kind` while keeping `check_return_expr`
-        // because we will trigger "unreachable expression" lints unconditionally.
-        // Because of all of this, we perform a crude check to know whether the simplest `!Sized`
-        // case that a newcomer might make, returning a bare trait, and in that case we populate
-        // the tail expression's type so that the suggestion will be correct, but ignore all other
-        // possible cases.
-        fcx.check_expr(&body.value);
-        fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType);
-        tcx.sess.delay_span_bug(decl.output.span(), "`!Sized` return type");
-    } else {
-        fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType);
-        fcx.check_return_expr(&body.value);
-    }
-    fcx.in_tail_expr = false;
-
-    // We insert the deferred_generator_interiors entry after visiting the body.
-    // This ensures that all nested generators appear before the entry of this generator.
-    // resolve_generator_interiors relies on this property.
-    let gen_ty = if let (Some(_), Some(gen_kind)) = (can_be_generator, body.generator_kind) {
-        let interior = fcx
-            .next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::MiscVariable, span });
-        fcx.deferred_generator_interiors.borrow_mut().push((body.id(), interior, gen_kind));
-
-        let (resume_ty, yield_ty) = fcx.resume_yield_tys.unwrap();
-        Some(GeneratorTypes {
-            resume_ty,
-            yield_ty,
-            interior,
-            movability: can_be_generator.unwrap(),
-        })
-    } else {
-        None
-    };
-
-    // Finalize the return check by taking the LUB of the return types
-    // we saw and assigning it to the expected return type. This isn't
-    // really expected to fail, since the coercions would have failed
-    // earlier when trying to find a LUB.
-    //
-    // However, the behavior around `!` is sort of complex. In the
-    // event that the `actual_return_ty` comes back as `!`, that
-    // indicates that the fn either does not return or "returns" only
-    // values of type `!`. In this case, if there is an expected
-    // return type that is *not* `!`, that should be ok. But if the
-    // return type is being inferred, we want to "fallback" to `!`:
-    //
-    //     let x = move || panic!();
-    //
-    // To allow for that, I am creating a type variable with diverging
-    // fallback. This was deemed ever so slightly better than unifying
-    // the return value with `!` because it allows for the caller to
-    // make more assumptions about the return type (e.g., they could do
-    //
-    //     let y: Option<u32> = Some(x());
-    //
-    // which would then cause this return type to become `u32`, not
-    // `!`).
-    let coercion = fcx.ret_coercion.take().unwrap().into_inner();
-    let mut actual_return_ty = coercion.complete(&fcx);
-    if actual_return_ty.is_never() {
-        actual_return_ty = fcx.next_diverging_ty_var(TypeVariableOrigin {
-            kind: TypeVariableOriginKind::DivergingFn,
-            span,
-        });
-    }
-    fcx.demand_suptype(span, revealed_ret_ty, actual_return_ty);
-
-    // Check that the main return type implements the termination trait.
-    if let Some(term_id) = tcx.lang_items().termination() {
-        if let Some((def_id, EntryFnType::Main)) = tcx.entry_fn(LOCAL_CRATE) {
-            let main_id = hir.local_def_id_to_hir_id(def_id);
-            if main_id == fn_id {
-                let substs = tcx.mk_substs_trait(declared_ret_ty, &[]);
-                let trait_ref = ty::TraitRef::new(term_id, substs);
-                let return_ty_span = decl.output.span();
-                let cause = traits::ObligationCause::new(
-                    return_ty_span,
-                    fn_id,
-                    ObligationCauseCode::MainFunctionType,
-                );
-
-                inherited.register_predicate(traits::Obligation::new(
-                    cause,
-                    param_env,
-                    trait_ref.without_const().to_predicate(tcx),
-                ));
-            }
-        }
-    }
-
-    // Check that a function marked as `#[panic_handler]` has signature `fn(&PanicInfo) -> !`
-    if let Some(panic_impl_did) = tcx.lang_items().panic_impl() {
-        if panic_impl_did == hir.local_def_id(fn_id).to_def_id() {
-            if let Some(panic_info_did) = tcx.lang_items().panic_info() {
-                if *declared_ret_ty.kind() != ty::Never {
-                    sess.span_err(decl.output.span(), "return type should be `!`");
-                }
-
-                let inputs = fn_sig.inputs();
-                let span = hir.span(fn_id);
-                if inputs.len() == 1 {
-                    let arg_is_panic_info = match *inputs[0].kind() {
-                        ty::Ref(region, ty, mutbl) => match *ty.kind() {
-                            ty::Adt(ref adt, _) => {
-                                adt.did == panic_info_did
-                                    && mutbl == hir::Mutability::Not
-                                    && *region != RegionKind::ReStatic
-                            }
-                            _ => false,
-                        },
-                        _ => false,
-                    };
-
-                    if !arg_is_panic_info {
-                        sess.span_err(decl.inputs[0].span, "argument should be `&PanicInfo`");
-                    }
-
-                    if let Node::Item(item) = hir.get(fn_id) {
-                        if let ItemKind::Fn(_, ref generics, _) = item.kind {
-                            if !generics.params.is_empty() {
-                                sess.span_err(span, "should have no type parameters");
-                            }
-                        }
-                    }
-                } else {
-                    let span = sess.source_map().guess_head_span(span);
-                    sess.span_err(span, "function should have one argument");
-                }
-            } else {
-                sess.err("language item required, but not found: `panic_info`");
-            }
-        }
-    }
-
-    // Check that a function marked as `#[alloc_error_handler]` has signature `fn(Layout) -> !`
-    if let Some(alloc_error_handler_did) = tcx.lang_items().oom() {
-        if alloc_error_handler_did == hir.local_def_id(fn_id).to_def_id() {
-            if let Some(alloc_layout_did) = tcx.lang_items().alloc_layout() {
-                if *declared_ret_ty.kind() != ty::Never {
-                    sess.span_err(decl.output.span(), "return type should be `!`");
-                }
-
-                let inputs = fn_sig.inputs();
-                let span = hir.span(fn_id);
-                if inputs.len() == 1 {
-                    let arg_is_alloc_layout = match inputs[0].kind() {
-                        ty::Adt(ref adt, _) => adt.did == alloc_layout_did,
-                        _ => false,
-                    };
-
-                    if !arg_is_alloc_layout {
-                        sess.span_err(decl.inputs[0].span, "argument should be `Layout`");
-                    }
-
-                    if let Node::Item(item) = hir.get(fn_id) {
-                        if let ItemKind::Fn(_, ref generics, _) = item.kind {
-                            if !generics.params.is_empty() {
-                                sess.span_err(
-                                    span,
-                                    "`#[alloc_error_handler]` function should have no type \
-                                     parameters",
-                                );
-                            }
-                        }
-                    }
-                } else {
-                    let span = sess.source_map().guess_head_span(span);
-                    sess.span_err(span, "function should have one argument");
-                }
-            } else {
-                sess.err("language item required, but not found: `alloc_layout`");
-            }
-        }
-    }
-
-    (fcx, gen_ty)
-}
-
-fn check_struct(tcx: TyCtxt<'_>, id: hir::HirId, span: Span) {
-    let def_id = tcx.hir().local_def_id(id);
-    let def = tcx.adt_def(def_id);
-    def.destructor(tcx); // force the destructor to be evaluated
-    check_representable(tcx, span, def_id);
-
-    if def.repr.simd() {
-        check_simd(tcx, span, def_id);
-    }
-
-    check_transparent(tcx, span, def);
-    check_packed(tcx, span, def);
-}
-
-fn check_union(tcx: TyCtxt<'_>, id: hir::HirId, span: Span) {
-    let def_id = tcx.hir().local_def_id(id);
-    let def = tcx.adt_def(def_id);
-    def.destructor(tcx); // force the destructor to be evaluated
-    check_representable(tcx, span, def_id);
-    check_transparent(tcx, span, def);
-    check_union_fields(tcx, span, def_id);
-    check_packed(tcx, span, def);
-}
-
-/// When the `#![feature(untagged_unions)]` gate is active,
-/// check that the fields of the `union` does not contain fields that need dropping.
-fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> bool {
-    let item_type = tcx.type_of(item_def_id);
-    if let ty::Adt(def, substs) = item_type.kind() {
-        assert!(def.is_union());
-        let fields = &def.non_enum_variant().fields;
-        let param_env = tcx.param_env(item_def_id);
-        for field in fields {
-            let field_ty = field.ty(tcx, substs);
-            // We are currently checking the type this field came from, so it must be local.
-            let field_span = tcx.hir().span_if_local(field.did).unwrap();
-            if field_ty.needs_drop(tcx, param_env) {
-                struct_span_err!(
-                    tcx.sess,
-                    field_span,
-                    E0740,
-                    "unions may not contain fields that need dropping"
-                )
-                .span_note(field_span, "`std::mem::ManuallyDrop` can be used to wrap the type")
-                .emit();
-                return false;
-            }
-        }
-    } else {
-        span_bug!(span, "unions must be ty::Adt, but got {:?}", item_type.kind());
-    }
-    true
-}
-
-/// Checks that an opaque type does not contain cycles and does not use `Self` or `T::Foo`
-/// projections that would result in "inheriting lifetimes".
-fn check_opaque<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    def_id: LocalDefId,
-    substs: SubstsRef<'tcx>,
-    span: Span,
-    origin: &hir::OpaqueTyOrigin,
-) {
-    check_opaque_for_inheriting_lifetimes(tcx, def_id, span);
-    check_opaque_for_cycles(tcx, def_id, substs, span, origin);
-}
-
-/// Checks that an opaque type does not use `Self` or `T::Foo` projections that would result
-/// in "inheriting lifetimes".
-fn check_opaque_for_inheriting_lifetimes(tcx: TyCtxt<'tcx>, def_id: LocalDefId, span: Span) {
-    let item = tcx.hir().expect_item(tcx.hir().local_def_id_to_hir_id(def_id));
-    debug!(
-        "check_opaque_for_inheriting_lifetimes: def_id={:?} span={:?} item={:?}",
-        def_id, span, item
-    );
-
-    #[derive(Debug)]
-    struct ProhibitOpaqueVisitor<'tcx> {
-        opaque_identity_ty: Ty<'tcx>,
-        generics: &'tcx ty::Generics,
-        ty: Option<Ty<'tcx>>,
-    };
-
-    impl<'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueVisitor<'tcx> {
-        fn visit_ty(&mut self, t: Ty<'tcx>) -> bool {
-            debug!("check_opaque_for_inheriting_lifetimes: (visit_ty) t={:?}", t);
-            if t != self.opaque_identity_ty && t.super_visit_with(self) {
-                self.ty = Some(t);
-                return true;
-            }
-            false
-        }
-
-        fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool {
-            debug!("check_opaque_for_inheriting_lifetimes: (visit_region) r={:?}", r);
-            if let RegionKind::ReEarlyBound(ty::EarlyBoundRegion { index, .. }) = r {
-                return *index < self.generics.parent_count as u32;
-            }
-
-            r.super_visit_with(self)
-        }
-
-        fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> bool {
-            if let ty::ConstKind::Unevaluated(..) = c.val {
-                // FIXME(#72219) We currenctly don't detect lifetimes within substs
-                // which would violate this check. Even though the particular substitution is not used
-                // within the const, this should still be fixed.
-                return false;
-            }
-            c.super_visit_with(self)
-        }
-    }
-
-    if let ItemKind::OpaqueTy(hir::OpaqueTy {
-        origin: hir::OpaqueTyOrigin::AsyncFn | hir::OpaqueTyOrigin::FnReturn,
-        ..
-    }) = item.kind
-    {
-        let mut visitor = ProhibitOpaqueVisitor {
-            opaque_identity_ty: tcx.mk_opaque(
-                def_id.to_def_id(),
-                InternalSubsts::identity_for_item(tcx, def_id.to_def_id()),
-            ),
-            generics: tcx.generics_of(def_id),
-            ty: None,
-        };
-        let prohibit_opaque = tcx
-            .predicates_of(def_id)
-            .predicates
-            .iter()
-            .any(|(predicate, _)| predicate.visit_with(&mut visitor));
-        debug!(
-            "check_opaque_for_inheriting_lifetimes: prohibit_opaque={:?}, visitor={:?}",
-            prohibit_opaque, visitor
-        );
-
-        if prohibit_opaque {
-            let is_async = match item.kind {
-                ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => match origin {
-                    hir::OpaqueTyOrigin::AsyncFn => true,
-                    _ => false,
-                },
-                _ => unreachable!(),
-            };
-
-            let mut err = struct_span_err!(
-                tcx.sess,
-                span,
-                E0760,
-                "`{}` return type cannot contain a projection or `Self` that references lifetimes from \
-             a parent scope",
-                if is_async { "async fn" } else { "impl Trait" },
-            );
-
-            if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(span) {
-                if snippet == "Self" {
-                    if let Some(ty) = visitor.ty {
-                        err.span_suggestion(
-                            span,
-                            "consider spelling out the type instead",
-                            format!("{:?}", ty),
-                            Applicability::MaybeIncorrect,
-                        );
-                    }
-                }
-            }
-            err.emit();
-        }
-    }
-}
-
 /// Given a `DefId` for an opaque type in return position, find its parent item's return
 /// expressions.
 fn get_owner_return_paths(
@@ -1754,86 +663,6 @@ fn get_owner_return_paths(
         })
 }
 
-/// Emit an error for recursive opaque types.
-///
-/// If this is a return `impl Trait`, find the item's return expressions and point at them. For
-/// direct recursion this is enough, but for indirect recursion also point at the last intermediary
-/// `impl Trait`.
-///
-/// If all the return expressions evaluate to `!`, then we explain that the error will go away
-/// after changing it. This can happen when a user uses `panic!()` or similar as a placeholder.
-fn opaque_type_cycle_error(tcx: TyCtxt<'tcx>, def_id: LocalDefId, span: Span) {
-    let mut err = struct_span_err!(tcx.sess, span, E0720, "cannot resolve opaque type");
-
-    let mut label = false;
-    if let Some((hir_id, visitor)) = get_owner_return_paths(tcx, def_id) {
-        let typeck_results = tcx.typeck(tcx.hir().local_def_id(hir_id));
-        if visitor
-            .returns
-            .iter()
-            .filter_map(|expr| typeck_results.node_type_opt(expr.hir_id))
-            .all(|ty| matches!(ty.kind(), ty::Never))
-        {
-            let spans = visitor
-                .returns
-                .iter()
-                .filter(|expr| typeck_results.node_type_opt(expr.hir_id).is_some())
-                .map(|expr| expr.span)
-                .collect::<Vec<Span>>();
-            let span_len = spans.len();
-            if span_len == 1 {
-                err.span_label(spans[0], "this returned value is of `!` type");
-            } else {
-                let mut multispan: MultiSpan = spans.clone().into();
-                for span in spans {
-                    multispan
-                        .push_span_label(span, "this returned value is of `!` type".to_string());
-                }
-                err.span_note(multispan, "these returned values have a concrete \"never\" type");
-            }
-            err.help("this error will resolve once the item's body returns a concrete type");
-        } else {
-            let mut seen = FxHashSet::default();
-            seen.insert(span);
-            err.span_label(span, "recursive opaque type");
-            label = true;
-            for (sp, ty) in visitor
-                .returns
-                .iter()
-                .filter_map(|e| typeck_results.node_type_opt(e.hir_id).map(|t| (e.span, t)))
-                .filter(|(_, ty)| !matches!(ty.kind(), ty::Never))
-            {
-                struct VisitTypes(Vec<DefId>);
-                impl<'tcx> ty::fold::TypeVisitor<'tcx> for VisitTypes {
-                    fn visit_ty(&mut self, t: Ty<'tcx>) -> bool {
-                        match *t.kind() {
-                            ty::Opaque(def, _) => {
-                                self.0.push(def);
-                                false
-                            }
-                            _ => t.super_visit_with(self),
-                        }
-                    }
-                }
-                let mut visitor = VisitTypes(vec![]);
-                ty.visit_with(&mut visitor);
-                for def_id in visitor.0 {
-                    let ty_span = tcx.def_span(def_id);
-                    if !seen.contains(&ty_span) {
-                        err.span_label(ty_span, &format!("returning this opaque type `{}`", ty));
-                        seen.insert(ty_span);
-                    }
-                    err.span_label(sp, &format!("returning here with type `{}`", ty));
-                }
-            }
-        }
-    }
-    if !label {
-        err.span_label(span, "cannot resolve opaque type");
-    }
-    err.emit();
-}
-
 /// Emit an error for recursive opaque types in a `let` binding.
 fn binding_opaque_type_cycle_error(
     tcx: TyCtxt<'tcx>,
@@ -1894,33 +723,6 @@ fn binding_opaque_type_cycle_error(
     err.emit();
 }
 
-fn async_opaque_type_cycle_error(tcx: TyCtxt<'tcx>, span: Span) {
-    struct_span_err!(tcx.sess, span, E0733, "recursion in an `async fn` requires boxing")
-        .span_label(span, "recursive `async fn`")
-        .note("a recursive `async fn` must be rewritten to return a boxed `dyn Future`")
-        .emit();
-}
-
-/// Checks that an opaque type does not contain cycles.
-fn check_opaque_for_cycles<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    def_id: LocalDefId,
-    substs: SubstsRef<'tcx>,
-    span: Span,
-    origin: &hir::OpaqueTyOrigin,
-) {
-    if let Err(partially_expanded_type) = tcx.try_expand_impl_trait_type(def_id.to_def_id(), substs)
-    {
-        match origin {
-            hir::OpaqueTyOrigin::AsyncFn => async_opaque_type_cycle_error(tcx, span),
-            hir::OpaqueTyOrigin::Binding => {
-                binding_opaque_type_cycle_error(tcx, def_id, span, partially_expanded_type)
-            }
-            _ => opaque_type_cycle_error(tcx, def_id, span),
-        }
-    }
-}
-
 // Forbid defining intrinsics in Rust code,
 // as they must always be defined by the compiler.
 fn fn_maybe_err(tcx: TyCtxt<'_>, sp: Span, abi: Abi) {
@@ -1929,126 +731,6 @@ fn fn_maybe_err(tcx: TyCtxt<'_>, sp: Span, abi: Abi) {
     }
 }
 
-pub fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, it: &'tcx hir::Item<'tcx>) {
-    debug!(
-        "check_item_type(it.hir_id={}, it.name={})",
-        it.hir_id,
-        tcx.def_path_str(tcx.hir().local_def_id(it.hir_id).to_def_id())
-    );
-    let _indenter = indenter();
-    match it.kind {
-        // Consts can play a role in type-checking, so they are included here.
-        hir::ItemKind::Static(..) => {
-            let def_id = tcx.hir().local_def_id(it.hir_id);
-            tcx.ensure().typeck(def_id);
-            maybe_check_static_with_link_section(tcx, def_id, it.span);
-        }
-        hir::ItemKind::Const(..) => {
-            tcx.ensure().typeck(tcx.hir().local_def_id(it.hir_id));
-        }
-        hir::ItemKind::Enum(ref enum_definition, _) => {
-            check_enum(tcx, it.span, &enum_definition.variants, it.hir_id);
-        }
-        hir::ItemKind::Fn(..) => {} // entirely within check_item_body
-        hir::ItemKind::Impl { ref items, .. } => {
-            debug!("ItemKind::Impl {} with id {}", it.ident, it.hir_id);
-            let impl_def_id = tcx.hir().local_def_id(it.hir_id);
-            if let Some(impl_trait_ref) = tcx.impl_trait_ref(impl_def_id) {
-                check_impl_items_against_trait(tcx, it.span, impl_def_id, impl_trait_ref, items);
-                let trait_def_id = impl_trait_ref.def_id;
-                check_on_unimplemented(tcx, trait_def_id, it);
-            }
-        }
-        hir::ItemKind::Trait(_, _, _, _, ref items) => {
-            let def_id = tcx.hir().local_def_id(it.hir_id);
-            check_on_unimplemented(tcx, def_id.to_def_id(), it);
-
-            for item in items.iter() {
-                let item = tcx.hir().trait_item(item.id);
-                if let hir::TraitItemKind::Fn(sig, _) = &item.kind {
-                    let abi = sig.header.abi;
-                    fn_maybe_err(tcx, item.ident.span, abi);
-                }
-            }
-        }
-        hir::ItemKind::Struct(..) => {
-            check_struct(tcx, it.hir_id, it.span);
-        }
-        hir::ItemKind::Union(..) => {
-            check_union(tcx, it.hir_id, it.span);
-        }
-        hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => {
-            // HACK(jynelson): trying to infer the type of `impl trait` breaks documenting
-            // `async-std` (and `pub async fn` in general).
-            // Since rustdoc doesn't care about the concrete type behind `impl Trait`, just don't look at it!
-            // See https://github.com/rust-lang/rust/issues/75100
-            if !tcx.sess.opts.actually_rustdoc {
-                let def_id = tcx.hir().local_def_id(it.hir_id);
-
-                let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
-                check_opaque(tcx, def_id, substs, it.span, &origin);
-            }
-        }
-        hir::ItemKind::TyAlias(..) => {
-            let def_id = tcx.hir().local_def_id(it.hir_id);
-            let pty_ty = tcx.type_of(def_id);
-            let generics = tcx.generics_of(def_id);
-            check_type_params_are_used(tcx, &generics, pty_ty);
-        }
-        hir::ItemKind::ForeignMod(ref m) => {
-            check_abi(tcx, it.span, m.abi);
-
-            if m.abi == Abi::RustIntrinsic {
-                for item in m.items {
-                    intrinsic::check_intrinsic_type(tcx, item);
-                }
-            } else if m.abi == Abi::PlatformIntrinsic {
-                for item in m.items {
-                    intrinsic::check_platform_intrinsic_type(tcx, item);
-                }
-            } else {
-                for item in m.items {
-                    let generics = tcx.generics_of(tcx.hir().local_def_id(item.hir_id));
-                    let own_counts = generics.own_counts();
-                    if generics.params.len() - own_counts.lifetimes != 0 {
-                        let (kinds, kinds_pl, egs) = match (own_counts.types, own_counts.consts) {
-                            (_, 0) => ("type", "types", Some("u32")),
-                            // We don't specify an example value, because we can't generate
-                            // a valid value for any type.
-                            (0, _) => ("const", "consts", None),
-                            _ => ("type or const", "types or consts", None),
-                        };
-                        struct_span_err!(
-                            tcx.sess,
-                            item.span,
-                            E0044,
-                            "foreign items may not have {} parameters",
-                            kinds,
-                        )
-                        .span_label(item.span, &format!("can't have {} parameters", kinds))
-                        .help(
-                            // FIXME: once we start storing spans for type arguments, turn this
-                            // into a suggestion.
-                            &format!(
-                                "replace the {} parameters with concrete {}{}",
-                                kinds,
-                                kinds_pl,
-                                egs.map(|egs| format!(" like `{}`", egs)).unwrap_or_default(),
-                            ),
-                        )
-                        .emit();
-                    }
-
-                    if let hir::ForeignItemKind::Fn(ref fn_decl, _, _) = item.kind {
-                        require_c_abi_if_c_variadic(tcx, fn_decl, m.abi, item.span);
-                    }
-                }
-            }
-        }
-        _ => { /* nothing to do */ }
-    }
-}
-
 fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDefId, span: Span) {
     // Only restricted on wasm32 target for now
     if !tcx.sess.opts.target_triple.triple().starts_with("wasm32") {
@@ -2082,12 +764,6 @@ fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDefId, span: S
     }
 }
 
-fn check_on_unimplemented(tcx: TyCtxt<'_>, trait_def_id: DefId, item: &hir::Item<'_>) {
-    let item_def_id = tcx.hir().local_def_id(item.hir_id);
-    // an error would be reported if this fails.
-    let _ = traits::OnUnimplementedDirective::of_item(tcx, trait_def_id, item_def_id.to_def_id());
-}
-
 fn report_forbidden_specialization(
     tcx: TyCtxt<'_>,
     impl_item: &hir::ImplItem<'_>,
@@ -2119,248 +795,6 @@ fn report_forbidden_specialization(
     err.emit();
 }
 
-fn check_specialization_validity<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    trait_def: &ty::TraitDef,
-    trait_item: &ty::AssocItem,
-    impl_id: DefId,
-    impl_item: &hir::ImplItem<'_>,
-) {
-    let kind = match impl_item.kind {
-        hir::ImplItemKind::Const(..) => ty::AssocKind::Const,
-        hir::ImplItemKind::Fn(..) => ty::AssocKind::Fn,
-        hir::ImplItemKind::TyAlias(_) => ty::AssocKind::Type,
-    };
-
-    let ancestors = match trait_def.ancestors(tcx, impl_id) {
-        Ok(ancestors) => ancestors,
-        Err(_) => return,
-    };
-    let mut ancestor_impls = ancestors
-        .skip(1)
-        .filter_map(|parent| {
-            if parent.is_from_trait() {
-                None
-            } else {
-                Some((parent, parent.item(tcx, trait_item.ident, kind, trait_def.def_id)))
-            }
-        })
-        .peekable();
-
-    if ancestor_impls.peek().is_none() {
-        // No parent, nothing to specialize.
-        return;
-    }
-
-    let opt_result = ancestor_impls.find_map(|(parent_impl, parent_item)| {
-        match parent_item {
-            // Parent impl exists, and contains the parent item we're trying to specialize, but
-            // doesn't mark it `default`.
-            Some(parent_item) if traits::impl_item_is_final(tcx, &parent_item) => {
-                Some(Err(parent_impl.def_id()))
-            }
-
-            // Parent impl contains item and makes it specializable.
-            Some(_) => Some(Ok(())),
-
-            // Parent impl doesn't mention the item. This means it's inherited from the
-            // grandparent. In that case, if parent is a `default impl`, inherited items use the
-            // "defaultness" from the grandparent, else they are final.
-            None => {
-                if tcx.impl_defaultness(parent_impl.def_id()).is_default() {
-                    None
-                } else {
-                    Some(Err(parent_impl.def_id()))
-                }
-            }
-        }
-    });
-
-    // If `opt_result` is `None`, we have only encountered `default impl`s that don't contain the
-    // item. This is allowed, the item isn't actually getting specialized here.
-    let result = opt_result.unwrap_or(Ok(()));
-
-    if let Err(parent_impl) = result {
-        report_forbidden_specialization(tcx, impl_item, parent_impl);
-    }
-}
-
-fn check_impl_items_against_trait<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    full_impl_span: Span,
-    impl_id: LocalDefId,
-    impl_trait_ref: ty::TraitRef<'tcx>,
-    impl_item_refs: &[hir::ImplItemRef<'_>],
-) {
-    let impl_span = tcx.sess.source_map().guess_head_span(full_impl_span);
-
-    // If the trait reference itself is erroneous (so the compilation is going
-    // to fail), skip checking the items here -- the `impl_item` table in `tcx`
-    // isn't populated for such impls.
-    if impl_trait_ref.references_error() {
-        return;
-    }
-
-    // Negative impls are not expected to have any items
-    match tcx.impl_polarity(impl_id) {
-        ty::ImplPolarity::Reservation | ty::ImplPolarity::Positive => {}
-        ty::ImplPolarity::Negative => {
-            if let [first_item_ref, ..] = impl_item_refs {
-                let first_item_span = tcx.hir().impl_item(first_item_ref.id).span;
-                struct_span_err!(
-                    tcx.sess,
-                    first_item_span,
-                    E0749,
-                    "negative impls cannot have any items"
-                )
-                .emit();
-            }
-            return;
-        }
-    }
-
-    // Locate trait definition and items
-    let trait_def = tcx.trait_def(impl_trait_ref.def_id);
-
-    let impl_items = || impl_item_refs.iter().map(|iiref| tcx.hir().impl_item(iiref.id));
-
-    // Check existing impl methods to see if they are both present in trait
-    // and compatible with trait signature
-    for impl_item in impl_items() {
-        let namespace = impl_item.kind.namespace();
-        let ty_impl_item = tcx.associated_item(tcx.hir().local_def_id(impl_item.hir_id));
-        let ty_trait_item = tcx
-            .associated_items(impl_trait_ref.def_id)
-            .find_by_name_and_namespace(tcx, ty_impl_item.ident, namespace, impl_trait_ref.def_id)
-            .or_else(|| {
-                // Not compatible, but needed for the error message
-                tcx.associated_items(impl_trait_ref.def_id)
-                    .filter_by_name(tcx, ty_impl_item.ident, impl_trait_ref.def_id)
-                    .next()
-            });
-
-        // Check that impl definition matches trait definition
-        if let Some(ty_trait_item) = ty_trait_item {
-            match impl_item.kind {
-                hir::ImplItemKind::Const(..) => {
-                    // Find associated const definition.
-                    if ty_trait_item.kind == ty::AssocKind::Const {
-                        compare_const_impl(
-                            tcx,
-                            &ty_impl_item,
-                            impl_item.span,
-                            &ty_trait_item,
-                            impl_trait_ref,
-                        );
-                    } else {
-                        let mut err = struct_span_err!(
-                            tcx.sess,
-                            impl_item.span,
-                            E0323,
-                            "item `{}` is an associated const, \
-                             which doesn't match its trait `{}`",
-                            ty_impl_item.ident,
-                            impl_trait_ref.print_only_trait_path()
-                        );
-                        err.span_label(impl_item.span, "does not match trait");
-                        // We can only get the spans from local trait definition
-                        // Same for E0324 and E0325
-                        if let Some(trait_span) = tcx.hir().span_if_local(ty_trait_item.def_id) {
-                            err.span_label(trait_span, "item in trait");
-                        }
-                        err.emit()
-                    }
-                }
-                hir::ImplItemKind::Fn(..) => {
-                    let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id);
-                    if ty_trait_item.kind == ty::AssocKind::Fn {
-                        compare_impl_method(
-                            tcx,
-                            &ty_impl_item,
-                            impl_item.span,
-                            &ty_trait_item,
-                            impl_trait_ref,
-                            opt_trait_span,
-                        );
-                    } else {
-                        let mut err = struct_span_err!(
-                            tcx.sess,
-                            impl_item.span,
-                            E0324,
-                            "item `{}` is an associated method, \
-                             which doesn't match its trait `{}`",
-                            ty_impl_item.ident,
-                            impl_trait_ref.print_only_trait_path()
-                        );
-                        err.span_label(impl_item.span, "does not match trait");
-                        if let Some(trait_span) = opt_trait_span {
-                            err.span_label(trait_span, "item in trait");
-                        }
-                        err.emit()
-                    }
-                }
-                hir::ImplItemKind::TyAlias(_) => {
-                    let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id);
-                    if ty_trait_item.kind == ty::AssocKind::Type {
-                        compare_ty_impl(
-                            tcx,
-                            &ty_impl_item,
-                            impl_item.span,
-                            &ty_trait_item,
-                            impl_trait_ref,
-                            opt_trait_span,
-                        );
-                    } else {
-                        let mut err = struct_span_err!(
-                            tcx.sess,
-                            impl_item.span,
-                            E0325,
-                            "item `{}` is an associated type, \
-                             which doesn't match its trait `{}`",
-                            ty_impl_item.ident,
-                            impl_trait_ref.print_only_trait_path()
-                        );
-                        err.span_label(impl_item.span, "does not match trait");
-                        if let Some(trait_span) = opt_trait_span {
-                            err.span_label(trait_span, "item in trait");
-                        }
-                        err.emit()
-                    }
-                }
-            }
-
-            check_specialization_validity(
-                tcx,
-                trait_def,
-                &ty_trait_item,
-                impl_id.to_def_id(),
-                impl_item,
-            );
-        }
-    }
-
-    // Check for missing items from trait
-    let mut missing_items = Vec::new();
-    if let Ok(ancestors) = trait_def.ancestors(tcx, impl_id.to_def_id()) {
-        for trait_item in tcx.associated_items(impl_trait_ref.def_id).in_definition_order() {
-            let is_implemented = ancestors
-                .leaf_def(tcx, trait_item.ident, trait_item.kind)
-                .map(|node_item| !node_item.defining_node.is_from_trait())
-                .unwrap_or(false);
-
-            if !is_implemented && tcx.impl_defaultness(impl_id).is_final() {
-                if !trait_item.defaultness.has_value() {
-                    missing_items.push(*trait_item);
-                }
-            }
-        }
-    }
-
-    if !missing_items.is_empty() {
-        missing_items_err(tcx, impl_span, &missing_items, full_impl_span);
-    }
-}
-
 fn missing_items_err(
     tcx: TyCtxt<'_>,
     impl_span: Span,
@@ -2560,161 +994,6 @@ fn suggestion_signature(assoc: &ty::AssocItem, tcx: TyCtxt<'_>) -> String {
     }
 }
 
-/// Checks whether a type can be represented in memory. In particular, it
-/// identifies types that contain themselves without indirection through a
-/// pointer, which would mean their size is unbounded.
-fn check_representable(tcx: TyCtxt<'_>, sp: Span, item_def_id: LocalDefId) -> bool {
-    let rty = tcx.type_of(item_def_id);
-
-    // Check that it is possible to represent this type. This call identifies
-    // (1) types that contain themselves and (2) types that contain a different
-    // recursive type. It is only necessary to throw an error on those that
-    // contain themselves. For case 2, there must be an inner type that will be
-    // caught by case 1.
-    match rty.is_representable(tcx, sp) {
-        Representability::SelfRecursive(spans) => {
-            recursive_type_with_infinite_size_error(tcx, item_def_id.to_def_id(), spans);
-            return false;
-        }
-        Representability::Representable | Representability::ContainsRecursive => (),
-    }
-    true
-}
-
-pub fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) {
-    let t = tcx.type_of(def_id);
-    if let ty::Adt(def, substs) = t.kind() {
-        if def.is_struct() {
-            let fields = &def.non_enum_variant().fields;
-            if fields.is_empty() {
-                struct_span_err!(tcx.sess, sp, E0075, "SIMD vector cannot be empty").emit();
-                return;
-            }
-            let e = fields[0].ty(tcx, substs);
-            if !fields.iter().all(|f| f.ty(tcx, substs) == e) {
-                struct_span_err!(tcx.sess, sp, E0076, "SIMD vector should be homogeneous")
-                    .span_label(sp, "SIMD elements must have the same type")
-                    .emit();
-                return;
-            }
-            match e.kind() {
-                ty::Param(_) => { /* struct<T>(T, T, T, T) is ok */ }
-                _ if e.is_machine() => { /* struct(u8, u8, u8, u8) is ok */ }
-                _ => {
-                    struct_span_err!(
-                        tcx.sess,
-                        sp,
-                        E0077,
-                        "SIMD vector element type should be machine type"
-                    )
-                    .emit();
-                    return;
-                }
-            }
-        }
-    }
-}
-
-fn check_packed(tcx: TyCtxt<'_>, sp: Span, def: &ty::AdtDef) {
-    let repr = def.repr;
-    if repr.packed() {
-        for attr in tcx.get_attrs(def.did).iter() {
-            for r in attr::find_repr_attrs(&tcx.sess, attr) {
-                if let attr::ReprPacked(pack) = r {
-                    if let Some(repr_pack) = repr.pack {
-                        if pack as u64 != repr_pack.bytes() {
-                            struct_span_err!(
-                                tcx.sess,
-                                sp,
-                                E0634,
-                                "type has conflicting packed representation hints"
-                            )
-                            .emit();
-                        }
-                    }
-                }
-            }
-        }
-        if repr.align.is_some() {
-            struct_span_err!(
-                tcx.sess,
-                sp,
-                E0587,
-                "type has conflicting packed and align representation hints"
-            )
-            .emit();
-        } else {
-            if let Some(def_spans) = check_packed_inner(tcx, def.did, &mut vec![]) {
-                let mut err = struct_span_err!(
-                    tcx.sess,
-                    sp,
-                    E0588,
-                    "packed type cannot transitively contain a `#[repr(align)]` type"
-                );
-
-                err.span_note(
-                    tcx.def_span(def_spans[0].0),
-                    &format!(
-                        "`{}` has a `#[repr(align)]` attribute",
-                        tcx.item_name(def_spans[0].0)
-                    ),
-                );
-
-                if def_spans.len() > 2 {
-                    let mut first = true;
-                    for (adt_def, span) in def_spans.iter().skip(1).rev() {
-                        let ident = tcx.item_name(*adt_def);
-                        err.span_note(
-                            *span,
-                            &if first {
-                                format!(
-                                    "`{}` contains a field of type `{}`",
-                                    tcx.type_of(def.did),
-                                    ident
-                                )
-                            } else {
-                                format!("...which contains a field of type `{}`", ident)
-                            },
-                        );
-                        first = false;
-                    }
-                }
-
-                err.emit();
-            }
-        }
-    }
-}
-
-fn check_packed_inner(
-    tcx: TyCtxt<'_>,
-    def_id: DefId,
-    stack: &mut Vec<DefId>,
-) -> Option<Vec<(DefId, Span)>> {
-    if let ty::Adt(def, substs) = tcx.type_of(def_id).kind() {
-        if def.is_struct() || def.is_union() {
-            if def.repr.align.is_some() {
-                return Some(vec![(def.did, DUMMY_SP)]);
-            }
-
-            stack.push(def_id);
-            for field in &def.non_enum_variant().fields {
-                if let ty::Adt(def, _) = field.ty(tcx, substs).kind() {
-                    if !stack.contains(&def.did) {
-                        if let Some(mut defs) = check_packed_inner(tcx, def.did, stack) {
-                            defs.push((def.did, field.ident.span));
-                            return Some(defs);
-                        }
-                    }
-                }
-            }
-            stack.pop();
-        }
-    }
-
-    None
-}
-
 /// Emit an error when encountering more or less than one variant in a transparent enum.
 fn bad_variant_count<'tcx>(tcx: TyCtxt<'tcx>, adt: &'tcx ty::AdtDef, sp: Span, did: DefId) {
     let variant_spans: Vec<_> = adt
@@ -2760,158 +1039,6 @@ fn bad_non_zero_sized_fields<'tcx>(
     err.emit();
 }
 
-fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, adt: &'tcx ty::AdtDef) {
-    if !adt.repr.transparent() {
-        return;
-    }
-    let sp = tcx.sess.source_map().guess_head_span(sp);
-
-    if adt.is_union() && !tcx.features().transparent_unions {
-        feature_err(
-            &tcx.sess.parse_sess,
-            sym::transparent_unions,
-            sp,
-            "transparent unions are unstable",
-        )
-        .emit();
-    }
-
-    if adt.variants.len() != 1 {
-        bad_variant_count(tcx, adt, sp, adt.did);
-        if adt.variants.is_empty() {
-            // Don't bother checking the fields. No variants (and thus no fields) exist.
-            return;
-        }
-    }
-
-    // For each field, figure out if it's known to be a ZST and align(1)
-    let field_infos = adt.all_fields().map(|field| {
-        let ty = field.ty(tcx, InternalSubsts::identity_for_item(tcx, field.did));
-        let param_env = tcx.param_env(field.did);
-        let layout = tcx.layout_of(param_env.and(ty));
-        // We are currently checking the type this field came from, so it must be local
-        let span = tcx.hir().span_if_local(field.did).unwrap();
-        let zst = layout.map(|layout| layout.is_zst()).unwrap_or(false);
-        let align1 = layout.map(|layout| layout.align.abi.bytes() == 1).unwrap_or(false);
-        (span, zst, align1)
-    });
-
-    let non_zst_fields =
-        field_infos.clone().filter_map(|(span, zst, _align1)| if !zst { Some(span) } else { None });
-    let non_zst_count = non_zst_fields.clone().count();
-    if non_zst_count != 1 {
-        bad_non_zero_sized_fields(tcx, adt, non_zst_count, non_zst_fields, sp);
-    }
-    for (span, zst, align1) in field_infos {
-        if zst && !align1 {
-            struct_span_err!(
-                tcx.sess,
-                span,
-                E0691,
-                "zero-sized field in transparent {} has alignment larger than 1",
-                adt.descr(),
-            )
-            .span_label(span, "has alignment larger than 1")
-            .emit();
-        }
-    }
-}
-
-#[allow(trivial_numeric_casts)]
-pub fn check_enum<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    sp: Span,
-    vs: &'tcx [hir::Variant<'tcx>],
-    id: hir::HirId,
-) {
-    let def_id = tcx.hir().local_def_id(id);
-    let def = tcx.adt_def(def_id);
-    def.destructor(tcx); // force the destructor to be evaluated
-
-    if vs.is_empty() {
-        let attributes = tcx.get_attrs(def_id.to_def_id());
-        if let Some(attr) = tcx.sess.find_by_name(&attributes, sym::repr) {
-            struct_span_err!(
-                tcx.sess,
-                attr.span,
-                E0084,
-                "unsupported representation for zero-variant enum"
-            )
-            .span_label(sp, "zero-variant enum")
-            .emit();
-        }
-    }
-
-    let repr_type_ty = def.repr.discr_type().to_ty(tcx);
-    if repr_type_ty == tcx.types.i128 || repr_type_ty == tcx.types.u128 {
-        if !tcx.features().repr128 {
-            feature_err(
-                &tcx.sess.parse_sess,
-                sym::repr128,
-                sp,
-                "repr with 128-bit type is unstable",
-            )
-            .emit();
-        }
-    }
-
-    for v in vs {
-        if let Some(ref e) = v.disr_expr {
-            tcx.ensure().typeck(tcx.hir().local_def_id(e.hir_id));
-        }
-    }
-
-    if tcx.adt_def(def_id).repr.int.is_none() && tcx.features().arbitrary_enum_discriminant {
-        let is_unit = |var: &hir::Variant<'_>| match var.data {
-            hir::VariantData::Unit(..) => true,
-            _ => false,
-        };
-
-        let has_disr = |var: &hir::Variant<'_>| var.disr_expr.is_some();
-        let has_non_units = vs.iter().any(|var| !is_unit(var));
-        let disr_units = vs.iter().any(|var| is_unit(&var) && has_disr(&var));
-        let disr_non_unit = vs.iter().any(|var| !is_unit(&var) && has_disr(&var));
-
-        if disr_non_unit || (disr_units && has_non_units) {
-            let mut err =
-                struct_span_err!(tcx.sess, sp, E0732, "`#[repr(inttype)]` must be specified");
-            err.emit();
-        }
-    }
-
-    let mut disr_vals: Vec<Discr<'tcx>> = Vec::with_capacity(vs.len());
-    for ((_, discr), v) in def.discriminants(tcx).zip(vs) {
-        // Check for duplicate discriminant values
-        if let Some(i) = disr_vals.iter().position(|&x| x.val == discr.val) {
-            let variant_did = def.variants[VariantIdx::new(i)].def_id;
-            let variant_i_hir_id = tcx.hir().local_def_id_to_hir_id(variant_did.expect_local());
-            let variant_i = tcx.hir().expect_variant(variant_i_hir_id);
-            let i_span = match variant_i.disr_expr {
-                Some(ref expr) => tcx.hir().span(expr.hir_id),
-                None => tcx.hir().span(variant_i_hir_id),
-            };
-            let span = match v.disr_expr {
-                Some(ref expr) => tcx.hir().span(expr.hir_id),
-                None => v.span,
-            };
-            struct_span_err!(
-                tcx.sess,
-                span,
-                E0081,
-                "discriminant value `{}` already exists",
-                disr_vals[i]
-            )
-            .span_label(i_span, format!("first use of `{}`", disr_vals[i]))
-            .span_label(span, format!("enum already has `{}`", disr_vals[i]))
-            .emit();
-        }
-        disr_vals.push(discr);
-    }
-
-    check_representable(tcx, sp, def_id);
-    check_transparent(tcx, sp, def);
-}
-
 fn report_unexpected_variant_res(tcx: TyCtxt<'_>, res: Res, span: Span) {
     struct_span_err!(
         tcx.sess,
@@ -2924,136 +1051,6 @@ fn report_unexpected_variant_res(tcx: TyCtxt<'_>, res: Res, span: Span) {
     .emit();
 }
 
-impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
-    fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
-        self.tcx
-    }
-
-    fn item_def_id(&self) -> Option<DefId> {
-        None
-    }
-
-    fn default_constness_for_trait_bounds(&self) -> hir::Constness {
-        // FIXME: refactor this into a method
-        let node = self.tcx.hir().get(self.body_id);
-        if let Some(fn_like) = FnLikeNode::from_node(node) {
-            fn_like.constness()
-        } else {
-            hir::Constness::NotConst
-        }
-    }
-
-    fn get_type_parameter_bounds(&self, _: Span, def_id: DefId) -> ty::GenericPredicates<'tcx> {
-        let tcx = self.tcx;
-        let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
-        let item_id = tcx.hir().ty_param_owner(hir_id);
-        let item_def_id = tcx.hir().local_def_id(item_id);
-        let generics = tcx.generics_of(item_def_id);
-        let index = generics.param_def_id_to_index[&def_id];
-        ty::GenericPredicates {
-            parent: None,
-            predicates: tcx.arena.alloc_from_iter(
-                self.param_env.caller_bounds().iter().filter_map(|predicate| {
-                    match predicate.skip_binders() {
-                        ty::PredicateAtom::Trait(data, _) if data.self_ty().is_param(index) => {
-                            // HACK(eddyb) should get the original `Span`.
-                            let span = tcx.def_span(def_id);
-                            Some((predicate, span))
-                        }
-                        _ => None,
-                    }
-                }),
-            ),
-        }
-    }
-
-    fn re_infer(&self, def: Option<&ty::GenericParamDef>, span: Span) -> Option<ty::Region<'tcx>> {
-        let v = match def {
-            Some(def) => infer::EarlyBoundRegion(span, def.name),
-            None => infer::MiscVariable(span),
-        };
-        Some(self.next_region_var(v))
-    }
-
-    fn allow_ty_infer(&self) -> bool {
-        true
-    }
-
-    fn ty_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> {
-        if let Some(param) = param {
-            if let GenericArgKind::Type(ty) = self.var_for_def(span, param).unpack() {
-                return ty;
-            }
-            unreachable!()
-        } else {
-            self.next_ty_var(TypeVariableOrigin {
-                kind: TypeVariableOriginKind::TypeInference,
-                span,
-            })
-        }
-    }
-
-    fn ct_infer(
-        &self,
-        ty: Ty<'tcx>,
-        param: Option<&ty::GenericParamDef>,
-        span: Span,
-    ) -> &'tcx Const<'tcx> {
-        if let Some(param) = param {
-            if let GenericArgKind::Const(ct) = self.var_for_def(span, param).unpack() {
-                return ct;
-            }
-            unreachable!()
-        } else {
-            self.next_const_var(
-                ty,
-                ConstVariableOrigin { kind: ConstVariableOriginKind::ConstInference, span },
-            )
-        }
-    }
-
-    fn projected_ty_from_poly_trait_ref(
-        &self,
-        span: Span,
-        item_def_id: DefId,
-        item_segment: &hir::PathSegment<'_>,
-        poly_trait_ref: ty::PolyTraitRef<'tcx>,
-    ) -> Ty<'tcx> {
-        let (trait_ref, _) = self.replace_bound_vars_with_fresh_vars(
-            span,
-            infer::LateBoundRegionConversionTime::AssocTypeProjection(item_def_id),
-            &poly_trait_ref,
-        );
-
-        let item_substs = <dyn AstConv<'tcx>>::create_substs_for_associated_item(
-            self,
-            self.tcx,
-            span,
-            item_def_id,
-            item_segment,
-            trait_ref.substs,
-        );
-
-        self.tcx().mk_projection(item_def_id, item_substs)
-    }
-
-    fn normalize_ty(&self, span: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
-        if ty.has_escaping_bound_vars() {
-            ty // FIXME: normalization and escaping regions
-        } else {
-            self.normalize_associated_types_in(span, &ty)
-        }
-    }
-
-    fn set_tainted_by_errors(&self) {
-        self.infcx.set_tainted_by_errors()
-    }
-
-    fn record_ty(&self, hir_id: hir::HirId, ty: Ty<'tcx>, _span: Span) {
-        self.write_ty(hir_id, ty)
-    }
-}
-
 /// Controls whether the arguments are tupled. This is used for the call
 /// operator.
 ///
@@ -3086,2954 +1083,49 @@ enum FallbackMode {
     All,
 }
 
-impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
-    pub fn new(
-        inh: &'a Inherited<'a, 'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
-        body_id: hir::HirId,
-    ) -> FnCtxt<'a, 'tcx> {
-        FnCtxt {
-            body_id,
-            param_env,
-            err_count_on_creation: inh.tcx.sess.err_count(),
-            ret_coercion: None,
-            ret_coercion_impl_trait: None,
-            ret_type_span: None,
-            in_tail_expr: false,
-            ret_coercion_span: RefCell::new(None),
-            resume_yield_tys: None,
-            ps: RefCell::new(UnsafetyState::function(hir::Unsafety::Normal, hir::CRATE_HIR_ID)),
-            diverges: Cell::new(Diverges::Maybe),
-            has_errors: Cell::new(false),
-            enclosing_breakables: RefCell::new(EnclosingBreakables {
-                stack: Vec::new(),
-                by_id: Default::default(),
-            }),
-            inh,
-        }
-    }
-
-    pub fn sess(&self) -> &Session {
-        &self.tcx.sess
-    }
-
-    pub fn errors_reported_since_creation(&self) -> bool {
-        self.tcx.sess.err_count() > self.err_count_on_creation
-    }
-
-    /// Produces warning on the given node, if the current point in the
-    /// function is unreachable, and there hasn't been another warning.
-    fn warn_if_unreachable(&self, id: hir::HirId, span: Span, kind: &str) {
-        // FIXME: Combine these two 'if' expressions into one once
-        // let chains are implemented
-        if let Diverges::Always { span: orig_span, custom_note } = self.diverges.get() {
-            // If span arose from a desugaring of `if` or `while`, then it is the condition itself,
-            // which diverges, that we are about to lint on. This gives suboptimal diagnostics.
-            // Instead, stop here so that the `if`- or `while`-expression's block is linted instead.
-            if !span.is_desugaring(DesugaringKind::CondTemporary)
-                && !span.is_desugaring(DesugaringKind::Async)
-                && !orig_span.is_desugaring(DesugaringKind::Await)
-            {
-                self.diverges.set(Diverges::WarnedAlways);
-
-                debug!("warn_if_unreachable: id={:?} span={:?} kind={}", id, span, kind);
-
-                self.tcx().struct_span_lint_hir(lint::builtin::UNREACHABLE_CODE, id, span, |lint| {
-                    let msg = format!("unreachable {}", kind);
-                    lint.build(&msg)
-                        .span_label(span, &msg)
-                        .span_label(
-                            orig_span,
-                            custom_note
-                                .unwrap_or("any code following this expression is unreachable"),
-                        )
-                        .emit();
-                })
-            }
-        }
-    }
-
-    pub fn cause(&self, span: Span, code: ObligationCauseCode<'tcx>) -> ObligationCause<'tcx> {
-        ObligationCause::new(span, self.body_id, code)
-    }
-
-    pub fn misc(&self, span: Span) -> ObligationCause<'tcx> {
-        self.cause(span, ObligationCauseCode::MiscObligation)
-    }
-
-    /// Resolves type and const variables in `ty` if possible. Unlike the infcx
-    /// version (resolve_vars_if_possible), this version will
-    /// also select obligations if it seems useful, in an effort
-    /// to get more type information.
-    fn resolve_vars_with_obligations(&self, mut ty: Ty<'tcx>) -> Ty<'tcx> {
-        debug!("resolve_vars_with_obligations(ty={:?})", ty);
-
-        // No Infer()? Nothing needs doing.
-        if !ty.has_infer_types_or_consts() {
-            debug!("resolve_vars_with_obligations: ty={:?}", ty);
-            return ty;
-        }
-
-        // If `ty` is a type variable, see whether we already know what it is.
-        ty = self.resolve_vars_if_possible(&ty);
-        if !ty.has_infer_types_or_consts() {
-            debug!("resolve_vars_with_obligations: ty={:?}", ty);
-            return ty;
-        }
-
-        // If not, try resolving pending obligations as much as
-        // possible. This can help substantially when there are
-        // indirect dependencies that don't seem worth tracking
-        // precisely.
-        self.select_obligations_where_possible(false, |_| {});
-        ty = self.resolve_vars_if_possible(&ty);
-
-        debug!("resolve_vars_with_obligations: ty={:?}", ty);
-        ty
-    }
-
-    fn record_deferred_call_resolution(
-        &self,
-        closure_def_id: DefId,
-        r: DeferredCallResolution<'tcx>,
-    ) {
-        let mut deferred_call_resolutions = self.deferred_call_resolutions.borrow_mut();
-        deferred_call_resolutions.entry(closure_def_id).or_default().push(r);
-    }
-
-    fn remove_deferred_call_resolutions(
-        &self,
-        closure_def_id: DefId,
-    ) -> Vec<DeferredCallResolution<'tcx>> {
-        let mut deferred_call_resolutions = self.deferred_call_resolutions.borrow_mut();
-        deferred_call_resolutions.remove(&closure_def_id).unwrap_or(vec![])
-    }
-
-    pub fn tag(&self) -> String {
-        format!("{:p}", self)
-    }
-
-    pub fn local_ty(&self, span: Span, nid: hir::HirId) -> LocalTy<'tcx> {
-        self.locals.borrow().get(&nid).cloned().unwrap_or_else(|| {
-            span_bug!(span, "no type for local variable {}", self.tcx.hir().node_to_string(nid))
-        })
-    }
-
-    #[inline]
-    pub fn write_ty(&self, id: hir::HirId, ty: Ty<'tcx>) {
-        debug!(
-            "write_ty({:?}, {:?}) in fcx {}",
-            id,
-            self.resolve_vars_if_possible(&ty),
-            self.tag()
-        );
-        self.typeck_results.borrow_mut().node_types_mut().insert(id, ty);
-
-        if ty.references_error() {
-            self.has_errors.set(true);
-            self.set_tainted_by_errors();
-        }
-    }
-
-    pub fn write_field_index(&self, hir_id: hir::HirId, index: usize) {
-        self.typeck_results.borrow_mut().field_indices_mut().insert(hir_id, index);
-    }
-
-    fn write_resolution(&self, hir_id: hir::HirId, r: Result<(DefKind, DefId), ErrorReported>) {
-        self.typeck_results.borrow_mut().type_dependent_defs_mut().insert(hir_id, r);
-    }
-
-    pub fn write_method_call(&self, hir_id: hir::HirId, method: MethodCallee<'tcx>) {
-        debug!("write_method_call(hir_id={:?}, method={:?})", hir_id, method);
-        self.write_resolution(hir_id, Ok((DefKind::AssocFn, method.def_id)));
-        self.write_substs(hir_id, method.substs);
-
-        // When the method is confirmed, the `method.substs` includes
-        // parameters from not just the method, but also the impl of
-        // the method -- in particular, the `Self` type will be fully
-        // resolved. However, those are not something that the "user
-        // specified" -- i.e., those types come from the inferred type
-        // of the receiver, not something the user wrote. So when we
-        // create the user-substs, we want to replace those earlier
-        // types with just the types that the user actually wrote --
-        // that is, those that appear on the *method itself*.
-        //
-        // As an example, if the user wrote something like
-        // `foo.bar::<u32>(...)` -- the `Self` type here will be the
-        // type of `foo` (possibly adjusted), but we don't want to
-        // include that. We want just the `[_, u32]` part.
-        if !method.substs.is_noop() {
-            let method_generics = self.tcx.generics_of(method.def_id);
-            if !method_generics.params.is_empty() {
-                let user_type_annotation = self.infcx.probe(|_| {
-                    let user_substs = UserSubsts {
-                        substs: InternalSubsts::for_item(self.tcx, method.def_id, |param, _| {
-                            let i = param.index as usize;
-                            if i < method_generics.parent_count {
-                                self.infcx.var_for_def(DUMMY_SP, param)
-                            } else {
-                                method.substs[i]
-                            }
-                        }),
-                        user_self_ty: None, // not relevant here
-                    };
-
-                    self.infcx.canonicalize_user_type_annotation(&UserType::TypeOf(
-                        method.def_id,
-                        user_substs,
-                    ))
-                });
-
-                debug!("write_method_call: user_type_annotation={:?}", user_type_annotation);
-                self.write_user_type_annotation(hir_id, user_type_annotation);
-            }
-        }
-    }
-
-    pub fn write_substs(&self, node_id: hir::HirId, substs: SubstsRef<'tcx>) {
-        if !substs.is_noop() {
-            debug!("write_substs({:?}, {:?}) in fcx {}", node_id, substs, self.tag());
-
-            self.typeck_results.borrow_mut().node_substs_mut().insert(node_id, substs);
-        }
-    }
-
-    /// Given the substs that we just converted from the HIR, try to
-    /// canonicalize them and store them as user-given substitutions
-    /// (i.e., substitutions that must be respected by the NLL check).
-    ///
-    /// This should be invoked **before any unifications have
-    /// occurred**, so that annotations like `Vec<_>` are preserved
-    /// properly.
-    pub fn write_user_type_annotation_from_substs(
-        &self,
-        hir_id: hir::HirId,
-        def_id: DefId,
-        substs: SubstsRef<'tcx>,
-        user_self_ty: Option<UserSelfTy<'tcx>>,
-    ) {
-        debug!(
-            "write_user_type_annotation_from_substs: hir_id={:?} def_id={:?} substs={:?} \
-             user_self_ty={:?} in fcx {}",
-            hir_id,
-            def_id,
-            substs,
-            user_self_ty,
-            self.tag(),
-        );
-
-        if Self::can_contain_user_lifetime_bounds((substs, user_self_ty)) {
-            let canonicalized = self.infcx.canonicalize_user_type_annotation(&UserType::TypeOf(
-                def_id,
-                UserSubsts { substs, user_self_ty },
-            ));
-            debug!("write_user_type_annotation_from_substs: canonicalized={:?}", canonicalized);
-            self.write_user_type_annotation(hir_id, canonicalized);
-        }
-    }
-
-    pub fn write_user_type_annotation(
-        &self,
-        hir_id: hir::HirId,
-        canonical_user_type_annotation: CanonicalUserType<'tcx>,
-    ) {
-        debug!(
-            "write_user_type_annotation: hir_id={:?} canonical_user_type_annotation={:?} tag={}",
-            hir_id,
-            canonical_user_type_annotation,
-            self.tag(),
-        );
-
-        if !canonical_user_type_annotation.is_identity() {
-            self.typeck_results
-                .borrow_mut()
-                .user_provided_types_mut()
-                .insert(hir_id, canonical_user_type_annotation);
-        } else {
-            debug!("write_user_type_annotation: skipping identity substs");
-        }
-    }
-
-    pub fn apply_adjustments(&self, expr: &hir::Expr<'_>, adj: Vec<Adjustment<'tcx>>) {
-        debug!("apply_adjustments(expr={:?}, adj={:?})", expr, adj);
-
-        if adj.is_empty() {
-            return;
-        }
-
-        let autoborrow_mut = adj.iter().any(|adj| {
-            matches!(adj, &Adjustment {
-                kind: Adjust::Borrow(AutoBorrow::Ref(_, AutoBorrowMutability::Mut { .. })),
-                ..
-            })
-        });
-
-        match self.typeck_results.borrow_mut().adjustments_mut().entry(expr.hir_id) {
-            Entry::Vacant(entry) => {
-                entry.insert(adj);
-            }
-            Entry::Occupied(mut entry) => {
-                debug!(" - composing on top of {:?}", entry.get());
-                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(_), .. },
-                        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 {:?}",
-                             expr, entry.get(), adj)
-                };
-                *entry.get_mut() = adj;
-            }
-        }
-
-        // If there is an mutable auto-borrow, it is equivalent to `&mut <expr>`.
-        // In this case implicit use of `Deref` and `Index` within `<expr>` should
-        // instead be `DerefMut` and `IndexMut`, so fix those up.
-        if autoborrow_mut {
-            self.convert_place_derefs_to_mutable(expr);
-        }
-    }
-
-    /// Basically whenever we are converting from a type scheme into
-    /// the fn body space, we always want to normalize associated
-    /// types as well. This function combines the two.
-    fn instantiate_type_scheme<T>(&self, span: Span, substs: SubstsRef<'tcx>, value: &T) -> T
-    where
-        T: TypeFoldable<'tcx>,
-    {
-        let value = value.subst(self.tcx, substs);
-        let result = self.normalize_associated_types_in(span, &value);
-        debug!("instantiate_type_scheme(value={:?}, substs={:?}) = {:?}", value, substs, result);
-        result
-    }
-
-    /// As `instantiate_type_scheme`, but for the bounds found in a
-    /// generic type scheme.
-    fn instantiate_bounds(
-        &self,
-        span: Span,
-        def_id: DefId,
-        substs: SubstsRef<'tcx>,
-    ) -> (ty::InstantiatedPredicates<'tcx>, Vec<Span>) {
-        let bounds = self.tcx.predicates_of(def_id);
-        let spans: Vec<Span> = bounds.predicates.iter().map(|(_, span)| *span).collect();
-        let result = bounds.instantiate(self.tcx, substs);
-        let result = self.normalize_associated_types_in(span, &result);
-        debug!(
-            "instantiate_bounds(bounds={:?}, substs={:?}) = {:?}, {:?}",
-            bounds, substs, result, spans,
-        );
-        (result, spans)
-    }
-
-    /// Replaces the opaque types from the given value with type variables,
-    /// and records the `OpaqueTypeMap` for later use during writeback. See
-    /// `InferCtxt::instantiate_opaque_types` for more details.
-    fn instantiate_opaque_types_from_value<T: TypeFoldable<'tcx>>(
-        &self,
-        parent_id: hir::HirId,
-        value: &T,
-        value_span: Span,
-    ) -> T {
-        let parent_def_id = self.tcx.hir().local_def_id(parent_id);
-        debug!(
-            "instantiate_opaque_types_from_value(parent_def_id={:?}, value={:?})",
-            parent_def_id, value
-        );
-
-        let (value, opaque_type_map) =
-            self.register_infer_ok_obligations(self.instantiate_opaque_types(
-                parent_def_id,
-                self.body_id,
-                self.param_env,
-                value,
-                value_span,
-            ));
-
-        let mut opaque_types = self.opaque_types.borrow_mut();
-        let mut opaque_types_vars = self.opaque_types_vars.borrow_mut();
-        for (ty, decl) in opaque_type_map {
-            let _ = opaque_types.insert(ty, decl);
-            let _ = opaque_types_vars.insert(decl.concrete_ty, decl.opaque_type);
-        }
-
-        value
-    }
-
-    fn normalize_associated_types_in<T>(&self, span: Span, value: &T) -> T
-    where
-        T: TypeFoldable<'tcx>,
-    {
-        self.inh.normalize_associated_types_in(span, self.body_id, self.param_env, value)
-    }
-
-    fn normalize_associated_types_in_as_infer_ok<T>(
-        &self,
-        span: Span,
-        value: &T,
-    ) -> InferOk<'tcx, T>
-    where
-        T: TypeFoldable<'tcx>,
-    {
-        self.inh.partially_normalize_associated_types_in(span, self.body_id, self.param_env, value)
-    }
-
-    pub fn require_type_meets(
-        &self,
-        ty: Ty<'tcx>,
-        span: Span,
-        code: traits::ObligationCauseCode<'tcx>,
-        def_id: DefId,
-    ) {
-        self.register_bound(ty, def_id, traits::ObligationCause::new(span, self.body_id, code));
-    }
-
-    pub fn require_type_is_sized(
-        &self,
-        ty: Ty<'tcx>,
-        span: Span,
-        code: traits::ObligationCauseCode<'tcx>,
-    ) {
-        if !ty.references_error() {
-            let lang_item = self.tcx.require_lang_item(LangItem::Sized, None);
-            self.require_type_meets(ty, span, code, lang_item);
-        }
-    }
-
-    pub fn require_type_is_sized_deferred(
-        &self,
-        ty: Ty<'tcx>,
-        span: Span,
-        code: traits::ObligationCauseCode<'tcx>,
-    ) {
-        if !ty.references_error() {
-            self.deferred_sized_obligations.borrow_mut().push((ty, span, code));
-        }
-    }
-
-    pub fn register_bound(
-        &self,
-        ty: Ty<'tcx>,
-        def_id: DefId,
-        cause: traits::ObligationCause<'tcx>,
-    ) {
-        if !ty.references_error() {
-            self.fulfillment_cx.borrow_mut().register_bound(
-                self,
-                self.param_env,
-                ty,
-                def_id,
-                cause,
-            );
-        }
-    }
-
-    pub fn to_ty(&self, ast_t: &hir::Ty<'_>) -> Ty<'tcx> {
-        let t = AstConv::ast_ty_to_ty(self, ast_t);
-        self.register_wf_obligation(t.into(), ast_t.span, traits::MiscObligation);
-        t
-    }
-
-    pub fn to_ty_saving_user_provided_ty(&self, ast_ty: &hir::Ty<'_>) -> Ty<'tcx> {
-        let ty = self.to_ty(ast_ty);
-        debug!("to_ty_saving_user_provided_ty: ty={:?}", ty);
-
-        if Self::can_contain_user_lifetime_bounds(ty) {
-            let c_ty = self.infcx.canonicalize_response(&UserType::Ty(ty));
-            debug!("to_ty_saving_user_provided_ty: c_ty={:?}", c_ty);
-            self.typeck_results.borrow_mut().user_provided_types_mut().insert(ast_ty.hir_id, c_ty);
-        }
-
-        ty
-    }
-
-    pub fn to_const(&self, ast_c: &hir::AnonConst) -> &'tcx ty::Const<'tcx> {
-        let const_def_id = self.tcx.hir().local_def_id(ast_c.hir_id);
-        let c = ty::Const::from_anon_const(self.tcx, const_def_id);
-        self.register_wf_obligation(
-            c.into(),
-            self.tcx.hir().span(ast_c.hir_id),
-            ObligationCauseCode::MiscObligation,
-        );
-        c
-    }
-
-    pub fn const_arg_to_const(
-        &self,
-        ast_c: &hir::AnonConst,
-        param_def_id: DefId,
-    ) -> &'tcx ty::Const<'tcx> {
-        let const_def = ty::WithOptConstParam {
-            did: self.tcx.hir().local_def_id(ast_c.hir_id),
-            const_param_did: Some(param_def_id),
-        };
-        let c = ty::Const::from_opt_const_arg_anon_const(self.tcx, const_def);
-        self.register_wf_obligation(
-            c.into(),
-            self.tcx.hir().span(ast_c.hir_id),
-            ObligationCauseCode::MiscObligation,
-        );
-        c
-    }
-
-    // If the type given by the user has free regions, save it for later, since
-    // NLL would like to enforce those. Also pass in types that involve
-    // projections, since those can resolve to `'static` bounds (modulo #54940,
-    // which hopefully will be fixed by the time you see this comment, dear
-    // reader, although I have my doubts). Also pass in types with inference
-    // types, because they may be repeated. Other sorts of things are already
-    // sufficiently enforced with erased regions. =)
-    fn can_contain_user_lifetime_bounds<T>(t: T) -> bool
-    where
-        T: TypeFoldable<'tcx>,
-    {
-        t.has_free_regions() || t.has_projections() || t.has_infer_types()
-    }
-
-    pub fn node_ty(&self, id: hir::HirId) -> Ty<'tcx> {
-        match self.typeck_results.borrow().node_types().get(id) {
-            Some(&t) => t,
-            None if self.is_tainted_by_errors() => self.tcx.ty_error(),
-            None => {
-                bug!(
-                    "no type for node {}: {} in fcx {}",
-                    id,
-                    self.tcx.hir().node_to_string(id),
-                    self.tag()
-                );
-            }
-        }
-    }
-
-    /// Registers an obligation for checking later, during regionck, that `arg` is well-formed.
-    pub fn register_wf_obligation(
-        &self,
-        arg: subst::GenericArg<'tcx>,
-        span: Span,
-        code: traits::ObligationCauseCode<'tcx>,
-    ) {
-        // WF obligations never themselves fail, so no real need to give a detailed cause:
-        let cause = traits::ObligationCause::new(span, self.body_id, code);
-        self.register_predicate(traits::Obligation::new(
-            cause,
-            self.param_env,
-            ty::PredicateAtom::WellFormed(arg).to_predicate(self.tcx),
-        ));
-    }
-
-    /// Registers obligations that all `substs` are well-formed.
-    pub fn add_wf_bounds(&self, substs: SubstsRef<'tcx>, expr: &hir::Expr<'_>) {
-        for arg in substs.iter().filter(|arg| {
-            matches!(arg.unpack(), GenericArgKind::Type(..) | GenericArgKind::Const(..))
-        }) {
-            self.register_wf_obligation(arg, expr.span, traits::MiscObligation);
-        }
-    }
-
-    /// Given a fully substituted set of bounds (`generic_bounds`), and the values with which each
-    /// type/region parameter was instantiated (`substs`), creates and registers suitable
-    /// trait/region obligations.
-    ///
-    /// For example, if there is a function:
-    ///
-    /// ```
-    /// fn foo<'a,T:'a>(...)
-    /// ```
-    ///
-    /// and a reference:
-    ///
-    /// ```
-    /// let f = foo;
-    /// ```
-    ///
-    /// Then we will create a fresh region variable `'$0` and a fresh type variable `$1` for `'a`
-    /// and `T`. This routine will add a region obligation `$1:'$0` and register it locally.
-    pub fn add_obligations_for_parameters(
-        &self,
-        cause: traits::ObligationCause<'tcx>,
-        predicates: ty::InstantiatedPredicates<'tcx>,
-    ) {
-        assert!(!predicates.has_escaping_bound_vars());
-
-        debug!("add_obligations_for_parameters(predicates={:?})", predicates);
-
-        for obligation in traits::predicates_for_generics(cause, self.param_env, predicates) {
-            self.register_predicate(obligation);
-        }
-    }
-
-    // FIXME(arielb1): use this instead of field.ty everywhere
-    // Only for fields! Returns <none> for methods>
-    // Indifferent to privacy flags
-    pub fn field_ty(
-        &self,
-        span: Span,
-        field: &'tcx ty::FieldDef,
-        substs: SubstsRef<'tcx>,
-    ) -> Ty<'tcx> {
-        self.normalize_associated_types_in(span, &field.ty(self.tcx, substs))
-    }
-
-    fn check_casts(&self) {
-        let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut();
-        for cast in deferred_cast_checks.drain(..) {
-            cast.check(self);
-        }
-    }
-
-    fn resolve_generator_interiors(&self, def_id: DefId) {
-        let mut generators = self.deferred_generator_interiors.borrow_mut();
-        for (body_id, interior, kind) in generators.drain(..) {
-            self.select_obligations_where_possible(false, |_| {});
-            generator_interior::resolve_interior(self, def_id, body_id, interior, kind);
-        }
-    }
-
-    // Tries to apply a fallback to `ty` if it is an unsolved variable.
-    //
-    // - Unconstrained ints are replaced with `i32`.
-    //
-    // - Unconstrained floats are replaced with with `f64`.
-    //
-    // - Non-numerics get replaced with `!` when `#![feature(never_type_fallback)]`
-    //   is enabled. Otherwise, they are replaced with `()`.
-    //
-    // Fallback becomes very dubious if we have encountered type-checking errors.
-    // In that case, fallback to Error.
-    // The return value indicates whether fallback has occurred.
-    fn fallback_if_possible(&self, ty: Ty<'tcx>, mode: FallbackMode) -> bool {
-        use rustc_middle::ty::error::UnconstrainedNumeric::Neither;
-        use rustc_middle::ty::error::UnconstrainedNumeric::{UnconstrainedFloat, UnconstrainedInt};
-
-        assert!(ty.is_ty_infer());
-        let fallback = match self.type_is_unconstrained_numeric(ty) {
-            _ if self.is_tainted_by_errors() => self.tcx().ty_error(),
-            UnconstrainedInt => self.tcx.types.i32,
-            UnconstrainedFloat => self.tcx.types.f64,
-            Neither if self.type_var_diverges(ty) => self.tcx.mk_diverging_default(),
-            Neither => {
-                // This type variable was created from the instantiation of an opaque
-                // type. The fact that we're attempting to perform fallback for it
-                // means that the function neither constrained it to a concrete
-                // type, nor to the opaque type itself.
-                //
-                // For example, in this code:
-                //
-                //```
-                // type MyType = impl Copy;
-                // fn defining_use() -> MyType { true }
-                // fn other_use() -> MyType { defining_use() }
-                // ```
-                //
-                // `defining_use` will constrain the instantiated inference
-                // variable to `bool`, while `other_use` will constrain
-                // the instantiated inference variable to `MyType`.
-                //
-                // When we process opaque types during writeback, we
-                // will handle cases like `other_use`, and not count
-                // them as defining usages
-                //
-                // However, we also need to handle cases like this:
-                //
-                // ```rust
-                // pub type Foo = impl Copy;
-                // fn produce() -> Option<Foo> {
-                //     None
-                //  }
-                //  ```
-                //
-                // In the above snippet, the inference variable created by
-                // instantiating `Option<Foo>` will be completely unconstrained.
-                // We treat this as a non-defining use by making the inference
-                // variable fall back to the opaque type itself.
-                if let FallbackMode::All = mode {
-                    if let Some(opaque_ty) = self.opaque_types_vars.borrow().get(ty) {
-                        debug!(
-                            "fallback_if_possible: falling back opaque type var {:?} to {:?}",
-                            ty, opaque_ty
-                        );
-                        *opaque_ty
-                    } else {
-                        return false;
-                    }
-                } else {
-                    return false;
-                }
-            }
-        };
-        debug!("fallback_if_possible: defaulting `{:?}` to `{:?}`", ty, fallback);
-        self.demand_eqtype(rustc_span::DUMMY_SP, ty, fallback);
-        true
-    }
-
-    fn select_all_obligations_or_error(&self) {
-        debug!("select_all_obligations_or_error");
-        if let Err(errors) = self.fulfillment_cx.borrow_mut().select_all_or_error(&self) {
-            self.report_fulfillment_errors(&errors, self.inh.body_id, false);
-        }
-    }
-
-    /// Select as many obligations as we can at present.
-    fn select_obligations_where_possible(
-        &self,
-        fallback_has_occurred: bool,
-        mutate_fullfillment_errors: impl Fn(&mut Vec<traits::FulfillmentError<'tcx>>),
-    ) {
-        let result = self.fulfillment_cx.borrow_mut().select_where_possible(self);
-        if let Err(mut errors) = result {
-            mutate_fullfillment_errors(&mut errors);
-            self.report_fulfillment_errors(&errors, self.inh.body_id, fallback_has_occurred);
-        }
-    }
-
-    /// For the overloaded place expressions (`*x`, `x[3]`), the trait
-    /// returns a type of `&T`, but the actual type we assign to the
-    /// *expression* is `T`. So this function just peels off the return
-    /// type by one layer to yield `T`.
-    fn make_overloaded_place_return_type(
-        &self,
-        method: MethodCallee<'tcx>,
-    ) -> ty::TypeAndMut<'tcx> {
-        // extract method return type, which will be &T;
-        let ret_ty = method.sig.output();
-
-        // method returns &T, but the type as visible to user is T, so deref
-        ret_ty.builtin_deref(true).unwrap()
-    }
-
-    fn check_method_argument_types(
-        &self,
-        sp: Span,
-        expr: &'tcx hir::Expr<'tcx>,
-        method: Result<MethodCallee<'tcx>, ()>,
-        args_no_rcvr: &'tcx [hir::Expr<'tcx>],
-        tuple_arguments: TupleArgumentsFlag,
-        expected: Expectation<'tcx>,
-    ) -> Ty<'tcx> {
-        let has_error = match method {
-            Ok(method) => method.substs.references_error() || method.sig.references_error(),
-            Err(_) => true,
-        };
-        if has_error {
-            let err_inputs = self.err_args(args_no_rcvr.len());
-
-            let err_inputs = match tuple_arguments {
-                DontTupleArguments => err_inputs,
-                TupleArguments => vec![self.tcx.intern_tup(&err_inputs[..])],
-            };
-
-            self.check_argument_types(
-                sp,
-                expr,
-                &err_inputs[..],
-                &[],
-                args_no_rcvr,
-                false,
-                tuple_arguments,
-                None,
-            );
-            return self.tcx.ty_error();
-        }
-
-        let method = method.unwrap();
-        // HACK(eddyb) ignore self in the definition (see above).
-        let expected_arg_tys = self.expected_inputs_for_expected_output(
-            sp,
-            expected,
-            method.sig.output(),
-            &method.sig.inputs()[1..],
-        );
-        self.check_argument_types(
-            sp,
-            expr,
-            &method.sig.inputs()[1..],
-            &expected_arg_tys[..],
-            args_no_rcvr,
-            method.sig.c_variadic,
-            tuple_arguments,
-            self.tcx.hir().span_if_local(method.def_id),
-        );
-        method.sig.output()
-    }
-
-    fn self_type_matches_expected_vid(
-        &self,
-        trait_ref: ty::PolyTraitRef<'tcx>,
-        expected_vid: ty::TyVid,
-    ) -> bool {
-        let self_ty = self.shallow_resolve(trait_ref.skip_binder().self_ty());
-        debug!(
-            "self_type_matches_expected_vid(trait_ref={:?}, self_ty={:?}, expected_vid={:?})",
-            trait_ref, self_ty, expected_vid
-        );
-        match *self_ty.kind() {
-            ty::Infer(ty::TyVar(found_vid)) => {
-                // FIXME: consider using `sub_root_var` here so we
-                // can see through subtyping.
-                let found_vid = self.root_var(found_vid);
-                debug!("self_type_matches_expected_vid - found_vid={:?}", found_vid);
-                expected_vid == found_vid
-            }
-            _ => false,
-        }
-    }
-
-    fn obligations_for_self_ty<'b>(
-        &'b self,
-        self_ty: ty::TyVid,
-    ) -> impl Iterator<Item = (ty::PolyTraitRef<'tcx>, traits::PredicateObligation<'tcx>)>
-    + Captures<'tcx>
-    + 'b {
-        // FIXME: consider using `sub_root_var` here so we
-        // can see through subtyping.
-        let ty_var_root = self.root_var(self_ty);
-        debug!(
-            "obligations_for_self_ty: self_ty={:?} ty_var_root={:?} pending_obligations={:?}",
-            self_ty,
-            ty_var_root,
-            self.fulfillment_cx.borrow().pending_obligations()
-        );
-
-        self.fulfillment_cx
-            .borrow()
-            .pending_obligations()
-            .into_iter()
-            .filter_map(move |obligation| {
-                match obligation.predicate.skip_binders() {
-                    ty::PredicateAtom::Projection(data) => {
-                        Some((ty::Binder::bind(data).to_poly_trait_ref(self.tcx), obligation))
-                    }
-                    ty::PredicateAtom::Trait(data, _) => {
-                        Some((ty::Binder::bind(data).to_poly_trait_ref(), obligation))
-                    }
-                    ty::PredicateAtom::Subtype(..) => None,
-                    ty::PredicateAtom::RegionOutlives(..) => None,
-                    ty::PredicateAtom::TypeOutlives(..) => None,
-                    ty::PredicateAtom::WellFormed(..) => None,
-                    ty::PredicateAtom::ObjectSafe(..) => None,
-                    ty::PredicateAtom::ConstEvaluatable(..) => None,
-                    ty::PredicateAtom::ConstEquate(..) => None,
-                    // N.B., this predicate is created by breaking down a
-                    // `ClosureType: FnFoo()` predicate, where
-                    // `ClosureType` represents some `Closure`. It can't
-                    // possibly be referring to the current closure,
-                    // because we haven't produced the `Closure` for
-                    // this closure yet; this is exactly why the other
-                    // code is looking for a self type of a unresolved
-                    // inference variable.
-                    ty::PredicateAtom::ClosureKind(..) => None,
-                    ty::PredicateAtom::TypeWellFormedFromEnv(..) => None,
-                }
-            })
-            .filter(move |(tr, _)| self.self_type_matches_expected_vid(*tr, ty_var_root))
-    }
-
-    fn type_var_is_sized(&self, self_ty: ty::TyVid) -> bool {
-        self.obligations_for_self_ty(self_ty)
-            .any(|(tr, _)| Some(tr.def_id()) == self.tcx.lang_items().sized_trait())
-    }
-
-    /// Generic function that factors out common logic from function calls,
-    /// method calls and overloaded operators.
-    fn check_argument_types(
-        &self,
-        sp: Span,
-        expr: &'tcx hir::Expr<'tcx>,
-        fn_inputs: &[Ty<'tcx>],
-        expected_arg_tys: &[Ty<'tcx>],
-        args: &'tcx [hir::Expr<'tcx>],
-        c_variadic: bool,
-        tuple_arguments: TupleArgumentsFlag,
-        def_span: Option<Span>,
-    ) {
-        let tcx = self.tcx;
-        // Grab the argument types, supplying fresh type variables
-        // if the wrong number of arguments were supplied
-        let supplied_arg_count = if tuple_arguments == DontTupleArguments { args.len() } else { 1 };
-
-        // All the input types from the fn signature must outlive the call
-        // so as to validate implied bounds.
-        for (&fn_input_ty, arg_expr) in fn_inputs.iter().zip(args.iter()) {
-            self.register_wf_obligation(fn_input_ty.into(), arg_expr.span, traits::MiscObligation);
-        }
-
-        let expected_arg_count = fn_inputs.len();
-
-        let param_count_error = |expected_count: usize,
-                                 arg_count: usize,
-                                 error_code: &str,
-                                 c_variadic: bool,
-                                 sugg_unit: bool| {
-            let (span, start_span, args) = match &expr.kind {
-                hir::ExprKind::Call(hir::Expr { span, .. }, args) => (*span, *span, &args[..]),
-                hir::ExprKind::MethodCall(path_segment, span, args, _) => (
-                    *span,
-                    // `sp` doesn't point at the whole `foo.bar()`, only at `bar`.
-                    path_segment
-                        .args
-                        .and_then(|args| args.args.iter().last())
-                        // Account for `foo.bar::<T>()`.
-                        .map(|arg| {
-                            // Skip the closing `>`.
-                            tcx.sess
-                                .source_map()
-                                .next_point(tcx.sess.source_map().next_point(arg.span()))
-                        })
-                        .unwrap_or(*span),
-                    &args[1..], // Skip the receiver.
-                ),
-                k => span_bug!(sp, "checking argument types on a non-call: `{:?}`", k),
-            };
-            let arg_spans = if args.is_empty() {
-                // foo()
-                // ^^^-- supplied 0 arguments
-                // |
-                // expected 2 arguments
-                vec![tcx.sess.source_map().next_point(start_span).with_hi(sp.hi())]
-            } else {
-                // foo(1, 2, 3)
-                // ^^^ -  -  - supplied 3 arguments
-                // |
-                // expected 2 arguments
-                args.iter().map(|arg| arg.span).collect::<Vec<Span>>()
-            };
-
-            let mut err = tcx.sess.struct_span_err_with_code(
-                span,
-                &format!(
-                    "this function takes {}{} but {} {} supplied",
-                    if c_variadic { "at least " } else { "" },
-                    potentially_plural_count(expected_count, "argument"),
-                    potentially_plural_count(arg_count, "argument"),
-                    if arg_count == 1 { "was" } else { "were" }
-                ),
-                DiagnosticId::Error(error_code.to_owned()),
-            );
-            let label = format!("supplied {}", potentially_plural_count(arg_count, "argument"));
-            for (i, span) in arg_spans.into_iter().enumerate() {
-                err.span_label(
-                    span,
-                    if arg_count == 0 || i + 1 == arg_count { &label } else { "" },
-                );
-            }
-
-            if let Some(def_s) = def_span.map(|sp| tcx.sess.source_map().guess_head_span(sp)) {
-                err.span_label(def_s, "defined here");
-            }
-            if sugg_unit {
-                let sugg_span = tcx.sess.source_map().end_point(expr.span);
-                // remove closing `)` from the span
-                let sugg_span = sugg_span.shrink_to_lo();
-                err.span_suggestion(
-                    sugg_span,
-                    "expected the unit value `()`; create it with empty parentheses",
-                    String::from("()"),
-                    Applicability::MachineApplicable,
-                );
-            } else {
-                err.span_label(
-                    span,
-                    format!(
-                        "expected {}{}",
-                        if c_variadic { "at least " } else { "" },
-                        potentially_plural_count(expected_count, "argument")
-                    ),
-                );
-            }
-            err.emit();
-        };
-
-        let mut expected_arg_tys = expected_arg_tys.to_vec();
-
-        let formal_tys = if tuple_arguments == TupleArguments {
-            let tuple_type = self.structurally_resolved_type(sp, fn_inputs[0]);
-            match tuple_type.kind() {
-                ty::Tuple(arg_types) if arg_types.len() != args.len() => {
-                    param_count_error(arg_types.len(), args.len(), "E0057", false, false);
-                    expected_arg_tys = vec![];
-                    self.err_args(args.len())
-                }
-                ty::Tuple(arg_types) => {
-                    expected_arg_tys = match expected_arg_tys.get(0) {
-                        Some(&ty) => match ty.kind() {
-                            ty::Tuple(ref tys) => tys.iter().map(|k| k.expect_ty()).collect(),
-                            _ => vec![],
-                        },
-                        None => vec![],
-                    };
-                    arg_types.iter().map(|k| k.expect_ty()).collect()
-                }
-                _ => {
-                    struct_span_err!(
-                        tcx.sess,
-                        sp,
-                        E0059,
-                        "cannot use call notation; the first type parameter \
-                         for the function trait is neither a tuple nor unit"
-                    )
-                    .emit();
-                    expected_arg_tys = vec![];
-                    self.err_args(args.len())
-                }
-            }
-        } else if expected_arg_count == supplied_arg_count {
-            fn_inputs.to_vec()
-        } else if c_variadic {
-            if supplied_arg_count >= expected_arg_count {
-                fn_inputs.to_vec()
-            } else {
-                param_count_error(expected_arg_count, supplied_arg_count, "E0060", true, false);
-                expected_arg_tys = vec![];
-                self.err_args(supplied_arg_count)
-            }
-        } else {
-            // is the missing argument of type `()`?
-            let sugg_unit = if expected_arg_tys.len() == 1 && supplied_arg_count == 0 {
-                self.resolve_vars_if_possible(&expected_arg_tys[0]).is_unit()
-            } else if fn_inputs.len() == 1 && supplied_arg_count == 0 {
-                self.resolve_vars_if_possible(&fn_inputs[0]).is_unit()
-            } else {
-                false
-            };
-            param_count_error(expected_arg_count, supplied_arg_count, "E0061", false, sugg_unit);
-
-            expected_arg_tys = vec![];
-            self.err_args(supplied_arg_count)
-        };
-
-        debug!(
-            "check_argument_types: formal_tys={:?}",
-            formal_tys.iter().map(|t| self.ty_to_string(*t)).collect::<Vec<String>>()
-        );
-
-        // If there is no expectation, expect formal_tys.
-        let expected_arg_tys =
-            if !expected_arg_tys.is_empty() { expected_arg_tys } else { formal_tys.clone() };
-
-        let mut final_arg_types: Vec<(usize, Ty<'_>, Ty<'_>)> = vec![];
-
-        // Check the arguments.
-        // We do this in a pretty awful way: first we type-check any arguments
-        // that are not closures, then we type-check the closures. This is so
-        // that we have more information about the types of arguments when we
-        // type-check the functions. This isn't really the right way to do this.
-        for &check_closures in &[false, true] {
-            debug!("check_closures={}", check_closures);
-
-            // More awful hacks: before we check argument types, try to do
-            // an "opportunistic" trait resolution of any trait bounds on
-            // the call. This helps coercions.
-            if check_closures {
-                self.select_obligations_where_possible(false, |errors| {
-                    self.point_at_type_arg_instead_of_call_if_possible(errors, expr);
-                    self.point_at_arg_instead_of_call_if_possible(
-                        errors,
-                        &final_arg_types[..],
-                        sp,
-                        &args,
-                    );
-                })
-            }
-
-            // For C-variadic functions, we don't have a declared type for all of
-            // the arguments hence we only do our usual type checking with
-            // the arguments who's types we do know.
-            let t = if c_variadic {
-                expected_arg_count
-            } else if tuple_arguments == TupleArguments {
-                args.len()
-            } else {
-                supplied_arg_count
-            };
-            for (i, arg) in args.iter().take(t).enumerate() {
-                // Warn only for the first loop (the "no closures" one).
-                // Closure arguments themselves can't be diverging, but
-                // a previous argument can, e.g., `foo(panic!(), || {})`.
-                if !check_closures {
-                    self.warn_if_unreachable(arg.hir_id, arg.span, "expression");
-                }
-
-                let is_closure = match arg.kind {
-                    ExprKind::Closure(..) => true,
-                    _ => false,
-                };
-
-                if is_closure != check_closures {
-                    continue;
-                }
-
-                debug!("checking the argument");
-                let formal_ty = formal_tys[i];
-
-                // The special-cased logic below has three functions:
-                // 1. Provide as good of an expected type as possible.
-                let expected = Expectation::rvalue_hint(self, expected_arg_tys[i]);
-
-                let checked_ty = self.check_expr_with_expectation(&arg, expected);
-
-                // 2. Coerce to the most detailed type that could be coerced
-                //    to, which is `expected_ty` if `rvalue_hint` returns an
-                //    `ExpectHasType(expected_ty)`, or the `formal_ty` otherwise.
-                let coerce_ty = expected.only_has_type(self).unwrap_or(formal_ty);
-                // We're processing function arguments so we definitely want to use
-                // two-phase borrows.
-                self.demand_coerce(&arg, checked_ty, coerce_ty, None, AllowTwoPhase::Yes);
-                final_arg_types.push((i, checked_ty, coerce_ty));
-
-                // 3. Relate the expected type and the formal one,
-                //    if the expected type was used for the coercion.
-                self.demand_suptype(arg.span, formal_ty, coerce_ty);
-            }
-        }
-
-        // We also need to make sure we at least write the ty of the other
-        // arguments which we skipped above.
-        if c_variadic {
-            fn variadic_error<'tcx>(s: &Session, span: Span, t: Ty<'tcx>, cast_ty: &str) {
-                use crate::structured_errors::{StructuredDiagnostic, VariadicError};
-                VariadicError::new(s, span, t, cast_ty).diagnostic().emit();
-            }
-
-            for arg in args.iter().skip(expected_arg_count) {
-                let arg_ty = self.check_expr(&arg);
-
-                // There are a few types which get autopromoted when passed via varargs
-                // in C but we just error out instead and require explicit casts.
-                let arg_ty = self.structurally_resolved_type(arg.span, arg_ty);
-                match arg_ty.kind() {
-                    ty::Float(ast::FloatTy::F32) => {
-                        variadic_error(tcx.sess, arg.span, arg_ty, "c_double");
-                    }
-                    ty::Int(ast::IntTy::I8 | ast::IntTy::I16) | ty::Bool => {
-                        variadic_error(tcx.sess, arg.span, arg_ty, "c_int");
-                    }
-                    ty::Uint(ast::UintTy::U8 | ast::UintTy::U16) => {
-                        variadic_error(tcx.sess, arg.span, arg_ty, "c_uint");
-                    }
-                    ty::FnDef(..) => {
-                        let ptr_ty = self.tcx.mk_fn_ptr(arg_ty.fn_sig(self.tcx));
-                        let ptr_ty = self.resolve_vars_if_possible(&ptr_ty);
-                        variadic_error(tcx.sess, arg.span, arg_ty, &ptr_ty.to_string());
-                    }
-                    _ => {}
-                }
-            }
-        }
-    }
-
-    fn err_args(&self, len: usize) -> Vec<Ty<'tcx>> {
-        vec![self.tcx.ty_error(); len]
-    }
-
-    /// Given a vec of evaluated `FulfillmentError`s and an `fn` call argument expressions, we walk
-    /// the checked and coerced types for each argument to see if any of the `FulfillmentError`s
-    /// reference a type argument. The reason to walk also the checked type is that the coerced type
-    /// can be not easily comparable with predicate type (because of coercion). If the types match
-    /// for either checked or coerced type, and there's only *one* argument that does, we point at
-    /// the corresponding argument's expression span instead of the `fn` call path span.
-    fn point_at_arg_instead_of_call_if_possible(
-        &self,
-        errors: &mut Vec<traits::FulfillmentError<'tcx>>,
-        final_arg_types: &[(usize, Ty<'tcx>, Ty<'tcx>)],
-        call_sp: Span,
-        args: &'tcx [hir::Expr<'tcx>],
-    ) {
-        // We *do not* do this for desugared call spans to keep good diagnostics when involving
-        // the `?` operator.
-        if call_sp.desugaring_kind().is_some() {
-            return;
-        }
-
-        for error in errors {
-            // Only if the cause is somewhere inside the expression we want try to point at arg.
-            // Otherwise, it means that the cause is somewhere else and we should not change
-            // anything because we can break the correct span.
-            if !call_sp.contains(error.obligation.cause.span) {
-                continue;
-            }
-
-            if let ty::PredicateAtom::Trait(predicate, _) =
-                error.obligation.predicate.skip_binders()
-            {
-                // Collect the argument position for all arguments that could have caused this
-                // `FulfillmentError`.
-                let mut referenced_in = final_arg_types
-                    .iter()
-                    .map(|&(i, checked_ty, _)| (i, checked_ty))
-                    .chain(final_arg_types.iter().map(|&(i, _, coerced_ty)| (i, coerced_ty)))
-                    .flat_map(|(i, ty)| {
-                        let ty = self.resolve_vars_if_possible(&ty);
-                        // We walk the argument type because the argument's type could have
-                        // been `Option<T>`, but the `FulfillmentError` references `T`.
-                        if ty.walk().any(|arg| arg == predicate.self_ty().into()) {
-                            Some(i)
-                        } else {
-                            None
-                        }
-                    })
-                    .collect::<Vec<usize>>();
-
-                // Both checked and coerced types could have matched, thus we need to remove
-                // duplicates.
-
-                // We sort primitive type usize here and can use unstable sort
-                referenced_in.sort_unstable();
-                referenced_in.dedup();
-
-                if let (Some(ref_in), None) = (referenced_in.pop(), referenced_in.pop()) {
-                    // We make sure that only *one* argument matches the obligation failure
-                    // and we assign the obligation's span to its expression's.
-                    error.obligation.cause.make_mut().span = args[ref_in].span;
-                    error.points_at_arg_span = true;
-                }
-            }
-        }
-    }
-
-    /// Given a vec of evaluated `FulfillmentError`s and an `fn` call expression, we walk the
-    /// `PathSegment`s and resolve their type parameters to see if any of the `FulfillmentError`s
-    /// were caused by them. If they were, we point at the corresponding type argument's span
-    /// instead of the `fn` call path span.
-    fn point_at_type_arg_instead_of_call_if_possible(
-        &self,
-        errors: &mut Vec<traits::FulfillmentError<'tcx>>,
-        call_expr: &'tcx hir::Expr<'tcx>,
-    ) {
-        if let hir::ExprKind::Call(path, _) = &call_expr.kind {
-            if let hir::ExprKind::Path(qpath) = &path.kind {
-                if let hir::QPath::Resolved(_, path) = &qpath {
-                    for error in errors {
-                        if let ty::PredicateAtom::Trait(predicate, _) =
-                            error.obligation.predicate.skip_binders()
-                        {
-                            // If any of the type arguments in this path segment caused the
-                            // `FullfillmentError`, point at its span (#61860).
-                            for arg in path
-                                .segments
-                                .iter()
-                                .filter_map(|seg| seg.args.as_ref())
-                                .flat_map(|a| a.args.iter())
-                            {
-                                if let hir::GenericArg::Type(hir_ty) = &arg {
-                                    if let hir::TyKind::Path(hir::QPath::TypeRelative(..)) =
-                                        &hir_ty.kind
-                                    {
-                                        // Avoid ICE with associated types. As this is best
-                                        // effort only, it's ok to ignore the case. It
-                                        // would trigger in `is_send::<T::AssocType>();`
-                                        // from `typeck-default-trait-impl-assoc-type.rs`.
-                                    } else {
-                                        let ty = AstConv::ast_ty_to_ty(self, hir_ty);
-                                        let ty = self.resolve_vars_if_possible(&ty);
-                                        if ty == predicate.self_ty() {
-                                            error.obligation.cause.make_mut().span = hir_ty.span;
-                                        }
-                                    }
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    // AST fragment checking
-    fn check_lit(&self, lit: &hir::Lit, expected: Expectation<'tcx>) -> Ty<'tcx> {
-        let tcx = self.tcx;
-
-        match lit.node {
-            ast::LitKind::Str(..) => tcx.mk_static_str(),
-            ast::LitKind::ByteStr(ref v) => {
-                tcx.mk_imm_ref(tcx.lifetimes.re_static, tcx.mk_array(tcx.types.u8, v.len() as u64))
-            }
-            ast::LitKind::Byte(_) => tcx.types.u8,
-            ast::LitKind::Char(_) => tcx.types.char,
-            ast::LitKind::Int(_, ast::LitIntType::Signed(t)) => tcx.mk_mach_int(t),
-            ast::LitKind::Int(_, ast::LitIntType::Unsigned(t)) => tcx.mk_mach_uint(t),
-            ast::LitKind::Int(_, ast::LitIntType::Unsuffixed) => {
-                let opt_ty = expected.to_option(self).and_then(|ty| match ty.kind() {
-                    ty::Int(_) | ty::Uint(_) => Some(ty),
-                    ty::Char => Some(tcx.types.u8),
-                    ty::RawPtr(..) => Some(tcx.types.usize),
-                    ty::FnDef(..) | ty::FnPtr(_) => Some(tcx.types.usize),
-                    _ => None,
-                });
-                opt_ty.unwrap_or_else(|| self.next_int_var())
-            }
-            ast::LitKind::Float(_, ast::LitFloatType::Suffixed(t)) => tcx.mk_mach_float(t),
-            ast::LitKind::Float(_, ast::LitFloatType::Unsuffixed) => {
-                let opt_ty = expected.to_option(self).and_then(|ty| match ty.kind() {
-                    ty::Float(_) => Some(ty),
-                    _ => None,
-                });
-                opt_ty.unwrap_or_else(|| self.next_float_var())
-            }
-            ast::LitKind::Bool(_) => tcx.types.bool,
-            ast::LitKind::Err(_) => tcx.ty_error(),
-        }
-    }
-
-    /// Unifies the output type with the expected type early, for more coercions
-    /// and forward type information on the input expressions.
-    fn expected_inputs_for_expected_output(
-        &self,
-        call_span: Span,
-        expected_ret: Expectation<'tcx>,
-        formal_ret: Ty<'tcx>,
-        formal_args: &[Ty<'tcx>],
-    ) -> Vec<Ty<'tcx>> {
-        let formal_ret = self.resolve_vars_with_obligations(formal_ret);
-        let ret_ty = match expected_ret.only_has_type(self) {
-            Some(ret) => ret,
-            None => return Vec::new(),
-        };
-        let expect_args = self
-            .fudge_inference_if_ok(|| {
-                // Attempt to apply a subtyping relationship between the formal
-                // return type (likely containing type variables if the function
-                // is polymorphic) and the expected return type.
-                // No argument expectations are produced if unification fails.
-                let origin = self.misc(call_span);
-                let ures = self.at(&origin, self.param_env).sup(ret_ty, &formal_ret);
-
-                // FIXME(#27336) can't use ? here, Try::from_error doesn't default
-                // to identity so the resulting type is not constrained.
-                match ures {
-                    Ok(ok) => {
-                        // Process any obligations locally as much as
-                        // we can.  We don't care if some things turn
-                        // out unconstrained or ambiguous, as we're
-                        // just trying to get hints here.
-                        self.save_and_restore_in_snapshot_flag(|_| {
-                            let mut fulfill = TraitEngine::new(self.tcx);
-                            for obligation in ok.obligations {
-                                fulfill.register_predicate_obligation(self, obligation);
-                            }
-                            fulfill.select_where_possible(self)
-                        })
-                        .map_err(|_| ())?;
-                    }
-                    Err(_) => return Err(()),
-                }
-
-                // Record all the argument types, with the substitutions
-                // produced from the above subtyping unification.
-                Ok(formal_args.iter().map(|ty| self.resolve_vars_if_possible(ty)).collect())
-            })
-            .unwrap_or_default();
-        debug!(
-            "expected_inputs_for_expected_output(formal={:?} -> {:?}, expected={:?} -> {:?})",
-            formal_args, formal_ret, expect_args, expected_ret
-        );
-        expect_args
-    }
-
-    pub fn check_struct_path(
-        &self,
-        qpath: &QPath<'_>,
-        hir_id: hir::HirId,
-    ) -> Option<(&'tcx ty::VariantDef, Ty<'tcx>)> {
-        let path_span = qpath.qself_span();
-        let (def, ty) = self.finish_resolving_struct_path(qpath, path_span, hir_id);
-        let variant = match def {
-            Res::Err => {
-                self.set_tainted_by_errors();
-                return None;
-            }
-            Res::Def(DefKind::Variant, _) => match ty.kind() {
-                ty::Adt(adt, substs) => Some((adt.variant_of_res(def), adt.did, substs)),
-                _ => bug!("unexpected type: {:?}", ty),
-            },
-            Res::Def(DefKind::Struct | DefKind::Union | DefKind::TyAlias | DefKind::AssocTy, _)
-            | Res::SelfTy(..) => match ty.kind() {
-                ty::Adt(adt, substs) if !adt.is_enum() => {
-                    Some((adt.non_enum_variant(), adt.did, substs))
-                }
-                _ => None,
-            },
-            _ => bug!("unexpected definition: {:?}", def),
-        };
-
-        if let Some((variant, did, substs)) = variant {
-            debug!("check_struct_path: did={:?} substs={:?}", did, substs);
-            self.write_user_type_annotation_from_substs(hir_id, did, substs, None);
-
-            // Check bounds on type arguments used in the path.
-            let (bounds, _) = self.instantiate_bounds(path_span, did, substs);
-            let cause =
-                traits::ObligationCause::new(path_span, self.body_id, traits::ItemObligation(did));
-            self.add_obligations_for_parameters(cause, bounds);
-
-            Some((variant, ty))
-        } else {
-            struct_span_err!(
-                self.tcx.sess,
-                path_span,
-                E0071,
-                "expected struct, variant or union type, found {}",
-                ty.sort_string(self.tcx)
-            )
-            .span_label(path_span, "not a struct")
-            .emit();
-            None
-        }
-    }
-
-    // Finish resolving a path in a struct expression or pattern `S::A { .. }` if necessary.
-    // The newly resolved definition is written into `type_dependent_defs`.
-    fn finish_resolving_struct_path(
-        &self,
-        qpath: &QPath<'_>,
-        path_span: Span,
-        hir_id: hir::HirId,
-    ) -> (Res, Ty<'tcx>) {
-        match *qpath {
-            QPath::Resolved(ref maybe_qself, ref path) => {
-                let self_ty = maybe_qself.as_ref().map(|qself| self.to_ty(qself));
-                let ty = AstConv::res_to_ty(self, self_ty, path, true);
-                (path.res, ty)
-            }
-            QPath::TypeRelative(ref qself, ref segment) => {
-                let ty = self.to_ty(qself);
-
-                let res = if let hir::TyKind::Path(QPath::Resolved(_, ref path)) = qself.kind {
-                    path.res
-                } else {
-                    Res::Err
-                };
-                let result =
-                    AstConv::associated_path_to_ty(self, hir_id, path_span, ty, res, segment, true);
-                let ty = result.map(|(ty, _, _)| ty).unwrap_or_else(|_| self.tcx().ty_error());
-                let result = result.map(|(_, kind, def_id)| (kind, def_id));
-
-                // Write back the new resolution.
-                self.write_resolution(hir_id, result);
-
-                (result.map(|(kind, def_id)| Res::Def(kind, def_id)).unwrap_or(Res::Err), ty)
-            }
-            QPath::LangItem(lang_item, span) => {
-                self.resolve_lang_item_path(lang_item, span, hir_id)
-            }
-        }
-    }
-
-    fn resolve_lang_item_path(
-        &self,
-        lang_item: hir::LangItem,
-        span: Span,
-        hir_id: hir::HirId,
-    ) -> (Res, Ty<'tcx>) {
-        let def_id = self.tcx.require_lang_item(lang_item, Some(span));
-        let def_kind = self.tcx.def_kind(def_id);
-
-        let item_ty = if let DefKind::Variant = def_kind {
-            self.tcx.type_of(self.tcx.parent(def_id).expect("variant w/out parent"))
-        } else {
-            self.tcx.type_of(def_id)
-        };
-        let substs = self.infcx.fresh_substs_for_item(span, def_id);
-        let ty = item_ty.subst(self.tcx, substs);
-
-        self.write_resolution(hir_id, Ok((def_kind, def_id)));
-        self.add_required_obligations(span, def_id, &substs);
-        (Res::Def(def_kind, def_id), ty)
-    }
-
-    /// Resolves an associated value path into a base type and associated constant, or method
-    /// resolution. The newly resolved definition is written into `type_dependent_defs`.
-    pub fn resolve_ty_and_res_ufcs<'b>(
-        &self,
-        qpath: &'b QPath<'b>,
-        hir_id: hir::HirId,
-        span: Span,
-    ) -> (Res, Option<Ty<'tcx>>, &'b [hir::PathSegment<'b>]) {
-        debug!("resolve_ty_and_res_ufcs: qpath={:?} hir_id={:?} span={:?}", qpath, hir_id, span);
-        let (ty, qself, item_segment) = match *qpath {
-            QPath::Resolved(ref opt_qself, ref path) => {
-                return (
-                    path.res,
-                    opt_qself.as_ref().map(|qself| self.to_ty(qself)),
-                    &path.segments[..],
-                );
-            }
-            QPath::TypeRelative(ref qself, ref segment) => (self.to_ty(qself), qself, segment),
-            QPath::LangItem(..) => bug!("`resolve_ty_and_res_ufcs` called on `LangItem`"),
-        };
-        if let Some(&cached_result) = self.typeck_results.borrow().type_dependent_defs().get(hir_id)
-        {
-            // Return directly on cache hit. This is useful to avoid doubly reporting
-            // errors with default match binding modes. See #44614.
-            let def =
-                cached_result.map(|(kind, def_id)| Res::Def(kind, def_id)).unwrap_or(Res::Err);
-            return (def, Some(ty), slice::from_ref(&**item_segment));
-        }
-        let item_name = item_segment.ident;
-        let result = self.resolve_ufcs(span, item_name, ty, hir_id).or_else(|error| {
-            let result = match error {
-                method::MethodError::PrivateMatch(kind, def_id, _) => Ok((kind, def_id)),
-                _ => Err(ErrorReported),
-            };
-            if item_name.name != kw::Invalid {
-                if let Some(mut e) = self.report_method_error(
-                    span,
-                    ty,
-                    item_name,
-                    SelfSource::QPath(qself),
-                    error,
-                    None,
-                ) {
-                    e.emit();
-                }
-            }
-            result
-        });
-
-        // Write back the new resolution.
-        self.write_resolution(hir_id, result);
-        (
-            result.map(|(kind, def_id)| Res::Def(kind, def_id)).unwrap_or(Res::Err),
-            Some(ty),
-            slice::from_ref(&**item_segment),
-        )
-    }
-
-    pub fn check_decl_initializer(
-        &self,
-        local: &'tcx hir::Local<'tcx>,
-        init: &'tcx hir::Expr<'tcx>,
-    ) -> Ty<'tcx> {
-        // FIXME(tschottdorf): `contains_explicit_ref_binding()` must be removed
-        // for #42640 (default match binding modes).
-        //
-        // See #44848.
-        let ref_bindings = local.pat.contains_explicit_ref_binding();
-
-        let local_ty = self.local_ty(init.span, local.hir_id).revealed_ty;
-        if let Some(m) = ref_bindings {
-            // Somewhat subtle: if we have a `ref` binding in the pattern,
-            // we want to avoid introducing coercions for the RHS. This is
-            // both because it helps preserve sanity and, in the case of
-            // ref mut, for soundness (issue #23116). In particular, in
-            // the latter case, we need to be clear that the type of the
-            // referent for the reference that results is *equal to* the
-            // type of the place it is referencing, and not some
-            // supertype thereof.
-            let init_ty = self.check_expr_with_needs(init, Needs::maybe_mut_place(m));
-            self.demand_eqtype(init.span, local_ty, init_ty);
-            init_ty
-        } else {
-            self.check_expr_coercable_to_type(init, local_ty, None)
-        }
-    }
-
-    /// Type check a `let` statement.
-    pub fn check_decl_local(&self, local: &'tcx hir::Local<'tcx>) {
-        // Determine and write the type which we'll check the pattern against.
-        let ty = self.local_ty(local.span, local.hir_id).decl_ty;
-        self.write_ty(local.hir_id, ty);
-
-        // Type check the initializer.
-        if let Some(ref init) = local.init {
-            let init_ty = self.check_decl_initializer(local, &init);
-            self.overwrite_local_ty_if_err(local, ty, init_ty);
-        }
-
-        // Does the expected pattern type originate from an expression and what is the span?
-        let (origin_expr, ty_span) = match (local.ty, local.init) {
-            (Some(ty), _) => (false, Some(ty.span)), // Bias towards the explicit user type.
-            (_, Some(init)) => (true, Some(init.span)), // No explicit type; so use the scrutinee.
-            _ => (false, None), // We have `let $pat;`, so the expected type is unconstrained.
-        };
-
-        // Type check the pattern. Override if necessary to avoid knock-on errors.
-        self.check_pat_top(&local.pat, ty, ty_span, origin_expr);
-        let pat_ty = self.node_ty(local.pat.hir_id);
-        self.overwrite_local_ty_if_err(local, ty, pat_ty);
-    }
-
-    fn overwrite_local_ty_if_err(
-        &self,
-        local: &'tcx hir::Local<'tcx>,
-        decl_ty: Ty<'tcx>,
-        ty: Ty<'tcx>,
-    ) {
-        if ty.references_error() {
-            // Override the types everywhere with `err()` to avoid knock on errors.
-            self.write_ty(local.hir_id, ty);
-            self.write_ty(local.pat.hir_id, ty);
-            let local_ty = LocalTy { decl_ty, revealed_ty: ty };
-            self.locals.borrow_mut().insert(local.hir_id, local_ty);
-            self.locals.borrow_mut().insert(local.pat.hir_id, local_ty);
-        }
-    }
-
-    fn suggest_semicolon_at_end(&self, span: Span, err: &mut DiagnosticBuilder<'_>) {
-        err.span_suggestion_short(
-            span.shrink_to_hi(),
-            "consider using a semicolon here",
-            ";".to_string(),
-            Applicability::MachineApplicable,
-        );
-    }
-
-    pub fn check_stmt(&self, stmt: &'tcx hir::Stmt<'tcx>) {
-        // Don't do all the complex logic below for `DeclItem`.
-        match stmt.kind {
-            hir::StmtKind::Item(..) => return,
-            hir::StmtKind::Local(..) | hir::StmtKind::Expr(..) | hir::StmtKind::Semi(..) => {}
-        }
-
-        self.warn_if_unreachable(stmt.hir_id, stmt.span, "statement");
-
-        // Hide the outer diverging and `has_errors` flags.
-        let old_diverges = self.diverges.replace(Diverges::Maybe);
-        let old_has_errors = self.has_errors.replace(false);
-
-        match stmt.kind {
-            hir::StmtKind::Local(ref l) => {
-                self.check_decl_local(&l);
-            }
-            // Ignore for now.
-            hir::StmtKind::Item(_) => {}
-            hir::StmtKind::Expr(ref expr) => {
-                // Check with expected type of `()`.
-                self.check_expr_has_type_or_error(&expr, self.tcx.mk_unit(), |err| {
-                    self.suggest_semicolon_at_end(expr.span, err);
-                });
-            }
-            hir::StmtKind::Semi(ref expr) => {
-                self.check_expr(&expr);
-            }
-        }
-
-        // Combine the diverging and `has_error` flags.
-        self.diverges.set(self.diverges.get() | old_diverges);
-        self.has_errors.set(self.has_errors.get() | old_has_errors);
-    }
-
-    pub fn check_block_no_value(&self, blk: &'tcx hir::Block<'tcx>) {
-        let unit = self.tcx.mk_unit();
-        let ty = self.check_block_with_expected(blk, ExpectHasType(unit));
-
-        // if the block produces a `!` value, that can always be
-        // (effectively) coerced to unit.
-        if !ty.is_never() {
-            self.demand_suptype(blk.span, unit, ty);
-        }
-    }
-
-    /// If `expr` is a `match` expression that has only one non-`!` arm, use that arm's tail
-    /// expression's `Span`, otherwise return `expr.span`. This is done to give better errors
-    /// when given code like the following:
-    /// ```text
-    /// if false { return 0i32; } else { 1u32 }
-    /// //                               ^^^^ point at this instead of the whole `if` expression
-    /// ```
-    fn get_expr_coercion_span(&self, expr: &hir::Expr<'_>) -> rustc_span::Span {
-        if let hir::ExprKind::Match(_, arms, _) = &expr.kind {
-            let arm_spans: Vec<Span> = arms
-                .iter()
-                .filter_map(|arm| {
-                    self.in_progress_typeck_results
-                        .and_then(|typeck_results| {
-                            typeck_results.borrow().node_type_opt(arm.body.hir_id)
-                        })
-                        .and_then(|arm_ty| {
-                            if arm_ty.is_never() {
-                                None
-                            } else {
-                                Some(match &arm.body.kind {
-                                    // Point at the tail expression when possible.
-                                    hir::ExprKind::Block(block, _) => {
-                                        block.expr.as_ref().map(|e| e.span).unwrap_or(block.span)
-                                    }
-                                    _ => arm.body.span,
-                                })
-                            }
-                        })
-                })
-                .collect();
-            if arm_spans.len() == 1 {
-                return arm_spans[0];
-            }
-        }
-        expr.span
-    }
-
-    fn check_block_with_expected(
-        &self,
-        blk: &'tcx hir::Block<'tcx>,
-        expected: Expectation<'tcx>,
-    ) -> Ty<'tcx> {
-        let prev = {
-            let mut fcx_ps = self.ps.borrow_mut();
-            let unsafety_state = fcx_ps.recurse(blk);
-            replace(&mut *fcx_ps, unsafety_state)
-        };
-
-        // In some cases, blocks have just one exit, but other blocks
-        // can be targeted by multiple breaks. This can happen both
-        // with labeled blocks as well as when we desugar
-        // a `try { ... }` expression.
-        //
-        // Example 1:
-        //
-        //    'a: { if true { break 'a Err(()); } Ok(()) }
-        //
-        // Here we would wind up with two coercions, one from
-        // `Err(())` and the other from the tail expression
-        // `Ok(())`. If the tail expression is omitted, that's a
-        // "forced unit" -- unless the block diverges, in which
-        // case we can ignore the tail expression (e.g., `'a: {
-        // break 'a 22; }` would not force the type of the block
-        // to be `()`).
-        let tail_expr = blk.expr.as_ref();
-        let coerce_to_ty = expected.coercion_target_type(self, blk.span);
-        let coerce = if blk.targeted_by_break {
-            CoerceMany::new(coerce_to_ty)
-        } else {
-            let tail_expr: &[&hir::Expr<'_>] = match tail_expr {
-                Some(e) => slice::from_ref(e),
-                None => &[],
-            };
-            CoerceMany::with_coercion_sites(coerce_to_ty, tail_expr)
-        };
-
-        let prev_diverges = self.diverges.get();
-        let ctxt = BreakableCtxt { coerce: Some(coerce), may_break: false };
-
-        let (ctxt, ()) = self.with_breakable_ctxt(blk.hir_id, ctxt, || {
-            for s in blk.stmts {
-                self.check_stmt(s);
-            }
-
-            // check the tail expression **without** holding the
-            // `enclosing_breakables` lock below.
-            let tail_expr_ty = tail_expr.map(|t| self.check_expr_with_expectation(t, expected));
-
-            let mut enclosing_breakables = self.enclosing_breakables.borrow_mut();
-            let ctxt = enclosing_breakables.find_breakable(blk.hir_id);
-            let coerce = ctxt.coerce.as_mut().unwrap();
-            if let Some(tail_expr_ty) = tail_expr_ty {
-                let tail_expr = tail_expr.unwrap();
-                let span = self.get_expr_coercion_span(tail_expr);
-                let cause = self.cause(span, ObligationCauseCode::BlockTailExpression(blk.hir_id));
-                coerce.coerce(self, &cause, tail_expr, tail_expr_ty);
-            } else {
-                // Subtle: if there is no explicit tail expression,
-                // that is typically equivalent to a tail expression
-                // of `()` -- except if the block diverges. In that
-                // case, there is no value supplied from the tail
-                // expression (assuming there are no other breaks,
-                // this implies that the type of the block will be
-                // `!`).
-                //
-                // #41425 -- label the implicit `()` as being the
-                // "found type" here, rather than the "expected type".
-                if !self.diverges.get().is_always() {
-                    // #50009 -- Do not point at the entire fn block span, point at the return type
-                    // span, as it is the cause of the requirement, and
-                    // `consider_hint_about_removing_semicolon` will point at the last expression
-                    // if it were a relevant part of the error. This improves usability in editors
-                    // that highlight errors inline.
-                    let mut sp = blk.span;
-                    let mut fn_span = None;
-                    if let Some((decl, ident)) = self.get_parent_fn_decl(blk.hir_id) {
-                        let ret_sp = decl.output.span();
-                        if let Some(block_sp) = self.parent_item_span(blk.hir_id) {
-                            // HACK: on some cases (`ui/liveness/liveness-issue-2163.rs`) the
-                            // output would otherwise be incorrect and even misleading. Make sure
-                            // the span we're aiming at correspond to a `fn` body.
-                            if block_sp == blk.span {
-                                sp = ret_sp;
-                                fn_span = Some(ident.span);
-                            }
-                        }
-                    }
-                    coerce.coerce_forced_unit(
-                        self,
-                        &self.misc(sp),
-                        &mut |err| {
-                            if let Some(expected_ty) = expected.only_has_type(self) {
-                                self.consider_hint_about_removing_semicolon(blk, expected_ty, err);
-                            }
-                            if let Some(fn_span) = fn_span {
-                                err.span_label(
-                                    fn_span,
-                                    "implicitly returns `()` as its body has no tail or `return` \
-                                     expression",
-                                );
-                            }
-                        },
-                        false,
-                    );
-                }
-            }
-        });
-
-        if ctxt.may_break {
-            // If we can break from the block, then the block's exit is always reachable
-            // (... as long as the entry is reachable) - regardless of the tail of the block.
-            self.diverges.set(prev_diverges);
-        }
-
-        let mut ty = ctxt.coerce.unwrap().complete(self);
-
-        if self.has_errors.get() || ty.references_error() {
-            ty = self.tcx.ty_error()
-        }
-
-        self.write_ty(blk.hir_id, ty);
-
-        *self.ps.borrow_mut() = prev;
-        ty
-    }
-
-    fn parent_item_span(&self, id: hir::HirId) -> Option<Span> {
-        let node = self.tcx.hir().get(self.tcx.hir().get_parent_item(id));
-        match node {
-            Node::Item(&hir::Item { kind: hir::ItemKind::Fn(_, _, body_id), .. })
-            | Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(_, body_id), .. }) => {
-                let body = self.tcx.hir().body(body_id);
-                if let ExprKind::Block(block, _) = &body.value.kind {
-                    return Some(block.span);
-                }
-            }
-            _ => {}
-        }
-        None
-    }
-
-    /// Given a function block's `HirId`, returns its `FnDecl` if it exists, or `None` otherwise.
-    fn get_parent_fn_decl(&self, blk_id: hir::HirId) -> Option<(&'tcx hir::FnDecl<'tcx>, Ident)> {
-        let parent = self.tcx.hir().get(self.tcx.hir().get_parent_item(blk_id));
-        self.get_node_fn_decl(parent).map(|(fn_decl, ident, _)| (fn_decl, ident))
-    }
-
-    /// Given a function `Node`, return its `FnDecl` if it exists, or `None` otherwise.
-    fn get_node_fn_decl(&self, node: Node<'tcx>) -> Option<(&'tcx hir::FnDecl<'tcx>, Ident, bool)> {
-        match node {
-            Node::Item(&hir::Item { ident, kind: hir::ItemKind::Fn(ref sig, ..), .. }) => {
-                // This is less than ideal, it will not suggest a return type span on any
-                // method called `main`, regardless of whether it is actually the entry point,
-                // but it will still present it as the reason for the expected type.
-                Some((&sig.decl, ident, ident.name != sym::main))
-            }
-            Node::TraitItem(&hir::TraitItem {
-                ident,
-                kind: hir::TraitItemKind::Fn(ref sig, ..),
-                ..
-            }) => Some((&sig.decl, ident, true)),
-            Node::ImplItem(&hir::ImplItem {
-                ident,
-                kind: hir::ImplItemKind::Fn(ref sig, ..),
-                ..
-            }) => Some((&sig.decl, ident, false)),
-            _ => None,
-        }
-    }
-
-    /// Given a `HirId`, return the `FnDecl` of the method it is enclosed by and whether a
-    /// suggestion can be made, `None` otherwise.
-    pub fn get_fn_decl(&self, blk_id: hir::HirId) -> Option<(&'tcx hir::FnDecl<'tcx>, bool)> {
-        // Get enclosing Fn, if it is a function or a trait method, unless there's a `loop` or
-        // `while` before reaching it, as block tail returns are not available in them.
-        self.tcx.hir().get_return_block(blk_id).and_then(|blk_id| {
-            let parent = self.tcx.hir().get(blk_id);
-            self.get_node_fn_decl(parent).map(|(fn_decl, _, is_main)| (fn_decl, is_main))
-        })
-    }
-
-    /// On implicit return expressions with mismatched types, provides the following suggestions:
-    ///
-    /// - Points out the method's return type as the reason for the expected type.
-    /// - Possible missing semicolon.
-    /// - Possible missing return type if the return type is the default, and not `fn main()`.
-    pub fn suggest_mismatched_types_on_tail(
-        &self,
-        err: &mut DiagnosticBuilder<'_>,
-        expr: &'tcx hir::Expr<'tcx>,
-        expected: Ty<'tcx>,
-        found: Ty<'tcx>,
-        cause_span: Span,
-        blk_id: hir::HirId,
-    ) -> bool {
-        let expr = expr.peel_drop_temps();
-        self.suggest_missing_semicolon(err, expr, expected, cause_span);
-        let mut pointing_at_return_type = false;
-        if let Some((fn_decl, can_suggest)) = self.get_fn_decl(blk_id) {
-            pointing_at_return_type =
-                self.suggest_missing_return_type(err, &fn_decl, expected, found, can_suggest);
-        }
-        pointing_at_return_type
-    }
-
-    /// When encountering an fn-like ctor that needs to unify with a value, check whether calling
-    /// the ctor would successfully solve the type mismatch and if so, suggest it:
-    /// ```
-    /// fn foo(x: usize) -> usize { x }
-    /// let x: usize = foo;  // suggest calling the `foo` function: `foo(42)`
-    /// ```
-    fn suggest_fn_call(
-        &self,
-        err: &mut DiagnosticBuilder<'_>,
-        expr: &hir::Expr<'_>,
-        expected: Ty<'tcx>,
-        found: Ty<'tcx>,
-    ) -> bool {
-        let hir = self.tcx.hir();
-        let (def_id, sig) = match *found.kind() {
-            ty::FnDef(def_id, _) => (def_id, found.fn_sig(self.tcx)),
-            ty::Closure(def_id, substs) => (def_id, substs.as_closure().sig()),
-            _ => return false,
-        };
-
-        let sig = self.replace_bound_vars_with_fresh_vars(expr.span, infer::FnCall, &sig).0;
-        let sig = self.normalize_associated_types_in(expr.span, &sig);
-        if self.can_coerce(sig.output(), expected) {
-            let (mut sugg_call, applicability) = if sig.inputs().is_empty() {
-                (String::new(), Applicability::MachineApplicable)
-            } else {
-                ("...".to_string(), Applicability::HasPlaceholders)
-            };
-            let mut msg = "call this function";
-            match hir.get_if_local(def_id) {
-                Some(
-                    Node::Item(hir::Item { kind: ItemKind::Fn(.., body_id), .. })
-                    | Node::ImplItem(hir::ImplItem {
-                        kind: hir::ImplItemKind::Fn(_, body_id), ..
-                    })
-                    | Node::TraitItem(hir::TraitItem {
-                        kind: hir::TraitItemKind::Fn(.., hir::TraitFn::Provided(body_id)),
-                        ..
-                    }),
-                ) => {
-                    let body = hir.body(*body_id);
-                    sugg_call = body
-                        .params
-                        .iter()
-                        .map(|param| match &param.pat.kind {
-                            hir::PatKind::Binding(_, _, ident, None)
-                                if ident.name != kw::SelfLower =>
-                            {
-                                ident.to_string()
-                            }
-                            _ => "_".to_string(),
-                        })
-                        .collect::<Vec<_>>()
-                        .join(", ");
-                }
-                Some(Node::Expr(hir::Expr {
-                    kind: ExprKind::Closure(_, _, body_id, _, _),
-                    span: full_closure_span,
-                    ..
-                })) => {
-                    if *full_closure_span == expr.span {
-                        return false;
-                    }
-                    msg = "call this closure";
-                    let body = hir.body(*body_id);
-                    sugg_call = body
-                        .params
-                        .iter()
-                        .map(|param| match &param.pat.kind {
-                            hir::PatKind::Binding(_, _, ident, None)
-                                if ident.name != kw::SelfLower =>
-                            {
-                                ident.to_string()
-                            }
-                            _ => "_".to_string(),
-                        })
-                        .collect::<Vec<_>>()
-                        .join(", ");
-                }
-                Some(Node::Ctor(hir::VariantData::Tuple(fields, _))) => {
-                    sugg_call = fields.iter().map(|_| "_").collect::<Vec<_>>().join(", ");
-                    match def_id.as_local().map(|def_id| hir.def_kind(def_id)) {
-                        Some(DefKind::Ctor(hir::def::CtorOf::Variant, _)) => {
-                            msg = "instantiate this tuple variant";
-                        }
-                        Some(DefKind::Ctor(CtorOf::Struct, _)) => {
-                            msg = "instantiate this tuple struct";
-                        }
-                        _ => {}
-                    }
-                }
-                Some(Node::ForeignItem(hir::ForeignItem {
-                    kind: hir::ForeignItemKind::Fn(_, idents, _),
-                    ..
-                })) => {
-                    sugg_call = idents
-                        .iter()
-                        .map(|ident| {
-                            if ident.name != kw::SelfLower {
-                                ident.to_string()
-                            } else {
-                                "_".to_string()
-                            }
-                        })
-                        .collect::<Vec<_>>()
-                        .join(", ")
-                }
-                Some(Node::TraitItem(hir::TraitItem {
-                    kind: hir::TraitItemKind::Fn(.., hir::TraitFn::Required(idents)),
-                    ..
-                })) => {
-                    sugg_call = idents
-                        .iter()
-                        .map(|ident| {
-                            if ident.name != kw::SelfLower {
-                                ident.to_string()
-                            } else {
-                                "_".to_string()
-                            }
-                        })
-                        .collect::<Vec<_>>()
-                        .join(", ")
-                }
-                _ => {}
-            }
-            err.span_suggestion_verbose(
-                expr.span.shrink_to_hi(),
-                &format!("use parentheses to {}", msg),
-                format!("({})", sugg_call),
-                applicability,
-            );
-            return true;
-        }
-        false
-    }
-
-    pub fn suggest_deref_ref_or_into(
-        &self,
-        err: &mut DiagnosticBuilder<'_>,
-        expr: &hir::Expr<'_>,
-        expected: Ty<'tcx>,
-        found: Ty<'tcx>,
-        expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
-    ) {
-        if let Some((sp, msg, suggestion, applicability)) = self.check_ref(expr, found, expected) {
-            err.span_suggestion(sp, msg, suggestion, applicability);
-        } else if let (ty::FnDef(def_id, ..), true) =
-            (&found.kind(), self.suggest_fn_call(err, expr, expected, found))
-        {
-            if let Some(sp) = self.tcx.hir().span_if_local(*def_id) {
-                let sp = self.sess().source_map().guess_head_span(sp);
-                err.span_label(sp, &format!("{} defined here", found));
-            }
-        } else if !self.check_for_cast(err, expr, found, expected, expected_ty_expr) {
-            let is_struct_pat_shorthand_field =
-                self.is_hir_id_from_struct_pattern_shorthand_field(expr.hir_id, expr.span);
-            let methods = self.get_conversion_methods(expr.span, expected, found, expr.hir_id);
-            if let Ok(expr_text) = self.sess().source_map().span_to_snippet(expr.span) {
-                let mut suggestions = iter::repeat(&expr_text)
-                    .zip(methods.iter())
-                    .filter_map(|(receiver, method)| {
-                        let method_call = format!(".{}()", method.ident);
-                        if receiver.ends_with(&method_call) {
-                            None // do not suggest code that is already there (#53348)
-                        } else {
-                            let method_call_list = [".to_vec()", ".to_string()"];
-                            let sugg = if receiver.ends_with(".clone()")
-                                && method_call_list.contains(&method_call.as_str())
-                            {
-                                let max_len = receiver.rfind('.').unwrap();
-                                format!("{}{}", &receiver[..max_len], method_call)
-                            } else {
-                                if expr.precedence().order() < ExprPrecedence::MethodCall.order() {
-                                    format!("({}){}", receiver, method_call)
-                                } else {
-                                    format!("{}{}", receiver, method_call)
-                                }
-                            };
-                            Some(if is_struct_pat_shorthand_field {
-                                format!("{}: {}", receiver, sugg)
-                            } else {
-                                sugg
-                            })
-                        }
-                    })
-                    .peekable();
-                if suggestions.peek().is_some() {
-                    err.span_suggestions(
-                        expr.span,
-                        "try using a conversion method",
-                        suggestions,
-                        Applicability::MaybeIncorrect,
-                    );
-                }
-            }
-        }
-    }
-
-    /// When encountering the expected boxed value allocated in the stack, suggest allocating it
-    /// in the heap by calling `Box::new()`.
-    fn suggest_boxing_when_appropriate(
-        &self,
-        err: &mut DiagnosticBuilder<'_>,
-        expr: &hir::Expr<'_>,
-        expected: Ty<'tcx>,
-        found: Ty<'tcx>,
-    ) {
-        if self.tcx.hir().is_inside_const_context(expr.hir_id) {
-            // Do not suggest `Box::new` in const context.
-            return;
-        }
-        if !expected.is_box() || found.is_box() {
-            return;
-        }
-        let boxed_found = self.tcx.mk_box(found);
-        if let (true, Ok(snippet)) = (
-            self.can_coerce(boxed_found, expected),
-            self.sess().source_map().span_to_snippet(expr.span),
-        ) {
-            err.span_suggestion(
-                expr.span,
-                "store this in the heap by calling `Box::new`",
-                format!("Box::new({})", snippet),
-                Applicability::MachineApplicable,
-            );
-            err.note(
-                "for more on the distinction between the stack and the heap, read \
-                 https://doc.rust-lang.org/book/ch15-01-box.html, \
-                 https://doc.rust-lang.org/rust-by-example/std/box.html, and \
-                 https://doc.rust-lang.org/std/boxed/index.html",
-            );
-        }
-    }
-
-    fn note_internal_mutation_in_method(
-        &self,
-        err: &mut DiagnosticBuilder<'_>,
-        expr: &hir::Expr<'_>,
-        expected: Ty<'tcx>,
-        found: Ty<'tcx>,
-    ) {
-        if found != self.tcx.types.unit {
-            return;
-        }
-        if let ExprKind::MethodCall(path_segment, _, [rcvr, ..], _) = expr.kind {
-            if self
-                .typeck_results
-                .borrow()
-                .expr_ty_adjusted_opt(rcvr)
-                .map_or(true, |ty| expected.peel_refs() != ty.peel_refs())
-            {
-                return;
-            }
-            let mut sp = MultiSpan::from_span(path_segment.ident.span);
-            sp.push_span_label(
-                path_segment.ident.span,
-                format!(
-                    "this call modifies {} in-place",
-                    match rcvr.kind {
-                        ExprKind::Path(QPath::Resolved(
-                            None,
-                            hir::Path { segments: [segment], .. },
-                        )) => format!("`{}`", segment.ident),
-                        _ => "its receiver".to_string(),
-                    }
-                ),
-            );
-            sp.push_span_label(
-                rcvr.span,
-                "you probably want to use this value after calling the method...".to_string(),
-            );
-            err.span_note(
-                sp,
-                &format!("method `{}` modifies its receiver in-place", path_segment.ident),
-            );
-            err.note(&format!("...instead of the `()` output of method `{}`", path_segment.ident));
-        }
-    }
-
-    /// When encountering an `impl Future` where `BoxFuture` is expected, suggest `Box::pin`.
-    fn suggest_calling_boxed_future_when_appropriate(
-        &self,
-        err: &mut DiagnosticBuilder<'_>,
-        expr: &hir::Expr<'_>,
-        expected: Ty<'tcx>,
-        found: Ty<'tcx>,
-    ) -> bool {
-        // Handle #68197.
-
-        if self.tcx.hir().is_inside_const_context(expr.hir_id) {
-            // Do not suggest `Box::new` in const context.
-            return false;
-        }
-        let pin_did = self.tcx.lang_items().pin_type();
-        match expected.kind() {
-            ty::Adt(def, _) if Some(def.did) != pin_did => return false,
-            // This guards the `unwrap` and `mk_box` below.
-            _ if pin_did.is_none() || self.tcx.lang_items().owned_box().is_none() => return false,
-            _ => {}
-        }
-        let boxed_found = self.tcx.mk_box(found);
-        let new_found = self.tcx.mk_lang_item(boxed_found, LangItem::Pin).unwrap();
-        if let (true, Ok(snippet)) = (
-            self.can_coerce(new_found, expected),
-            self.sess().source_map().span_to_snippet(expr.span),
-        ) {
-            match found.kind() {
-                ty::Adt(def, _) if def.is_box() => {
-                    err.help("use `Box::pin`");
-                }
-                _ => {
-                    err.span_suggestion(
-                        expr.span,
-                        "you need to pin and box this expression",
-                        format!("Box::pin({})", snippet),
-                        Applicability::MachineApplicable,
-                    );
-                }
-            }
-            true
-        } else {
-            false
-        }
-    }
-
-    /// A common error is to forget to add a semicolon at the end of a block, e.g.,
-    ///
-    /// ```
-    /// fn foo() {
-    ///     bar_that_returns_u32()
-    /// }
-    /// ```
-    ///
-    /// This routine checks if the return expression in a block would make sense on its own as a
-    /// statement and the return type has been left as default or has been specified as `()`. If so,
-    /// it suggests adding a semicolon.
-    fn suggest_missing_semicolon(
-        &self,
-        err: &mut DiagnosticBuilder<'_>,
-        expression: &'tcx hir::Expr<'tcx>,
-        expected: Ty<'tcx>,
-        cause_span: Span,
-    ) {
-        if expected.is_unit() {
-            // `BlockTailExpression` only relevant if the tail expr would be
-            // useful on its own.
-            match expression.kind {
-                ExprKind::Call(..)
-                | ExprKind::MethodCall(..)
-                | ExprKind::Loop(..)
-                | ExprKind::Match(..)
-                | ExprKind::Block(..) => {
-                    err.span_suggestion(
-                        cause_span.shrink_to_hi(),
-                        "try adding a semicolon",
-                        ";".to_string(),
-                        Applicability::MachineApplicable,
-                    );
-                }
-                _ => (),
-            }
-        }
-    }
-
-    /// A possible error is to forget to add a return type that is needed:
-    ///
-    /// ```
-    /// fn foo() {
-    ///     bar_that_returns_u32()
-    /// }
-    /// ```
-    ///
-    /// This routine checks if the return type is left as default, the method is not part of an
-    /// `impl` block and that it isn't the `main` method. If so, it suggests setting the return
-    /// type.
-    fn suggest_missing_return_type(
-        &self,
-        err: &mut DiagnosticBuilder<'_>,
-        fn_decl: &hir::FnDecl<'_>,
-        expected: Ty<'tcx>,
-        found: Ty<'tcx>,
-        can_suggest: bool,
-    ) -> bool {
-        // Only suggest changing the return type for methods that
-        // haven't set a return type at all (and aren't `fn main()` or an impl).
-        match (&fn_decl.output, found.is_suggestable(), can_suggest, expected.is_unit()) {
-            (&hir::FnRetTy::DefaultReturn(span), true, true, true) => {
-                err.span_suggestion(
-                    span,
-                    "try adding a return type",
-                    format!("-> {} ", self.resolve_vars_with_obligations(found)),
-                    Applicability::MachineApplicable,
-                );
-                true
-            }
-            (&hir::FnRetTy::DefaultReturn(span), false, true, true) => {
-                err.span_label(span, "possibly return type missing here?");
-                true
-            }
-            (&hir::FnRetTy::DefaultReturn(span), _, false, true) => {
-                // `fn main()` must return `()`, do not suggest changing return type
-                err.span_label(span, "expected `()` because of default return type");
-                true
-            }
-            // expectation was caused by something else, not the default return
-            (&hir::FnRetTy::DefaultReturn(_), _, _, false) => false,
-            (&hir::FnRetTy::Return(ref ty), _, _, _) => {
-                // Only point to return type if the expected type is the return type, as if they
-                // are not, the expectation must have been caused by something else.
-                debug!("suggest_missing_return_type: return type {:?} node {:?}", ty, ty.kind);
-                let sp = ty.span;
-                let ty = AstConv::ast_ty_to_ty(self, ty);
-                debug!("suggest_missing_return_type: return type {:?}", ty);
-                debug!("suggest_missing_return_type: expected type {:?}", ty);
-                if ty.kind() == expected.kind() {
-                    err.span_label(sp, format!("expected `{}` because of return type", expected));
-                    return true;
-                }
-                false
-            }
-        }
-    }
-
-    /// A possible error is to forget to add `.await` when using futures:
-    ///
-    /// ```
-    /// async fn make_u32() -> u32 {
-    ///     22
-    /// }
-    ///
-    /// fn take_u32(x: u32) {}
-    ///
-    /// async fn foo() {
-    ///     let x = make_u32();
-    ///     take_u32(x);
-    /// }
-    /// ```
-    ///
-    /// This routine checks if the found type `T` implements `Future<Output=U>` where `U` is the
-    /// expected type. If this is the case, and we are inside of an async body, it suggests adding
-    /// `.await` to the tail of the expression.
-    fn suggest_missing_await(
-        &self,
-        err: &mut DiagnosticBuilder<'_>,
-        expr: &hir::Expr<'_>,
-        expected: Ty<'tcx>,
-        found: Ty<'tcx>,
-    ) {
-        debug!("suggest_missing_await: expr={:?} expected={:?}, found={:?}", expr, expected, found);
-        // `.await` is not permitted outside of `async` bodies, so don't bother to suggest if the
-        // body isn't `async`.
-        let item_id = self.tcx().hir().get_parent_node(self.body_id);
-        if let Some(body_id) = self.tcx().hir().maybe_body_owned_by(item_id) {
-            let body = self.tcx().hir().body(body_id);
-            if let Some(hir::GeneratorKind::Async(_)) = body.generator_kind {
-                let sp = expr.span;
-                // Check for `Future` implementations by constructing a predicate to
-                // prove: `<T as Future>::Output == U`
-                let future_trait = self.tcx.require_lang_item(LangItem::Future, Some(sp));
-                let item_def_id = self
-                    .tcx
-                    .associated_items(future_trait)
-                    .in_definition_order()
-                    .next()
-                    .unwrap()
-                    .def_id;
-                // `<T as Future>::Output`
-                let projection_ty = ty::ProjectionTy {
-                    // `T`
-                    substs: self
-                        .tcx
-                        .mk_substs_trait(found, self.fresh_substs_for_item(sp, item_def_id)),
-                    // `Future::Output`
-                    item_def_id,
-                };
-
-                let predicate = ty::PredicateAtom::Projection(ty::ProjectionPredicate {
-                    projection_ty,
-                    ty: expected,
-                })
-                .potentially_quantified(self.tcx, ty::PredicateKind::ForAll);
-                let obligation = traits::Obligation::new(self.misc(sp), self.param_env, predicate);
-
-                debug!("suggest_missing_await: trying obligation {:?}", obligation);
-
-                if self.infcx.predicate_may_hold(&obligation) {
-                    debug!("suggest_missing_await: obligation held: {:?}", obligation);
-                    if let Ok(code) = self.sess().source_map().span_to_snippet(sp) {
-                        err.span_suggestion(
-                            sp,
-                            "consider using `.await` here",
-                            format!("{}.await", code),
-                            Applicability::MaybeIncorrect,
-                        );
-                    } else {
-                        debug!("suggest_missing_await: no snippet for {:?}", sp);
-                    }
-                } else {
-                    debug!("suggest_missing_await: obligation did not hold: {:?}", obligation)
-                }
-            }
-        }
-    }
-
-    fn suggest_missing_parentheses(&self, err: &mut DiagnosticBuilder<'_>, expr: &hir::Expr<'_>) {
-        let sp = self.tcx.sess.source_map().start_point(expr.span);
-        if let Some(sp) = self.tcx.sess.parse_sess.ambiguous_block_expr_parse.borrow().get(&sp) {
-            // `{ 42 } &&x` (#61475) or `{ 42 } && if x { 1 } else { 0 }`
-            self.tcx.sess.parse_sess.expr_parentheses_needed(err, *sp, None);
-        }
-    }
-
-    fn note_need_for_fn_pointer(
-        &self,
-        err: &mut DiagnosticBuilder<'_>,
-        expected: Ty<'tcx>,
-        found: Ty<'tcx>,
-    ) {
-        let (sig, did, substs) = match (&expected.kind(), &found.kind()) {
-            (ty::FnDef(did1, substs1), ty::FnDef(did2, substs2)) => {
-                let sig1 = self.tcx.fn_sig(*did1).subst(self.tcx, substs1);
-                let sig2 = self.tcx.fn_sig(*did2).subst(self.tcx, substs2);
-                if sig1 != sig2 {
-                    return;
-                }
-                err.note(
-                    "different `fn` items always have unique types, even if their signatures are \
-                     the same",
-                );
-                (sig1, *did1, substs1)
-            }
-            (ty::FnDef(did, substs), ty::FnPtr(sig2)) => {
-                let sig1 = self.tcx.fn_sig(*did).subst(self.tcx, substs);
-                if sig1 != *sig2 {
-                    return;
-                }
-                (sig1, *did, substs)
-            }
-            _ => return,
-        };
-        err.help(&format!("change the expected type to be function pointer `{}`", sig));
-        err.help(&format!(
-            "if the expected type is due to type inference, cast the expected `fn` to a function \
-             pointer: `{} as {}`",
-            self.tcx.def_path_str_with_substs(did, substs),
-            sig
-        ));
-    }
-
-    /// A common error is to add an extra semicolon:
-    ///
-    /// ```
-    /// fn foo() -> usize {
-    ///     22;
-    /// }
-    /// ```
-    ///
-    /// This routine checks if the final statement in a block is an
-    /// expression with an explicit semicolon whose type is compatible
-    /// with `expected_ty`. If so, it suggests removing the semicolon.
-    fn consider_hint_about_removing_semicolon(
-        &self,
-        blk: &'tcx hir::Block<'tcx>,
-        expected_ty: Ty<'tcx>,
-        err: &mut DiagnosticBuilder<'_>,
-    ) {
-        if let Some(span_semi) = self.could_remove_semicolon(blk, expected_ty) {
-            err.span_suggestion(
-                span_semi,
-                "consider removing this semicolon",
-                String::new(),
-                Applicability::MachineApplicable,
-            );
-        }
-    }
-
-    fn could_remove_semicolon(
-        &self,
-        blk: &'tcx hir::Block<'tcx>,
-        expected_ty: Ty<'tcx>,
-    ) -> Option<Span> {
-        // Be helpful when the user wrote `{... expr;}` and
-        // taking the `;` off is enough to fix the error.
-        let last_stmt = blk.stmts.last()?;
-        let last_expr = match last_stmt.kind {
-            hir::StmtKind::Semi(ref e) => e,
-            _ => return None,
-        };
-        let last_expr_ty = self.node_ty(last_expr.hir_id);
-        if matches!(last_expr_ty.kind(), ty::Error(_))
-            || self.can_sub(self.param_env, last_expr_ty, expected_ty).is_err()
-        {
-            return None;
-        }
-        let original_span = original_sp(last_stmt.span, blk.span);
-        Some(original_span.with_lo(original_span.hi() - BytePos(1)))
-    }
-
-    // Instantiates the given path, which must refer to an item with the given
-    // number of type parameters and type.
-    pub fn instantiate_value_path(
-        &self,
-        segments: &[hir::PathSegment<'_>],
-        self_ty: Option<Ty<'tcx>>,
-        res: Res,
-        span: Span,
-        hir_id: hir::HirId,
-    ) -> (Ty<'tcx>, Res) {
-        debug!(
-            "instantiate_value_path(segments={:?}, self_ty={:?}, res={:?}, hir_id={})",
-            segments, self_ty, res, hir_id,
-        );
-
-        let tcx = self.tcx;
-
-        let path_segs = match res {
-            Res::Local(_) | Res::SelfCtor(_) => vec![],
-            Res::Def(kind, def_id) => {
-                AstConv::def_ids_for_value_path_segments(self, segments, self_ty, kind, def_id)
-            }
-            _ => bug!("instantiate_value_path on {:?}", res),
-        };
-
-        let mut user_self_ty = None;
-        let mut is_alias_variant_ctor = false;
-        match res {
-            Res::Def(DefKind::Ctor(CtorOf::Variant, _), _) => {
-                if let Some(self_ty) = self_ty {
-                    let adt_def = self_ty.ty_adt_def().unwrap();
-                    user_self_ty = Some(UserSelfTy { impl_def_id: adt_def.did, self_ty });
-                    is_alias_variant_ctor = true;
-                }
-            }
-            Res::Def(DefKind::AssocFn | DefKind::AssocConst, def_id) => {
-                let container = tcx.associated_item(def_id).container;
-                debug!("instantiate_value_path: def_id={:?} container={:?}", def_id, container);
-                match container {
-                    ty::TraitContainer(trait_did) => {
-                        callee::check_legal_trait_for_method_call(tcx, span, None, trait_did)
-                    }
-                    ty::ImplContainer(impl_def_id) => {
-                        if segments.len() == 1 {
-                            // `<T>::assoc` will end up here, and so
-                            // can `T::assoc`. It this came from an
-                            // inherent impl, we need to record the
-                            // `T` for posterity (see `UserSelfTy` for
-                            // details).
-                            let self_ty = self_ty.expect("UFCS sugared assoc missing Self");
-                            user_self_ty = Some(UserSelfTy { impl_def_id, self_ty });
-                        }
-                    }
-                }
-            }
-            _ => {}
-        }
-
-        // Now that we have categorized what space the parameters for each
-        // segment belong to, let's sort out the parameters that the user
-        // provided (if any) into their appropriate spaces. We'll also report
-        // errors if type parameters are provided in an inappropriate place.
-
-        let generic_segs: FxHashSet<_> = path_segs.iter().map(|PathSeg(_, index)| index).collect();
-        let generics_has_err = AstConv::prohibit_generics(
-            self,
-            segments.iter().enumerate().filter_map(|(index, seg)| {
-                if !generic_segs.contains(&index) || is_alias_variant_ctor {
-                    Some(seg)
-                } else {
-                    None
-                }
-            }),
-        );
-
-        if let Res::Local(hid) = res {
-            let ty = self.local_ty(span, hid).decl_ty;
-            let ty = self.normalize_associated_types_in(span, &ty);
-            self.write_ty(hir_id, ty);
-            return (ty, res);
-        }
-
-        if generics_has_err {
-            // Don't try to infer type parameters when prohibited generic arguments were given.
-            user_self_ty = None;
-        }
-
-        // Now we have to compare the types that the user *actually*
-        // provided against the types that were *expected*. If the user
-        // did not provide any types, then we want to substitute inference
-        // variables. If the user provided some types, we may still need
-        // to add defaults. If the user provided *too many* types, that's
-        // a problem.
-
-        let mut infer_args_for_err = FxHashSet::default();
-        for &PathSeg(def_id, index) in &path_segs {
-            let seg = &segments[index];
-            let generics = tcx.generics_of(def_id);
-            // Argument-position `impl Trait` is treated as a normal generic
-            // parameter internally, but we don't allow users to specify the
-            // parameter's value explicitly, so we have to do some error-
-            // checking here.
-            if let GenericArgCountResult {
-                correct: Err(GenericArgCountMismatch { reported: Some(ErrorReported), .. }),
-                ..
-            } = AstConv::check_generic_arg_count_for_call(
-                tcx, span, &generics, &seg, false, // `is_method_call`
-            ) {
-                infer_args_for_err.insert(index);
-                self.set_tainted_by_errors(); // See issue #53251.
-            }
-        }
-
-        let has_self = path_segs
-            .last()
-            .map(|PathSeg(def_id, _)| tcx.generics_of(*def_id).has_self)
-            .unwrap_or(false);
-
-        let (res, self_ctor_substs) = if let Res::SelfCtor(impl_def_id) = res {
-            let ty = self.normalize_ty(span, tcx.at(span).type_of(impl_def_id));
-            match *ty.kind() {
-                ty::Adt(adt_def, substs) if adt_def.has_ctor() => {
-                    let variant = adt_def.non_enum_variant();
-                    let ctor_def_id = variant.ctor_def_id.unwrap();
-                    (
-                        Res::Def(DefKind::Ctor(CtorOf::Struct, variant.ctor_kind), ctor_def_id),
-                        Some(substs),
-                    )
-                }
-                _ => {
-                    let mut err = tcx.sess.struct_span_err(
-                        span,
-                        "the `Self` constructor can only be used with tuple or unit structs",
-                    );
-                    if let Some(adt_def) = ty.ty_adt_def() {
-                        match adt_def.adt_kind() {
-                            AdtKind::Enum => {
-                                err.help("did you mean to use one of the enum's variants?");
-                            }
-                            AdtKind::Struct | AdtKind::Union => {
-                                err.span_suggestion(
-                                    span,
-                                    "use curly brackets",
-                                    String::from("Self { /* fields */ }"),
-                                    Applicability::HasPlaceholders,
-                                );
-                            }
-                        }
-                    }
-                    err.emit();
-
-                    return (tcx.ty_error(), res);
-                }
-            }
-        } else {
-            (res, None)
-        };
-        let def_id = res.def_id();
-
-        // The things we are substituting into the type should not contain
-        // escaping late-bound regions, and nor should the base type scheme.
-        let ty = tcx.type_of(def_id);
-
-        let arg_count = GenericArgCountResult {
-            explicit_late_bound: ExplicitLateBound::No,
-            correct: if infer_args_for_err.is_empty() {
-                Ok(())
-            } else {
-                Err(GenericArgCountMismatch::default())
-            },
-        };
-
-        let substs = self_ctor_substs.unwrap_or_else(|| {
-            AstConv::create_substs_for_generic_args(
-                tcx,
-                def_id,
-                &[][..],
-                has_self,
-                self_ty,
-                arg_count,
-                // Provide the generic args, and whether types should be inferred.
-                |def_id| {
-                    if let Some(&PathSeg(_, index)) =
-                        path_segs.iter().find(|&PathSeg(did, _)| *did == def_id)
-                    {
-                        // If we've encountered an `impl Trait`-related error, we're just
-                        // going to infer the arguments for better error messages.
-                        if !infer_args_for_err.contains(&index) {
-                            // Check whether the user has provided generic arguments.
-                            if let Some(ref data) = segments[index].args {
-                                return (Some(data), segments[index].infer_args);
-                            }
-                        }
-                        return (None, segments[index].infer_args);
-                    }
-
-                    (None, true)
-                },
-                // Provide substitutions for parameters for which (valid) arguments have been provided.
-                |param, arg| match (&param.kind, arg) {
-                    (GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => {
-                        AstConv::ast_region_to_region(self, lt, Some(param)).into()
-                    }
-                    (GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => {
-                        self.to_ty(ty).into()
-                    }
-                    (GenericParamDefKind::Const, GenericArg::Const(ct)) => {
-                        self.const_arg_to_const(&ct.value, param.def_id).into()
-                    }
-                    _ => unreachable!(),
-                },
-                // Provide substitutions for parameters for which arguments are inferred.
-                |substs, param, infer_args| {
-                    match param.kind {
-                        GenericParamDefKind::Lifetime => {
-                            self.re_infer(Some(param), span).unwrap().into()
-                        }
-                        GenericParamDefKind::Type { has_default, .. } => {
-                            if !infer_args && has_default {
-                                // If we have a default, then we it doesn't matter that we're not
-                                // inferring the type arguments: we provide the default where any
-                                // is missing.
-                                let default = tcx.type_of(param.def_id);
-                                self.normalize_ty(
-                                    span,
-                                    default.subst_spanned(tcx, substs.unwrap(), Some(span)),
-                                )
-                                .into()
-                            } else {
-                                // If no type arguments were provided, we have to infer them.
-                                // This case also occurs as a result of some malformed input, e.g.
-                                // a lifetime argument being given instead of a type parameter.
-                                // Using inference instead of `Error` gives better error messages.
-                                self.var_for_def(span, param)
-                            }
-                        }
-                        GenericParamDefKind::Const => {
-                            // FIXME(const_generics:defaults)
-                            // No const parameters were provided, we have to infer them.
-                            self.var_for_def(span, param)
-                        }
-                    }
-                },
-            )
-        });
-        assert!(!substs.has_escaping_bound_vars());
-        assert!(!ty.has_escaping_bound_vars());
-
-        // First, store the "user substs" for later.
-        self.write_user_type_annotation_from_substs(hir_id, def_id, substs, user_self_ty);
-
-        self.add_required_obligations(span, def_id, &substs);
-
-        // Substitute the values for the type parameters into the type of
-        // the referenced item.
-        let ty_substituted = self.instantiate_type_scheme(span, &substs, &ty);
-
-        if let Some(UserSelfTy { impl_def_id, self_ty }) = user_self_ty {
-            // In the case of `Foo<T>::method` and `<Foo<T>>::method`, if `method`
-            // is inherent, there is no `Self` parameter; instead, the impl needs
-            // type parameters, which we can infer by unifying the provided `Self`
-            // with the substituted impl type.
-            // This also occurs for an enum variant on a type alias.
-            let ty = tcx.type_of(impl_def_id);
-
-            let impl_ty = self.instantiate_type_scheme(span, &substs, &ty);
-            match self.at(&self.misc(span), self.param_env).sup(impl_ty, self_ty) {
-                Ok(ok) => self.register_infer_ok_obligations(ok),
-                Err(_) => {
-                    self.tcx.sess.delay_span_bug(
-                        span,
-                        &format!(
-                        "instantiate_value_path: (UFCS) {:?} was a subtype of {:?} but now is not?",
-                        self_ty,
-                        impl_ty,
-                    ),
-                    );
-                }
-            }
-        }
-
-        self.check_rustc_args_require_const(def_id, hir_id, span);
-
-        debug!("instantiate_value_path: type of {:?} is {:?}", hir_id, ty_substituted);
-        self.write_substs(hir_id, substs);
-
-        (ty_substituted, res)
-    }
-
-    /// Add all the obligations that are required, substituting and normalized appropriately.
-    fn add_required_obligations(&self, span: Span, def_id: DefId, substs: &SubstsRef<'tcx>) {
-        let (bounds, spans) = self.instantiate_bounds(span, def_id, &substs);
-
-        for (i, mut obligation) in traits::predicates_for_generics(
-            traits::ObligationCause::new(span, self.body_id, traits::ItemObligation(def_id)),
-            self.param_env,
-            bounds,
-        )
-        .enumerate()
-        {
-            // This makes the error point at the bound, but we want to point at the argument
-            if let Some(span) = spans.get(i) {
-                obligation.cause.make_mut().code = traits::BindingObligation(def_id, *span);
-            }
-            self.register_predicate(obligation);
-        }
-    }
-
-    fn check_rustc_args_require_const(&self, def_id: DefId, hir_id: hir::HirId, span: Span) {
-        // We're only interested in functions tagged with
-        // #[rustc_args_required_const], so ignore anything that's not.
-        if !self.tcx.has_attr(def_id, sym::rustc_args_required_const) {
-            return;
-        }
-
-        // If our calling expression is indeed the function itself, we're good!
-        // If not, generate an error that this can only be called directly.
-        if let Node::Expr(expr) = self.tcx.hir().get(self.tcx.hir().get_parent_node(hir_id)) {
-            if let ExprKind::Call(ref callee, ..) = expr.kind {
-                if callee.hir_id == hir_id {
-                    return;
-                }
-            }
-        }
-
-        self.tcx.sess.span_err(
-            span,
-            "this function can only be invoked directly, not through a function pointer",
-        );
-    }
-
-    /// Resolves `typ` by a single level if `typ` is a type variable.
-    /// If no resolution is possible, then an error is reported.
-    /// Numeric inference variables may be left unresolved.
-    pub fn structurally_resolved_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
-        let ty = self.resolve_vars_with_obligations(ty);
-        if !ty.is_ty_var() {
-            ty
-        } else {
-            if !self.is_tainted_by_errors() {
-                self.need_type_info_err((**self).body_id, sp, ty, E0282)
-                    .note("type must be known at this point")
-                    .emit();
-            }
-            let err = self.tcx.ty_error();
-            self.demand_suptype(sp, err, ty);
-            err
-        }
-    }
+/// A wrapper for `InferCtxt`'s `in_progress_typeck_results` field.
+#[derive(Copy, Clone)]
+struct MaybeInProgressTables<'a, 'tcx> {
+    maybe_typeck_results: Option<&'a RefCell<ty::TypeckResults<'tcx>>>,
+}
 
-    fn with_breakable_ctxt<F: FnOnce() -> R, R>(
-        &self,
-        id: hir::HirId,
-        ctxt: BreakableCtxt<'tcx>,
-        f: F,
-    ) -> (BreakableCtxt<'tcx>, R) {
-        let index;
-        {
-            let mut enclosing_breakables = self.enclosing_breakables.borrow_mut();
-            index = enclosing_breakables.stack.len();
-            enclosing_breakables.by_id.insert(id, index);
-            enclosing_breakables.stack.push(ctxt);
+impl<'a, 'tcx> MaybeInProgressTables<'a, 'tcx> {
+    fn borrow(self) -> Ref<'a, ty::TypeckResults<'tcx>> {
+        match self.maybe_typeck_results {
+            Some(typeck_results) => typeck_results.borrow(),
+            None => bug!(
+                "MaybeInProgressTables: inh/fcx.typeck_results.borrow() with no typeck results"
+            ),
         }
-        let result = f();
-        let ctxt = {
-            let mut enclosing_breakables = self.enclosing_breakables.borrow_mut();
-            debug_assert!(enclosing_breakables.stack.len() == index + 1);
-            enclosing_breakables.by_id.remove(&id).expect("missing breakable context");
-            enclosing_breakables.stack.pop().expect("missing breakable context")
-        };
-        (ctxt, result)
-    }
-
-    /// Instantiate a QueryResponse in a probe context, without a
-    /// good ObligationCause.
-    fn probe_instantiate_query_response(
-        &self,
-        span: Span,
-        original_values: &OriginalQueryValues<'tcx>,
-        query_result: &Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>,
-    ) -> InferResult<'tcx, Ty<'tcx>> {
-        self.instantiate_query_response_and_region_obligations(
-            &traits::ObligationCause::misc(span, self.body_id),
-            self.param_env,
-            original_values,
-            query_result,
-        )
     }
 
-    /// Returns `true` if an expression is contained inside the LHS of an assignment expression.
-    fn expr_in_place(&self, mut expr_id: hir::HirId) -> bool {
-        let mut contained_in_place = false;
-
-        while let hir::Node::Expr(parent_expr) =
-            self.tcx.hir().get(self.tcx.hir().get_parent_node(expr_id))
-        {
-            match &parent_expr.kind {
-                hir::ExprKind::Assign(lhs, ..) | hir::ExprKind::AssignOp(_, lhs, ..) => {
-                    if lhs.hir_id == expr_id {
-                        contained_in_place = true;
-                        break;
-                    }
-                }
-                _ => (),
-            }
-            expr_id = parent_expr.hir_id;
+    fn borrow_mut(self) -> RefMut<'a, ty::TypeckResults<'tcx>> {
+        match self.maybe_typeck_results {
+            Some(typeck_results) => typeck_results.borrow_mut(),
+            None => bug!(
+                "MaybeInProgressTables: inh/fcx.typeck_results.borrow_mut() with no typeck results"
+            ),
         }
-
-        contained_in_place
     }
 }
 
-fn check_type_params_are_used<'tcx>(tcx: TyCtxt<'tcx>, generics: &ty::Generics, ty: Ty<'tcx>) {
-    debug!("check_type_params_are_used(generics={:?}, ty={:?})", generics, ty);
-
-    assert_eq!(generics.parent, None);
-
-    if generics.own_counts().types == 0 {
-        return;
-    }
-
-    let mut params_used = BitSet::new_empty(generics.params.len());
-
-    if ty.references_error() {
-        // If there is already another error, do not emit
-        // an error for not using a type parameter.
-        assert!(tcx.sess.has_errors());
-        return;
-    }
+struct CheckItemTypesVisitor<'tcx> {
+    tcx: TyCtxt<'tcx>,
+}
 
-    for leaf in ty.walk() {
-        if let GenericArgKind::Type(leaf_ty) = leaf.unpack() {
-            if let ty::Param(param) = leaf_ty.kind() {
-                debug!("found use of ty param {:?}", param);
-                params_used.insert(param.index);
-            }
-        }
+impl ItemLikeVisitor<'tcx> for CheckItemTypesVisitor<'tcx> {
+    fn visit_item(&mut self, i: &'tcx hir::Item<'tcx>) {
+        check_item_type(self.tcx, i);
     }
+    fn visit_trait_item(&mut self, _: &'tcx hir::TraitItem<'tcx>) {}
+    fn visit_impl_item(&mut self, _: &'tcx hir::ImplItem<'tcx>) {}
+}
 
-    for param in &generics.params {
-        if !params_used.contains(param.index) {
-            if let ty::GenericParamDefKind::Type { .. } = param.kind {
-                let span = tcx.def_span(param.def_id);
-                struct_span_err!(
-                    tcx.sess,
-                    span,
-                    E0091,
-                    "type parameter `{}` is unused",
-                    param.name,
-                )
-                .span_label(span, "unused type parameter")
-                .emit();
-            }
-        }
-    }
+fn typeck_item_bodies(tcx: TyCtxt<'_>, crate_num: CrateNum) {
+    debug_assert!(crate_num == LOCAL_CRATE);
+    tcx.par_body_owners(|body_owner_def_id| {
+        tcx.ensure().typeck(body_owner_def_id);
+    });
 }
 
 fn fatally_break_rust(sess: &Session) {