summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAli MJ Al-Nasrawy <alimjalnasrawy@gmail.com>2023-03-03 03:56:42 +0300
committerMark Rousskov <mark.simulacrum@gmail.com>2023-03-11 18:10:26 -0500
commit668ae05cd419a3cc918e0ff2ea18bcba98d0ef9b (patch)
tree6a5c50de5df7a4136451fe4830b43bdb6f80d3f2
parentc44042d3962a6cc807e4812298ab1cf62e58c50c (diff)
downloadrust-668ae05cd419a3cc918e0ff2ea18bcba98d0ef9b.tar.gz
promote subject even if it has unnamed regions
Don't require a region to have an `external_name` in order to be promoted.
-rw-r--r--compiler/rustc_borrowck/src/region_infer/mod.rs35
-rw-r--r--compiler/rustc_borrowck/src/type_check/constraint_conversion.rs4
-rw-r--r--compiler/rustc_middle/src/mir/query.rs57
-rw-r--r--tests/ui/nll/closure-requirements/type-test-subject-opaque-1.rs4
-rw-r--r--tests/ui/nll/closure-requirements/type-test-subject-opaque-1.stderr8
-rw-r--r--tests/ui/nll/closure-requirements/type-test-subject-unnamed-region.rs4
-rw-r--r--tests/ui/nll/closure-requirements/type-test-subject-unnamed-region.stderr21
7 files changed, 66 insertions, 67 deletions
diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs
index 21b5bd7cb94..b3132cc71ea 100644
--- a/compiler/rustc_borrowck/src/region_infer/mod.rs
+++ b/compiler/rustc_borrowck/src/region_infer/mod.rs
@@ -12,8 +12,9 @@ use rustc_infer::infer::outlives::test_type_match;
use rustc_infer::infer::region_constraints::{GenericKind, VarInfos, VerifyBound, VerifyIfEq};
use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin};
use rustc_middle::mir::{
- Body, ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureRegionRequirements,
- ConstraintCategory, Local, Location, ReturnConstraint, TerminatorKind,
+ Body, ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureOutlivesSubjectTy,
+ ClosureRegionRequirements, ConstraintCategory, Local, Location, ReturnConstraint,
+ TerminatorKind,
};
use rustc_middle::traits::ObligationCause;
use rustc_middle::traits::ObligationCauseCode;
@@ -1084,18 +1085,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
true
}
- /// When we promote a type test `T: 'r`, we have to convert the
- /// type `T` into something we can store in a query result (so
- /// something allocated for `'tcx`). This is problematic if `ty`
- /// contains regions. During the course of NLL region checking, we
- /// will have replaced all of those regions with fresh inference
- /// variables. To create a test subject, we want to replace those
- /// inference variables with some region from the closure
- /// signature -- this is not always possible, so this is a
- /// fallible process. Presuming we do find a suitable region, we
- /// will use it's *external name*, which will be a `RegionKind`
- /// variant that can be used in query responses such as
- /// `ReEarlyBound`.
+ /// When we promote a type test `T: 'r`, we have to replace all region
+ /// variables in the type `T` with an equal universal region from the
+ /// closure signature.
+ /// This is not always possible, so this is a fallible process.
#[instrument(level = "debug", skip(self, infcx))]
fn try_promote_type_test_subject(
&self,
@@ -1144,22 +1137,22 @@ impl<'tcx> RegionInferenceContext<'tcx> {
// find an equivalent.
let upper_bound = self.non_local_universal_upper_bound(region_vid);
if self.region_contains(region_vid, upper_bound) {
- self.definitions[upper_bound].external_name.unwrap_or(r)
+ tcx.mk_re_var(upper_bound)
} else {
- // In the case of a failure, use a `ReVar` result. This will
- // cause the `needs_infer` later on to return `None`.
- r
+ // In the case of a failure, use `ReErased`. We will eventually
+ // return `None` in this case.
+ tcx.lifetimes.re_erased
}
});
debug!("try_promote_type_test_subject: folded ty = {:?}", ty);
- // `needs_infer` will only be true if we failed to promote some region.
- if ty.needs_infer() {
+ // This will be true if we failed to promote some region.
+ if ty.has_erased_regions() {
return None;
}
- Some(ClosureOutlivesSubject::Ty(ty))
+ Some(ClosureOutlivesSubject::Ty(ClosureOutlivesSubjectTy::new(tcx, ty)))
}
/// Given some universal or existential region `r`, finds a
diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
index 504633c6a5c..a9356135006 100644
--- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
+++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
@@ -116,7 +116,9 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
let outlived_region = closure_mapping[outlives_requirement.outlived_free_region];
let subject = match outlives_requirement.subject {
ClosureOutlivesSubject::Region(re) => closure_mapping[re].into(),
- ClosureOutlivesSubject::Ty(ty) => ty.into(),
+ ClosureOutlivesSubject::Ty(subject_ty) => {
+ subject_ty.instantiate(self.tcx, |vid| closure_mapping[vid]).into()
+ }
};
self.category = outlives_requirement.category;
diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs
index e2ab3fd35b3..87a2b9ec73e 100644
--- a/compiler/rustc_middle/src/mir/query.rs
+++ b/compiler/rustc_middle/src/mir/query.rs
@@ -8,7 +8,7 @@ use rustc_errors::ErrorGuaranteed;
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_index::bit_set::BitMatrix;
-use rustc_index::vec::IndexVec;
+use rustc_index::vec::{Idx, IndexVec};
use rustc_span::Span;
use rustc_target::abi::VariantIdx;
use smallvec::SmallVec;
@@ -289,13 +289,6 @@ pub struct ConstQualifs {
/// instance of the closure is created, the corresponding free regions
/// can be extracted from its type and constrained to have the given
/// outlives relationship.
-///
-/// In some cases, we have to record outlives requirements between types and
-/// regions as well. In that case, if those types include any regions, those
-/// regions are recorded using their external names (`ReStatic`,
-/// `ReEarlyBound`, `ReFree`). We use these because in a query response we
-/// cannot use `ReVar` (which is what we use internally within the rest of the
-/// NLL code).
#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)]
pub struct ClosureRegionRequirements<'tcx> {
/// The number of external regions defined on the closure. In our
@@ -392,16 +385,56 @@ pub enum ClosureOutlivesSubject<'tcx> {
/// Subject is a type, typically a type parameter, but could also
/// be a projection. Indicates a requirement like `T: 'a` being
/// passed to the caller, where the type here is `T`.
- ///
- /// The type here is guaranteed not to contain any free regions at
- /// present.
- Ty(Ty<'tcx>),
+ Ty(ClosureOutlivesSubjectTy<'tcx>),
/// Subject is a free region from the closure. Indicates a requirement
/// like `'a: 'b` being passed to the caller; the region here is `'a`.
Region(ty::RegionVid),
}
+/// Represents a `ty::Ty` for use in [`ClosureOutlivesSubject`].
+///
+/// This indirection is necessary because the type may include `ReVar` regions,
+/// which is what we use internally within NLL code,
+/// and we can't use `ReVar`s in a query response.
+#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
+pub struct ClosureOutlivesSubjectTy<'tcx> {
+ inner: Ty<'tcx>,
+}
+
+impl<'tcx> ClosureOutlivesSubjectTy<'tcx> {
+ // All regions of `ty` must be of kind `ReVar`
+ // and must point to an early-bound region in the closure's signature.
+ pub fn new(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Self {
+ let inner = tcx.fold_regions(ty, |r, depth| match r.kind() {
+ ty::ReVar(vid) => {
+ let br = ty::BoundRegion {
+ var: ty::BoundVar::new(vid.index()),
+ kind: ty::BrAnon(0u32, None),
+ };
+ tcx.mk_re_late_bound(depth, br)
+ }
+ _ => bug!("unexpected region in ClosureOutlivesSubjectTy: {r:?}"),
+ });
+
+ Self { inner }
+ }
+
+ pub fn instantiate(
+ self,
+ tcx: TyCtxt<'tcx>,
+ mut map: impl FnMut(ty::RegionVid) -> ty::Region<'tcx>,
+ ) -> Ty<'tcx> {
+ tcx.fold_regions(self.inner, |r, depth| match r.kind() {
+ ty::ReLateBound(debruijn, br) => {
+ debug_assert_eq!(debruijn, depth);
+ map(ty::RegionVid::new(br.var.index()))
+ }
+ _ => bug!("unexpected region {r:?}"),
+ })
+ }
+}
+
/// The constituent parts of a mir constant of kind ADT or array.
#[derive(Copy, Clone, Debug, HashStable)]
pub struct DestructuredConstant<'tcx> {
diff --git a/tests/ui/nll/closure-requirements/type-test-subject-opaque-1.rs b/tests/ui/nll/closure-requirements/type-test-subject-opaque-1.rs
index 4e015833669..fce6f2fee7f 100644
--- a/tests/ui/nll/closure-requirements/type-test-subject-opaque-1.rs
+++ b/tests/ui/nll/closure-requirements/type-test-subject-opaque-1.rs
@@ -1,5 +1,5 @@
-// check-fail
-// known-bug: #107426
+// Regression test for #107426.
+// check-pass
use std::marker::PhantomData;
#[derive(Clone, Copy)]
diff --git a/tests/ui/nll/closure-requirements/type-test-subject-opaque-1.stderr b/tests/ui/nll/closure-requirements/type-test-subject-opaque-1.stderr
deleted file mode 100644
index e54bc8406de..00000000000
--- a/tests/ui/nll/closure-requirements/type-test-subject-opaque-1.stderr
+++ /dev/null
@@ -1,8 +0,0 @@
-error: `make_fn::{opaque#0}<'_>` does not live long enough
- --> $DIR/type-test-subject-opaque-1.rs:15:8
- |
-LL | || event(cx, open_toggle);
- | ^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to previous error
-
diff --git a/tests/ui/nll/closure-requirements/type-test-subject-unnamed-region.rs b/tests/ui/nll/closure-requirements/type-test-subject-unnamed-region.rs
index 25ce0891a8a..b5a95c17009 100644
--- a/tests/ui/nll/closure-requirements/type-test-subject-unnamed-region.rs
+++ b/tests/ui/nll/closure-requirements/type-test-subject-unnamed-region.rs
@@ -1,5 +1,5 @@
-// check-fail
-// known-bug: #108635
+// See #108635 for description.
+// check-pass
trait Trait {
type Item<'a>: 'a;
diff --git a/tests/ui/nll/closure-requirements/type-test-subject-unnamed-region.stderr b/tests/ui/nll/closure-requirements/type-test-subject-unnamed-region.stderr
deleted file mode 100644
index 201329bb005..00000000000
--- a/tests/ui/nll/closure-requirements/type-test-subject-unnamed-region.stderr
+++ /dev/null
@@ -1,21 +0,0 @@
-error[E0310]: the associated type `<I as Trait>::Item<'_>` may not live long enough
- --> $DIR/type-test-subject-unnamed-region.rs:11:27
- |
-LL | let closure = |a, _b| assert_static(a);
- | ^^^^^^^^^^^^^^^^
- |
- = help: consider adding an explicit lifetime bound `<I as Trait>::Item<'_>: 'static`...
- = note: ...so that the type `<I as Trait>::Item<'_>` will meet its required lifetime bounds
-
-error[E0310]: the associated type `<I as Trait>::Item<'_>` may not live long enough
- --> $DIR/type-test-subject-unnamed-region.rs:20:9
- |
-LL | assert_static(a);
- | ^^^^^^^^^^^^^^^^
- |
- = help: consider adding an explicit lifetime bound `<I as Trait>::Item<'_>: 'static`...
- = note: ...so that the type `<I as Trait>::Item<'_>` will meet its required lifetime bounds
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0310`.