Neither require nor imply lifetime bounds on opaque type for well formedness

This commit is contained in:
Oli Scherer 2022-05-18 16:01:10 +00:00
parent c8ecf09a25
commit 37928f5986
30 changed files with 497 additions and 42 deletions

View File

@ -362,6 +362,11 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
self.region_bound_pairs
.insert(ty::OutlivesPredicate(GenericKind::Projection(projection_b), r_a));
}
OutlivesBound::RegionSubOpaque(r_a, def_id, substs) => {
self.region_bound_pairs
.insert(ty::OutlivesPredicate(GenericKind::Opaque(def_id, substs), r_a));
}
}
}
}

View File

@ -2374,6 +2374,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
let labeled_user_string = match bound_kind {
GenericKind::Param(ref p) => format!("the parameter type `{}`", p),
GenericKind::Projection(ref p) => format!("the associated type `{}`", p),
GenericKind::Opaque(def_id, substs) => {
format!("the opaque type `{}`", self.tcx.def_path_str_with_substs(def_id, substs))
}
};
if let Some(SubregionOrigin::CompareImplItemObligation {

View File

@ -3,8 +3,9 @@
// RFC for reference.
use rustc_data_structures::sso::SsoHashSet;
use rustc_hir::def_id::DefId;
use rustc_middle::ty::subst::{GenericArg, GenericArgKind};
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable};
use rustc_middle::ty::{self, SubstsRef, Ty, TyCtxt, TypeVisitable};
use smallvec::{smallvec, SmallVec};
#[derive(Debug)]
@ -45,6 +46,8 @@ pub enum Component<'tcx> {
// them. This gives us room to improve the regionck reasoning in
// the future without breaking backwards compat.
EscapingProjection(Vec<Component<'tcx>>),
Opaque(DefId, SubstsRef<'tcx>),
}
/// Push onto `out` all the things that must outlive `'a` for the condition
@ -120,6 +123,17 @@ fn compute_components<'tcx>(
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::Opaque(def_id, substs) => {
out.push(Component::Opaque(def_id, substs));
},
// For projections, we prefer to generate an obligation like
// `<P0 as Trait<P1...Pn>>::Foo: 'a`, because this gives the
// regionck more ways to prove that it holds. However,
@ -168,7 +182,6 @@ fn compute_components<'tcx>(
ty::Float(..) | // OutlivesScalar
ty::Never | // ...
ty::Adt(..) | // OutlivesNominalType
ty::Opaque(..) | // OutlivesNominalType (ish)
ty::Foreign(..) | // OutlivesNominalType
ty::Str | // OutlivesScalar (ish)
ty::Slice(..) | // ...

View File

@ -140,6 +140,10 @@ impl<'a, 'tcx> OutlivesEnvironmentBuilder<'tcx> {
self.region_bound_pairs
.insert(ty::OutlivesPredicate(GenericKind::Projection(projection_b), r_a));
}
OutlivesBound::RegionSubOpaque(r_a, def_id, substs) => {
self.region_bound_pairs
.insert(ty::OutlivesPredicate(GenericKind::Opaque(def_id, substs), r_a));
}
OutlivesBound::RegionSubRegion(r_a, r_b) => {
if let (ReEarlyBound(_) | ReFree(_), ReVar(vid_b)) = (r_a.kind(), r_b.kind()) {
infcx

View File

@ -284,6 +284,9 @@ where
Component::Param(param_ty) => {
self.param_ty_must_outlive(origin, region, *param_ty);
}
Component::Opaque(def_id, substs) => {
self.opaque_must_outlive(*def_id, substs, origin, region)
}
Component::Projection(projection_ty) => {
self.projection_must_outlive(origin, region, *projection_ty);
}
@ -319,6 +322,27 @@ where
self.delegate.push_verify(origin, generic, region, verify_bound);
}
#[instrument(level = "debug", skip(self))]
fn opaque_must_outlive(
&mut self,
def_id: DefId,
substs: SubstsRef<'tcx>,
origin: infer::SubregionOrigin<'tcx>,
region: ty::Region<'tcx>,
) {
self.generic_must_outlive(
origin,
region,
GenericKind::Opaque(def_id, substs),
def_id,
substs,
|ty| match *ty.kind() {
ty::Opaque(def_id, substs) => (def_id, substs),
_ => bug!("expected only projection types from env, not {:?}", ty),
},
);
}
#[instrument(level = "debug", skip(self))]
fn projection_must_outlive(
&mut self,

View File

@ -47,6 +47,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
GenericKind::Projection(projection_ty) => {
self.projection_bound(projection_ty, &mut visited)
}
GenericKind::Opaque(def_id, substs) => self.opaque_bound(def_id, substs),
}
}
@ -155,6 +156,20 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
VerifyBound::AnyBound(env_bounds.chain(trait_bounds).collect()).or(recursive_bound)
}
fn opaque_bound(&self, def_id: DefId, substs: SubstsRef<'tcx>) -> VerifyBound<'tcx> {
let bounds: Vec<_> =
self.bounds(def_id, substs).map(|r| VerifyBound::OutlivedBy(r)).collect();
trace!("{:#?}", bounds);
if bounds.is_empty() {
// No bounds means the value must not have any lifetimes.
// FIXME: should we implicitly add 'static to `tcx.item_bounds` for opaque types, just
// like we add `Sized`?
VerifyBound::OutlivedBy(self.tcx.lifetimes.re_static)
} else {
VerifyBound::AnyBound(bounds)
}
}
fn bound_from_components(
&self,
components: &[Component<'tcx>],
@ -184,6 +199,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
match *component {
Component::Region(lt) => VerifyBound::OutlivedBy(lt),
Component::Param(param_ty) => self.param_bound(param_ty),
Component::Opaque(did, substs) => self.opaque_bound(did, substs),
Component::Projection(projection_ty) => self.projection_bound(projection_ty, visited),
Component::EscapingProjection(ref components) => {
self.bound_from_components(components, visited)

View File

@ -12,8 +12,10 @@ use rustc_data_structures::intern::Interned;
use rustc_data_structures::sync::Lrc;
use rustc_data_structures::undo_log::UndoLogs;
use rustc_data_structures::unify as ut;
use rustc_hir::def_id::DefId;
use rustc_index::vec::IndexVec;
use rustc_middle::infer::unify_key::{RegionVidKey, UnifiedRegion};
use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::ReStatic;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_middle::ty::{ReLateBound, ReVar};
@ -168,6 +170,7 @@ pub struct Verify<'tcx> {
pub enum GenericKind<'tcx> {
Param(ty::ParamTy),
Projection(ty::ProjectionTy<'tcx>),
Opaque(DefId, SubstsRef<'tcx>),
}
/// Describes the things that some `GenericKind` value `G` is known to
@ -747,6 +750,9 @@ impl<'tcx> fmt::Debug for GenericKind<'tcx> {
match *self {
GenericKind::Param(ref p) => write!(f, "{:?}", p),
GenericKind::Projection(ref p) => write!(f, "{:?}", p),
GenericKind::Opaque(def_id, substs) => ty::tls::with(|tcx| {
write!(f, "{}", tcx.def_path_str_with_substs(def_id, tcx.lift(substs).unwrap()))
}),
}
}
}
@ -756,6 +762,9 @@ impl<'tcx> fmt::Display for GenericKind<'tcx> {
match *self {
GenericKind::Param(ref p) => write!(f, "{}", p),
GenericKind::Projection(ref p) => write!(f, "{}", p),
GenericKind::Opaque(def_id, substs) => ty::tls::with(|tcx| {
write!(f, "{}", tcx.def_path_str_with_substs(def_id, tcx.lift(substs).unwrap()))
}),
}
}
}
@ -765,6 +774,7 @@ impl<'tcx> GenericKind<'tcx> {
match *self {
GenericKind::Param(ref p) => p.to_ty(tcx),
GenericKind::Projection(ref p) => tcx.mk_projection(p.item_def_id, p.substs),
GenericKind::Opaque(def_id, substs) => tcx.mk_opaque(def_id, substs),
}
}
}

View File

@ -246,6 +246,13 @@ impl<'tcx> Elaborator<'tcx> {
Component::UnresolvedInferenceVariable(_) => None,
Component::Opaque(def_id, substs) => {
let ty = tcx.mk_opaque(def_id, substs);
Some(ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(
ty, r_min,
)))
}
Component::Projection(projection) => {
// 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`.
@ -262,8 +269,9 @@ impl<'tcx> Elaborator<'tcx> {
None
}
})
.map(ty::Binder::dummy)
.map(|predicate_kind| predicate_kind.to_predicate(tcx))
.map(|predicate_kind| {
bound_predicate.rebind(predicate_kind).to_predicate(tcx)
})
.filter(|&predicate| visited.insert(predicate))
.map(|predicate| {
predicate_obligation(

View File

@ -8,8 +8,9 @@
use crate::error::DropCheckOverflow;
use crate::infer::canonical::{Canonical, QueryResponse};
use crate::ty::error::TypeError;
use crate::ty::subst::GenericArg;
use crate::ty::subst::{GenericArg, SubstsRef};
use crate::ty::{self, Ty, TyCtxt};
use rustc_hir::def_id::DefId;
use rustc_span::source_map::Span;
use std::iter::FromIterator;
@ -219,4 +220,5 @@ pub enum OutlivesBound<'tcx> {
RegionSubRegion(ty::Region<'tcx>, ty::Region<'tcx>),
RegionSubParam(ty::Region<'tcx>, ty::ParamTy),
RegionSubProjection(ty::Region<'tcx>, ty::ProjectionTy<'tcx>),
RegionSubOpaque(ty::Region<'tcx>, DefId, SubstsRef<'tcx>),
}

View File

@ -153,6 +153,9 @@ fn implied_bounds_from_components<'tcx>(
Component::Region(r) => Some(OutlivesBound::RegionSubRegion(sub_region, r)),
Component::Param(p) => Some(OutlivesBound::RegionSubParam(sub_region, p)),
Component::Projection(p) => Some(OutlivesBound::RegionSubProjection(sub_region, p)),
Component::Opaque(def_id, substs) => {
Some(OutlivesBound::RegionSubOpaque(sub_region, def_id, substs))
}
Component::EscapingProjection(_) =>
// If the projection has escaping regions, don't
// try to infer any implied bounds even for its

View File

@ -265,6 +265,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
self.cat_expr_adjusted_with(expr, || Ok(previous), adjustment)
}
#[instrument(level = "debug", skip(self, previous))]
fn cat_expr_adjusted_with<F>(
&self,
expr: &hir::Expr<'_>,
@ -274,7 +275,6 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
where
F: FnOnce() -> McResult<PlaceWithHirId<'tcx>>,
{
debug!("cat_expr_adjusted_with({:?}): {:?}", adjustment, expr);
let target = self.resolve_vars_if_possible(adjustment.target);
match adjustment.kind {
adjustment::Adjust::Deref(overloaded) => {
@ -299,6 +299,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
}
}
#[instrument(level = "debug", skip(self))]
pub(crate) fn cat_expr_unadjusted(
&self,
expr: &hir::Expr<'_>,
@ -387,6 +388,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
}
}
#[instrument(level = "debug", skip(self, span))]
pub(crate) fn cat_res(
&self,
hir_id: hir::HirId,
@ -394,8 +396,6 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
expr_ty: Ty<'tcx>,
res: Res,
) -> McResult<PlaceWithHirId<'tcx>> {
debug!("cat_res: id={:?} expr={:?} def={:?}", hir_id, expr_ty, res);
match res {
Res::Def(
DefKind::Ctor(..)
@ -475,13 +475,12 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
ret
}
#[instrument(level = "debug", skip(self))]
fn cat_overloaded_place(
&self,
expr: &hir::Expr<'_>,
base: &hir::Expr<'_>,
) -> McResult<PlaceWithHirId<'tcx>> {
debug!("cat_overloaded_place(expr={:?}, base={:?})", expr, base);
// Reconstruct the output assuming it's a reference with the
// same region and mutability as the receiver. This holds for
// `Deref(Mut)::Deref(_mut)` and `Index(Mut)::index(_mut)`.
@ -497,13 +496,12 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
self.cat_deref(expr, base)
}
#[instrument(level = "debug", skip(self, node))]
fn cat_deref(
&self,
node: &impl HirNode,
base_place: PlaceWithHirId<'tcx>,
) -> McResult<PlaceWithHirId<'tcx>> {
debug!("cat_deref: base_place={:?}", base_place);
let base_curr_ty = base_place.place.ty();
let deref_ty = match base_curr_ty.builtin_deref(true) {
Some(mt) => mt.ty,

View File

@ -1,6 +1,6 @@
use rustc_infer::infer::outlives::components::{push_outlives_components, Component};
use rustc_middle::ty::subst::{GenericArg, GenericArgKind};
use rustc_middle::ty::{self, Region, Ty, TyCtxt};
use rustc_middle::ty::{self, EarlyBinder, Region, Ty, TyCtxt};
use rustc_span::Span;
use smallvec::smallvec;
use std::collections::BTreeMap;
@ -96,6 +96,39 @@ pub(crate) fn insert_outlives_predicate<'tcx>(
.or_insert(span);
}
Component::Opaque(def_id, substs) => {
for predicate in tcx.item_bounds(def_id) {
let predicate = EarlyBinder(predicate).subst(tcx, substs);
// FIXME(oli-obk): fishy skip-binder
match predicate.kind().skip_binder() {
ty::PredicateKind::Trait(tp) => {
for subst in tp.trait_ref.substs {
insert_outlives_predicate(
tcx,
subst,
outlived_region,
span,
required_predicates,
)
}
}
ty::PredicateKind::RegionOutlives(_)
| ty::PredicateKind::TypeOutlives(_)
| ty::PredicateKind::Projection(_)
| ty::PredicateKind::WellFormed(_)
| ty::PredicateKind::ObjectSafe(_)
| ty::PredicateKind::ClosureKind(_, _, _)
| ty::PredicateKind::Subtype(_)
| ty::PredicateKind::Coerce(_)
| ty::PredicateKind::ConstEvaluatable(_)
| ty::PredicateKind::ConstEquate(_, _)
| ty::PredicateKind::TypeWellFormedFromEnv(_) => {
todo!("{:#?}", predicate)
}
}
}
}
Component::EscapingProjection(_) => {
// As above, but the projection involves
// late-bound regions. Therefore, the WF

View File

@ -1,23 +0,0 @@
error[E0477]: the type `<() as Yay<&'a ()>>::InnerStream<'s>` does not fulfill the required lifetime
--> $DIR/issue-86218.rs:22:28
|
LL | type InnerStream<'s> = impl Stream<Item = i32> + 's;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: type must outlive the lifetime `'s` as defined here as required by this binding
--> $DIR/issue-86218.rs:22:22
|
LL | type InnerStream<'s> = impl Stream<Item = i32> + 's;
| ^^
error: unconstrained opaque type
--> $DIR/issue-86218.rs:22:28
|
LL | type InnerStream<'s> = impl Stream<Item = i32> + 's;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `InnerStream` must be used in combination with a concrete type within the same module
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0477`.

View File

@ -0,0 +1,24 @@
// check-pass
#![feature(type_alias_impl_trait)]
pub trait Stream {
type Item;
}
impl Stream for () {
type Item = i32;
}
trait Yay<AdditionalValue> {
type InnerStream<'s>: Stream<Item = i32> + 's;
fn foo<'s>() -> Self::InnerStream<'s>;
}
impl<T> Yay<T> for () {
type InnerStream<'s> = impl Stream<Item = i32> + 's;
//^ ERROR does not fulfill the required lifetime
fn foo<'s>() -> Self::InnerStream<'s> { () }
}
fn main() {}

View File

@ -1,7 +1,4 @@
// check-fail
// known-bug: #86218
// This should pass, but seems to run into a TAIT issue.
// check-pass
#![feature(type_alias_impl_trait)]
@ -20,7 +17,8 @@ trait Yay<AdditionalValue> {
impl<'a> Yay<&'a ()> for () {
type InnerStream<'s> = impl Stream<Item = i32> + 's;
fn foo<'s>() -> Self::InnerStream<'s> { todo!() }
//^ ERROR does not fulfill the required lifetime
fn foo<'s>() -> Self::InnerStream<'s> { () }
}
fn main() {}

View File

@ -0,0 +1,51 @@
#![feature(type_alias_impl_trait)]
type WithLifetime<'a> = impl Equals<SelfType = ()>;
fn _defining_use<'a>() -> WithLifetime<'a> {}
trait Convert<'a> {
type Witness;
fn convert<'b, T: ?Sized>(_proof: &'b Self::Witness, x: &'a T) -> &'b T;
}
impl<'a> Convert<'a> for () {
type Witness = WithLifetime<'a>;
fn convert<'b, T: ?Sized>(_proof: &'b WithLifetime<'a>, x: &'a T) -> &'b T {
// compiler used to think it gets to assume 'a: 'b here because
// of the `&'b WithLifetime<'a>` argument
x
//~^ ERROR lifetime may not live long enough
}
}
fn extend_lifetime<'a, 'b, T: ?Sized>(x: &'a T) -> &'b T {
WithLifetime::<'a>::convert_helper::<(), T>(&(), x)
}
trait Equals {
type SelfType;
fn convert_helper<'a, 'b, W: Convert<'a, Witness = Self>, T: ?Sized>(
proof: &'b Self::SelfType,
x: &'a T,
) -> &'b T;
}
impl<S> Equals for S {
type SelfType = Self;
fn convert_helper<'a, 'b, W: Convert<'a, Witness = Self>, T: ?Sized>(
proof: &'b Self,
x: &'a T,
) -> &'b T {
W::convert(proof, x)
}
}
fn main() {
let r;
{
let x = String::from("Hello World?");
r = extend_lifetime(&x);
}
println!("{}", r);
}

View File

@ -0,0 +1,16 @@
error: lifetime may not live long enough
--> $DIR/implied_bounds.rs:17:9
|
LL | impl<'a> Convert<'a> for () {
| -- lifetime `'a` defined here
...
LL | fn convert<'b, T: ?Sized>(_proof: &'b WithLifetime<'a>, x: &'a T) -> &'b T {
| -- lifetime `'b` defined here
...
LL | x
| ^ associated function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
|
= help: consider adding the following bound: `'a: 'b`
error: aborting due to previous error

View File

@ -0,0 +1,9 @@
#![feature(type_alias_impl_trait)]
type Ty<'a, A> = impl Sized + 'a;
fn defining<'a, A>() -> Ty<'a, A> {}
fn assert_static<T: 'static>() {}
fn test<'a, A>() where Ty<'a, A>: 'static, { assert_static::<Ty<'a, A>>() }
//~^ ERROR: may not live long enough
fn main() {}

View File

@ -0,0 +1,12 @@
error[E0310]: the opaque type `Ty<'_, A>::{opaque#0}` may not live long enough
--> $DIR/implied_bounds2.rs:6:46
|
LL | fn test<'a, A>() where Ty<'a, A>: 'static, { assert_static::<Ty<'a, A>>() }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: consider adding an explicit lifetime bound `Ty<'_, A>::{opaque#0}: 'static`...
= note: ...so that the type `Ty<'_, A>` will meet its required lifetime bounds
error: aborting due to previous error
For more information about this error, try `rustc --explain E0310`.

View File

@ -0,0 +1,31 @@
trait StaticDefaultRef: 'static {
fn default_ref() -> &'static Self;
}
impl StaticDefaultRef for str {
fn default_ref() -> &'static str {
""
}
}
fn into_impl(x: &str) -> &(impl ?Sized + AsRef<str> + StaticDefaultRef + '_) {
x
}
fn extend_lifetime<'a>(x: &'a str) -> &'static str {
let t = into_impl(x);
helper(|_| t) //~ ERROR lifetime may not live long enough
}
fn helper<T: ?Sized + AsRef<str> + StaticDefaultRef>(f: impl FnOnce(&T) -> &T) -> &'static str {
f(T::default_ref()).as_ref()
}
fn main() {
let r;
{
let x = String::from("Hello World?");
r = extend_lifetime(&x);
}
println!("{}", r);
}

