Neither require nor imply lifetime bounds on opaque type for well formedness
This commit is contained in:
parent
c8ecf09a25
commit
37928f5986
30 changed files with 497 additions and 42 deletions
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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(..) | // ...
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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>),
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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`.
|
24
src/test/ui/generic-associated-types/issue-86218-2.rs
Normal file
24
src/test/ui/generic-associated-types/issue-86218-2.rs
Normal 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() {}
|
|
@ -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() {}
|
51
src/test/ui/type-alias-impl-trait/implied_bounds.rs
Normal file
51
src/test/ui/type-alias-impl-trait/implied_bounds.rs
Normal 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);
|
||||
}
|
16
src/test/ui/type-alias-impl-trait/implied_bounds.stderr
Normal file
16
src/test/ui/type-alias-impl-trait/implied_bounds.stderr
Normal 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
|
||||
|
9
src/test/ui/type-alias-impl-trait/implied_bounds2.rs
Normal file
9
src/test/ui/type-alias-impl-trait/implied_bounds2.rs
Normal 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() {}
|
12
src/test/ui/type-alias-impl-trait/implied_bounds2.stderr
Normal file
12
src/test/ui/type-alias-impl-trait/implied_bounds2.stderr
Normal 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`.
|
31
src/test/ui/type-alias-impl-trait/implied_bounds_closure.rs
Normal file
31
src/test/ui/type-alias-impl-trait/implied_bounds_closure.rs
Normal 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);
|
||||
}
|
|
@ -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
|
||||
|
|
@ -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);
|
||||
}
|
|
@ -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
|
||||
|
|
@ -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() {}
|
|
@ -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`.
|
|
@ -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() {}
|
|
@ -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() {}
|
|
@ -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`.
|
|
@ -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 || {
|
||||
|
|
20
src/test/ui/type-alias-impl-trait/issue-58662-simplified.rs
Normal file
20
src/test/ui/type-alias-impl-trait/issue-58662-simplified.rs
Normal 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() {
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue