Auto merge of #106910 - aliemjay:alias-ty-in-regionck, r=oli-obk
even more unify Projection/Opaque handling in region outlives code edit: This continues ate the same pace as #106829. New changes are described in https://github.com/rust-lang/rust/pull/106910#issuecomment-1383251254. ~This touches `OutlivesBound`, `Component`, `GenericKind` enums.~ r? `@oli-obk` (because of overlap with #95474)
This commit is contained in:
commit
19423b5944
13 changed files with 108 additions and 151 deletions
|
@ -359,9 +359,9 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
|
||||||
.insert(ty::OutlivesPredicate(GenericKind::Param(param_b), r_a));
|
.insert(ty::OutlivesPredicate(GenericKind::Param(param_b), r_a));
|
||||||
}
|
}
|
||||||
|
|
||||||
OutlivesBound::RegionSubAlias(r_a, kind, alias_b) => {
|
OutlivesBound::RegionSubAlias(r_a, alias_b) => {
|
||||||
self.region_bound_pairs
|
self.region_bound_pairs
|
||||||
.insert(ty::OutlivesPredicate(GenericKind::Alias(kind, alias_b), r_a));
|
.insert(ty::OutlivesPredicate(GenericKind::Alias(alias_b), r_a));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,7 +80,7 @@ pub(crate) fn insert_outlives_predicate<'tcx>(
|
||||||
.or_insert(span);
|
.or_insert(span);
|
||||||
}
|
}
|
||||||
|
|
||||||
Component::Alias(kind, alias) => {
|
Component::Alias(alias_ty) => {
|
||||||
// This would either arise from something like:
|
// This would either arise from something like:
|
||||||
//
|
//
|
||||||
// ```
|
// ```
|
||||||
|
@ -99,13 +99,13 @@ pub(crate) fn insert_outlives_predicate<'tcx>(
|
||||||
//
|
//
|
||||||
// Here we want to add an explicit `where <T as Iterator>::Item: 'a`
|
// Here we want to add an explicit `where <T as Iterator>::Item: 'a`
|
||||||
// or `Opaque<T>: 'a` depending on the alias kind.
|
// or `Opaque<T>: 'a` depending on the alias kind.
|
||||||
let ty: Ty<'tcx> = tcx.mk_ty(ty::Alias(kind, alias));
|
let ty = alias_ty.to_ty(tcx);
|
||||||
required_predicates
|
required_predicates
|
||||||
.entry(ty::OutlivesPredicate(ty.into(), outlived_region))
|
.entry(ty::OutlivesPredicate(ty.into(), outlived_region))
|
||||||
.or_insert(span);
|
.or_insert(span);
|
||||||
}
|
}
|
||||||
|
|
||||||
Component::EscapingProjection(_) => {
|
Component::EscapingAlias(_) => {
|
||||||
// As above, but the projection involves
|
// As above, but the projection involves
|
||||||
// late-bound regions. Therefore, the WF
|
// late-bound regions. Therefore, the WF
|
||||||
// requirement is not checked in type definition
|
// requirement is not checked in type definition
|
||||||
|
|
|
@ -2272,13 +2272,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||||
|
|
||||||
let labeled_user_string = match bound_kind {
|
let labeled_user_string = match bound_kind {
|
||||||
GenericKind::Param(ref p) => format!("the parameter type `{}`", p),
|
GenericKind::Param(ref p) => format!("the parameter type `{}`", p),
|
||||||
GenericKind::Alias(ty::Projection, ref p) => format!("the associated type `{}`", p),
|
GenericKind::Alias(ref p) => match p.kind(self.tcx) {
|
||||||
GenericKind::Alias(ty::Opaque, ref p) => {
|
ty::AliasKind::Projection => format!("the associated type `{}`", p),
|
||||||
format!(
|
ty::AliasKind::Opaque => format!("the opaque type `{}`", p),
|
||||||
"the opaque type `{}`",
|
},
|
||||||
self.tcx.def_path_str_with_substs(p.def_id, p.substs)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(SubregionOrigin::CompareImplItemObligation {
|
if let Some(SubregionOrigin::CompareImplItemObligation {
|
||||||
|
|
|
@ -22,7 +22,7 @@ pub enum Component<'tcx> {
|
||||||
// is not in a position to judge which is the best technique, so
|
// is not in a position to judge which is the best technique, so
|
||||||
// we just product the projection as a component and leave it to
|
// we just product the projection as a component and leave it to
|
||||||
// the consumer to decide (but see `EscapingProjection` below).
|
// the consumer to decide (but see `EscapingProjection` below).
|
||||||
Alias(ty::AliasKind, ty::AliasTy<'tcx>),
|
Alias(ty::AliasTy<'tcx>),
|
||||||
|
|
||||||
// In the case where a projection has escaping regions -- meaning
|
// In the case where a projection has escaping regions -- meaning
|
||||||
// regions bound within the type itself -- we always use
|
// regions bound within the type itself -- we always use
|
||||||
|
@ -44,7 +44,7 @@ pub enum Component<'tcx> {
|
||||||
// projection, so that implied bounds code can avoid relying on
|
// projection, so that implied bounds code can avoid relying on
|
||||||
// them. This gives us room to improve the regionck reasoning in
|
// them. This gives us room to improve the regionck reasoning in
|
||||||
// the future without breaking backwards compat.
|
// the future without breaking backwards compat.
|
||||||
EscapingProjection(Vec<Component<'tcx>>),
|
EscapingAlias(Vec<Component<'tcx>>),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Push onto `out` all the things that must outlive `'a` for the condition
|
/// Push onto `out` all the things that must outlive `'a` for the condition
|
||||||
|
@ -120,17 +120,6 @@ fn compute_components<'tcx>(
|
||||||
out.push(Component::Param(p));
|
out.push(Component::Param(p));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ignore lifetimes found in opaque types. Opaque types can
|
|
||||||
// have lifetimes in their substs which their hidden type doesn't
|
|
||||||
// actually use. If we inferred that an opaque type is outlived by
|
|
||||||
// its parameter lifetimes, then we could prove that any lifetime
|
|
||||||
// outlives any other lifetime, which is unsound.
|
|
||||||
// See https://github.com/rust-lang/rust/issues/84305 for
|
|
||||||
// more details.
|
|
||||||
ty::Alias(ty::Opaque, data) => {
|
|
||||||
out.push(Component::Alias(ty::Opaque, data));
|
|
||||||
},
|
|
||||||
|
|
||||||
// For projections, we prefer to generate an obligation like
|
// For projections, we prefer to generate an obligation like
|
||||||
// `<P0 as Trait<P1...Pn>>::Foo: 'a`, because this gives the
|
// `<P0 as Trait<P1...Pn>>::Foo: 'a`, because this gives the
|
||||||
// regionck more ways to prove that it holds. However,
|
// regionck more ways to prove that it holds. However,
|
||||||
|
@ -139,15 +128,15 @@ fn compute_components<'tcx>(
|
||||||
// trait-ref. Therefore, if we see any higher-ranked regions,
|
// trait-ref. Therefore, if we see any higher-ranked regions,
|
||||||
// we simply fallback to the most restrictive rule, which
|
// we simply fallback to the most restrictive rule, which
|
||||||
// requires that `Pi: 'a` for all `i`.
|
// requires that `Pi: 'a` for all `i`.
|
||||||
ty::Alias(ty::Projection, data) => {
|
ty::Alias(_, alias_ty) => {
|
||||||
if !data.has_escaping_bound_vars() {
|
if !alias_ty.has_escaping_bound_vars() {
|
||||||
// best case: no escaping regions, so push the
|
// best case: no escaping regions, so push the
|
||||||
// projection and skip the subtree (thus generating no
|
// projection and skip the subtree (thus generating no
|
||||||
// constraints for Pi). This defers the choice between
|
// constraints for Pi). This defers the choice between
|
||||||
// the rules OutlivesProjectionEnv,
|
// the rules OutlivesProjectionEnv,
|
||||||
// OutlivesProjectionTraitDef, and
|
// OutlivesProjectionTraitDef, and
|
||||||
// OutlivesProjectionComponents to regionck.
|
// OutlivesProjectionComponents to regionck.
|
||||||
out.push(Component::Alias(ty::Projection, data));
|
out.push(Component::Alias(alias_ty));
|
||||||
} else {
|
} else {
|
||||||
// fallback case: hard code
|
// fallback case: hard code
|
||||||
// OutlivesProjectionComponents. Continue walking
|
// OutlivesProjectionComponents. Continue walking
|
||||||
|
@ -155,7 +144,7 @@ fn compute_components<'tcx>(
|
||||||
let mut subcomponents = smallvec![];
|
let mut subcomponents = smallvec![];
|
||||||
let mut subvisited = SsoHashSet::new();
|
let mut subvisited = SsoHashSet::new();
|
||||||
compute_components_recursive(tcx, ty.into(), &mut subcomponents, &mut subvisited);
|
compute_components_recursive(tcx, ty.into(), &mut subcomponents, &mut subvisited);
|
||||||
out.push(Component::EscapingProjection(subcomponents.into_iter().collect()));
|
out.push(Component::EscapingAlias(subcomponents.into_iter().collect()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -138,9 +138,9 @@ impl<'tcx> OutlivesEnvironmentBuilder<'tcx> {
|
||||||
self.region_bound_pairs
|
self.region_bound_pairs
|
||||||
.insert(ty::OutlivesPredicate(GenericKind::Param(param_b), r_a));
|
.insert(ty::OutlivesPredicate(GenericKind::Param(param_b), r_a));
|
||||||
}
|
}
|
||||||
OutlivesBound::RegionSubAlias(r_a, kind, projection_b) => {
|
OutlivesBound::RegionSubAlias(r_a, alias_b) => {
|
||||||
self.region_bound_pairs
|
self.region_bound_pairs
|
||||||
.insert(ty::OutlivesPredicate(GenericKind::Alias(kind, projection_b), r_a));
|
.insert(ty::OutlivesPredicate(GenericKind::Alias(alias_b), r_a));
|
||||||
}
|
}
|
||||||
OutlivesBound::RegionSubRegion(r_a, r_b) => {
|
OutlivesBound::RegionSubRegion(r_a, r_b) => {
|
||||||
if let (ReEarlyBound(_) | ReFree(_), ReVar(vid_b)) = (r_a.kind(), r_b.kind()) {
|
if let (ReEarlyBound(_) | ReFree(_), ReVar(vid_b)) = (r_a.kind(), r_b.kind()) {
|
||||||
|
|
|
@ -67,7 +67,6 @@ use crate::infer::{
|
||||||
};
|
};
|
||||||
use crate::traits::{ObligationCause, ObligationCauseCode};
|
use crate::traits::{ObligationCause, ObligationCauseCode};
|
||||||
use rustc_data_structures::undo_log::UndoLogs;
|
use rustc_data_structures::undo_log::UndoLogs;
|
||||||
use rustc_hir::def_id::DefId;
|
|
||||||
use rustc_middle::mir::ConstraintCategory;
|
use rustc_middle::mir::ConstraintCategory;
|
||||||
use rustc_middle::ty::subst::GenericArgKind;
|
use rustc_middle::ty::subst::GenericArgKind;
|
||||||
use rustc_middle::ty::{self, Region, SubstsRef, Ty, TyCtxt, TypeVisitable};
|
use rustc_middle::ty::{self, Region, SubstsRef, Ty, TyCtxt, TypeVisitable};
|
||||||
|
@ -266,10 +265,8 @@ where
|
||||||
Component::Param(param_ty) => {
|
Component::Param(param_ty) => {
|
||||||
self.param_ty_must_outlive(origin, region, *param_ty);
|
self.param_ty_must_outlive(origin, region, *param_ty);
|
||||||
}
|
}
|
||||||
Component::Alias(kind, data) => {
|
Component::Alias(alias_ty) => self.alias_ty_must_outlive(origin, region, *alias_ty),
|
||||||
self.alias_must_outlive(*kind, *data, origin, region)
|
Component::EscapingAlias(subcomponents) => {
|
||||||
}
|
|
||||||
Component::EscapingProjection(subcomponents) => {
|
|
||||||
self.components_must_outlive(origin, &subcomponents, region, category);
|
self.components_must_outlive(origin, &subcomponents, region, category);
|
||||||
}
|
}
|
||||||
Component::UnresolvedInferenceVariable(v) => {
|
Component::UnresolvedInferenceVariable(v) => {
|
||||||
|
@ -285,61 +282,26 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument(level = "debug", skip(self))]
|
||||||
fn param_ty_must_outlive(
|
fn param_ty_must_outlive(
|
||||||
&mut self,
|
&mut self,
|
||||||
origin: infer::SubregionOrigin<'tcx>,
|
origin: infer::SubregionOrigin<'tcx>,
|
||||||
region: ty::Region<'tcx>,
|
region: ty::Region<'tcx>,
|
||||||
param_ty: ty::ParamTy,
|
param_ty: ty::ParamTy,
|
||||||
) {
|
) {
|
||||||
debug!(
|
|
||||||
"param_ty_must_outlive(region={:?}, param_ty={:?}, origin={:?})",
|
|
||||||
region, param_ty, origin
|
|
||||||
);
|
|
||||||
|
|
||||||
let generic = GenericKind::Param(param_ty);
|
|
||||||
let verify_bound = self.verify_bound.param_bound(param_ty);
|
let verify_bound = self.verify_bound.param_bound(param_ty);
|
||||||
self.delegate.push_verify(origin, generic, region, verify_bound);
|
self.delegate.push_verify(origin, GenericKind::Param(param_ty), region, verify_bound);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(level = "debug", skip(self))]
|
#[instrument(level = "debug", skip(self))]
|
||||||
fn alias_must_outlive(
|
fn alias_ty_must_outlive(
|
||||||
&mut self,
|
|
||||||
kind: ty::AliasKind,
|
|
||||||
data: ty::AliasTy<'tcx>,
|
|
||||||
origin: infer::SubregionOrigin<'tcx>,
|
|
||||||
region: ty::Region<'tcx>,
|
|
||||||
) {
|
|
||||||
self.generic_must_outlive(
|
|
||||||
origin,
|
|
||||||
region,
|
|
||||||
GenericKind::Alias(kind, data),
|
|
||||||
data.def_id,
|
|
||||||
data.substs,
|
|
||||||
kind == ty::Opaque,
|
|
||||||
|ty| match *ty.kind() {
|
|
||||||
ty::Alias(filter_kind, ty::AliasTy { def_id, substs, .. })
|
|
||||||
if kind == filter_kind =>
|
|
||||||
{
|
|
||||||
(def_id, substs)
|
|
||||||
}
|
|
||||||
_ => bug!("expected only projection types from env, not {:?}", ty),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[instrument(level = "debug", skip(self, filter))]
|
|
||||||
fn generic_must_outlive(
|
|
||||||
&mut self,
|
&mut self,
|
||||||
origin: infer::SubregionOrigin<'tcx>,
|
origin: infer::SubregionOrigin<'tcx>,
|
||||||
region: ty::Region<'tcx>,
|
region: ty::Region<'tcx>,
|
||||||
generic: GenericKind<'tcx>,
|
alias_ty: ty::AliasTy<'tcx>,
|
||||||
def_id: DefId,
|
|
||||||
substs: SubstsRef<'tcx>,
|
|
||||||
is_opaque: bool,
|
|
||||||
filter: impl Fn(Ty<'tcx>) -> (DefId, SubstsRef<'tcx>),
|
|
||||||
) {
|
) {
|
||||||
// An optimization for a common case with opaque types.
|
// An optimization for a common case with opaque types.
|
||||||
if substs.is_empty() {
|
if alias_ty.substs.is_empty() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -361,14 +323,14 @@ where
|
||||||
// These are guaranteed to apply, no matter the inference
|
// These are guaranteed to apply, no matter the inference
|
||||||
// results.
|
// results.
|
||||||
let trait_bounds: Vec<_> =
|
let trait_bounds: Vec<_> =
|
||||||
self.verify_bound.declared_region_bounds(def_id, substs).collect();
|
self.verify_bound.declared_bounds_from_definition(alias_ty).collect();
|
||||||
|
|
||||||
debug!(?trait_bounds);
|
debug!(?trait_bounds);
|
||||||
|
|
||||||
// Compute the bounds we can derive from the environment. This
|
// Compute the bounds we can derive from the environment. This
|
||||||
// is an "approximate" match -- in some cases, these bounds
|
// is an "approximate" match -- in some cases, these bounds
|
||||||
// may not apply.
|
// may not apply.
|
||||||
let mut approx_env_bounds = self.verify_bound.approx_declared_bounds_from_env(generic);
|
let mut approx_env_bounds = self.verify_bound.approx_declared_bounds_from_env(alias_ty);
|
||||||
debug!(?approx_env_bounds);
|
debug!(?approx_env_bounds);
|
||||||
|
|
||||||
// Remove outlives bounds that we get from the environment but
|
// Remove outlives bounds that we get from the environment but
|
||||||
|
@ -383,8 +345,8 @@ where
|
||||||
// If the declaration is `trait Trait<'b> { type Item: 'b; }`, then `projection_declared_bounds_from_trait`
|
// If the declaration is `trait Trait<'b> { type Item: 'b; }`, then `projection_declared_bounds_from_trait`
|
||||||
// will be invoked with `['b => ^1]` and so we will get `^1` returned.
|
// will be invoked with `['b => ^1]` and so we will get `^1` returned.
|
||||||
let bound = bound_outlives.skip_binder();
|
let bound = bound_outlives.skip_binder();
|
||||||
let (def_id, substs) = filter(bound.0);
|
let ty::Alias(_, alias_ty) = bound.0.kind() else { bug!("expected AliasTy") };
|
||||||
self.verify_bound.declared_region_bounds(def_id, substs).all(|r| r != bound.1)
|
self.verify_bound.declared_bounds_from_definition(*alias_ty).all(|r| r != bound.1)
|
||||||
});
|
});
|
||||||
|
|
||||||
// If declared bounds list is empty, the only applicable rule is
|
// If declared bounds list is empty, the only applicable rule is
|
||||||
|
@ -401,12 +363,12 @@ where
|
||||||
// the problem is to add `T: 'r`, which isn't true. So, if there are no
|
// the problem is to add `T: 'r`, which isn't true. So, if there are no
|
||||||
// inference variables, we use a verify constraint instead of adding
|
// inference variables, we use a verify constraint instead of adding
|
||||||
// edges, which winds up enforcing the same condition.
|
// edges, which winds up enforcing the same condition.
|
||||||
let needs_infer = substs.needs_infer();
|
if approx_env_bounds.is_empty()
|
||||||
if approx_env_bounds.is_empty() && trait_bounds.is_empty() && (needs_infer || is_opaque) {
|
&& trait_bounds.is_empty()
|
||||||
|
&& (alias_ty.needs_infer() || alias_ty.kind(self.tcx) == ty::Opaque)
|
||||||
|
{
|
||||||
debug!("no declared bounds");
|
debug!("no declared bounds");
|
||||||
|
self.substs_must_outlive(alias_ty.substs, origin, region);
|
||||||
self.substs_must_outlive(substs, origin, region);
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -447,14 +409,9 @@ where
|
||||||
// projection outlive; in some cases, this may add insufficient
|
// projection outlive; in some cases, this may add insufficient
|
||||||
// edges into the inference graph, leading to inference failures
|
// edges into the inference graph, leading to inference failures
|
||||||
// even though a satisfactory solution exists.
|
// even though a satisfactory solution exists.
|
||||||
let verify_bound = self.verify_bound.projection_opaque_bounds(
|
let verify_bound = self.verify_bound.alias_bound(alias_ty, &mut Default::default());
|
||||||
generic,
|
debug!("alias_must_outlive: pushing {:?}", verify_bound);
|
||||||
def_id,
|
self.delegate.push_verify(origin, GenericKind::Alias(alias_ty), region, verify_bound);
|
||||||
substs,
|
|
||||||
&mut Default::default(),
|
|
||||||
);
|
|
||||||
debug!("projection_must_outlive: pushing {:?}", verify_bound);
|
|
||||||
self.delegate.push_verify(origin, generic, region, verify_bound);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn substs_must_outlive(
|
fn substs_must_outlive(
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
use crate::infer::outlives::components::{compute_components_recursive, Component};
|
use crate::infer::outlives::components::{compute_components_recursive, Component};
|
||||||
use crate::infer::outlives::env::RegionBoundPairs;
|
use crate::infer::outlives::env::RegionBoundPairs;
|
||||||
use crate::infer::region_constraints::VerifyIfEq;
|
use crate::infer::region_constraints::VerifyIfEq;
|
||||||
use crate::infer::{GenericKind, VerifyBound};
|
use crate::infer::VerifyBound;
|
||||||
use rustc_data_structures::sso::SsoHashSet;
|
use rustc_data_structures::sso::SsoHashSet;
|
||||||
use rustc_hir::def_id::DefId;
|
|
||||||
use rustc_middle::ty::GenericArg;
|
use rustc_middle::ty::GenericArg;
|
||||||
use rustc_middle::ty::{self, OutlivesPredicate, SubstsRef, Ty, TyCtxt};
|
use rustc_middle::ty::{self, OutlivesPredicate, Ty, TyCtxt};
|
||||||
|
|
||||||
use smallvec::smallvec;
|
use smallvec::smallvec;
|
||||||
|
|
||||||
|
@ -94,29 +93,26 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
|
||||||
/// this list.
|
/// this list.
|
||||||
pub fn approx_declared_bounds_from_env(
|
pub fn approx_declared_bounds_from_env(
|
||||||
&self,
|
&self,
|
||||||
generic: GenericKind<'tcx>,
|
alias_ty: ty::AliasTy<'tcx>,
|
||||||
) -> Vec<ty::Binder<'tcx, ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>>> {
|
) -> Vec<ty::Binder<'tcx, ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>>> {
|
||||||
let projection_ty = generic.to_ty(self.tcx);
|
let erased_alias_ty = self.tcx.erase_regions(alias_ty.to_ty(self.tcx));
|
||||||
let erased_projection_ty = self.tcx.erase_regions(projection_ty);
|
self.declared_generic_bounds_from_env_for_erased_ty(erased_alias_ty)
|
||||||
self.declared_generic_bounds_from_env_for_erased_ty(erased_projection_ty)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(level = "debug", skip(self, visited))]
|
#[instrument(level = "debug", skip(self, visited))]
|
||||||
pub fn projection_opaque_bounds(
|
pub fn alias_bound(
|
||||||
&self,
|
&self,
|
||||||
generic: GenericKind<'tcx>,
|
alias_ty: ty::AliasTy<'tcx>,
|
||||||
def_id: DefId,
|
|
||||||
substs: SubstsRef<'tcx>,
|
|
||||||
visited: &mut SsoHashSet<GenericArg<'tcx>>,
|
visited: &mut SsoHashSet<GenericArg<'tcx>>,
|
||||||
) -> VerifyBound<'tcx> {
|
) -> VerifyBound<'tcx> {
|
||||||
let generic_ty = generic.to_ty(self.tcx);
|
let alias_ty_as_ty = alias_ty.to_ty(self.tcx);
|
||||||
|
|
||||||
// Search the env for where clauses like `P: 'a`.
|
// Search the env for where clauses like `P: 'a`.
|
||||||
let projection_opaque_bounds = self
|
let env_bounds = self
|
||||||
.approx_declared_bounds_from_env(generic)
|
.approx_declared_bounds_from_env(alias_ty)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|binder| {
|
.map(|binder| {
|
||||||
if let Some(ty::OutlivesPredicate(ty, r)) = binder.no_bound_vars() && ty == generic_ty {
|
if let Some(ty::OutlivesPredicate(ty, r)) = binder.no_bound_vars() && ty == alias_ty_as_ty {
|
||||||
// Micro-optimize if this is an exact match (this
|
// Micro-optimize if this is an exact match (this
|
||||||
// occurs often when there are no region variables
|
// occurs often when there are no region variables
|
||||||
// involved).
|
// involved).
|
||||||
|
@ -126,19 +122,19 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
|
||||||
VerifyBound::IfEq(verify_if_eq_b)
|
VerifyBound::IfEq(verify_if_eq_b)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// Extend with bounds that we can find from the trait.
|
|
||||||
let trait_bounds =
|
// Extend with bounds that we can find from the definition.
|
||||||
self.declared_region_bounds(def_id, substs).map(|r| VerifyBound::OutlivedBy(r));
|
let definition_bounds =
|
||||||
|
self.declared_bounds_from_definition(alias_ty).map(|r| VerifyBound::OutlivedBy(r));
|
||||||
|
|
||||||
// see the extensive comment in projection_must_outlive
|
// see the extensive comment in projection_must_outlive
|
||||||
let recursive_bound = {
|
let recursive_bound = {
|
||||||
let mut components = smallvec![];
|
let mut components = smallvec![];
|
||||||
compute_components_recursive(self.tcx, generic_ty.into(), &mut components, visited);
|
compute_components_recursive(self.tcx, alias_ty_as_ty.into(), &mut components, visited);
|
||||||
self.bound_from_components(&components, visited)
|
self.bound_from_components(&components, visited)
|
||||||
};
|
};
|
||||||
|
|
||||||
VerifyBound::AnyBound(projection_opaque_bounds.chain(trait_bounds).collect())
|
VerifyBound::AnyBound(env_bounds.chain(definition_bounds).collect()).or(recursive_bound)
|
||||||
.or(recursive_bound)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bound_from_components(
|
fn bound_from_components(
|
||||||
|
@ -149,10 +145,8 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
|
||||||
let mut bounds = components
|
let mut bounds = components
|
||||||
.iter()
|
.iter()
|
||||||
.map(|component| self.bound_from_single_component(component, visited))
|
.map(|component| self.bound_from_single_component(component, visited))
|
||||||
.filter(|bound| {
|
|
||||||
// Remove bounds that must hold, since they are not interesting.
|
// Remove bounds that must hold, since they are not interesting.
|
||||||
!bound.must_hold()
|
.filter(|bound| !bound.must_hold());
|
||||||
});
|
|
||||||
|
|
||||||
match (bounds.next(), bounds.next()) {
|
match (bounds.next(), bounds.next()) {
|
||||||
(Some(first), None) => first,
|
(Some(first), None) => first,
|
||||||
|
@ -170,13 +164,8 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
|
||||||
match *component {
|
match *component {
|
||||||
Component::Region(lt) => VerifyBound::OutlivedBy(lt),
|
Component::Region(lt) => VerifyBound::OutlivedBy(lt),
|
||||||
Component::Param(param_ty) => self.param_bound(param_ty),
|
Component::Param(param_ty) => self.param_bound(param_ty),
|
||||||
Component::Alias(kind, data) => self.projection_opaque_bounds(
|
Component::Alias(alias_ty) => self.alias_bound(alias_ty, visited),
|
||||||
GenericKind::Alias(kind, data),
|
Component::EscapingAlias(ref components) => {
|
||||||
data.def_id,
|
|
||||||
data.substs,
|
|
||||||
visited,
|
|
||||||
),
|
|
||||||
Component::EscapingProjection(ref components) => {
|
|
||||||
self.bound_from_components(components, visited)
|
self.bound_from_components(components, visited)
|
||||||
}
|
}
|
||||||
Component::UnresolvedInferenceVariable(v) => {
|
Component::UnresolvedInferenceVariable(v) => {
|
||||||
|
@ -292,16 +281,15 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
|
||||||
///
|
///
|
||||||
/// This is for simplicity, and because we are not really smart
|
/// This is for simplicity, and because we are not really smart
|
||||||
/// enough to cope with such bounds anywhere.
|
/// enough to cope with such bounds anywhere.
|
||||||
pub fn declared_region_bounds(
|
pub fn declared_bounds_from_definition(
|
||||||
&self,
|
&self,
|
||||||
def_id: DefId,
|
alias_ty: ty::AliasTy<'tcx>,
|
||||||
substs: SubstsRef<'tcx>,
|
|
||||||
) -> impl Iterator<Item = ty::Region<'tcx>> {
|
) -> impl Iterator<Item = ty::Region<'tcx>> {
|
||||||
let tcx = self.tcx;
|
let tcx = self.tcx;
|
||||||
let bounds = tcx.item_bounds(def_id);
|
let bounds = tcx.item_bounds(alias_ty.def_id);
|
||||||
trace!("{:#?}", bounds.0);
|
trace!("{:#?}", bounds.0);
|
||||||
bounds
|
bounds
|
||||||
.subst_iter(tcx, substs)
|
.subst_iter(tcx, alias_ty.substs)
|
||||||
.filter_map(|p| p.to_opt_type_outlives())
|
.filter_map(|p| p.to_opt_type_outlives())
|
||||||
.filter_map(|p| p.no_bound_vars())
|
.filter_map(|p| p.no_bound_vars())
|
||||||
.map(|OutlivesPredicate(_, r)| r)
|
.map(|OutlivesPredicate(_, r)| r)
|
||||||
|
|
|
@ -167,7 +167,7 @@ pub struct Verify<'tcx> {
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable)]
|
#[derive(Copy, Clone, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable)]
|
||||||
pub enum GenericKind<'tcx> {
|
pub enum GenericKind<'tcx> {
|
||||||
Param(ty::ParamTy),
|
Param(ty::ParamTy),
|
||||||
Alias(ty::AliasKind, ty::AliasTy<'tcx>),
|
Alias(ty::AliasTy<'tcx>),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Describes the things that some `GenericKind` value `G` is known to
|
/// Describes the things that some `GenericKind` value `G` is known to
|
||||||
|
@ -746,10 +746,7 @@ impl<'tcx> fmt::Debug for GenericKind<'tcx> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match *self {
|
match *self {
|
||||||
GenericKind::Param(ref p) => write!(f, "{:?}", p),
|
GenericKind::Param(ref p) => write!(f, "{:?}", p),
|
||||||
GenericKind::Alias(ty::Projection, ref p) => write!(f, "{:?}", p),
|
GenericKind::Alias(ref p) => write!(f, "{:?}", p),
|
||||||
GenericKind::Alias(ty::Opaque, ref p) => ty::tls::with(|tcx| {
|
|
||||||
write!(f, "{}", tcx.def_path_str_with_substs(p.def_id, tcx.lift(p.substs).unwrap()))
|
|
||||||
}),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -758,10 +755,7 @@ impl<'tcx> fmt::Display for GenericKind<'tcx> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match *self {
|
match *self {
|
||||||
GenericKind::Param(ref p) => write!(f, "{}", p),
|
GenericKind::Param(ref p) => write!(f, "{}", p),
|
||||||
GenericKind::Alias(ty::Projection, ref p) => write!(f, "{}", p),
|
GenericKind::Alias(ref p) => write!(f, "{}", p),
|
||||||
GenericKind::Alias(ty::Opaque, ref p) => ty::tls::with(|tcx| {
|
|
||||||
write!(f, "{}", tcx.def_path_str_with_substs(p.def_id, tcx.lift(p.substs).unwrap()))
|
|
||||||
}),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -770,7 +764,7 @@ impl<'tcx> GenericKind<'tcx> {
|
||||||
pub fn to_ty(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
|
pub fn to_ty(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
|
||||||
match *self {
|
match *self {
|
||||||
GenericKind::Param(ref p) => p.to_ty(tcx),
|
GenericKind::Param(ref p) => p.to_ty(tcx),
|
||||||
GenericKind::Alias(kind, data) => tcx.mk_ty(ty::Alias(kind, data)),
|
GenericKind::Alias(ref p) => p.to_ty(tcx),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -261,14 +261,15 @@ impl<'tcx> Elaborator<'tcx> {
|
||||||
|
|
||||||
Component::UnresolvedInferenceVariable(_) => None,
|
Component::UnresolvedInferenceVariable(_) => None,
|
||||||
|
|
||||||
Component::Alias(kind, data) => {
|
Component::Alias(alias_ty) => {
|
||||||
let ty = tcx.mk_ty(ty::Alias(kind, data));
|
// We might end up here if we have `Foo<<Bar as Baz>::Assoc>: 'a`.
|
||||||
|
// With this, we can deduce that `<Bar as Baz>::Assoc: 'a`.
|
||||||
Some(ty::PredicateKind::Clause(ty::Clause::TypeOutlives(
|
Some(ty::PredicateKind::Clause(ty::Clause::TypeOutlives(
|
||||||
ty::OutlivesPredicate(ty, r_min),
|
ty::OutlivesPredicate(alias_ty.to_ty(tcx), r_min),
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
|
|
||||||
Component::EscapingProjection(_) => {
|
Component::EscapingAlias(_) => {
|
||||||
// We might be able to do more here, but we don't
|
// We might be able to do more here, but we don't
|
||||||
// want to deal with escaping vars right now.
|
// want to deal with escaping vars right now.
|
||||||
None
|
None
|
||||||
|
|
|
@ -213,5 +213,5 @@ pub struct NormalizationResult<'tcx> {
|
||||||
pub enum OutlivesBound<'tcx> {
|
pub enum OutlivesBound<'tcx> {
|
||||||
RegionSubRegion(ty::Region<'tcx>, ty::Region<'tcx>),
|
RegionSubRegion(ty::Region<'tcx>, ty::Region<'tcx>),
|
||||||
RegionSubParam(ty::Region<'tcx>, ty::ParamTy),
|
RegionSubParam(ty::Region<'tcx>, ty::ParamTy),
|
||||||
RegionSubAlias(ty::Region<'tcx>, ty::AliasKind, ty::AliasTy<'tcx>),
|
RegionSubAlias(ty::Region<'tcx>, ty::AliasTy<'tcx>),
|
||||||
}
|
}
|
||||||
|
|
|
@ -1245,11 +1245,26 @@ pub struct AliasTy<'tcx> {
|
||||||
/// aka. `tcx.parent(def_id)`.
|
/// aka. `tcx.parent(def_id)`.
|
||||||
pub def_id: DefId,
|
pub def_id: DefId,
|
||||||
|
|
||||||
/// This field exists to prevent the creation of `ProjectionTy` without using
|
/// This field exists to prevent the creation of `AliasTy` without using
|
||||||
/// [TyCtxt::mk_alias_ty].
|
/// [TyCtxt::mk_alias_ty].
|
||||||
pub(super) _use_mk_alias_ty_instead: (),
|
pub(super) _use_mk_alias_ty_instead: (),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'tcx> AliasTy<'tcx> {
|
||||||
|
pub fn kind(self, tcx: TyCtxt<'tcx>) -> ty::AliasKind {
|
||||||
|
match tcx.def_kind(self.def_id) {
|
||||||
|
DefKind::AssocTy | DefKind::ImplTraitPlaceholder => ty::Projection,
|
||||||
|
DefKind::OpaqueTy => ty::Opaque,
|
||||||
|
kind => bug!("unexpected DefKind in AliasTy: {kind:?}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_ty(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
|
||||||
|
tcx.mk_ty(ty::Alias(self.kind(tcx), self))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The following methods work only with associated type projections.
|
||||||
impl<'tcx> AliasTy<'tcx> {
|
impl<'tcx> AliasTy<'tcx> {
|
||||||
pub fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId {
|
pub fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId {
|
||||||
match tcx.def_kind(self.def_id) {
|
match tcx.def_kind(self.def_id) {
|
||||||
|
@ -1257,7 +1272,7 @@ impl<'tcx> AliasTy<'tcx> {
|
||||||
DefKind::ImplTraitPlaceholder => {
|
DefKind::ImplTraitPlaceholder => {
|
||||||
tcx.parent(tcx.impl_trait_in_trait_parent(self.def_id))
|
tcx.parent(tcx.impl_trait_in_trait_parent(self.def_id))
|
||||||
}
|
}
|
||||||
kind => bug!("unexpected DefKind in ProjectionTy: {kind:?}"),
|
kind => bug!("expected a projection AliasTy; found {kind:?}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -154,10 +154,8 @@ fn implied_bounds_from_components<'tcx>(
|
||||||
match component {
|
match component {
|
||||||
Component::Region(r) => Some(OutlivesBound::RegionSubRegion(sub_region, r)),
|
Component::Region(r) => Some(OutlivesBound::RegionSubRegion(sub_region, r)),
|
||||||
Component::Param(p) => Some(OutlivesBound::RegionSubParam(sub_region, p)),
|
Component::Param(p) => Some(OutlivesBound::RegionSubParam(sub_region, p)),
|
||||||
Component::Alias(kind, p) => {
|
Component::Alias(p) => Some(OutlivesBound::RegionSubAlias(sub_region, p)),
|
||||||
Some(OutlivesBound::RegionSubAlias(sub_region, kind, p))
|
Component::EscapingAlias(_) =>
|
||||||
}
|
|
||||||
Component::EscapingProjection(_) =>
|
|
||||||
// If the projection has escaping regions, don't
|
// If the projection has escaping regions, don't
|
||||||
// try to infer any implied bounds even for its
|
// try to infer any implied bounds even for its
|
||||||
// free components. This is conservative, because
|
// free components. This is conservative, because
|
||||||
|
|
18
tests/ui/type-alias-impl-trait/outlives-bound-var.rs
Normal file
18
tests/ui/type-alias-impl-trait/outlives-bound-var.rs
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
// Here we process outlive obligations involving
|
||||||
|
// opaque types with bound vars in substs.
|
||||||
|
// This was an ICE.
|
||||||
|
//
|
||||||
|
// check-pass
|
||||||
|
#![feature(type_alias_impl_trait)]
|
||||||
|
|
||||||
|
type Ty<'a> = impl Sized + 'a;
|
||||||
|
fn define<'a>() -> Ty<'a> {}
|
||||||
|
|
||||||
|
// Ty<'^0>: 'static
|
||||||
|
fn test1(_: &'static fn(Ty<'_>)) {}
|
||||||
|
|
||||||
|
fn test2() {
|
||||||
|
None::<&fn(Ty<'_>)>;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() { }
|
Loading…
Add table
Add a link
Reference in a new issue