View File

@ -0,0 +1,11 @@
error: lifetime may not live long enough
--> $DIR/implied_bounds_closure.rs:17:16
|
LL | fn extend_lifetime<'a>(x: &'a str) -> &'static str {
| -- lifetime `'a` defined here
LL | let t = into_impl(x);
LL | helper(|_| t)
| ^ returning this value requires that `'a` must outlive `'static`
error: aborting due to previous error

View File

@ -0,0 +1,51 @@
#![feature(type_alias_impl_trait)]
type WithLifetime<T> = impl Equals<SelfType = ()>;
fn _defining_use<T>() -> WithLifetime<T> {}
trait Convert<'a> {
type Witness;
fn convert<'b, T: ?Sized>(_proof: &'b Self::Witness, x: &'a T) -> &'b T;
}
impl<'a> Convert<'a> for () {
type Witness = WithLifetime<&'a ()>;
fn convert<'b, T: ?Sized>(_proof: &'b WithLifetime<&'a ()>, x: &'a T) -> &'b T {
// compiler used to think it gets to assume 'a: 'b here because
// of the `&'b WithLifetime<&'a ()>` argument
x
//~^ ERROR lifetime may not live long enough
}
}
fn extend_lifetime<'a, 'b, T: ?Sized>(x: &'a T) -> &'b T {
WithLifetime::<&'a ()>::convert_helper::<(), T>(&(), x)
}
trait Equals {
type SelfType;
fn convert_helper<'a, 'b, W: Convert<'a, Witness = Self>, T: ?Sized>(
proof: &'b Self::SelfType,
x: &'a T,
) -> &'b T;
}
impl<S> Equals for S {
type SelfType = Self;
fn convert_helper<'a, 'b, W: Convert<'a, Witness = Self>, T: ?Sized>(
proof: &'b Self,
x: &'a T,
) -> &'b T {
W::convert(proof, x)
}
}
fn main() {
let r;
{
let x = String::from("Hello World?");
r = extend_lifetime(&x);
}
println!("{}", r);
}

