Auto merge of #108691 - aliemjay:closure-subject, r=jackh726
fix multiple issues when promoting type-test subject Multiple interdependent fixes. See linked issues for a short description of each. When Promoting a type-test `T: 'a` from within the closure back to its parent function, there are a couple pre-existing bugs and limitations. They were exposed by the recent changes to opaque types because the type-test subject (`T`) is no longer a simple ParamTy. Commit 1: Fixes #108635 Fixes #107426 Commit 2: Fixes #108639 Commit 3: Fixes #107516
This commit is contained in:
commit
8824994ccd
@ -10,10 +10,9 @@
|
|||||||
BasicBlock, Body, ClosureOutlivesSubject, ClosureRegionRequirements, LocalKind, Location,
|
BasicBlock, Body, ClosureOutlivesSubject, ClosureRegionRequirements, LocalKind, Location,
|
||||||
Promoted,
|
Promoted,
|
||||||
};
|
};
|
||||||
use rustc_middle::ty::{self, OpaqueHiddenType, Region, RegionVid};
|
use rustc_middle::ty::{self, OpaqueHiddenType, Region, RegionVid, TyCtxt};
|
||||||
use rustc_span::symbol::sym;
|
use rustc_span::symbol::sym;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::fmt::Debug;
|
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
@ -325,7 +324,7 @@ pub(super) fn dump_mir_results<'tcx>(
|
|||||||
infcx: &BorrowckInferCtxt<'_, 'tcx>,
|
infcx: &BorrowckInferCtxt<'_, 'tcx>,
|
||||||
body: &Body<'tcx>,
|
body: &Body<'tcx>,
|
||||||
regioncx: &RegionInferenceContext<'tcx>,
|
regioncx: &RegionInferenceContext<'tcx>,
|
||||||
closure_region_requirements: &Option<ClosureRegionRequirements<'_>>,
|
closure_region_requirements: &Option<ClosureRegionRequirements<'tcx>>,
|
||||||
) {
|
) {
|
||||||
if !dump_enabled(infcx.tcx, "nll", body.source.def_id()) {
|
if !dump_enabled(infcx.tcx, "nll", body.source.def_id()) {
|
||||||
return;
|
return;
|
||||||
@ -340,9 +339,11 @@ pub(super) fn dump_mir_results<'tcx>(
|
|||||||
|
|
||||||
if let Some(closure_region_requirements) = closure_region_requirements {
|
if let Some(closure_region_requirements) = closure_region_requirements {
|
||||||
writeln!(out, "| Free Region Constraints")?;
|
writeln!(out, "| Free Region Constraints")?;
|
||||||
for_each_region_constraint(closure_region_requirements, &mut |msg| {
|
for_each_region_constraint(
|
||||||
writeln!(out, "| {}", msg)
|
infcx.tcx,
|
||||||
})?;
|
closure_region_requirements,
|
||||||
|
&mut |msg| writeln!(out, "| {}", msg),
|
||||||
|
)?;
|
||||||
writeln!(out, "|")?;
|
writeln!(out, "|")?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -375,7 +376,7 @@ pub(super) fn dump_annotation<'tcx>(
|
|||||||
infcx: &BorrowckInferCtxt<'_, 'tcx>,
|
infcx: &BorrowckInferCtxt<'_, 'tcx>,
|
||||||
body: &Body<'tcx>,
|
body: &Body<'tcx>,
|
||||||
regioncx: &RegionInferenceContext<'tcx>,
|
regioncx: &RegionInferenceContext<'tcx>,
|
||||||
closure_region_requirements: &Option<ClosureRegionRequirements<'_>>,
|
closure_region_requirements: &Option<ClosureRegionRequirements<'tcx>>,
|
||||||
opaque_type_values: &VecMap<LocalDefId, OpaqueHiddenType<'tcx>>,
|
opaque_type_values: &VecMap<LocalDefId, OpaqueHiddenType<'tcx>>,
|
||||||
errors: &mut crate::error::BorrowckErrors<'tcx>,
|
errors: &mut crate::error::BorrowckErrors<'tcx>,
|
||||||
) {
|
) {
|
||||||
@ -405,7 +406,7 @@ pub(super) fn dump_annotation<'tcx>(
|
|||||||
|
|
||||||
// Dump the region constraints we are imposing *between* those
|
// Dump the region constraints we are imposing *between* those
|
||||||
// newly created variables.
|
// newly created variables.
|
||||||
for_each_region_constraint(closure_region_requirements, &mut |msg| {
|
for_each_region_constraint(tcx, closure_region_requirements, &mut |msg| {
|
||||||
err.note(msg);
|
err.note(msg);
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
@ -426,16 +427,19 @@ pub(super) fn dump_annotation<'tcx>(
|
|||||||
errors.buffer_non_error_diag(err);
|
errors.buffer_non_error_diag(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn for_each_region_constraint(
|
fn for_each_region_constraint<'tcx>(
|
||||||
closure_region_requirements: &ClosureRegionRequirements<'_>,
|
tcx: TyCtxt<'tcx>,
|
||||||
|
closure_region_requirements: &ClosureRegionRequirements<'tcx>,
|
||||||
with_msg: &mut dyn FnMut(&str) -> io::Result<()>,
|
with_msg: &mut dyn FnMut(&str) -> io::Result<()>,
|
||||||
) -> io::Result<()> {
|
) -> io::Result<()> {
|
||||||
for req in &closure_region_requirements.outlives_requirements {
|
for req in &closure_region_requirements.outlives_requirements {
|
||||||
let subject: &dyn Debug = match &req.subject {
|
let subject = match req.subject {
|
||||||
ClosureOutlivesSubject::Region(subject) => subject,
|
ClosureOutlivesSubject::Region(subject) => format!("{:?}", subject),
|
||||||
ClosureOutlivesSubject::Ty(ty) => ty,
|
ClosureOutlivesSubject::Ty(ty) => {
|
||||||
|
format!("{:?}", ty.instantiate(tcx, |vid| tcx.mk_re_var(vid)))
|
||||||
|
}
|
||||||
};
|
};
|
||||||
with_msg(&format!("where {:?}: {:?}", subject, req.outlived_free_region,))?;
|
with_msg(&format!("where {}: {:?}", subject, req.outlived_free_region,))?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -12,8 +12,9 @@
|
|||||||
use rustc_infer::infer::region_constraints::{GenericKind, VarInfos, VerifyBound, VerifyIfEq};
|
use rustc_infer::infer::region_constraints::{GenericKind, VarInfos, VerifyBound, VerifyIfEq};
|
||||||
use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin};
|
use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin};
|
||||||
use rustc_middle::mir::{
|
use rustc_middle::mir::{
|
||||||
Body, ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureRegionRequirements,
|
Body, ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureOutlivesSubjectTy,
|
||||||
ConstraintCategory, Local, Location, ReturnConstraint, TerminatorKind,
|
ClosureRegionRequirements, ConstraintCategory, Local, Location, ReturnConstraint,
|
||||||
|
TerminatorKind,
|
||||||
};
|
};
|
||||||
use rustc_middle::traits::ObligationCause;
|
use rustc_middle::traits::ObligationCause;
|
||||||
use rustc_middle::traits::ObligationCauseCode;
|
use rustc_middle::traits::ObligationCauseCode;
|
||||||
@ -1084,18 +1085,10 @@ fn try_promote_type_test(
|
|||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
/// When we promote a type test `T: 'r`, we have to convert the
|
/// When we promote a type test `T: 'r`, we have to replace all region
|
||||||
/// type `T` into something we can store in a query result (so
|
/// variables in the type `T` with an equal universal region from the
|
||||||
/// something allocated for `'tcx`). This is problematic if `ty`
|
/// closure signature.
|
||||||
/// contains regions. During the course of NLL region checking, we
|
/// This is not always possible, so this is a fallible process.
|
||||||
/// 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`.
|
|
||||||
#[instrument(level = "debug", skip(self, infcx))]
|
#[instrument(level = "debug", skip(self, infcx))]
|
||||||
fn try_promote_type_test_subject(
|
fn try_promote_type_test_subject(
|
||||||
&self,
|
&self,
|
||||||
@ -1104,91 +1097,63 @@ fn try_promote_type_test_subject(
|
|||||||
) -> Option<ClosureOutlivesSubject<'tcx>> {
|
) -> Option<ClosureOutlivesSubject<'tcx>> {
|
||||||
let tcx = infcx.tcx;
|
let tcx = infcx.tcx;
|
||||||
|
|
||||||
|
// Opaque types' substs may include useless lifetimes.
|
||||||
|
// We will replace them with ReStatic.
|
||||||
|
struct OpaqueFolder<'tcx> {
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
}
|
||||||
|
impl<'tcx> ty::TypeFolder<TyCtxt<'tcx>> for OpaqueFolder<'tcx> {
|
||||||
|
fn interner(&self) -> TyCtxt<'tcx> {
|
||||||
|
self.tcx
|
||||||
|
}
|
||||||
|
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
|
||||||
|
use ty::TypeSuperFoldable as _;
|
||||||
|
let tcx = self.tcx;
|
||||||
|
let &ty::Alias(ty::Opaque, ty::AliasTy { substs, def_id, .. }) = t.kind() else {
|
||||||
|
return t.super_fold_with(self);
|
||||||
|
};
|
||||||
|
let substs =
|
||||||
|
std::iter::zip(substs, tcx.variances_of(def_id)).map(|(arg, v)| {
|
||||||
|
match (arg.unpack(), v) {
|
||||||
|
(ty::GenericArgKind::Lifetime(_), ty::Bivariant) => {
|
||||||
|
tcx.lifetimes.re_static.into()
|
||||||
|
}
|
||||||
|
_ => arg.fold_with(self),
|
||||||
|
}
|
||||||
|
});
|
||||||
|
tcx.mk_opaque(def_id, tcx.mk_substs_from_iter(substs))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let ty = ty.fold_with(&mut OpaqueFolder { tcx });
|
||||||
|
|
||||||
let ty = tcx.fold_regions(ty, |r, _depth| {
|
let ty = tcx.fold_regions(ty, |r, _depth| {
|
||||||
let region_vid = self.to_region_vid(r);
|
let r_vid = self.to_region_vid(r);
|
||||||
|
let r_scc = self.constraint_sccs.scc(r_vid);
|
||||||
|
|
||||||
// The challenge if this. We have some region variable `r`
|
// The challenge if this. We have some region variable `r`
|
||||||
// whose value is a set of CFG points and universal
|
// whose value is a set of CFG points and universal
|
||||||
// regions. We want to find if that set is *equivalent* to
|
// regions. We want to find if that set is *equivalent* to
|
||||||
// any of the named regions found in the closure.
|
// any of the named regions found in the closure.
|
||||||
//
|
// To do so, we simply check every candidate `u_r` for equality.
|
||||||
// To do so, we compute the
|
self.scc_values
|
||||||
// `non_local_universal_upper_bound`. This will be a
|
.universal_regions_outlived_by(r_scc)
|
||||||
// non-local, universal region that is greater than `r`.
|
.filter(|&u_r| !self.universal_regions.is_local_free_region(u_r))
|
||||||
// However, it might not be *contained* within `r`, so
|
.find(|&u_r| self.eval_equal(u_r, r_vid))
|
||||||
// then we further check whether this bound is contained
|
.map(|u_r| tcx.mk_re_var(u_r))
|
||||||
// in `r`. If so, we can say that `r` is equivalent to the
|
// In the case of a failure, use `ReErased`. We will eventually
|
||||||
// bound.
|
// return `None` in this case.
|
||||||
//
|
.unwrap_or(tcx.lifetimes.re_erased)
|
||||||
// Let's work through a few examples. For these, imagine
|
|
||||||
// that we have 3 non-local regions (I'll denote them as
|
|
||||||
// `'static`, `'a`, and `'b`, though of course in the code
|
|
||||||
// they would be represented with indices) where:
|
|
||||||
//
|
|
||||||
// - `'static: 'a`
|
|
||||||
// - `'static: 'b`
|
|
||||||
//
|
|
||||||
// First, let's assume that `r` is some existential
|
|
||||||
// variable with an inferred value `{'a, 'static}` (plus
|
|
||||||
// some CFG nodes). In this case, the non-local upper
|
|
||||||
// bound is `'static`, since that outlives `'a`. `'static`
|
|
||||||
// is also a member of `r` and hence we consider `r`
|
|
||||||
// equivalent to `'static` (and replace it with
|
|
||||||
// `'static`).
|
|
||||||
//
|
|
||||||
// Now let's consider the inferred value `{'a, 'b}`. This
|
|
||||||
// means `r` is effectively `'a | 'b`. I'm not sure if
|
|
||||||
// this can come about, actually, but assuming it did, we
|
|
||||||
// would get a non-local upper bound of `'static`. Since
|
|
||||||
// `'static` is not contained in `r`, we would fail to
|
|
||||||
// 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)
|
|
||||||
} else {
|
|
||||||
// In the case of a failure, use a `ReVar` result. This will
|
|
||||||
// cause the `needs_infer` later on to return `None`.
|
|
||||||
r
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
debug!("try_promote_type_test_subject: folded ty = {:?}", ty);
|
debug!("try_promote_type_test_subject: folded ty = {:?}", ty);
|
||||||
|
|
||||||
// `needs_infer` will only be true if we failed to promote some region.
|
// This will be true if we failed to promote some region.
|
||||||
if ty.needs_infer() {
|
if ty.has_erased_regions() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(ClosureOutlivesSubject::Ty(ty))
|
Some(ClosureOutlivesSubject::Ty(ClosureOutlivesSubjectTy::bind(tcx, ty)))
|
||||||
}
|
|
||||||
|
|
||||||
/// Given some universal or existential region `r`, finds a
|
|
||||||
/// non-local, universal region `r+` that outlives `r` at entry to (and
|
|
||||||
/// exit from) the closure. In the worst case, this will be
|
|
||||||
/// `'static`.
|
|
||||||
///
|
|
||||||
/// This is used for two purposes. First, if we are propagated
|
|
||||||
/// some requirement `T: r`, we can use this method to enlarge `r`
|
|
||||||
/// to something we can encode for our creator (which only knows
|
|
||||||
/// about non-local, universal regions). It is also used when
|
|
||||||
/// encoding `T` as part of `try_promote_type_test_subject` (see
|
|
||||||
/// that fn for details).
|
|
||||||
///
|
|
||||||
/// This is based on the result `'y` of `universal_upper_bound`,
|
|
||||||
/// except that it converts further takes the non-local upper
|
|
||||||
/// bound of `'y`, so that the final result is non-local.
|
|
||||||
fn non_local_universal_upper_bound(&self, r: RegionVid) -> RegionVid {
|
|
||||||
debug!("non_local_universal_upper_bound(r={:?}={})", r, self.region_value_str(r));
|
|
||||||
|
|
||||||
let lub = self.universal_upper_bound(r);
|
|
||||||
|
|
||||||
// Grow further to get smallest universal region known to
|
|
||||||
// creator.
|
|
||||||
let non_local_lub = self.universal_region_relations.non_local_upper_bound(lub);
|
|
||||||
|
|
||||||
debug!("non_local_universal_upper_bound: non_local_lub={:?}", non_local_lub);
|
|
||||||
|
|
||||||
non_local_lub
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a universally quantified region that outlives the
|
/// Returns a universally quantified region that outlives the
|
||||||
|
@ -116,7 +116,9 @@ pub fn apply_closure_requirements(
|
|||||||
let outlived_region = closure_mapping[outlives_requirement.outlived_free_region];
|
let outlived_region = closure_mapping[outlives_requirement.outlived_free_region];
|
||||||
let subject = match outlives_requirement.subject {
|
let subject = match outlives_requirement.subject {
|
||||||
ClosureOutlivesSubject::Region(re) => closure_mapping[re].into(),
|
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;
|
self.category = outlives_requirement.category;
|
||||||
|
@ -93,31 +93,6 @@ pub(crate) fn non_local_upper_bounds(&self, fr: RegionVid) -> Vec<RegionVid> {
|
|||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the "postdominating" bound of the set of
|
|
||||||
/// `non_local_upper_bounds` for the given region.
|
|
||||||
pub(crate) fn non_local_upper_bound(&self, fr: RegionVid) -> RegionVid {
|
|
||||||
let upper_bounds = self.non_local_upper_bounds(fr);
|
|
||||||
|
|
||||||
// In case we find more than one, reduce to one for
|
|
||||||
// convenience. This is to prevent us from generating more
|
|
||||||
// complex constraints, but it will cause spurious errors.
|
|
||||||
let post_dom = self.inverse_outlives.mutual_immediate_postdominator(upper_bounds);
|
|
||||||
|
|
||||||
debug!("non_local_bound: post_dom={:?}", post_dom);
|
|
||||||
|
|
||||||
post_dom
|
|
||||||
.and_then(|post_dom| {
|
|
||||||
// If the mutual immediate postdom is not local, then
|
|
||||||
// there is no non-local result we can return.
|
|
||||||
if !self.universal_regions.is_local_free_region(post_dom) {
|
|
||||||
Some(post_dom)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.unwrap_or(self.universal_regions.fr_static)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Finds a "lower bound" for `fr` that is not local. In other
|
/// Finds a "lower bound" for `fr` that is not local. In other
|
||||||
/// words, returns the largest (*) known region `fr1` that (a) is
|
/// words, returns the largest (*) known region `fr1` that (a) is
|
||||||
/// outlived by `fr` and (b) is not local.
|
/// outlived by `fr` and (b) is not local.
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||||
use rustc_index::bit_set::BitMatrix;
|
use rustc_index::bit_set::BitMatrix;
|
||||||
use rustc_index::vec::IndexVec;
|
use rustc_index::vec::{Idx, IndexVec};
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
use rustc_target::abi::VariantIdx;
|
use rustc_target::abi::VariantIdx;
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
@ -289,13 +289,6 @@ pub struct ConstQualifs {
|
|||||||
/// instance of the closure is created, the corresponding free regions
|
/// instance of the closure is created, the corresponding free regions
|
||||||
/// can be extracted from its type and constrained to have the given
|
/// can be extracted from its type and constrained to have the given
|
||||||
/// outlives relationship.
|
/// 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)]
|
#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)]
|
||||||
pub struct ClosureRegionRequirements<'tcx> {
|
pub struct ClosureRegionRequirements<'tcx> {
|
||||||
/// The number of external regions defined on the closure. In our
|
/// The number of external regions defined on the closure. In our
|
||||||
@ -392,16 +385,59 @@ pub enum ClosureOutlivesSubject<'tcx> {
|
|||||||
/// Subject is a type, typically a type parameter, but could also
|
/// Subject is a type, typically a type parameter, but could also
|
||||||
/// be a projection. Indicates a requirement like `T: 'a` being
|
/// be a projection. Indicates a requirement like `T: 'a` being
|
||||||
/// passed to the caller, where the type here is `T`.
|
/// passed to the caller, where the type here is `T`.
|
||||||
///
|
Ty(ClosureOutlivesSubjectTy<'tcx>),
|
||||||
/// The type here is guaranteed not to contain any free regions at
|
|
||||||
/// present.
|
|
||||||
Ty(Ty<'tcx>),
|
|
||||||
|
|
||||||
/// Subject is a free region from the closure. Indicates a requirement
|
/// Subject is a free region from the closure. Indicates a requirement
|
||||||
/// like `'a: 'b` being passed to the caller; the region here is `'a`.
|
/// like `'a: 'b` being passed to the caller; the region here is `'a`.
|
||||||
Region(ty::RegionVid),
|
Region(ty::RegionVid),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Represents a `ty::Ty` for use in [`ClosureOutlivesSubject`].
|
||||||
|
///
|
||||||
|
/// This abstraction is necessary because the type may include `ReVar` regions,
|
||||||
|
/// which is what we use internally within NLL code, and they can't be used in
|
||||||
|
/// a query response.
|
||||||
|
///
|
||||||
|
/// DO NOT implement `TypeVisitable` or `TypeFoldable` traits, because this
|
||||||
|
/// type is not recognized as a binder for late-bound region.
|
||||||
|
#[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 represent
|
||||||
|
/// universal regions *external* to the closure.
|
||||||
|
pub fn bind(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(vid.as_u32(), 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.
|
/// The constituent parts of a mir constant of kind ADT or array.
|
||||||
#[derive(Copy, Clone, Debug, HashStable)]
|
#[derive(Copy, Clone, Debug, HashStable)]
|
||||||
pub struct DestructuredConstant<'tcx> {
|
pub struct DestructuredConstant<'tcx> {
|
||||||
|
@ -0,0 +1,19 @@
|
|||||||
|
// See #108639 for description.
|
||||||
|
// check-pass
|
||||||
|
|
||||||
|
trait Trait {
|
||||||
|
type Item<'a>: 'a;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn assert_static<T: 'static>(_: T) {}
|
||||||
|
fn relate<T>(_: T, _: T) {}
|
||||||
|
|
||||||
|
fn test_args<I: Trait>() {
|
||||||
|
let closure = |a, b| {
|
||||||
|
relate(&a, b);
|
||||||
|
assert_static(a);
|
||||||
|
};
|
||||||
|
closure(None::<I::Item<'_>>, &None::<I::Item<'_>>);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
@ -0,0 +1,18 @@
|
|||||||
|
// Regression test for #107426.
|
||||||
|
// check-pass
|
||||||
|
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub struct Scope<'a>(&'a PhantomData<&'a mut &'a ()>);
|
||||||
|
fn event<'a, F: FnMut() + 'a>(_: Scope<'a>, _: F) {}
|
||||||
|
fn make_fn<'a>(_: Scope<'a>) -> impl Fn() + Copy + 'a {
|
||||||
|
|| {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn foo(cx: Scope) {
|
||||||
|
let open_toggle = make_fn(cx);
|
||||||
|
|
||||||
|
|| event(cx, open_toggle);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
@ -0,0 +1,17 @@
|
|||||||
|
// Resgression test for #107516.
|
||||||
|
// check-pass
|
||||||
|
|
||||||
|
fn iter1<'a: 'a>() -> impl Iterator<Item = &'static str> {
|
||||||
|
None.into_iter()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn iter2<'a>() -> impl Iterator<Item = &'a str> {
|
||||||
|
None.into_iter()
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Bivar<'a, I: Iterator<Item = &'a str> + 'a>(I);
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let _ = || Bivar(iter1());
|
||||||
|
let _ = || Bivar(iter2());
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
// See #108635 for description.
|
||||||
|
// check-pass
|
||||||
|
|
||||||
|
trait Trait {
|
||||||
|
type Item<'a>: 'a;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn assert_static<T: 'static>(_: T) {}
|
||||||
|
|
||||||
|
fn test_args<I: Trait>() {
|
||||||
|
let closure = |a, _b| assert_static(a);
|
||||||
|
|
||||||
|
closure(None::<I::Item<'_>>, &None::<I::Item<'_>>);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_upvars<I: Trait>() {
|
||||||
|
let upvars = (None::<I::Item<'_>>, &None::<I::Item<'_>>);
|
||||||
|
let _closure = || {
|
||||||
|
let (a, _b) = upvars;
|
||||||
|
assert_static(a);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
@ -110,7 +110,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t));
|
|||||||
(),
|
(),
|
||||||
]
|
]
|
||||||
= note: number of external vids: 4
|
= note: number of external vids: 4
|
||||||
= note: where <T as Anything<ReEarlyBound(1, 'b)>>::AssocType: '_#3r
|
= note: where <T as Anything<'_#2r>>::AssocType: '_#3r
|
||||||
|
|
||||||
note: no external requirements
|
note: no external requirements
|
||||||
--> $DIR/projection-one-region-closure.rs:62:1
|
--> $DIR/projection-one-region-closure.rs:62:1
|
||||||
|
@ -86,7 +86,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t));
|
|||||||
(),
|
(),
|
||||||
]
|
]
|
||||||
= note: number of external vids: 4
|
= note: number of external vids: 4
|
||||||
= note: where <T as Anything<ReEarlyBound(1, 'b)>>::AssocType: '_#3r
|
= note: where <T as Anything<'_#2r>>::AssocType: '_#3r
|
||||||
|
|
||||||
note: no external requirements
|
note: no external requirements
|
||||||
--> $DIR/projection-one-region-trait-bound-closure.rs:52:1
|
--> $DIR/projection-one-region-trait-bound-closure.rs:52:1
|
||||||
|
@ -11,7 +11,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t));
|
|||||||
]
|
]
|
||||||
= note: late-bound region is '_#4r
|
= note: late-bound region is '_#4r
|
||||||
= note: number of external vids: 5
|
= note: number of external vids: 5
|
||||||
= note: where <T as Anything<ReEarlyBound(0, 'b), ReEarlyBound(1, 'c)>>::AssocType: '_#3r
|
= note: where <T as Anything<'_#1r, '_#2r>>::AssocType: '_#3r
|
||||||
|
|
||||||
note: no external requirements
|
note: no external requirements
|
||||||
--> $DIR/projection-two-region-trait-bound-closure.rs:34:1
|
--> $DIR/projection-two-region-trait-bound-closure.rs:34:1
|
||||||
@ -23,14 +23,14 @@ LL | | T: Anything<'b, 'c>,
|
|||||||
|
|
|
|
||||||
= note: defining type: no_relationships_late::<'_#1r, '_#2r, T>
|
= note: defining type: no_relationships_late::<'_#1r, '_#2r, T>
|
||||||
|
|
||||||
error[E0309]: the associated type `<T as Anything<ReEarlyBound(0, 'b), ReEarlyBound(1, 'c)>>::AssocType` may not live long enough
|
error[E0309]: the associated type `<T as Anything<'_#5r, '_#6r>>::AssocType` may not live long enough
|
||||||
--> $DIR/projection-two-region-trait-bound-closure.rs:38:39
|
--> $DIR/projection-two-region-trait-bound-closure.rs:38:39
|
||||||
|
|
|
|
||||||
LL | with_signature(cell, t, |cell, t| require(cell, t));
|
LL | with_signature(cell, t, |cell, t| require(cell, t));
|
||||||
| ^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= help: consider adding an explicit lifetime bound `<T as Anything<ReEarlyBound(0, 'b), ReEarlyBound(1, 'c)>>::AssocType: 'a`...
|
= help: consider adding an explicit lifetime bound `<T as Anything<'_#5r, '_#6r>>::AssocType: 'a`...
|
||||||
= note: ...so that the type `<T as Anything<ReEarlyBound(0, 'b), ReEarlyBound(1, 'c)>>::AssocType` will meet its required lifetime bounds
|
= note: ...so that the type `<T as Anything<'_#5r, '_#6r>>::AssocType` will meet its required lifetime bounds
|
||||||
|
|
||||||
note: external requirements
|
note: external requirements
|
||||||
--> $DIR/projection-two-region-trait-bound-closure.rs:48:29
|
--> $DIR/projection-two-region-trait-bound-closure.rs:48:29
|
||||||
@ -44,7 +44,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t));
|
|||||||
(),
|
(),
|
||||||
]
|
]
|
||||||
= note: number of external vids: 5
|
= note: number of external vids: 5
|
||||||
= note: where <T as Anything<ReEarlyBound(1, 'b), ReEarlyBound(2, 'c)>>::AssocType: '_#4r
|
= note: where <T as Anything<'_#2r, '_#3r>>::AssocType: '_#4r
|
||||||
|
|
||||||
note: no external requirements
|
note: no external requirements
|
||||||
--> $DIR/projection-two-region-trait-bound-closure.rs:43:1
|
--> $DIR/projection-two-region-trait-bound-closure.rs:43:1
|
||||||
@ -57,14 +57,14 @@ LL | | 'a: 'a,
|
|||||||
|
|
|
|
||||||
= note: defining type: no_relationships_early::<'_#1r, '_#2r, '_#3r, T>
|
= note: defining type: no_relationships_early::<'_#1r, '_#2r, '_#3r, T>
|
||||||
|
|
||||||
error[E0309]: the associated type `<T as Anything<ReEarlyBound(1, 'b), ReEarlyBound(2, 'c)>>::AssocType` may not live long enough
|
error[E0309]: the associated type `<T as Anything<'_#6r, '_#7r>>::AssocType` may not live long enough
|
||||||
--> $DIR/projection-two-region-trait-bound-closure.rs:48:39
|
--> $DIR/projection-two-region-trait-bound-closure.rs:48:39
|
||||||
|
|
|
|
||||||
LL | with_signature(cell, t, |cell, t| require(cell, t));
|
LL | with_signature(cell, t, |cell, t| require(cell, t));
|
||||||
| ^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= help: consider adding an explicit lifetime bound `<T as Anything<ReEarlyBound(1, 'b), ReEarlyBound(2, 'c)>>::AssocType: 'a`...
|
= help: consider adding an explicit lifetime bound `<T as Anything<'_#6r, '_#7r>>::AssocType: 'a`...
|
||||||
= note: ...so that the type `<T as Anything<ReEarlyBound(1, 'b), ReEarlyBound(2, 'c)>>::AssocType` will meet its required lifetime bounds
|
= note: ...so that the type `<T as Anything<'_#6r, '_#7r>>::AssocType` will meet its required lifetime bounds
|
||||||
|
|
||||||
note: external requirements
|
note: external requirements
|
||||||
--> $DIR/projection-two-region-trait-bound-closure.rs:61:29
|
--> $DIR/projection-two-region-trait-bound-closure.rs:61:29
|
||||||
@ -78,7 +78,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t));
|
|||||||
(),
|
(),
|
||||||
]
|
]
|
||||||
= note: number of external vids: 5
|
= note: number of external vids: 5
|
||||||
= note: where <T as Anything<ReEarlyBound(1, 'b), ReEarlyBound(2, 'c)>>::AssocType: '_#4r
|
= note: where <T as Anything<'_#2r, '_#3r>>::AssocType: '_#4r
|
||||||
|
|
||||||
note: no external requirements
|
note: no external requirements
|
||||||
--> $DIR/projection-two-region-trait-bound-closure.rs:53:1
|
--> $DIR/projection-two-region-trait-bound-closure.rs:53:1
|
||||||
@ -103,7 +103,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t));
|
|||||||
(),
|
(),
|
||||||
]
|
]
|
||||||
= note: number of external vids: 5
|
= note: number of external vids: 5
|
||||||
= note: where <T as Anything<ReEarlyBound(1, 'b), ReEarlyBound(2, 'c)>>::AssocType: '_#4r
|
= note: where <T as Anything<'_#2r, '_#3r>>::AssocType: '_#4r
|
||||||
|
|
||||||
note: no external requirements
|
note: no external requirements
|
||||||
--> $DIR/projection-two-region-trait-bound-closure.rs:65:1
|
--> $DIR/projection-two-region-trait-bound-closure.rs:65:1
|
||||||
@ -128,7 +128,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t));
|
|||||||
(),
|
(),
|
||||||
]
|
]
|
||||||
= note: number of external vids: 5
|
= note: number of external vids: 5
|
||||||
= note: where <T as Anything<ReEarlyBound(1, 'b), ReEarlyBound(2, 'c)>>::AssocType: '_#4r
|
= note: where <T as Anything<'_#2r, '_#3r>>::AssocType: '_#4r
|
||||||
|
|
||||||
note: no external requirements
|
note: no external requirements
|
||||||
--> $DIR/projection-two-region-trait-bound-closure.rs:74:1
|
--> $DIR/projection-two-region-trait-bound-closure.rs:74:1
|
||||||
@ -154,7 +154,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t));
|
|||||||
]
|
]
|
||||||
= note: late-bound region is '_#3r
|
= note: late-bound region is '_#3r
|
||||||
= note: number of external vids: 4
|
= note: number of external vids: 4
|
||||||
= note: where <T as Anything<ReEarlyBound(0, 'b), ReEarlyBound(0, 'b)>>::AssocType: '_#2r
|
= note: where <T as Anything<'_#1r, '_#1r>>::AssocType: '_#2r
|
||||||
|
|
||||||
note: no external requirements
|
note: no external requirements
|
||||||
--> $DIR/projection-two-region-trait-bound-closure.rs:83:1
|
--> $DIR/projection-two-region-trait-bound-closure.rs:83:1
|
||||||
@ -194,7 +194,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t));
|
|||||||
(),
|
(),
|
||||||
]
|
]
|
||||||
= note: number of external vids: 4
|
= note: number of external vids: 4
|
||||||
= note: where <T as Anything<ReEarlyBound(1, 'b), ReEarlyBound(1, 'b)>>::AssocType: '_#3r
|
= note: where <T as Anything<'_#2r, '_#2r>>::AssocType: '_#3r
|
||||||
|
|
||||||
note: no external requirements
|
note: no external requirements
|
||||||
--> $DIR/projection-two-region-trait-bound-closure.rs:92:1
|
--> $DIR/projection-two-region-trait-bound-closure.rs:92:1
|
||||||
@ -219,7 +219,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t));
|
|||||||
(),
|
(),
|
||||||
]
|
]
|
||||||
= note: number of external vids: 3
|
= note: number of external vids: 3
|
||||||
= note: where <T as Anything<ReEarlyBound(0, 'a), ReEarlyBound(0, 'a)>>::AssocType: '_#2r
|
= note: where <T as Anything<'_#1r, '_#1r>>::AssocType: '_#2r
|
||||||
|
|
||||||
note: no external requirements
|
note: no external requirements
|
||||||
--> $DIR/projection-two-region-trait-bound-closure.rs:101:1
|
--> $DIR/projection-two-region-trait-bound-closure.rs:101:1
|
||||||
|
Loading…
Reference in New Issue
Block a user