//! Code to extract the universally quantified regions declared on a
//! function and the relationships between them. For example:
//!
//! ```
//! fn foo<'a, 'b, 'c: 'b>() { }
//! ```
//!
//! here we would be returning a map assigning each of `{'a, 'b, 'c}`
//! to an index, as well as the `FreeRegionMap` which can compute
//! relationships between them.
//!
//! The code in this file doesn't *do anything* with those results; it
//! just returns them for other code to use.

use either::Either;
use rustc::hir::def_id::DefId;
use rustc::hir::{self, BodyOwnerKind, HirId};
use rustc::infer::{InferCtxt, NLLRegionVariableOrigin};
use rustc::middle::lang_items;
use rustc::ty::fold::TypeFoldable;
use rustc::ty::subst::{InternalSubsts, SubstsRef, Subst};
use rustc::ty::{self, RegionVid, Ty, TyCtxt};
use rustc::util::nodemap::FxHashMap;
use rustc_index::vec::{Idx, IndexVec};
use rustc_errors::DiagnosticBuilder;
use std::iter;

use super::ToRegionVid;

#[derive(Debug)]
pub struct UniversalRegions<'tcx> {
    indices: UniversalRegionIndices<'tcx>,

    /// The vid assigned to `'static`
    pub fr_static: RegionVid,

    /// A special region vid created to represent the current MIR fn
    /// body. It will outlive the entire CFG but it will not outlive
    /// any other universal regions.
    pub fr_fn_body: RegionVid,

    /// We create region variables such that they are ordered by their
    /// `RegionClassification`. The first block are globals, then
    /// externals, then locals. So, things from:
    /// - `FIRST_GLOBAL_INDEX..first_extern_index` are global,
    /// - `first_extern_index..first_local_index` are external,
    /// - `first_local_index..num_universals` are local.
    first_extern_index: usize,

    /// See `first_extern_index`.
    first_local_index: usize,

    /// The total number of universal region variables instantiated.
    num_universals: usize,

    /// The "defining" type for this function, with all universal
    /// regions instantiated. For a closure or generator, this is the
    /// closure type, but for a top-level function it's the `FnDef`.
    pub defining_ty: DefiningTy<'tcx>,

    /// The return type of this function, with all regions replaced by
    /// their universal `RegionVid` equivalents.
    ///
    /// N.B., associated types in this type have not been normalized,
    /// as the name suggests. =)
    pub unnormalized_output_ty: Ty<'tcx>,

    /// The fully liberated input types of this function, with all
    /// regions replaced by their universal `RegionVid` equivalents.
    ///
    /// N.B., associated types in these types have not been normalized,
    /// as the name suggests. =)
    pub unnormalized_input_tys: &'tcx [Ty<'tcx>],

    pub yield_ty: Option<Ty<'tcx>>,
}

/// The "defining type" for this MIR. The key feature of the "defining
/// type" is that it contains the information needed to derive all the
/// universal regions that are in scope as well as the types of the
/// inputs/output from the MIR. In general, early-bound universal
/// regions appear free in the defining type and late-bound regions
/// appear bound in the signature.
#[derive(Copy, Clone, Debug)]
pub enum DefiningTy<'tcx> {
    /// The MIR is a closure. The signature is found via
    /// `ClosureSubsts::closure_sig_ty`.
    Closure(DefId, SubstsRef<'tcx>),

    /// The MIR is a generator. The signature is that generators take
    /// no parameters and return the result of
    /// `ClosureSubsts::generator_return_ty`.
    Generator(DefId, SubstsRef<'tcx>, hir::Movability),

    /// The MIR is a fn item with the given `DefId` and substs. The signature
    /// of the function can be bound then with the `fn_sig` query.
    FnDef(DefId, SubstsRef<'tcx>),

    /// The MIR represents some form of constant. The signature then
    /// is that it has no inputs and a single return value, which is
    /// the value of the constant.
    Const(DefId, SubstsRef<'tcx>),
}

impl<'tcx> DefiningTy<'tcx> {
    /// Returns a list of all the upvar types for this MIR. If this is
    /// not a closure or generator, there are no upvars, and hence it
    /// will be an empty list. The order of types in this list will
    /// match up with the upvar order in the HIR, typesystem, and MIR.
    pub fn upvar_tys(self, tcx: TyCtxt<'tcx>) -> impl Iterator<Item = Ty<'tcx>> + 'tcx {
        match self {
            DefiningTy::Closure(def_id, substs) => Either::Left(
                substs.as_closure().upvar_tys(def_id, tcx)
            ),
            DefiningTy::Generator(def_id, substs, _) => {
                Either::Right(Either::Left(substs.as_generator().upvar_tys(def_id, tcx)))
            }
            DefiningTy::FnDef(..) | DefiningTy::Const(..) => {
                Either::Right(Either::Right(iter::empty()))
            }
        }
    }

    /// Number of implicit inputs -- notably the "environment"
    /// parameter for closures -- that appear in MIR but not in the
    /// user's code.
    pub fn implicit_inputs(self) -> usize {
        match self {
            DefiningTy::Closure(..) | DefiningTy::Generator(..) => 1,
            DefiningTy::FnDef(..) | DefiningTy::Const(..) => 0,
        }
    }
}

#[derive(Debug)]
struct UniversalRegionIndices<'tcx> {
    /// For those regions that may appear in the parameter environment
    /// ('static and early-bound regions), we maintain a map from the
    /// `ty::Region` to the internal `RegionVid` we are using. This is
    /// used because trait matching and type-checking will feed us
    /// region constraints that reference those regions and we need to
    /// be able to map them our internal `RegionVid`. This is
    /// basically equivalent to a `InternalSubsts`, except that it also
    /// contains an entry for `ReStatic` -- it might be nice to just
    /// use a substs, and then handle `ReStatic` another way.
    indices: FxHashMap<ty::Region<'tcx>, RegionVid>,
}

#[derive(Debug, PartialEq)]
pub enum RegionClassification {
    /// A **global** region is one that can be named from
    /// anywhere. There is only one, `'static`.
    Global,

    /// An **external** region is only relevant for closures. In that
    /// case, it refers to regions that are free in the closure type
    /// -- basically, something bound in the surrounding context.
    ///
    /// Consider this example:
    ///
    /// ```
    /// fn foo<'a, 'b>(a: &'a u32, b: &'b u32, c: &'static u32) {
    ///   let closure = for<'x> |x: &'x u32| { .. };
    ///                 ^^^^^^^ pretend this were legal syntax
    ///                         for declaring a late-bound region in
    ///                         a closure signature
    /// }
    /// ```
    ///
    /// Here, the lifetimes `'a` and `'b` would be **external** to the
    /// closure.
    ///
    /// If we are not analyzing a closure, there are no external
    /// lifetimes.
    External,

    /// A **local** lifetime is one about which we know the full set
    /// of relevant constraints (that is, relationships to other named
    /// regions). For a closure, this includes any region bound in
    /// the closure's signature. For a fn item, this includes all
    /// regions other than global ones.
    ///
    /// Continuing with the example from `External`, if we were
    /// analyzing the closure, then `'x` would be local (and `'a` and
    /// `'b` are external). If we are analyzing the function item
    /// `foo`, then `'a` and `'b` are local (and `'x` is not in
    /// scope).
    Local,
}

const FIRST_GLOBAL_INDEX: usize = 0;

impl<'tcx> UniversalRegions<'tcx> {
    /// Creates a new and fully initialized `UniversalRegions` that
    /// contains indices for all the free regions found in the given
    /// MIR -- that is, all the regions that appear in the function's
    /// signature. This will also compute the relationships that are
    /// known between those regions.
    pub fn new(
        infcx: &InferCtxt<'_, 'tcx>,
        mir_def_id: DefId,
        param_env: ty::ParamEnv<'tcx>,
    ) -> Self {
        let tcx = infcx.tcx;
        let mir_hir_id = tcx.hir().as_local_hir_id(mir_def_id).unwrap();
        UniversalRegionsBuilder {
            infcx,
            mir_def_id,
            mir_hir_id,
            param_env,
        }.build()
    }

    /// Given a reference to a closure type, extracts all the values
    /// from its free regions and returns a vector with them. This is
    /// used when the closure's creator checks that the
    /// `ClosureRegionRequirements` are met. The requirements from
    /// `ClosureRegionRequirements` are expressed in terms of
    /// `RegionVid` entries that map into the returned vector `V`: so
    /// if the `ClosureRegionRequirements` contains something like
    /// `'1: '2`, then the caller would impose the constraint that
    /// `V[1]: V[2]`.
    pub fn closure_mapping(
        tcx: TyCtxt<'tcx>,
        closure_substs: SubstsRef<'tcx>,
        expected_num_vars: usize,
        closure_base_def_id: DefId,
    ) -> IndexVec<RegionVid, ty::Region<'tcx>> {
        let mut region_mapping = IndexVec::with_capacity(expected_num_vars);
        region_mapping.push(tcx.lifetimes.re_static);
        tcx.for_each_free_region(&closure_substs, |fr| {
            region_mapping.push(fr);
        });

        for_each_late_bound_region_defined_on(tcx, closure_base_def_id, |r| {
            region_mapping.push(r);
        });

        assert_eq!(
            region_mapping.len(),
            expected_num_vars,
            "index vec had unexpected number of variables"
        );

        region_mapping
    }

    /// Returns `true` if `r` is a member of this set of universal regions.
    pub fn is_universal_region(&self, r: RegionVid) -> bool {
        (FIRST_GLOBAL_INDEX..self.num_universals).contains(&r.index())
    }

    /// Classifies `r` as a universal region, returning `None` if this
    /// is not a member of this set of universal regions.
    pub fn region_classification(&self, r: RegionVid) -> Option<RegionClassification> {
        let index = r.index();
        if (FIRST_GLOBAL_INDEX..self.first_extern_index).contains(&index) {
            Some(RegionClassification::Global)
        } else if (self.first_extern_index..self.first_local_index).contains(&index) {
            Some(RegionClassification::External)
        } else if (self.first_local_index..self.num_universals).contains(&index) {
            Some(RegionClassification::Local)
        } else {
            None
        }
    }

    /// Returns an iterator over all the RegionVids corresponding to
    /// universally quantified free regions.
    pub fn universal_regions(&self) -> impl Iterator<Item = RegionVid> {
        (FIRST_GLOBAL_INDEX..self.num_universals).map(RegionVid::new)
    }

    /// Returns `true` if `r` is classified as an local region.
    pub fn is_local_free_region(&self, r: RegionVid) -> bool {
        self.region_classification(r) == Some(RegionClassification::Local)
    }

    /// Returns the number of universal regions created in any category.
    pub fn len(&self) -> usize {
        self.num_universals
    }

    /// Returns the number of global plus external universal regions.
    /// For closures, these are the regions that appear free in the
    /// closure type (versus those bound in the closure
    /// signature). They are therefore the regions between which the
    /// closure may impose constraints that its creator must verify.
    pub fn num_global_and_external_regions(&self) -> usize {
        self.first_local_index
    }

    /// Gets an iterator over all the early-bound regions that have names.
    pub fn named_universal_regions<'s>(
        &'s self,
    ) -> impl Iterator<Item = (ty::Region<'tcx>, ty::RegionVid)> + 's {
        self.indices.indices.iter().map(|(&r, &v)| (r, v))
    }

    /// See `UniversalRegionIndices::to_region_vid`.
    pub fn to_region_vid(&self, r: ty::Region<'tcx>) -> RegionVid {
        self.indices.to_region_vid(r)
    }

    /// As part of the NLL unit tests, you can annotate a function with
    /// `#[rustc_regions]`, and we will emit information about the region
    /// inference context and -- in particular -- the external constraints
    /// that this region imposes on others. The methods in this file
    /// handle the part about dumping the inference context internal
    /// state.
    crate fn annotate(&self, tcx: TyCtxt<'tcx>, err: &mut DiagnosticBuilder<'_>) {
        match self.defining_ty {
            DefiningTy::Closure(def_id, substs) => {
                err.note(&format!(
                    "defining type: {:?} with closure substs {:#?}",
                    def_id,
                    &substs[..]
                ));

                // FIXME: It'd be nice to print the late-bound regions
                // here, but unfortunately these wind up stored into
                // tests, and the resulting print-outs include def-ids
                // and other things that are not stable across tests!
                // So we just include the region-vid. Annoying.
                let closure_base_def_id = tcx.closure_base_def_id(def_id);
                for_each_late_bound_region_defined_on(tcx, closure_base_def_id, |r| {
                    err.note(&format!(
                        "late-bound region is {:?}",
                        self.to_region_vid(r),
                    ));
                });
            }
            DefiningTy::Generator(def_id, substs, _) => {
                err.note(&format!(
                    "defining type: {:?} with generator substs {:#?}",
                    def_id,
                    &substs[..]
                ));

                // FIXME: As above, we'd like to print out the region
                // `r` but doing so is not stable across architectures
                // and so forth.
                let closure_base_def_id = tcx.closure_base_def_id(def_id);
                for_each_late_bound_region_defined_on(tcx, closure_base_def_id, |r| {
                    err.note(&format!(
                        "late-bound region is {:?}",
                        self.to_region_vid(r),
                    ));
                });
            }
            DefiningTy::FnDef(def_id, substs) => {
                err.note(&format!(
                    "defining type: {:?} with substs {:#?}",
                    def_id,
                    &substs[..]
                ));
            }
            DefiningTy::Const(def_id, substs) => {
                err.note(&format!(
                    "defining constant type: {:?} with substs {:#?}",
                    def_id,
                    &substs[..]
                ));
            }
        }
    }
}

struct UniversalRegionsBuilder<'cx, 'tcx> {
    infcx: &'cx InferCtxt<'cx, 'tcx>,
    mir_def_id: DefId,
    mir_hir_id: HirId,
    param_env: ty::ParamEnv<'tcx>,
}

const FR: NLLRegionVariableOrigin = NLLRegionVariableOrigin::FreeRegion;

impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
    fn build(self) -> UniversalRegions<'tcx> {
        debug!("build(mir_def_id={:?})", self.mir_def_id);

        let param_env = self.param_env;
        debug!("build: param_env={:?}", param_env);

        assert_eq!(FIRST_GLOBAL_INDEX, self.infcx.num_region_vars());

        // Create the "global" region that is always free in all contexts: 'static.
        let fr_static = self.infcx.next_nll_region_var(FR).to_region_vid();

        // We've now added all the global regions. The next ones we
        // add will be external.
        let first_extern_index = self.infcx.num_region_vars();

        let defining_ty = self.defining_ty();
        debug!("build: defining_ty={:?}", defining_ty);

        let mut indices = self.compute_indices(fr_static, defining_ty);
        debug!("build: indices={:?}", indices);

        let closure_base_def_id = self.infcx.tcx.closure_base_def_id(self.mir_def_id);

        // If this is a closure or generator, then the late-bound regions from the enclosing
        // function are actually external regions to us. For example, here, 'a is not local
        // to the closure c (although it is local to the fn foo):
        // fn foo<'a>() {
        //     let c = || { let x: &'a u32 = ...; }
        // }
        if self.mir_def_id != closure_base_def_id {
            self.infcx
                .replace_late_bound_regions_with_nll_infer_vars(self.mir_def_id, &mut indices)
        }

        let bound_inputs_and_output = self.compute_inputs_and_output(&indices, defining_ty);

        // "Liberate" the late-bound regions. These correspond to
        // "local" free regions.
        let first_local_index = self.infcx.num_region_vars();
        let inputs_and_output = self.infcx.replace_bound_regions_with_nll_infer_vars(
            FR,
            self.mir_def_id,
            &bound_inputs_and_output,
            &mut indices,
        );
        // Converse of above, if this is a function then the late-bound regions declared on its
        // signature are local to the fn.
        if self.mir_def_id == closure_base_def_id {
            self.infcx
                .replace_late_bound_regions_with_nll_infer_vars(self.mir_def_id, &mut indices);
        }

        let (unnormalized_output_ty, mut unnormalized_input_tys) =
            inputs_and_output.split_last().unwrap();

        // C-variadic fns also have a `VaList` input that's not listed in the signature
        // (as it's created inside the body itself, not passed in from outside).
        if let DefiningTy::FnDef(def_id, _) = defining_ty {
            if self.infcx.tcx.fn_sig(def_id).c_variadic() {
                let va_list_did = self.infcx.tcx.require_lang_item(
                    lang_items::VaListTypeLangItem,
                    Some(self.infcx.tcx.def_span(self.mir_def_id),),
                );
                let region = self.infcx.tcx.mk_region(ty::ReVar(
                    self.infcx.next_nll_region_var(FR).to_region_vid(),
                ));
                let va_list_ty = self.infcx.tcx.type_of(va_list_did)
                    .subst(self.infcx.tcx, &[region.into()]);

                unnormalized_input_tys = self.infcx.tcx.mk_type_list(
                    unnormalized_input_tys.iter().copied()
                        .chain(iter::once(va_list_ty)),
                );
            }
        }

        let fr_fn_body = self.infcx.next_nll_region_var(FR).to_region_vid();
        let num_universals = self.infcx.num_region_vars();

        debug!(
            "build: global regions = {}..{}",
            FIRST_GLOBAL_INDEX, first_extern_index
        );
        debug!(
            "build: extern regions = {}..{}",
            first_extern_index, first_local_index
        );
        debug!(
            "build: local regions  = {}..{}",
            first_local_index, num_universals
        );

        let yield_ty = match defining_ty {
            DefiningTy::Generator(def_id, substs, _) => {
                Some(substs.as_generator().yield_ty(def_id, self.infcx.tcx))
            }
            _ => None,
        };

        UniversalRegions {
            indices,
            fr_static,
            fr_fn_body,
            first_extern_index,
            first_local_index,
            num_universals,
            defining_ty,
            unnormalized_output_ty,
            unnormalized_input_tys,
            yield_ty: yield_ty,
        }
    }

    /// Returns the "defining type" of the current MIR;
    /// see `DefiningTy` for details.
    fn defining_ty(&self) -> DefiningTy<'tcx> {
        let tcx = self.infcx.tcx;
        let closure_base_def_id = tcx.closure_base_def_id(self.mir_def_id);

        match tcx.hir().body_owner_kind(self.mir_hir_id) {
            BodyOwnerKind::Closure |
            BodyOwnerKind::Fn => {
                let defining_ty = if self.mir_def_id == closure_base_def_id {
                    tcx.type_of(closure_base_def_id)
                } else {
                    let tables = tcx.typeck_tables_of(self.mir_def_id);
                    tables.node_type(self.mir_hir_id)
                };

                debug!("defining_ty (pre-replacement): {:?}", defining_ty);

                let defining_ty = self.infcx
                    .replace_free_regions_with_nll_infer_vars(FR, &defining_ty);

                match defining_ty.kind {
                    ty::Closure(def_id, substs) => DefiningTy::Closure(def_id, substs),
                    ty::Generator(def_id, substs, movability) => {
                        DefiningTy::Generator(def_id, substs, movability)
                    }
                    ty::FnDef(def_id, substs) => DefiningTy::FnDef(def_id, substs),
                    _ => span_bug!(
                        tcx.def_span(self.mir_def_id),
                        "expected defining type for `{:?}`: `{:?}`",
                        self.mir_def_id,
                        defining_ty
                    ),
                }
            }

            BodyOwnerKind::Const | BodyOwnerKind::Static(..) => {
                assert_eq!(closure_base_def_id, self.mir_def_id);
                let identity_substs = InternalSubsts::identity_for_item(tcx, closure_base_def_id);
                let substs = self.infcx
                    .replace_free_regions_with_nll_infer_vars(FR, &identity_substs);
                DefiningTy::Const(self.mir_def_id, substs)
            }
        }
    }

    /// Builds a hashmap that maps from the universal regions that are
    /// in scope (as a `ty::Region<'tcx>`) to their indices (as a
    /// `RegionVid`). The map returned by this function contains only
    /// the early-bound regions.
    fn compute_indices(
        &self,
        fr_static: RegionVid,
        defining_ty: DefiningTy<'tcx>,
    ) -> UniversalRegionIndices<'tcx> {
        let tcx = self.infcx.tcx;
        let closure_base_def_id = tcx.closure_base_def_id(self.mir_def_id);
        let identity_substs = InternalSubsts::identity_for_item(tcx, closure_base_def_id);
        let fr_substs = match defining_ty {
            DefiningTy::Closure(_, ref substs)
            | DefiningTy::Generator(_, ref substs, _) => {
                // In the case of closures, we rely on the fact that
                // the first N elements in the ClosureSubsts are
                // inherited from the `closure_base_def_id`.
                // Therefore, when we zip together (below) with
                // `identity_substs`, we will get only those regions
                // that correspond to early-bound regions declared on
                // the `closure_base_def_id`.
                assert!(substs.len() >= identity_substs.len());
                assert_eq!(substs.regions().count(), identity_substs.regions().count());
                substs
            }

            DefiningTy::FnDef(_, substs) | DefiningTy::Const(_, substs) => substs,
        };

        let global_mapping = iter::once((tcx.lifetimes.re_static, fr_static));
        let subst_mapping = identity_substs
            .regions()
            .zip(fr_substs.regions().map(|r| r.to_region_vid()));

        UniversalRegionIndices {
            indices: global_mapping.chain(subst_mapping).collect(),
        }
    }

    fn compute_inputs_and_output(
        &self,
        indices: &UniversalRegionIndices<'tcx>,
        defining_ty: DefiningTy<'tcx>,
    ) -> ty::Binder<&'tcx ty::List<Ty<'tcx>>> {
        let tcx = self.infcx.tcx;
        match defining_ty {
            DefiningTy::Closure(def_id, substs) => {
                assert_eq!(self.mir_def_id, def_id);
                let closure_sig = substs.as_closure().sig_ty(def_id, tcx).fn_sig(tcx);
                let inputs_and_output = closure_sig.inputs_and_output();
                let closure_ty = tcx.closure_env_ty(def_id, substs).unwrap();
                ty::Binder::fuse(
                    closure_ty,
                    inputs_and_output,
                    |closure_ty, inputs_and_output| {
                        // The "inputs" of the closure in the
                        // signature appear as a tuple.  The MIR side
                        // flattens this tuple.
                        let (&output, tuplized_inputs) = inputs_and_output.split_last().unwrap();
                        assert_eq!(tuplized_inputs.len(), 1, "multiple closure inputs");
                        let inputs = match tuplized_inputs[0].kind {
                            ty::Tuple(inputs) => inputs,
                            _ => bug!("closure inputs not a tuple: {:?}", tuplized_inputs[0]),
                        };

                        tcx.mk_type_list(
                            iter::once(closure_ty)
                                .chain(inputs.iter().map(|k| k.expect_ty()))
                                .chain(iter::once(output)),
                        )
                    },
                )
            }

            DefiningTy::Generator(def_id, substs, movability) => {
                assert_eq!(self.mir_def_id, def_id);
                let output = substs.as_generator().return_ty(def_id, tcx);
                let generator_ty = tcx.mk_generator(def_id, substs, movability);
                let inputs_and_output = self.infcx.tcx.intern_type_list(&[generator_ty, output]);
                ty::Binder::dummy(inputs_and_output)
            }

            DefiningTy::FnDef(def_id, _) => {
                let sig = tcx.fn_sig(def_id);
                let sig = indices.fold_to_region_vids(tcx, &sig);
                sig.inputs_and_output()
            }

            DefiningTy::Const(def_id, _) => {
                // For a constant body, there are no inputs, and one
                // "output" (the type of the constant).
                assert_eq!(self.mir_def_id, def_id);
                let ty = tcx.type_of(def_id);
                let ty = indices.fold_to_region_vids(tcx, &ty);
                ty::Binder::dummy(tcx.intern_type_list(&[ty]))
            }
        }
    }
}

