compiler/rustc_borrowck/src/universal_regions.rs RUST 1,006 lines View on github.com → Search inside
1//! Code to extract the universally quantified regions declared on a2//! function. For example:3//!4//! ```5//! fn foo<'a, 'b, 'c: 'b>() { }6//! ```7//!8//! here we would return a map assigning each of `{'a, 'b, 'c}`9//! to an index.10//!11//! The code in this file doesn't *do anything* with those results; it12//! just returns them for other code to use.1314use std::cell::Cell;15use std::iter;1617use rustc_data_structures::fx::FxIndexMap;18use rustc_errors::Diag;19use rustc_hir::BodyOwnerKind;20use rustc_hir::def::DefKind;21use rustc_hir::def_id::{DefId, LocalDefId};22use rustc_hir::lang_items::LangItem;23use rustc_index::IndexVec;24use rustc_infer::infer::NllRegionVariableOrigin;25use rustc_macros::extension;26use rustc_middle::mir::RETURN_PLACE;27use rustc_middle::ty::print::with_no_trimmed_paths;28use rustc_middle::ty::{29    self, GenericArgs, GenericArgsRef, InlineConstArgs, InlineConstArgsParts, RegionVid, Ty,30    TyCtxt, TypeFoldable, TypeVisitableExt, fold_regions,31};32use rustc_middle::{bug, span_bug};33use rustc_span::{ErrorGuaranteed, kw, sym};34use tracing::{debug, instrument};3536use crate::BorrowckInferCtxt;37use crate::renumber::RegionCtxt;3839#[derive(Debug)]40#[derive(Clone)] // FIXME(#146079)41pub(crate) struct UniversalRegions<'tcx> {42    indices: UniversalRegionIndices<'tcx>,4344    /// The vid assigned to `'static`45    pub fr_static: RegionVid,4647    /// A special region vid created to represent the current MIR fn48    /// body. It will outlive the entire CFG but it will not outlive49    /// any other universal regions.50    pub fr_fn_body: RegionVid,5152    /// We create region variables such that they are ordered by their53    /// `RegionClassification`. The first block are globals, then54    /// externals, then locals. So, things from:55    /// - `FIRST_GLOBAL_INDEX..first_extern_index` are global,56    /// - `first_extern_index..first_local_index` are external,57    /// - `first_local_index..num_universals` are local.58    first_extern_index: usize,5960    /// See `first_extern_index`.61    first_local_index: usize,6263    /// The total number of universal region variables instantiated.64    num_universals: usize,6566    /// The "defining" type for this function, with all universal67    /// regions instantiated. For a closure or coroutine, this is the68    /// closure type, but for a top-level function it's the `FnDef`.69    pub defining_ty: DefiningTy<'tcx>,7071    /// The return type of this function, with all regions replaced by72    /// their universal `RegionVid` equivalents.73    ///74    /// N.B., associated types in this type have not been normalized,75    /// as the name suggests. =)76    pub unnormalized_output_ty: Ty<'tcx>,7778    /// The fully liberated input types of this function, with all79    /// regions replaced by their universal `RegionVid` equivalents.80    ///81    /// N.B., associated types in these types have not been normalized,82    /// as the name suggests. =)83    ///84    /// N.B., in the case of a closure, index 0 is the implicit self parameter,85    /// and not the first input as seen by the user.86    pub unnormalized_input_tys: &'tcx [Ty<'tcx>],8788    pub yield_ty: Option<Ty<'tcx>>,8990    pub resume_ty: Option<Ty<'tcx>>,91}9293/// The "defining type" for this MIR. The key feature of the "defining94/// type" is that it contains the information needed to derive all the95/// universal regions that are in scope as well as the types of the96/// inputs/output from the MIR. In general, early-bound universal97/// regions appear free in the defining type and late-bound regions98/// appear bound in the signature.99#[derive(Copy, Clone, Debug)]100pub(crate) enum DefiningTy<'tcx> {101    /// The MIR is a closure. The signature is found via102    /// `ClosureArgs::closure_sig_ty`.103    Closure(DefId, GenericArgsRef<'tcx>),104105    /// The MIR is a coroutine. The signature is that coroutines take106    /// no parameters and return the result of107    /// `ClosureArgs::coroutine_return_ty`.108    Coroutine(DefId, GenericArgsRef<'tcx>),109110    /// The MIR is a special kind of closure that returns coroutines.111    ///112    /// See the documentation on `CoroutineClosureSignature` for details113    /// on how to construct the callable signature of the coroutine from114    /// its args.115    CoroutineClosure(DefId, GenericArgsRef<'tcx>),116117    /// The MIR is a fn item with the given `DefId` and args. The signature118    /// of the function can be bound then with the `fn_sig` query.119    FnDef(DefId, GenericArgsRef<'tcx>),120121    /// The MIR represents some form of constant. The signature then122    /// is that it has no inputs and a single return value, which is123    /// the value of the constant.124    Const(DefId, GenericArgsRef<'tcx>),125126    /// The MIR represents an inline const. The signature has no inputs and a127    /// single return value found via `InlineConstArgs::ty`.128    InlineConst(DefId, GenericArgsRef<'tcx>),129130    // Fake body for a global asm. Not particularly useful or interesting,131    // but we need it so we can properly store the typeck results of the asm132    // operands, which aren't associated with a body otherwise.133    GlobalAsm(DefId),134}135136impl<'tcx> DefiningTy<'tcx> {137    /// Returns a list of all the upvar types for this MIR. If this is138    /// not a closure or coroutine, there are no upvars, and hence it139    /// will be an empty list. The order of types in this list will140    /// match up with the upvar order in the HIR, typesystem, and MIR.141    pub(crate) fn upvar_tys(self) -> &'tcx ty::List<Ty<'tcx>> {142        match self {143            DefiningTy::Closure(_, args) => args.as_closure().upvar_tys(),144            DefiningTy::CoroutineClosure(_, args) => args.as_coroutine_closure().upvar_tys(),145            DefiningTy::Coroutine(_, args) => args.as_coroutine().upvar_tys(),146            DefiningTy::FnDef(..)147            | DefiningTy::Const(..)148            | DefiningTy::InlineConst(..)149            | DefiningTy::GlobalAsm(_) => ty::List::empty(),150        }151    }152153    /// Number of implicit inputs -- notably the "environment"154    /// parameter for closures -- that appear in MIR but not in the155    /// user's code.156    pub(crate) fn implicit_inputs(self) -> usize {157        match self {158            DefiningTy::Closure(..)159            | DefiningTy::CoroutineClosure(..)160            | DefiningTy::Coroutine(..) => 1,161            DefiningTy::FnDef(..)162            | DefiningTy::Const(..)163            | DefiningTy::InlineConst(..)164            | DefiningTy::GlobalAsm(_) => 0,165        }166    }167168    pub(crate) fn is_fn_def(&self) -> bool {169        matches!(*self, DefiningTy::FnDef(..))170    }171172    pub(crate) fn is_const(&self) -> bool {173        matches!(*self, DefiningTy::Const(..) | DefiningTy::InlineConst(..))174    }175176    pub(crate) fn def_id(&self) -> DefId {177        match *self {178            DefiningTy::Closure(def_id, ..)179            | DefiningTy::CoroutineClosure(def_id, ..)180            | DefiningTy::Coroutine(def_id, ..)181            | DefiningTy::FnDef(def_id, ..)182            | DefiningTy::Const(def_id, ..)183            | DefiningTy::InlineConst(def_id, ..)184            | DefiningTy::GlobalAsm(def_id) => def_id,185        }186    }187188    /// Returns the args of the `DefiningTy`. These are equivalent to the identity189    /// substs of the body, but replaced with region vids.190    pub(crate) fn args(&self) -> ty::GenericArgsRef<'tcx> {191        match *self {192            DefiningTy::Closure(_, args)193            | DefiningTy::Coroutine(_, args)194            | DefiningTy::CoroutineClosure(_, args)195            | DefiningTy::FnDef(_, args)196            | DefiningTy::Const(_, args)197            | DefiningTy::InlineConst(_, args) => args,198            DefiningTy::GlobalAsm(_) => ty::List::empty(),199        }200    }201}202203#[derive(Debug)]204#[derive(Clone)] // FIXME(#146079)205struct UniversalRegionIndices<'tcx> {206    /// For those regions that may appear in the parameter environment207    /// ('static and early-bound regions), we maintain a map from the208    /// `ty::Region` to the internal `RegionVid` we are using. This is209    /// used because trait matching and type-checking will feed us210    /// region constraints that reference those regions and we need to211    /// be able to map them to our internal `RegionVid`.212    ///213    /// This is similar to just using `GenericArgs`, except that it contains214    /// an entry for `'static`, and also late bound parameters in scope.215    indices: FxIndexMap<ty::Region<'tcx>, RegionVid>,216217    /// The vid assigned to `'static`. Used only for diagnostics.218    pub fr_static: RegionVid,219220    /// Whether we've encountered an error region. If we have, cancel all221    /// outlives errors, as they are likely bogus.222    pub encountered_re_error: Cell<Option<ErrorGuaranteed>>,223}224225#[derive(Debug, PartialEq)]226pub(crate) enum RegionClassification {227    /// A **global** region is one that can be named from228    /// anywhere. There is only one, `'static`.229    Global,230231    /// An **external** region is only relevant for232    /// closures, coroutines, and inline consts. In that233    /// case, it refers to regions that are free in the type234    /// -- basically, something bound in the surrounding context.235    ///236    /// Consider this example:237    ///238    /// ```ignore (pseudo-rust)239    /// fn foo<'a, 'b>(a: &'a u32, b: &'b u32, c: &'static u32) {240    ///   let closure = for<'x> |x: &'x u32| { .. };241    ///    //           ^^^^^^^ pretend this were legal syntax242    ///    //                   for declaring a late-bound region in243    ///    //                   a closure signature244    /// }245    /// ```246    ///247    /// Here, the lifetimes `'a` and `'b` would be **external** to the248    /// closure.249    ///250    /// If we are not analyzing a closure/coroutine/inline-const,251    /// there are no external lifetimes.252    External,253254    /// A **local** lifetime is one about which we know the full set255    /// of relevant constraints (that is, relationships to other named256    /// regions). For a closure, this includes any region bound in257    /// the closure's signature. For a fn item, this includes all258    /// regions other than global ones.259    ///260    /// Continuing with the example from `External`, if we were261    /// analyzing the closure, then `'x` would be local (and `'a` and262    /// `'b` are external). If we are analyzing the function item263    /// `foo`, then `'a` and `'b` are local (and `'x` is not in264    /// scope).265    Local,266}267268const FIRST_GLOBAL_INDEX: usize = 0;269270impl<'tcx> UniversalRegions<'tcx> {271    /// Creates a new and fully initialized `UniversalRegions` that272    /// contains indices for all the free regions found in the given273    /// MIR -- that is, all the regions that appear in the function's274    /// signature.275    pub(crate) fn new(infcx: &BorrowckInferCtxt<'tcx>, mir_def: LocalDefId) -> Self {276        UniversalRegionsBuilder { infcx, mir_def }.build()277    }278279    /// Given a reference to a closure type, extracts all the values280    /// from its free regions and returns a vector with them. This is281    /// used when the closure's creator checks that the282    /// `ClosureRegionRequirements` are met. The requirements from283    /// `ClosureRegionRequirements` are expressed in terms of284    /// `RegionVid` entries that map into the returned vector `V`: so285    /// if the `ClosureRegionRequirements` contains something like286    /// `'1: '2`, then the caller would impose the constraint that287    /// `V[1]: V[2]`.288    pub(crate) fn closure_mapping(289        tcx: TyCtxt<'tcx>,290        closure_args: GenericArgsRef<'tcx>,291        expected_num_vars: usize,292        closure_def_id: LocalDefId,293    ) -> IndexVec<RegionVid, ty::Region<'tcx>> {294        let mut region_mapping = IndexVec::with_capacity(expected_num_vars);295        region_mapping.push(tcx.lifetimes.re_static);296        tcx.for_each_free_region(&closure_args, |fr| {297            region_mapping.push(fr);298        });299300        for_each_late_bound_region_in_recursive_scope(tcx, tcx.local_parent(closure_def_id), |r| {301            region_mapping.push(r);302        });303304        assert_eq!(305            region_mapping.len(),306            expected_num_vars,307            "index vec had unexpected number of variables"308        );309310        region_mapping311    }312313    /// Returns `true` if `r` is a member of this set of universal regions.314    pub(crate) fn is_universal_region(&self, r: RegionVid) -> bool {315        (FIRST_GLOBAL_INDEX..self.num_universals).contains(&r.index())316    }317318    /// Classifies `r` as a universal region, returning `None` if this319    /// is not a member of this set of universal regions.320    pub(crate) fn region_classification(&self, r: RegionVid) -> Option<RegionClassification> {321        let index = r.index();322        if (FIRST_GLOBAL_INDEX..self.first_extern_index).contains(&index) {323            Some(RegionClassification::Global)324        } else if (self.first_extern_index..self.first_local_index).contains(&index) {325            Some(RegionClassification::External)326        } else if (self.first_local_index..self.num_universals).contains(&index) {327            Some(RegionClassification::Local)328        } else {329            None330        }331    }332333    /// Returns an iterator over all the RegionVids corresponding to334    /// universally quantified free regions.335    pub(crate) fn universal_regions_iter(&self) -> impl Iterator<Item = RegionVid> + 'static {336        (FIRST_GLOBAL_INDEX..self.num_universals).map(RegionVid::from_usize)337    }338339    /// Returns `true` if `r` is classified as a local region.340    pub(crate) fn is_local_free_region(&self, r: RegionVid) -> bool {341        self.region_classification(r) == Some(RegionClassification::Local)342    }343344    /// Returns the number of universal regions created in any category.345    pub(crate) fn len(&self) -> usize {346        self.num_universals347    }348349    /// Returns the number of global plus external universal regions.350    /// For closures, these are the regions that appear free in the351    /// closure type (versus those bound in the closure352    /// signature). They are therefore the regions between which the353    /// closure may impose constraints that its creator must verify.354    pub(crate) fn num_global_and_external_regions(&self) -> usize {355        self.first_local_index356    }357358    /// Gets an iterator over all the early-bound regions that have names.359    pub(crate) fn named_universal_regions_iter(360        &self,361    ) -> impl Iterator<Item = (ty::Region<'tcx>, ty::RegionVid)> {362        self.indices.indices.iter().map(|(&r, &v)| (r, v))363    }364365    /// See [UniversalRegionIndices::to_region_vid].366    pub(crate) fn to_region_vid(&self, r: ty::Region<'tcx>) -> RegionVid {367        self.indices.to_region_vid(r)368    }369370    /// As part of the NLL unit tests, you can annotate a function with371    /// `#[rustc_regions]`, and we will emit information about the region372    /// inference context and -- in particular -- the external constraints373    /// that this region imposes on others. The methods in this file374    /// handle the part about dumping the inference context internal375    /// state.376    pub(crate) fn annotate(&self, tcx: TyCtxt<'tcx>, err: &mut Diag<'_, ()>) {377        match self.defining_ty {378            DefiningTy::Closure(def_id, args) => {379                let v = with_no_trimmed_paths!(380                    args[tcx.generics_of(def_id).parent_count..]381                        .iter()382                        .map(|arg| arg.to_string())383                        .collect::<Vec<_>>()384                );385                err.note(format!(386                    "defining type: {} with closure args [\n    {},\n]",387                    tcx.def_path_str_with_args(def_id, args),388                    v.join(",\n    "),389                ));390391                // FIXME: It'd be nice to print the late-bound regions392                // here, but unfortunately these wind up stored into393                // tests, and the resulting print-outs include def-ids394                // and other things that are not stable across tests!395                // So we just include the region-vid. Annoying.396                for_each_late_bound_region_in_recursive_scope(tcx, def_id.expect_local(), |r| {397                    err.note(format!("late-bound region is {:?}", self.to_region_vid(r)));398                });399            }400            DefiningTy::CoroutineClosure(..) => {401                todo!()402            }403            DefiningTy::Coroutine(def_id, args) => {404                let v = with_no_trimmed_paths!(405                    args[tcx.generics_of(def_id).parent_count..]406                        .iter()407                        .map(|arg| arg.to_string())408                        .collect::<Vec<_>>()409                );410                err.note(format!(411                    "defining type: {} with coroutine args [\n    {},\n]",412                    tcx.def_path_str_with_args(def_id, args),413                    v.join(",\n    "),414                ));415416                // FIXME: As above, we'd like to print out the region417                // `r` but doing so is not stable across architectures418                // and so forth.419                for_each_late_bound_region_in_recursive_scope(tcx, def_id.expect_local(), |r| {420                    err.note(format!("late-bound region is {:?}", self.to_region_vid(r)));421                });422            }423            DefiningTy::FnDef(def_id, args) => {424                err.note(format!("defining type: {}", tcx.def_path_str_with_args(def_id, args),));425            }426            DefiningTy::Const(def_id, args) => {427                err.note(format!(428                    "defining constant type: {}",429                    tcx.def_path_str_with_args(def_id, args),430                ));431            }432            DefiningTy::InlineConst(def_id, args) => {433                err.note(format!(434                    "defining inline constant type: {}",435                    tcx.def_path_str_with_args(def_id, args),436                ));437            }438            DefiningTy::GlobalAsm(_) => unreachable!(),439        }440    }441442    pub(crate) fn implicit_region_bound(&self) -> RegionVid {443        self.fr_fn_body444    }445446    pub(crate) fn encountered_re_error(&self) -> Option<ErrorGuaranteed> {447        self.indices.encountered_re_error.get()448    }449}450451struct UniversalRegionsBuilder<'infcx, 'tcx> {452    infcx: &'infcx BorrowckInferCtxt<'tcx>,453    mir_def: LocalDefId,454}455456impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {457    fn build(self) -> UniversalRegions<'tcx> {458        debug!("build(mir_def={:?})", self.mir_def);459460        let param_env = self.infcx.param_env;461        debug!("build: param_env={:?}", param_env);462463        assert_eq!(FIRST_GLOBAL_INDEX, self.infcx.num_region_vars());464465        // Create the "global" region that is always free in all contexts: 'static.466        let fr_static = self467            .infcx468            .next_nll_region_var(NllRegionVariableOrigin::FreeRegion, || {469                RegionCtxt::Free(kw::Static)470            })471            .as_var();472473        // We've now added all the global regions. The next ones we474        // add will be external.475        let first_extern_index = self.infcx.num_region_vars();476477        let defining_ty = self.defining_ty();478        debug!("build: defining_ty={:?}", defining_ty);479480        let mut indices = self.compute_indices(fr_static, defining_ty);481        debug!("build: indices={:?}", indices);482483        // If this is a 'root' body (not a closure/coroutine/inline const), then484        // there are no extern regions, so the local regions start at the same485        // position as the (empty) sub-list of extern regions486        let first_local_index = if !self.infcx.tcx.is_typeck_child(self.mir_def.to_def_id()) {487            first_extern_index488        } else {489            // If this is a closure, coroutine, or inline-const, then the late-bound regions from the enclosing490            // function/closures are actually external regions to us. For example, here, 'a is not local491            // to the closure c (although it is local to the fn foo):492            // fn foo<'a>() {493            //     let c = || { let x: &'a u32 = ...; }494            // }495            for_each_late_bound_region_in_recursive_scope(496                self.infcx.tcx,497                self.infcx.tcx.local_parent(self.mir_def),498                |r| {499                    debug!(?r);500                    let region_vid = {501                        let name = r.get_name_or_anon(self.infcx.tcx);502                        self.infcx.next_nll_region_var(NllRegionVariableOrigin::FreeRegion, || {503                            RegionCtxt::LateBound(name)504                        })505                    };506507                    debug!(?region_vid);508                    indices.insert_late_bound_region(r, region_vid.as_var());509                },510            );511512            // Any regions created during the execution of `defining_ty` or during the above513            // late-bound region replacement are all considered 'extern' regions514            self.infcx.num_region_vars()515        };516517        // Converse of above, if this is a function/closure then the late-bound regions declared518        // on its signature are local.519        //520        // We manually loop over `bound_inputs_and_output` instead of using521        // `for_each_late_bound_region_in_item` as we may need to add the otherwise522        // implicit `ClosureEnv` region.523        let bound_inputs_and_output = self.compute_inputs_and_output(&indices, defining_ty);524        for (idx, bound_var) in bound_inputs_and_output.bound_vars().iter().enumerate() {525            if let ty::BoundVariableKind::Region(kind) = bound_var {526                let kind = ty::LateParamRegionKind::from_bound(ty::BoundVar::from_usize(idx), kind);527                let r = ty::Region::new_late_param(self.infcx.tcx, self.mir_def.to_def_id(), kind);528                let region_vid = {529                    let name = r.get_name_or_anon(self.infcx.tcx);530                    self.infcx.next_nll_region_var(NllRegionVariableOrigin::FreeRegion, || {531                        RegionCtxt::LateBound(name)532                    })533                };534535                debug!(?region_vid);536                indices.insert_late_bound_region(r, region_vid.as_var());537            }538        }539        let inputs_and_output = self.infcx.replace_bound_regions_with_nll_infer_vars(540            self.mir_def,541            bound_inputs_and_output,542            &indices,543        );544545        let (unnormalized_output_ty, unnormalized_input_tys) =546            inputs_and_output.split_last().unwrap();547548        let fr_fn_body = self549            .infcx550            .next_nll_region_var(NllRegionVariableOrigin::FreeRegion, || {551                RegionCtxt::Free(sym::fn_body)552            })553            .as_var();554555        let num_universals = self.infcx.num_region_vars();556557        debug!("build: global regions = {}..{}", FIRST_GLOBAL_INDEX, first_extern_index);558        debug!("build: extern regions = {}..{}", first_extern_index, first_local_index);559        debug!("build: local regions  = {}..{}", first_local_index, num_universals);560561        let (resume_ty, yield_ty) = match defining_ty {562            DefiningTy::Coroutine(_, args) => {563                let tys = args.as_coroutine();564                (Some(tys.resume_ty()), Some(tys.yield_ty()))565            }566            _ => (None, None),567        };568569        UniversalRegions {570            indices,571            fr_static,572            fr_fn_body,573            first_extern_index,574            first_local_index,575            num_universals,576            defining_ty,577            unnormalized_output_ty: *unnormalized_output_ty,578            unnormalized_input_tys,579            yield_ty,580            resume_ty,581        }582    }583584    /// Returns the "defining type" of the current MIR;585    /// see `DefiningTy` for details.586    fn defining_ty(&self) -> DefiningTy<'tcx> {587        let tcx = self.infcx.tcx;588589        match tcx.hir_body_owner_kind(self.mir_def) {590            BodyOwnerKind::Closure | BodyOwnerKind::Fn => {591                let defining_ty = tcx.type_of(self.mir_def).instantiate_identity().skip_norm_wip();592593                debug!("defining_ty (pre-replacement): {:?}", defining_ty);594595                let defining_ty = self.infcx.replace_free_regions_with_nll_infer_vars(596                    NllRegionVariableOrigin::FreeRegion,597                    defining_ty,598                );599600                match *defining_ty.kind() {601                    ty::Closure(def_id, args) => DefiningTy::Closure(def_id, args),602                    ty::Coroutine(def_id, args) => DefiningTy::Coroutine(def_id, args),603                    ty::CoroutineClosure(def_id, args) => {604                        DefiningTy::CoroutineClosure(def_id, args)605                    }606                    ty::FnDef(def_id, args) => DefiningTy::FnDef(def_id, args),607                    _ => span_bug!(608                        tcx.def_span(self.mir_def),609                        "expected defining type for `{:?}`: `{:?}`",610                        self.mir_def,611                        defining_ty612                    ),613                }614            }615616            BodyOwnerKind::Const { .. } | BodyOwnerKind::Static(..) => {617                match tcx.def_kind(self.mir_def) {618                    DefKind::InlineConst => {619                        // This is required for `AscribeUserType` canonical query, which will call620                        // `type_of(inline_const_def_id)`. That `type_of` would inject erased lifetimes621                        // into borrowck, which is ICE #78174.622                        //623                        // As a workaround, inline consts have an additional generic param (`ty`624                        // below), so that `type_of(inline_const_def_id).substs(substs)` uses the625                        // proper type with NLL infer vars.626                        //627                        // Fetch the actual type from MIR, as `type_of` returns something useless628                        // like `<const_ty>`.629                        let body = tcx.mir_promoted(self.mir_def).0.borrow();630                        let ty = body.local_decls[RETURN_PLACE].ty;631                        let typeck_root_def_id = tcx.typeck_root_def_id(self.mir_def.to_def_id());632                        let parent_args = GenericArgs::identity_for_item(tcx, typeck_root_def_id);633                        let args =634                            InlineConstArgs::new(tcx, InlineConstArgsParts { parent_args, ty })635                                .args;636                        let args = self.infcx.replace_free_regions_with_nll_infer_vars(637                            NllRegionVariableOrigin::FreeRegion,638                            args,639                        );640                        DefiningTy::InlineConst(self.mir_def.to_def_id(), args)641                    }642                    _ => {643                        let identity_args =644                            GenericArgs::identity_for_item(tcx, self.mir_def.to_def_id());645                        let args = self.infcx.replace_free_regions_with_nll_infer_vars(646                            NllRegionVariableOrigin::FreeRegion,647                            identity_args,648                        );649                        DefiningTy::Const(self.mir_def.to_def_id(), args)650                    }651                }652            }653654            BodyOwnerKind::GlobalAsm => DefiningTy::GlobalAsm(self.mir_def.to_def_id()),655        }656    }657658    /// Builds a hashmap that maps from the universal regions that are659    /// in scope (as a `ty::Region<'tcx>`) to their indices (as a660    /// `RegionVid`). The map returned by this function contains only661    /// the early-bound regions.662    fn compute_indices(663        &self,664        fr_static: RegionVid,665        defining_ty: DefiningTy<'tcx>,666    ) -> UniversalRegionIndices<'tcx> {667        let tcx = self.infcx.tcx;668        let typeck_root_def_id = tcx.typeck_root_def_id_local(self.mir_def);669        let identity_args = GenericArgs::identity_for_item(tcx, typeck_root_def_id);670        let renumbered_args = defining_ty.args();671672        let global_mapping = iter::once((tcx.lifetimes.re_static, fr_static));673        // This relies on typeck roots being generics_of parents with their674        // parameters at the start of nested bodies' generics.675        assert!(renumbered_args.len() >= identity_args.len());676        let arg_mapping =677            iter::zip(identity_args.regions(), renumbered_args.regions().map(|r| r.as_var()));678679        UniversalRegionIndices {680            indices: global_mapping.chain(arg_mapping).collect(),681            fr_static,682            encountered_re_error: Cell::new(None),683        }684    }685686    fn compute_inputs_and_output(687        &self,688        indices: &UniversalRegionIndices<'tcx>,689        defining_ty: DefiningTy<'tcx>,690    ) -> ty::Binder<'tcx, &'tcx ty::List<Ty<'tcx>>> {691        let tcx = self.infcx.tcx;692693        let inputs_and_output = match defining_ty {694            DefiningTy::Closure(def_id, args) => {695                assert_eq!(self.mir_def.to_def_id(), def_id);696                let closure_sig = args.as_closure().sig();697                let inputs_and_output = closure_sig.inputs_and_output();698                let bound_vars = tcx.mk_bound_variable_kinds_from_iter(699                    inputs_and_output.bound_vars().iter().chain(iter::once(700                        ty::BoundVariableKind::Region(ty::BoundRegionKind::ClosureEnv),701                    )),702                );703                let br = ty::BoundRegion {704                    var: ty::BoundVar::from_usize(bound_vars.len() - 1),705                    kind: ty::BoundRegionKind::ClosureEnv,706                };707                let env_region = ty::Region::new_bound(tcx, ty::INNERMOST, br);708                let closure_ty = tcx.closure_env_ty(709                    Ty::new_closure(tcx, def_id, args),710                    args.as_closure().kind(),711                    env_region,712                );713714                // The "inputs" of the closure in the715                // signature appear as a tuple. The MIR side716                // flattens this tuple.717                let (&output, tuplized_inputs) =718                    inputs_and_output.skip_binder().split_last().unwrap();719                assert_eq!(tuplized_inputs.len(), 1, "multiple closure inputs");720                let &ty::Tuple(inputs) = tuplized_inputs[0].kind() else {721                    bug!("closure inputs not a tuple: {:?}", tuplized_inputs[0]);722                };723724                ty::Binder::bind_with_vars(725                    tcx.mk_type_list_from_iter(726                        iter::once(closure_ty).chain(inputs).chain(iter::once(output)),727                    ),728                    bound_vars,729                )730            }731732            DefiningTy::Coroutine(def_id, args) => {733                assert_eq!(self.mir_def.to_def_id(), def_id);734                let resume_ty = args.as_coroutine().resume_ty();735                let output = args.as_coroutine().return_ty();736                let coroutine_ty = Ty::new_coroutine(tcx, def_id, args);737                let inputs_and_output =738                    self.infcx.tcx.mk_type_list(&[coroutine_ty, resume_ty, output]);739                ty::Binder::dummy(inputs_and_output)740            }741742            // Construct the signature of the CoroutineClosure for the purposes of borrowck.743            // This is pretty straightforward -- we:744            // 1. first grab the `coroutine_closure_sig`,745            // 2. compute the self type (`&`/`&mut`/no borrow),746            // 3. flatten the tupled_input_tys,747            // 4. construct the correct generator type to return with748            //    `CoroutineClosureSignature::to_coroutine_given_kind_and_upvars`.749            // Then we wrap it all up into a list of inputs and output.750            DefiningTy::CoroutineClosure(def_id, args) => {751                assert_eq!(self.mir_def.to_def_id(), def_id);752                let closure_sig = args.as_coroutine_closure().coroutine_closure_sig();753                let bound_vars =754                    tcx.mk_bound_variable_kinds_from_iter(closure_sig.bound_vars().iter().chain(755                        iter::once(ty::BoundVariableKind::Region(ty::BoundRegionKind::ClosureEnv)),756                    ));757                let br = ty::BoundRegion {758                    var: ty::BoundVar::from_usize(bound_vars.len() - 1),759                    kind: ty::BoundRegionKind::ClosureEnv,760                };761                let env_region = ty::Region::new_bound(tcx, ty::INNERMOST, br);762                let closure_kind = args.as_coroutine_closure().kind();763764                let closure_ty = tcx.closure_env_ty(765                    Ty::new_coroutine_closure(tcx, def_id, args),766                    closure_kind,767                    env_region,768                );769770                let inputs = closure_sig.skip_binder().tupled_inputs_ty.tuple_fields();771                let output = closure_sig.skip_binder().to_coroutine_given_kind_and_upvars(772                    tcx,773                    args.as_coroutine_closure().parent_args(),774                    tcx.coroutine_for_closure(def_id),775                    closure_kind,776                    env_region,777                    args.as_coroutine_closure().tupled_upvars_ty(),778                    args.as_coroutine_closure().coroutine_captures_by_ref_ty(),779                );780781                ty::Binder::bind_with_vars(782                    tcx.mk_type_list_from_iter(783                        iter::once(closure_ty).chain(inputs).chain(iter::once(output)),784                    ),785                    bound_vars,786                )787            }788789            DefiningTy::FnDef(def_id, _) => {790                let sig = tcx.fn_sig(def_id).instantiate_identity().skip_norm_wip();791                let sig = indices.fold_to_region_vids(tcx, sig);792                let inputs_and_output = sig.inputs_and_output();793794                // C-variadic fns also have a `VaList` input that's not listed in the signature795                // (as it's created inside the body itself, not passed in from outside).796                if self.infcx.tcx.fn_sig(def_id).skip_binder().c_variadic() {797                    let va_list_did = self798                        .infcx799                        .tcx800                        .require_lang_item(LangItem::VaList, self.infcx.tcx.def_span(self.mir_def));801802                    let reg_vid = self803                        .infcx804                        .next_nll_region_var(NllRegionVariableOrigin::FreeRegion, || {805                            RegionCtxt::Free(sym::c_dash_variadic)806                        })807                        .as_var();808809                    let region = ty::Region::new_var(self.infcx.tcx, reg_vid);810                    let va_list_ty = self811                        .infcx812                        .tcx813                        .type_of(va_list_did)814                        .instantiate(self.infcx.tcx, &[region.into()])815                        .skip_norm_wip();816817                    // The signature needs to follow the order [input_tys, va_list_ty, output_ty]818                    return inputs_and_output.map_bound(|tys| {819                        let (output_ty, input_tys) = tys.split_last().unwrap();820                        tcx.mk_type_list_from_iter(821                            input_tys.iter().copied().chain([va_list_ty, *output_ty]),822                        )823                    });824                }825826                inputs_and_output827            }828829            DefiningTy::Const(def_id, _) => {830                // For a constant body, there are no inputs, and one831                // "output" (the type of the constant).832                assert_eq!(self.mir_def.to_def_id(), def_id);833                let ty = tcx.type_of(self.mir_def).instantiate_identity().skip_norm_wip();834835                let ty = indices.fold_to_region_vids(tcx, ty);836                ty::Binder::dummy(tcx.mk_type_list(&[ty]))837            }838839            DefiningTy::InlineConst(def_id, args) => {840                assert_eq!(self.mir_def.to_def_id(), def_id);841                let ty = args.as_inline_const().ty();842                ty::Binder::dummy(tcx.mk_type_list(&[ty]))843            }844845            DefiningTy::GlobalAsm(def_id) => ty::Binder::dummy(846                tcx.mk_type_list(&[tcx.type_of(def_id).instantiate_identity().skip_norm_wip()]),847            ),848        };849850        // FIXME(#129952): We probably want a more principled approach here.851        if let Err(e) = inputs_and_output.error_reported() {852            self.infcx.set_tainted_by_errors(e);853        }854855        inputs_and_output856    }857}858859#[extension(trait InferCtxtExt<'tcx>)]860impl<'tcx> BorrowckInferCtxt<'tcx> {861    #[instrument(skip(self), level = "debug")]862    fn replace_free_regions_with_nll_infer_vars<T>(863        &self,864        origin: NllRegionVariableOrigin<'tcx>,865        value: T,866    ) -> T867    where868        T: TypeFoldable<TyCtxt<'tcx>>,869    {870        fold_regions(self.infcx.tcx, value, |region, _depth| {871            let name = region.get_name_or_anon(self.infcx.tcx);872            debug!(?region, ?name);873874            self.next_nll_region_var(origin, || RegionCtxt::Free(name))875        })876    }877878    #[instrument(level = "debug", skip(self, indices))]879    fn replace_bound_regions_with_nll_infer_vars<T>(880        &self,881        all_outlive_scope: LocalDefId,882        value: ty::Binder<'tcx, T>,883        indices: &UniversalRegionIndices<'tcx>,884    ) -> T885    where886        T: TypeFoldable<TyCtxt<'tcx>>,887    {888        let (value, _map) = self.tcx.instantiate_bound_regions(value, |br| {889            debug!(?br);890            let kind = ty::LateParamRegionKind::from_bound(br.var, br.kind);891            let liberated_region =892                ty::Region::new_late_param(self.tcx, all_outlive_scope.to_def_id(), kind);893            ty::Region::new_var(self.tcx, indices.to_region_vid(liberated_region))894        });895        value896    }897}898899impl<'tcx> UniversalRegionIndices<'tcx> {900    /// Initially, the `UniversalRegionIndices` map contains only the901    /// early-bound regions in scope. Once that is all setup, we come902    /// in later and instantiate the late-bound regions, and then we903    /// insert the `ReLateParam` version of those into the map as904    /// well. These are used for error reporting.905    fn insert_late_bound_region(&mut self, r: ty::Region<'tcx>, vid: ty::RegionVid) {906        debug!("insert_late_bound_region({:?}, {:?})", r, vid);907        assert_eq!(self.indices.insert(r, vid), None);908    }909910    /// Converts `r` into a local inference variable: `r` can either911    /// be a `ReVar` (i.e., already a reference to an inference912    /// variable) or it can be `'static` or some early-bound913    /// region. This is useful when taking the results from914    /// type-checking and trait-matching, which may sometimes915    /// reference those regions from the `ParamEnv`. It is also used916    /// during initialization. Relies on the `indices` map having been917    /// fully initialized.918    ///919    /// Panics if `r` is not a registered universal region, most notably920    /// if it is a placeholder. Handling placeholders requires access to the921    /// `MirTypeckRegionConstraints`.922    fn to_region_vid(&self, r: ty::Region<'tcx>) -> RegionVid {923        match r.kind() {924            ty::ReVar(..) => r.as_var(),925            ty::ReError(guar) => {926                self.encountered_re_error.set(Some(guar));927                // We use the `'static` `RegionVid` because `ReError` doesn't actually exist in the928                // `UniversalRegionIndices`. This is fine because 1) it is a fallback only used if929                // errors are being emitted and 2) it leaves the happy path unaffected.930                self.fr_static931            }932            _ => *self933                .indices934                .get(&r)935                .unwrap_or_else(|| bug!("cannot convert `{:?}` to a region vid", r)),936        }937    }938939    /// Replaces all free regions in `value` with region vids, as940    /// returned by `to_region_vid`.941    fn fold_to_region_vids<T>(&self, tcx: TyCtxt<'tcx>, value: T) -> T942    where943        T: TypeFoldable<TyCtxt<'tcx>>,944    {945        fold_regions(tcx, value, |region, _| ty::Region::new_var(tcx, self.to_region_vid(region)))946    }947}948949/// Iterates over the late-bound regions defined on `mir_def_id` and all of its950/// parents, up to the typeck root, and invokes `f` with the liberated form951/// of each one.952fn for_each_late_bound_region_in_recursive_scope<'tcx>(953    tcx: TyCtxt<'tcx>,954    mut mir_def_id: LocalDefId,955    mut f: impl FnMut(ty::Region<'tcx>),956) {957    // Walk up the tree, collecting late-bound regions until we hit the typeck root958    loop {959        for_each_late_bound_region_in_item(tcx, mir_def_id, &mut f);960961        if tcx.is_typeck_child(mir_def_id.to_def_id()) {962            mir_def_id = tcx.local_parent(mir_def_id);963        } else {964            break;965        }966    }967}968969/// Iterates over the late-bound regions defined on `mir_def_id` and all of its970/// parents, up to the typeck root, and invokes `f` with the liberated form971/// of each one.972fn for_each_late_bound_region_in_item<'tcx>(973    tcx: TyCtxt<'tcx>,974    mir_def_id: LocalDefId,975    mut f: impl FnMut(ty::Region<'tcx>),976) {977    let bound_vars = match tcx.def_kind(mir_def_id) {978        DefKind::Fn | DefKind::AssocFn => {979            tcx.late_bound_vars(tcx.local_def_id_to_hir_id(mir_def_id))980        }981        // We extract the bound vars from the deduced closure signature, since we may have982        // only deduced that a param in the closure signature is late-bound from a constraint983        // that we discover during typeck.984        DefKind::Closure => {985            let ty = tcx.type_of(mir_def_id).instantiate_identity().skip_norm_wip();986            match *ty.kind() {987                ty::Closure(_, args) => args.as_closure().sig().bound_vars(),988                ty::CoroutineClosure(_, args) => {989                    args.as_coroutine_closure().coroutine_closure_sig().bound_vars()990                }991                ty::Coroutine(_, _) | ty::Error(_) => return,992                _ => unreachable!("unexpected type for closure: {ty}"),993            }994        }995        _ => return,996    };997998    for (idx, bound_var) in bound_vars.iter().enumerate() {999        if let ty::BoundVariableKind::Region(kind) = bound_var {1000            let kind = ty::LateParamRegionKind::from_bound(ty::BoundVar::from_usize(idx), kind);1001            let liberated_region = ty::Region::new_late_param(tcx, mir_def_id.to_def_id(), kind);1002            f(liberated_region);1003        }1004    }1005}

