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}