trait InferCtxtExt<'tcx> {
    fn replace_free_regions_with_nll_infer_vars<T>(
        &self,
        origin: NLLRegionVariableOrigin,
        value: &T,
    ) -> T
    where
        T: TypeFoldable<'tcx>;

    fn replace_bound_regions_with_nll_infer_vars<T>(
        &self,
        origin: NLLRegionVariableOrigin,
        all_outlive_scope: DefId,
        value: &ty::Binder<T>,
        indices: &mut UniversalRegionIndices<'tcx>,
    ) -> T
    where
        T: TypeFoldable<'tcx>;

    fn replace_late_bound_regions_with_nll_infer_vars(
        &self,
        mir_def_id: DefId,
        indices: &mut UniversalRegionIndices<'tcx>,
    );
}

impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
    fn replace_free_regions_with_nll_infer_vars<T>(
        &self,
        origin: NLLRegionVariableOrigin,
        value: &T,
    ) -> T
    where
        T: TypeFoldable<'tcx>,
    {
        self.tcx.fold_regions(value, &mut false, |_region, _depth| {
            self.next_nll_region_var(origin)
        })
    }

    fn replace_bound_regions_with_nll_infer_vars<T>(
        &self,
        origin: NLLRegionVariableOrigin,
        all_outlive_scope: DefId,
        value: &ty::Binder<T>,
        indices: &mut UniversalRegionIndices<'tcx>,
    ) -> T
    where
        T: TypeFoldable<'tcx>,
    {
        debug!(
            "replace_bound_regions_with_nll_infer_vars(value={:?}, all_outlive_scope={:?})",
            value, all_outlive_scope,
        );
        let (value, _map) = self.tcx.replace_late_bound_regions(value, |br| {
            debug!("replace_bound_regions_with_nll_infer_vars: br={:?}", br);
            let liberated_region = self.tcx.mk_region(ty::ReFree(ty::FreeRegion {
                scope: all_outlive_scope,
                bound_region: br,
            }));
            let region_vid = self.next_nll_region_var(origin);
            indices.insert_late_bound_region(liberated_region, region_vid.to_region_vid());
            debug!(
                "replace_bound_regions_with_nll_infer_vars: liberated_region={:?} => {:?}",
                liberated_region, region_vid
            );
            region_vid
        });
        value
    }

    /// Finds late-bound regions that do not appear in the parameter listing and adds them to the
    /// indices vector. Typically, we identify late-bound regions as we process the inputs and
    /// outputs of the closure/function. However, sometimes there are late-bound regions which do
    /// not appear in the fn parameters but which are nonetheless in scope. The simplest case of
    /// this are unused functions, like fn foo<'a>() { } (see e.g., #51351). Despite not being used,
    /// users can still reference these regions (e.g., let x: &'a u32 = &22;), so we need to create
    /// entries for them and store them in the indices map. This code iterates over the complete
    /// set of late-bound regions and checks for any that we have not yet seen, adding them to the
    /// inputs vector.
    fn replace_late_bound_regions_with_nll_infer_vars(
        &self,
        mir_def_id: DefId,
        indices: &mut UniversalRegionIndices<'tcx>,
    ) {
        debug!(
            "replace_late_bound_regions_with_nll_infer_vars(mir_def_id={:?})",
            mir_def_id
        );
        let closure_base_def_id = self.tcx.closure_base_def_id(mir_def_id);
        for_each_late_bound_region_defined_on(self.tcx, closure_base_def_id, |r| {
            debug!("replace_late_bound_regions_with_nll_infer_vars: r={:?}", r);
            if !indices.indices.contains_key(&r) {
                let region_vid = self.next_nll_region_var(FR);
                indices.insert_late_bound_region(r, region_vid.to_region_vid());
            }
        });
    }
}