Code quality findings 19

Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
pub unnormalized_input_tys: &'tcx [Ty<'tcx>],
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
/// `V[1]: V[2]`.
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
/// See [UniversalRegionIndices::to_region_vid].
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
args[tcx.generics_of(def_id).parent_count..]
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
"defining type: {} with closure args [\n {},\n]",
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
args[tcx.generics_of(def_id).parent_count..]
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
"defining type: {} with coroutine args [\n {},\n]",
Warning: '.unwrap()' will panic on None/Err variants. Prefer using pattern matching (match, if let), combinators (map, and_then), or the '?' operator for robust error handling.
warning correctness unwrap-usage
inputs_and_output.split_last().unwrap();
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
let ty = body.local_decls[RETURN_PLACE].ty;
Warning: '.unwrap()' will panic on None/Err variants. Prefer using pattern matching (match, if let), combinators (map, and_then), or the '?' operator for robust error handling.
warning correctness unwrap-usage
inputs_and_output.skip_binder().split_last().unwrap();
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
let &ty::Tuple(inputs) = tuplized_inputs[0].kind() else {
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
bug!("closure inputs not a tuple: {:?}", tuplized_inputs[0]);
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
// The signature needs to follow the order [input_tys, va_list_ty, output_ty]
Warning: '.unwrap()' will panic on None/Err variants. Prefer using pattern matching (match, if let), combinators (map, and_then), or the '?' operator for robust error handling.
warning correctness unwrap-usage
let (output_ty, input_tys) = tys.split_last().unwrap();
Maintainability Info: `todo!()` or `unimplemented!()` macros indicate incomplete code paths that will panic at runtime if reached. Ensure these are replaced with actual logic before production use.
info correctness todo-unimplemented
todo!()
Info: Ensure 'match' statements are exhaustive. If matching on enums, consider adding a wildcard arm `_ => {}` only if necessary and intentional, as it suppresses warnings about unhandled variants.
info correctness match-wildcard
let (resume_ty, yield_ty) = match defining_ty {
Info: Ensure 'match' statements are exhaustive. If matching on enums, consider adding a wildcard arm `_ => {}` only if necessary and intentional, as it suppresses warnings about unhandled variants.
info correctness match-wildcard
match *defining_ty.kind() {
Info: Ensure 'match' statements are exhaustive. If matching on enums, consider adding a wildcard arm `_ => {}` only if necessary and intentional, as it suppresses warnings about unhandled variants.
info correctness match-wildcard
match r.kind() {
Info: Ensure 'match' statements are exhaustive. If matching on enums, consider adding a wildcard arm `_ => {}` only if necessary and intentional, as it suppresses warnings about unhandled variants.
info correctness match-wildcard
match *ty.kind() {

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.