View File

@ -0,0 +1,16 @@
error: lifetime may not live long enough
--> $DIR/implied_bounds_from_types.rs:17:9
|
LL | impl<'a> Convert<'a> for () {
| -- lifetime `'a` defined here
...
LL | fn convert<'b, T: ?Sized>(_proof: &'b WithLifetime<&'a ()>, x: &'a T) -> &'b T {
| -- lifetime `'b` defined here
...
LL | x
| ^ associated function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
|
= help: consider adding the following bound: `'a: 'b`
error: aborting due to previous error

View File

@ -0,0 +1,18 @@
trait Mirror<'a> {
type Item;
}
impl<'a, T> Mirror<'a> for T {
type Item = T;
}
trait AnotherTrait {
type Blah;
}
impl<'a> AnotherTrait for <u32 as Mirror<'a>>::Item {
//~^ ERROR: the lifetime parameter `'a` is not constrained
type Blah = &'a u32;
}
fn main() {}

View File

@ -0,0 +1,9 @@
error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates
--> $DIR/implied_lifetime_wf_check.rs:13:6
|
LL | impl<'a> AnotherTrait for <u32 as Mirror<'a>>::Item {
| ^^ unconstrained lifetime parameter
error: aborting due to previous error
For more information about this error, try `rustc --explain E0207`.

View File

@ -0,0 +1,13 @@
#![feature(type_alias_impl_trait)]
// check-pass
trait Tr { type Assoc; }
impl<'a> Tr for &'a str { type Assoc = &'a str; }
type OpaqueTy<'a> = impl Tr;
fn defining(s: &str) -> OpaqueTy<'_> { s }
// now we must be able to conclude `'a: 'static` from `Opaque<'a>: 'static`
fn main() {}

View File

@ -0,0 +1,42 @@
#![feature(type_alias_impl_trait)]
mod test_lifetime_param {
type Ty<'a> = impl Sized;
fn defining(a: &str) -> Ty<'_> { a }
fn assert_static<'a: 'static>() {}
//~^ WARN: unnecessary lifetime parameter `'a`
fn test<'a>() where Ty<'a>: 'static { assert_static::<'a>() }
}
mod test_higher_kinded_lifetime_param {
type Ty<'a> = impl Sized;
fn defining(a: &str) -> Ty<'_> { a }
fn assert_static<'a: 'static>() {}
//~^ WARN: unnecessary lifetime parameter `'a`
fn test<'a>() where for<'b> Ty<'b>: 'a { assert_static::<'a>() }
}
mod test_higher_kinded_lifetime_param2 {
fn assert_static<'a: 'static>() {}
//~^ WARN: unnecessary lifetime parameter `'a`
fn test<'a>() { assert_static::<'a>() }
// no error because all the other errors happen first and then we abort before
// emitting an error here.
}
mod test_type_param {
type Ty<A> = impl Sized;
fn defining<A>(s: A) -> Ty<A> { s }
fn assert_static<A: 'static>() {}
fn test<A>() where Ty<A>: 'static { assert_static::<A>() }
}
mod test_type_param_static {
type Ty<A> = impl Sized + 'static;
//~^ ERROR: the parameter type `A` may not live long enough
fn defining<A: 'static>(s: A) -> Ty<A> { s }
fn assert_static<A: 'static>() {}
fn test<A>() where Ty<A>: 'static { assert_static::<A>() }
}
fn main() {}

View File

@ -0,0 +1,38 @@
warning: unnecessary lifetime parameter `'a`
--> $DIR/implied_lifetime_wf_check3.rs:6:22
|
LL | fn assert_static<'a: 'static>() {}
| ^^
|
= help: you can use the `'static` lifetime directly, in place of `'a`
warning: unnecessary lifetime parameter `'a`
--> $DIR/implied_lifetime_wf_check3.rs:14:22
|
LL | fn assert_static<'a: 'static>() {}
| ^^
|
= help: you can use the `'static` lifetime directly, in place of `'a`
warning: unnecessary lifetime parameter `'a`
--> $DIR/implied_lifetime_wf_check3.rs:20:22
|
LL | fn assert_static<'a: 'static>() {}
| ^^
|
= help: you can use the `'static` lifetime directly, in place of `'a`
error[E0310]: the parameter type `A` may not live long enough
--> $DIR/implied_lifetime_wf_check3.rs:35:18
|
LL | type Ty<A> = impl Sized + 'static;
| ^^^^^^^^^^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds
|
help: consider adding an explicit lifetime bound...
|
LL | type Ty<A: 'static> = impl Sized + 'static;
| +++++++++
error: aborting due to previous error; 3 warnings emitted
For more information about this error, try `rustc --explain E0310`.

View File

@ -16,7 +16,7 @@ fn rand_generator<'a>(rng: &'a ()) -> RandGenerator<'a> {
}
}
pub type RandGeneratorWithIndirection<'a> = impl Generator<Return = (), Yield = u64> + 'a;
pub type RandGeneratorWithIndirection<'c> = impl Generator<Return = (), Yield = u64> + 'c;
pub fn rand_generator_with_indirection<'a>(rng: &'a ()) -> RandGeneratorWithIndirection<'a> {
fn helper<'b>(rng: &'b ()) -> impl 'b + Generator<Return = (), Yield = u64> {
move || {

View File

@ -0,0 +1,20 @@
// check-pass
#![feature(generators, generator_trait)]
#![feature(type_alias_impl_trait)]
trait Trait {}
impl<T> Trait for T {}
type Foo<'c> = impl Trait + 'c;
fn foo<'a>(rng: &'a ()) -> Foo<'a> {
fn helper<'b>(rng: &'b ()) -> impl 'b + Trait {
rng
}
helper(rng)
}
fn main() {
}