impl<'tcx> UniversalRegionIndices<'tcx> {
    /// Initially, the `UniversalRegionIndices` map contains only the
    /// early-bound regions in scope. Once that is all setup, we come
    /// in later and instantiate the late-bound regions, and then we
    /// insert the `ReFree` version of those into the map as
    /// well. These are used for error reporting.
    fn insert_late_bound_region(&mut self, r: ty::Region<'tcx>, vid: ty::RegionVid) {
        debug!("insert_late_bound_region({:?}, {:?})", r, vid);
        self.indices.insert(r, vid);
    }

    /// Converts `r` into a local inference variable: `r` can either
    /// by a `ReVar` (i.e., already a reference to an inference
    /// variable) or it can be `'static` or some early-bound
    /// region. This is useful when taking the results from
    /// type-checking and trait-matching, which may sometimes
    /// reference those regions from the `ParamEnv`. It is also used
    /// during initialization. Relies on the `indices` map having been
    /// fully initialized.
    pub fn to_region_vid(&self, r: ty::Region<'tcx>) -> RegionVid {
        if let ty::ReVar(..) = r {
            r.to_region_vid()
        } else {
            *self.indices
                .get(&r)
                .unwrap_or_else(|| bug!("cannot convert `{:?}` to a region vid", r))
        }
    }

