outlives: ignore lifetimes shallowly found in ty::FnDefs.

This commit is contained in:
Eduard-Mihai Burtescu 2020-04-16 23:18:44 +03:00
parent 7fb5187d04
commit f86f03263c
3 changed files with 64 additions and 6 deletions

View File

@ -42,6 +42,31 @@ fn type_bound(&self, ty: Ty<'tcx>) -> VerifyBound<'tcx> {
match ty.kind {
ty::Param(p) => self.param_bound(p),
ty::Projection(data) => self.projection_bound(data),
ty::FnDef(_, substs) => {
// HACK(eddyb) ignore lifetimes found shallowly in `substs`.
// This is inconsistent with `ty::Adt` (including all substs),
// but consistent with previous (accidental) behavior.
// See https://github.com/rust-lang/rust/issues/70917
// for further background and discussion.
let mut bounds = substs
.iter()
.filter_map(|&child| match child.unpack() {
GenericArgKind::Type(ty) => Some(self.type_bound(ty)),
GenericArgKind::Lifetime(_) => None,
GenericArgKind::Const(_) => Some(self.recursive_bound(child)),
})
.filter(|bound| {
// Remove bounds that must hold, since they are not interesting.
!bound.must_hold()
});
match (bounds.next(), bounds.next()) {
(Some(first), None) => first,
(first, second) => VerifyBound::AllBounds(
first.into_iter().chain(second).chain(bounds).collect(),
),
}
}
_ => self.recursive_bound(ty.into()),
}
}

View File

@ -62,6 +62,27 @@ impl<'tcx> TyCtxt<'tcx> {
// in the `subtys` iterator (e.g., when encountering a
// projection).
match ty.kind {
ty::FnDef(_, substs) => {
// HACK(eddyb) ignore lifetimes found shallowly in `substs`.
// This is inconsistent with `ty::Adt` (including all substs)
// and with `ty::Closure` (ignoring all substs other than
// upvars, of which a `ty::FnDef` doesn't have any), but
// consistent with previous (accidental) behavior.
// See https://github.com/rust-lang/rust/issues/70917
// for further background and discussion.
for &child in substs {
match child.unpack() {
GenericArgKind::Type(ty) => {
compute_components(tcx, ty, out);
}
GenericArgKind::Lifetime(_) => {}
GenericArgKind::Const(_) => {
compute_components_recursive(tcx, child, out);
}
}
}
}
ty::Closure(_, ref substs) => {
for upvar_ty in substs.as_closure().upvar_tys() {
compute_components(tcx, upvar_ty, out);
@ -136,7 +157,7 @@ impl<'tcx> TyCtxt<'tcx> {
ty::Float(..) | // OutlivesScalar
ty::Never | // ...
ty::Adt(..) | // OutlivesNominalType
ty::Opaque(..) | // OutlivesNominalType (ish)
ty::Opaque(..) | // OutlivesNominalType (ish)
ty::Foreign(..) | // OutlivesNominalType
ty::Str | // OutlivesScalar (ish)
ty::Array(..) | // ...
@ -144,15 +165,14 @@ impl<'tcx> TyCtxt<'tcx> {
ty::RawPtr(..) | // ...
ty::Ref(..) | // OutlivesReference
ty::Tuple(..) | // ...
ty::FnDef(..) | // OutlivesFunction (*)
ty::FnPtr(_) | // OutlivesFunction (*)
ty::Dynamic(..) | // OutlivesObject, OutlivesFragment (*)
ty::Dynamic(..) | // OutlivesObject, OutlivesFragment (*)
ty::Placeholder(..) |
ty::Bound(..) |
ty::Error => {
// (*) Bare functions and traits are both binders. In the
// RFC, this means we would add the bound regions to the
// "bound regions list". In our representation, no such
// (*) Function pointers and trait objects are both binders.
// In the RFC, this means we would add the bound regions to
// the "bound regions list". In our representation, no such
// list is maintained explicitly, because bound regions
// themselves can be readily identified.
compute_components_recursive(tcx, ty.into(), out);

View File

@ -0,0 +1,13 @@
// check-pass
fn assert_static<T: 'static>(_: T) {}
// NOTE(eddyb) the `'a: 'a` may look a bit strange, but we *really* want
// `'a` to be an *early-bound* parameter, otherwise it doesn't matter anyway.
fn capture_lifetime<'a: 'a>() {}
fn test_lifetime<'a>() {
assert_static(capture_lifetime::<'a>);
}
fn main() {}