Skip to content

Commit 09524bf

Browse files
committed
promote subject even if it has unnamed regions
Don't require a region to have an `external_name` in order to be promoted.
1 parent 20b20b2 commit 09524bf

File tree

7 files changed

+66
-67
lines changed

7 files changed

+66
-67
lines changed

compiler/rustc_borrowck/src/region_infer/mod.rs

+14-21
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@ use rustc_infer::infer::outlives::test_type_match;
1212
use rustc_infer::infer::region_constraints::{GenericKind, VarInfos, VerifyBound, VerifyIfEq};
1313
use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin};
1414
use rustc_middle::mir::{
15-
Body, ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureRegionRequirements,
16-
ConstraintCategory, Local, Location, ReturnConstraint, TerminatorKind,
15+
Body, ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureOutlivesSubjectTy,
16+
ClosureRegionRequirements, ConstraintCategory, Local, Location, ReturnConstraint,
17+
TerminatorKind,
1718
};
1819
use rustc_middle::traits::ObligationCause;
1920
use rustc_middle::traits::ObligationCauseCode;
@@ -1084,18 +1085,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
10841085
true
10851086
}
10861087

1087-
/// When we promote a type test `T: 'r`, we have to convert the
1088-
/// type `T` into something we can store in a query result (so
1089-
/// something allocated for `'tcx`). This is problematic if `ty`
1090-
/// contains regions. During the course of NLL region checking, we
1091-
/// will have replaced all of those regions with fresh inference
1092-
/// variables. To create a test subject, we want to replace those
1093-
/// inference variables with some region from the closure
1094-
/// signature -- this is not always possible, so this is a
1095-
/// fallible process. Presuming we do find a suitable region, we
1096-
/// will use it's *external name*, which will be a `RegionKind`
1097-
/// variant that can be used in query responses such as
1098-
/// `ReEarlyBound`.
1088+
/// When we promote a type test `T: 'r`, we have to replace all region
1089+
/// variables in the type `T` with an equal universal region from the
1090+
/// closure signature.
1091+
/// This is not always possible, so this is a fallible process.
10991092
#[instrument(level = "debug", skip(self, infcx))]
11001093
fn try_promote_type_test_subject(
11011094
&self,
@@ -1144,22 +1137,22 @@ impl<'tcx> RegionInferenceContext<'tcx> {
11441137
// find an equivalent.
11451138
let upper_bound = self.non_local_universal_upper_bound(region_vid);
11461139
if self.region_contains(region_vid, upper_bound) {
1147-
self.definitions[upper_bound].external_name.unwrap_or(r)
1140+
tcx.mk_re_var(upper_bound)
11481141
} else {
1149-
// In the case of a failure, use a `ReVar` result. This will
1150-
// cause the `needs_infer` later on to return `None`.
1151-
r
1142+
// In the case of a failure, use `ReErased`. We will eventually
1143+
// return `None` in this case.
1144+
tcx.lifetimes.re_erased
11521145
}
11531146
});
11541147

11551148
debug!("try_promote_type_test_subject: folded ty = {:?}", ty);
11561149

1157-
// `needs_infer` will only be true if we failed to promote some region.
1158-
if ty.needs_infer() {
1150+
// This will be true if we failed to promote some region.
1151+
if ty.has_erased_regions() {
11591152
return None;
11601153
}
11611154

1162-
Some(ClosureOutlivesSubject::Ty(ty))
1155+
Some(ClosureOutlivesSubject::Ty(ClosureOutlivesSubjectTy::new(tcx, ty)))
11631156
}
11641157

11651158
/// Given some universal or existential region `r`, finds a

compiler/rustc_borrowck/src/type_check/constraint_conversion.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,9 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
116116
let outlived_region = closure_mapping[outlives_requirement.outlived_free_region];
117117
let subject = match outlives_requirement.subject {
118118
ClosureOutlivesSubject::Region(re) => closure_mapping[re].into(),
119-
ClosureOutlivesSubject::Ty(ty) => ty.into(),
119+
ClosureOutlivesSubject::Ty(subject_ty) => {
120+
subject_ty.instantiate(self.tcx, |vid| closure_mapping[vid]).into()
121+
}
120122
};
121123

122124
self.category = outlives_requirement.category;

compiler/rustc_middle/src/mir/query.rs