    /// Replaces all free regions in `value` with region vids, as
    /// returned by `to_region_vid`.
    pub fn fold_to_region_vids<T>(&self, tcx: TyCtxt<'tcx>, value: &T) -> T
    where
        T: TypeFoldable<'tcx>,
    {
        tcx.fold_regions(value, &mut false, |region, _| {
            tcx.mk_region(ty::ReVar(self.to_region_vid(region)))
        })
    }
}

/// Iterates over the late-bound regions defined on fn_def_id and
/// invokes `f` with the liberated form of each one.
fn for_each_late_bound_region_defined_on<'tcx>(
    tcx: TyCtxt<'tcx>,
    fn_def_id: DefId,
    mut f: impl FnMut(ty::Region<'tcx>),
) {
    if let Some(late_bounds) = tcx.is_late_bound_map(fn_def_id.index) {
        for late_bound in late_bounds.iter() {
            let hir_id = HirId {
                owner: fn_def_id.index,
                local_id: *late_bound,
            };
            let name = tcx.hir().name(hir_id);
            let region_def_id = tcx.hir().local_def_id(hir_id);
            let liberated_region = tcx.mk_region(ty::ReFree(ty::FreeRegion {
                scope: fn_def_id,
                bound_region: ty::BoundRegion::BrNamed(region_def_id, name),
            }));
            f(liberated_region);
        }
    }
}