+45-12
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use rustc_errors::ErrorGuaranteed;
88
use rustc_hir as hir;
99
use rustc_hir::def_id::{DefId, LocalDefId};
1010
use rustc_index::bit_set::BitMatrix;
11-
use rustc_index::vec::IndexVec;
11+
use rustc_index::vec::{Idx, IndexVec};
1212
use rustc_span::Span;
1313
use rustc_target::abi::VariantIdx;
1414
use smallvec::SmallVec;
@@ -289,13 +289,6 @@ pub struct ConstQualifs {
289289
/// instance of the closure is created, the corresponding free regions
290290
/// can be extracted from its type and constrained to have the given
291291
/// outlives relationship.
292-
///
293-
/// In some cases, we have to record outlives requirements between types and
294-
/// regions as well. In that case, if those types include any regions, those
295-
/// regions are recorded using their external names (`ReStatic`,
296-
/// `ReEarlyBound`, `ReFree`). We use these because in a query response we
297-
/// cannot use `ReVar` (which is what we use internally within the rest of the
298-
/// NLL code).
299292
#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)]
300293
pub struct ClosureRegionRequirements<'tcx> {
301294
/// The number of external regions defined on the closure. In our
@@ -392,16 +385,56 @@ pub enum ClosureOutlivesSubject<'tcx> {
392385
/// Subject is a type, typically a type parameter, but could also
393386
/// be a projection. Indicates a requirement like `T: 'a` being
394387
/// passed to the caller, where the type here is `T`.
395-
///
396-
/// The type here is guaranteed not to contain any free regions at
397-
/// present.
398-
Ty(Ty<'tcx>),
388+
Ty(ClosureOutlivesSubjectTy<'tcx>),
399389

400390
/// Subject is a free region from the closure. Indicates a requirement
401391
/// like `'a: 'b` being passed to the caller; the region here is `'a`.
402392
Region(ty::RegionVid),
403393
}
404394

395+
/// Represents a `ty::Ty` for use in [`ClosureOutlivesSubject`].
396+
///
397+
/// This indirection is necessary because the type may include `ReVar` regions,
398+
/// which is what we use internally within NLL code,
399+
/// and we can't use `ReVar`s in a query response.
400+
#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
401+
pub struct ClosureOutlivesSubjectTy<'tcx> {
402+
inner: Ty<'tcx>,
403+
}
404+
405+
impl<'tcx> ClosureOutlivesSubjectTy<'tcx> {
406+
// All regions of `ty` must be of kind `ReVar`
407+
// and must point to an early-bound region in the closure's signature.
408+
pub fn new(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Self {
409+
let inner = tcx.fold_regions(ty, |r, depth| match r.kind() {
410+
ty::ReVar(vid) => {
411+
let br = ty::BoundRegion {
412+
var: ty::BoundVar::new(vid.index()),
413+
kind: ty::BrAnon(0u32, None),
414+
};
415+
tcx.mk_re_late_bound(depth, br)
416+
}
417+
_ => bug!("unexpected region in ClosureOutlivesSubjectTy: {r:?}"),
418+
});
419+
420+
Self { inner }
421+
}
422+
423+
pub fn instantiate(
424+
self,
425+
tcx: TyCtxt<'tcx>,
426+
mut map: impl FnMut(ty::RegionVid) -> ty::Region<'tcx>,
427+
) -> Ty<'tcx> {
428+
tcx.fold_regions(self.inner, |r, depth| match r.kind() {
429+
ty::ReLateBound(debruijn, br) => {
430+
debug_assert_eq!(debruijn, depth);
431+
map(ty::RegionVid::new(br.var.index()))
432+
}
433+
_ => bug!("unexpected region {r:?}"),
434+
})
435+
}
436+
}
437+
405438
/// The constituent parts of a mir constant of kind ADT or array.
406439
#[derive(Copy, Clone, Debug, HashStable)]
407440
pub struct DestructuredConstant<'tcx> {

tests/ui/nll/closure-requirements/type-test-subject-opaque-1.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
// check-fail
2-
// known-bug: #107426
1+
// Regression test for #107426.
2+
// check-pass
33

44
use std::marker::PhantomData;
55
#[derive(Clone, Copy)]

tests/ui/nll/closure-requirements/type-test-subject-opaque-1.stderr

-8
This file was deleted.

tests/ui/nll/closure-requirements/type-test-subject-unnamed-region.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
// check-fail
2-
// known-bug: #108635
1+
// See #108635 for description.
2+
// check-pass
33

44
trait Trait {
55
type Item<'a>: 'a;

tests/ui/nll/closure-requirements/type-test-subject-unnamed-region.stderr

-21
This file was deleted.

0 commit comments

Comments
 (0)