mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-10 05:53:10 +00:00
Auto merge of #95474 - oli-obk:tait_ub, r=jackh726
Neither require nor imply lifetime bounds on opaque type for well formedness The actual hidden type can live arbitrarily longer than any individual lifetime and arbitrarily shorter than all but one of the lifetimes. fixes #86218 fixes #84305 This is a **breaking change** but it is a necessary soundness fix
This commit is contained in:
commit
f5193a9fcc
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2481,6 +2481,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(..) | // ...
|
||||
|
@ -142,6 +142,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
|
||||
|
@ -68,10 +68,11 @@ use crate::infer::{
|
||||
};
|
||||
use crate::traits::{ObligationCause, ObligationCauseCode};
|
||||
use rustc_data_structures::undo_log::UndoLogs;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_middle::mir::ConstraintCategory;
|
||||
use rustc_middle::ty::subst::GenericArgKind;
|
||||
use rustc_middle::ty::{self, Region, Ty, TyCtxt, TypeVisitable};
|
||||
use rustc_middle::ty::{self, Region, SubstsRef, Ty, TyCtxt, TypeVisitable};
|
||||
use smallvec::smallvec;
|
||||
|
||||
impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
|
||||
@ -283,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);
|
||||
}
|
||||
@ -314,10 +318,32 @@ where
|
||||
);
|
||||
|
||||
let generic = GenericKind::Param(param_ty);
|
||||
let verify_bound = self.verify_bound.generic_bound(generic);
|
||||
let verify_bound = self.verify_bound.param_bound(param_ty);
|
||||
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,
|
||||
true,
|
||||
|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,
|
||||
@ -325,6 +351,36 @@ where
|
||||
region: ty::Region<'tcx>,
|
||||
projection_ty: ty::ProjectionTy<'tcx>,
|
||||
) {
|
||||
self.generic_must_outlive(
|
||||
origin,
|
||||
region,
|
||||
GenericKind::Projection(projection_ty),
|
||||
projection_ty.item_def_id,
|
||||
projection_ty.substs,
|
||||
false,
|
||||
|ty| match ty.kind() {
|
||||
ty::Projection(projection_ty) => (projection_ty.item_def_id, projection_ty.substs),
|
||||
_ => bug!("expected only projection types from env, not {:?}", ty),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self, filter))]
|
||||
fn generic_must_outlive(
|
||||
&mut self,
|
||||
origin: infer::SubregionOrigin<'tcx>,
|
||||
region: ty::Region<'tcx>,
|
||||
generic: GenericKind<'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.
|
||||
if substs.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
// This case is thorny for inference. The fundamental problem is
|
||||
// that there are many cases where we have choice, and inference
|
||||
// doesn't like choice (the current region inference in
|
||||
@ -343,16 +399,15 @@ where
|
||||
// These are guaranteed to apply, no matter the inference
|
||||
// results.
|
||||
let trait_bounds: Vec<_> =
|
||||
self.verify_bound.projection_declared_bounds_from_trait(projection_ty).collect();
|
||||
self.verify_bound.declared_region_bounds(def_id, substs).collect();
|
||||
|
||||
debug!(?trait_bounds);
|
||||
|
||||
// Compute the bounds we can derive from the environment. This
|
||||
// is an "approximate" match -- in some cases, these bounds
|
||||
// may not apply.
|
||||
let mut approx_env_bounds =
|
||||
self.verify_bound.projection_approx_declared_bounds_from_env(projection_ty);
|
||||
debug!("projection_must_outlive: approx_env_bounds={:?}", approx_env_bounds);
|
||||
let mut approx_env_bounds = self.verify_bound.approx_declared_bounds_from_env(generic);
|
||||
debug!(?approx_env_bounds);
|
||||
|
||||
// Remove outlives bounds that we get from the environment but
|
||||
// which are also deducible from the trait. This arises (cc
|
||||
@ -366,14 +421,8 @@ where
|
||||
// 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.
|
||||
let bound = bound_outlives.skip_binder();
|
||||
match *bound.0.kind() {
|
||||
ty::Projection(projection_ty) => self
|
||||
.verify_bound
|
||||
.projection_declared_bounds_from_trait(projection_ty)
|
||||
.all(|r| r != bound.1),
|
||||
|
||||
_ => panic!("expected only projection types from env, not {:?}", bound.0),
|
||||
}
|
||||
let (def_id, substs) = filter(bound.0);
|
||||
self.verify_bound.declared_region_bounds(def_id, substs).all(|r| r != bound.1)
|
||||
});
|
||||
|
||||
// If declared bounds list is empty, the only applicable rule is
|
||||
@ -390,29 +439,11 @@ where
|
||||
// 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
|
||||
// edges, which winds up enforcing the same condition.
|
||||
let needs_infer = projection_ty.needs_infer();
|
||||
if approx_env_bounds.is_empty() && trait_bounds.is_empty() && needs_infer {
|
||||
debug!("projection_must_outlive: no declared bounds");
|
||||
let needs_infer = substs.needs_infer();
|
||||
if approx_env_bounds.is_empty() && trait_bounds.is_empty() && (needs_infer || is_opaque) {
|
||||
debug!("no declared bounds");
|
||||
|
||||
let constraint = origin.to_constraint_category();
|
||||
for k in projection_ty.substs {
|
||||
match k.unpack() {
|
||||
GenericArgKind::Lifetime(lt) => {
|
||||
self.delegate.push_sub_region_constraint(
|
||||
origin.clone(),
|
||||
region,
|
||||
lt,
|
||||
constraint,
|
||||
);
|
||||
}
|
||||
GenericArgKind::Type(ty) => {
|
||||
self.type_must_outlive(origin.clone(), ty, region, constraint);
|
||||
}
|
||||
GenericArgKind::Const(_) => {
|
||||
// Const parameters don't impose constraints.
|
||||
}
|
||||
}
|
||||
}
|
||||
self.substs_must_outlive(substs, origin, region);
|
||||
|
||||
return;
|
||||
}
|
||||
@ -442,8 +473,8 @@ where
|
||||
.all(|b| b == Some(trait_bounds[0]))
|
||||
{
|
||||
let unique_bound = trait_bounds[0];
|
||||
debug!("projection_must_outlive: unique trait bound = {:?}", unique_bound);
|
||||
debug!("projection_must_outlive: unique declared bound appears in trait ref");
|
||||
debug!(?unique_bound);
|
||||
debug!("unique declared bound appears in trait ref");
|
||||
let category = origin.to_constraint_category();
|
||||
self.delegate.push_sub_region_constraint(origin, region, unique_bound, category);
|
||||
return;
|
||||
@ -454,11 +485,42 @@ where
|
||||
// projection outlive; in some cases, this may add insufficient
|
||||
// edges into the inference graph, leading to inference failures
|
||||
// even though a satisfactory solution exists.
|
||||
let generic = GenericKind::Projection(projection_ty);
|
||||
let verify_bound = self.verify_bound.generic_bound(generic);
|
||||
let verify_bound = self.verify_bound.projection_opaque_bounds(
|
||||
generic,
|
||||
def_id,
|
||||
substs,
|
||||
&mut Default::default(),
|
||||
);
|
||||
debug!("projection_must_outlive: pushing {:?}", verify_bound);
|
||||
self.delegate.push_verify(origin, generic, region, verify_bound);
|
||||
}
|
||||
|
||||
fn substs_must_outlive(
|
||||
&mut self,
|
||||
substs: SubstsRef<'tcx>,
|
||||
origin: infer::SubregionOrigin<'tcx>,
|
||||
region: ty::Region<'tcx>,
|
||||
) {
|
||||
let constraint = origin.to_constraint_category();
|
||||
for k in substs {
|
||||
match k.unpack() {
|
||||
GenericArgKind::Lifetime(lt) => {
|
||||
self.delegate.push_sub_region_constraint(
|
||||
origin.clone(),
|
||||
region,
|
||||
lt,
|
||||
constraint,
|
||||
);
|
||||
}
|
||||
GenericArgKind::Type(ty) => {
|
||||
self.type_must_outlive(origin.clone(), ty, region, constraint);
|
||||
}
|
||||
GenericArgKind::Const(_) => {
|
||||
// Const parameters don't impose constraints.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'cx, 'tcx> TypeOutlivesDelegate<'tcx> for &'cx InferCtxt<'cx, 'tcx> {
|
||||
|
@ -2,11 +2,10 @@ use crate::infer::outlives::components::{compute_components_recursive, Component
|
||||
use crate::infer::outlives::env::RegionBoundPairs;
|
||||
use crate::infer::region_constraints::VerifyIfEq;
|
||||
use crate::infer::{GenericKind, VerifyBound};
|
||||
use rustc_data_structures::captures::Captures;
|
||||
use rustc_data_structures::sso::SsoHashSet;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_middle::ty::GenericArg;
|
||||
use rustc_middle::ty::{self, EarlyBinder, OutlivesPredicate, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{self, EarlyBinder, OutlivesPredicate, SubstsRef, Ty, TyCtxt};
|
||||
|
||||
use smallvec::smallvec;
|
||||
|
||||
@ -38,20 +37,8 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
|
||||
Self { tcx, region_bound_pairs, implicit_region_bound, param_env }
|
||||
}
|
||||
|
||||
/// Returns a "verify bound" that encodes what we know about
|
||||
/// `generic` and the regions it outlives.
|
||||
pub fn generic_bound(&self, generic: GenericKind<'tcx>) -> VerifyBound<'tcx> {
|
||||
let mut visited = SsoHashSet::new();
|
||||
match generic {
|
||||
GenericKind::Param(param_ty) => self.param_bound(param_ty),
|
||||
GenericKind::Projection(projection_ty) => {
|
||||
self.projection_bound(projection_ty, &mut visited)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
fn param_bound(&self, param_ty: ty::ParamTy) -> VerifyBound<'tcx> {
|
||||
pub fn param_bound(&self, param_ty: ty::ParamTy) -> VerifyBound<'tcx> {
|
||||
// Start with anything like `T: 'a` we can scrape from the
|
||||
// environment. If the environment contains something like
|
||||
// `for<'a> T: 'a`, then we know that `T` outlives everything.
|
||||
@ -105,41 +92,31 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
|
||||
/// the clause from the environment only applies if `'0 = 'a`,
|
||||
/// which we don't know yet. But we would still include `'b` in
|
||||
/// this list.
|
||||
pub fn projection_approx_declared_bounds_from_env(
|
||||
pub fn approx_declared_bounds_from_env(
|
||||
&self,
|
||||
projection_ty: ty::ProjectionTy<'tcx>,
|
||||
generic: GenericKind<'tcx>,
|
||||
) -> Vec<ty::Binder<'tcx, ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>>> {
|
||||
let projection_ty = GenericKind::Projection(projection_ty).to_ty(self.tcx);
|
||||
let projection_ty = generic.to_ty(self.tcx);
|
||||
let erased_projection_ty = self.tcx.erase_regions(projection_ty);
|
||||
self.declared_generic_bounds_from_env_for_erased_ty(erased_projection_ty)
|
||||
}
|
||||
|
||||
/// Searches the where-clauses in scope for regions that
|
||||
/// `projection_ty` is known to outlive. Currently requires an
|
||||
/// exact match.
|
||||
pub fn projection_declared_bounds_from_trait(
|
||||
#[instrument(level = "debug", skip(self, visited))]
|
||||
pub fn projection_opaque_bounds(
|
||||
&self,
|
||||
projection_ty: ty::ProjectionTy<'tcx>,
|
||||
) -> impl Iterator<Item = ty::Region<'tcx>> + 'cx + Captures<'tcx> {
|
||||
self.declared_projection_bounds_from_trait(projection_ty)
|
||||
}
|
||||
|
||||
pub fn projection_bound(
|
||||
&self,
|
||||
projection_ty: ty::ProjectionTy<'tcx>,
|
||||
generic: GenericKind<'tcx>,
|
||||
def_id: DefId,
|
||||
substs: SubstsRef<'tcx>,
|
||||
visited: &mut SsoHashSet<GenericArg<'tcx>>,
|
||||
) -> VerifyBound<'tcx> {
|
||||
debug!("projection_bound(projection_ty={:?})", projection_ty);
|
||||
|
||||
let projection_ty_as_ty =
|
||||
self.tcx.mk_projection(projection_ty.item_def_id, projection_ty.substs);
|
||||
let generic_ty = generic.to_ty(self.tcx);
|
||||
|
||||
// Search the env for where clauses like `P: 'a`.
|
||||
let env_bounds = self
|
||||
.projection_approx_declared_bounds_from_env(projection_ty)
|
||||
let projection_opaque_bounds = self
|
||||
.approx_declared_bounds_from_env(generic)
|
||||
.into_iter()
|
||||
.map(|binder| {
|
||||
if let Some(ty::OutlivesPredicate(ty, r)) = binder.no_bound_vars() && ty == projection_ty_as_ty {
|
||||
if let Some(ty::OutlivesPredicate(ty, r)) = binder.no_bound_vars() && ty == generic_ty {
|
||||
// Micro-optimize if this is an exact match (this
|
||||
// occurs often when there are no region variables
|
||||
// involved).
|
||||
@ -149,21 +126,19 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
|
||||
VerifyBound::IfEq(verify_if_eq_b)
|
||||
}
|
||||
});
|
||||
|
||||
// Extend with bounds that we can find from the trait.
|
||||
let trait_bounds = self
|
||||
.projection_declared_bounds_from_trait(projection_ty)
|
||||
.map(|r| VerifyBound::OutlivedBy(r));
|
||||
let trait_bounds =
|
||||
self.declared_region_bounds(def_id, substs).map(|r| VerifyBound::OutlivedBy(r));
|
||||
|
||||
// see the extensive comment in projection_must_outlive
|
||||
let recursive_bound = {
|
||||
let mut components = smallvec![];
|
||||
let ty = self.tcx.mk_projection(projection_ty.item_def_id, projection_ty.substs);
|
||||
compute_components_recursive(self.tcx, ty.into(), &mut components, visited);
|
||||
compute_components_recursive(self.tcx, generic_ty.into(), &mut components, visited);
|
||||
self.bound_from_components(&components, visited)
|
||||
};
|
||||
|
||||
VerifyBound::AnyBound(env_bounds.chain(trait_bounds).collect()).or(recursive_bound)
|
||||
VerifyBound::AnyBound(projection_opaque_bounds.chain(trait_bounds).collect())
|
||||
.or(recursive_bound)
|
||||
}
|
||||
|
||||
fn bound_from_components(
|
||||
@ -195,7 +170,18 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
|
||||
match *component {
|
||||
Component::Region(lt) => VerifyBound::OutlivedBy(lt),
|
||||
Component::Param(param_ty) => self.param_bound(param_ty),
|
||||
Component::Projection(projection_ty) => self.projection_bound(projection_ty, visited),
|
||||
Component::Opaque(did, substs) => self.projection_opaque_bounds(
|
||||
GenericKind::Opaque(did, substs),
|
||||
did,
|
||||
substs,
|
||||
visited,
|
||||
),
|
||||
Component::Projection(projection_ty) => self.projection_opaque_bounds(
|
||||
GenericKind::Projection(projection_ty),
|
||||
projection_ty.item_def_id,
|
||||
projection_ty.substs,
|
||||
visited,
|
||||
),
|
||||
Component::EscapingProjection(ref components) => {
|
||||
self.bound_from_components(components, visited)
|
||||
}
|
||||
@ -293,30 +279,6 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// then this function would return `'x`. This is subject to the
|
||||
/// limitations around higher-ranked bounds described in
|
||||
/// `region_bounds_declared_on_associated_item`.
|
||||
fn declared_projection_bounds_from_trait(
|
||||
&self,
|
||||
projection_ty: ty::ProjectionTy<'tcx>,
|
||||
) -> impl Iterator<Item = ty::Region<'tcx>> + 'cx + Captures<'tcx> {
|
||||
debug!("projection_bounds(projection_ty={:?})", projection_ty);
|
||||
let tcx = self.tcx;
|
||||
self.region_bounds_declared_on_associated_item(projection_ty.item_def_id)
|
||||
.map(move |r| EarlyBinder(r).subst(tcx, projection_ty.substs))
|
||||
}
|
||||
|
||||
/// Given the `DefId` of an associated item, returns any region
|
||||
/// bounds attached to that associated item from the trait definition.
|
||||
///
|
||||
/// For example:
|
||||
///
|
||||
/// ```rust
|
||||
/// trait Foo<'a> {
|
||||
/// type Bar: 'a;
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// If we were given the `DefId` of `Foo::Bar`, we would return
|
||||
/// `'a`. You could then apply the substitutions from the
|
||||
/// projection to convert this into your namespace. This also
|
||||
@ -336,17 +298,20 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
|
||||
///
|
||||
/// This is for simplicity, and because we are not really smart
|
||||
/// enough to cope with such bounds anywhere.
|
||||
fn region_bounds_declared_on_associated_item(
|
||||
pub fn declared_region_bounds(
|
||||
&self,
|
||||
assoc_item_def_id: DefId,
|
||||
def_id: DefId,
|
||||
substs: SubstsRef<'tcx>,
|
||||
) -> impl Iterator<Item = ty::Region<'tcx>> {
|
||||
let tcx = self.tcx;
|
||||
let bounds = tcx.item_bounds(assoc_item_def_id);
|
||||
let bounds = tcx.item_bounds(def_id);
|
||||
trace!("{:#?}", bounds);
|
||||
bounds
|
||||
.into_iter()
|
||||
.filter_map(|p| p.to_opt_type_outlives())
|
||||
.filter_map(|p| p.no_bound_vars())
|
||||
.map(|b| b.1)
|
||||
.map(move |r| EarlyBinder(r).subst(tcx, substs))
|
||||
}
|
||||
|
||||
/// Searches through a predicate list for a predicate `T: 'a`.
|
||||
|
@ -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>),
|
||||
}
|
||||
|
@ -156,6 +156,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,
|
||||
|
@ -96,6 +96,23 @@ pub(crate) fn insert_outlives_predicate<'tcx>(
|
||||
.or_insert(span);
|
||||
}
|
||||
|
||||
Component::Opaque(def_id, substs) => {
|
||||
// This would arise from something like:
|
||||
//
|
||||
// ```rust
|
||||
// type Opaque<T> = impl Sized;
|
||||
// fn defining<T>() -> Opaque<T> {}
|
||||
// struct Ss<'a, T>(&'a Opaque<T>);
|
||||
// ```
|
||||
//
|
||||
// Here we want to have an implied bound `Opaque<T>: 'a`
|
||||
|
||||
let ty = tcx.mk_opaque(def_id, substs);
|
||||
required_predicates
|
||||
.entry(ty::OutlivesPredicate(ty.into(), outlived_region))
|
||||
.or_insert(span);
|
||||
}
|
||||
|
||||
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`.
|
23
src/test/ui/generic-associated-types/issue-86218-2.rs
Normal file
23
src/test/ui/generic-associated-types/issue-86218-2.rs
Normal file
@ -0,0 +1,23 @@
|
||||
// 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;
|
||||
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() {}
|
25
src/test/ui/impl-trait/unactionable_diagnostic.fixed
Normal file
25
src/test/ui/impl-trait/unactionable_diagnostic.fixed
Normal file
@ -0,0 +1,25 @@
|
||||
// run-rustfix
|
||||
|
||||
pub trait Trait {}
|
||||
|
||||
pub struct Foo;
|
||||
|
||||
impl Trait for Foo {}
|
||||
|
||||
fn foo<'x, P>(
|
||||
_post: P,
|
||||
x: &'x Foo,
|
||||
) -> &'x impl Trait {
|
||||
x
|
||||
}
|
||||
|
||||
pub fn bar<'t, T: 't>(
|
||||
//~^ HELP: consider adding an explicit lifetime bound...
|
||||
post: T,
|
||||
x: &'t Foo,
|
||||
) -> &'t impl Trait {
|
||||
foo(post, x)
|
||||
//~^ ERROR: the parameter type `T` may not live long enough
|
||||
}
|
||||
|
||||
fn main() {}
|
25
src/test/ui/impl-trait/unactionable_diagnostic.rs
Normal file
25
src/test/ui/impl-trait/unactionable_diagnostic.rs
Normal file
@ -0,0 +1,25 @@
|
||||
// run-rustfix
|
||||
|
||||
pub trait Trait {}
|
||||
|
||||
pub struct Foo;
|
||||
|
||||
impl Trait for Foo {}
|
||||
|
||||
fn foo<'x, P>(
|
||||
_post: P,
|
||||
x: &'x Foo,
|
||||
) -> &'x impl Trait {
|
||||
x
|
||||
}
|
||||
|
||||
pub fn bar<'t, T>(
|
||||
//~^ HELP: consider adding an explicit lifetime bound...
|
||||
post: T,
|
||||
x: &'t Foo,
|
||||
) -> &'t impl Trait {
|
||||
foo(post, x)
|
||||
//~^ ERROR: the parameter type `T` may not live long enough
|
||||
}
|
||||
|
||||
fn main() {}
|
14
src/test/ui/impl-trait/unactionable_diagnostic.stderr
Normal file
14
src/test/ui/impl-trait/unactionable_diagnostic.stderr
Normal file
@ -0,0 +1,14 @@
|
||||
error[E0309]: the parameter type `T` may not live long enough
|
||||
--> $DIR/unactionable_diagnostic.rs:21:5
|
||||
|
|
||||
LL | foo(post, x)
|
||||
| ^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
|
||||
|
|
||||
help: consider adding an explicit lifetime bound...
|
||||
|
|
||||
LL | pub fn bar<'t, T: 't>(
|
||||
| ++++
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0309`.
|
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
|
||||
|
10
src/test/ui/type-alias-impl-trait/implied_bounds2.rs
Normal file
10
src/test/ui/type-alias-impl-trait/implied_bounds2.rs
Normal file
@ -0,0 +1,10 @@
|
||||
// check-pass
|
||||
|
||||
#![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>>() }
|
||||
|
||||
fn main() {}
|
18
src/test/ui/type-alias-impl-trait/implied_bounds3.rs
Normal file
18
src/test/ui/type-alias-impl-trait/implied_bounds3.rs
Normal file
@ -0,0 +1,18 @@
|
||||
// check-pass
|
||||
|
||||
fn foo<F>(_: F)
|
||||
where
|
||||
F: 'static,
|
||||
{
|
||||
}
|
||||
|
||||
fn from<F: Send>(f: F) -> impl Send {
|
||||
f
|
||||
}
|
||||
|
||||
fn bar<T>() {
|
||||
foo(from(|| ()))
|
||||
}
|
||||
|
||||
fn main() {
|
||||
}
|
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,27 @@
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
// known-bug: #99840
|
||||
// this should not compile
|
||||
// check-pass
|
||||
|
||||
type Alias = impl Sized;
|
||||
|
||||
fn constrain() -> Alias {
|
||||
1i32
|
||||
}
|
||||
|
||||
trait HideIt {
|
||||
type Assoc;
|
||||
}
|
||||
|
||||
impl HideIt for () {
|
||||
type Assoc = Alias;
|
||||
}
|
||||
|
||||
pub trait Yay {}
|
||||
|
||||
impl Yay for <() as HideIt>::Assoc {}
|
||||
// impl Yay for i32 {} // this already errors
|
||||
// impl Yay for u32 {} // this also already errors
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,43 @@
|
||||
#![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>() }
|
||||
//~^ ERROR: lifetime may not live long enough
|
||||
}
|
||||
|
||||
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>() }
|
||||
//~^ ERROR: lifetime may not live long enough
|
||||
}
|
||||
|
||||
mod test_higher_kinded_lifetime_param2 {
|
||||
fn assert_static<'a: 'static>() {}
|
||||
//~^ WARN: unnecessary lifetime parameter `'a`
|
||||
fn test<'a>() { assert_static::<'a>() }
|
||||
//~^ ERROR: lifetime may not live long enough
|
||||
}
|
||||
|
||||
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>() }
|
||||
//~^ ERROR: parameter type `A` may not live long enough
|
||||
}
|
||||
|
||||
mod test_implied_from_fn_sig {
|
||||
type Opaque<T: 'static> = impl Sized;
|
||||
fn defining<T: 'static>() -> Opaque<T> {}
|
||||
fn assert_static<T: 'static>() {}
|
||||
fn test<T>(_: Opaque<T>) { assert_static::<T>(); }
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,58 @@
|
||||
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:15: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:22:22
|
||||
|
|
||||
LL | fn assert_static<'a: 'static>() {}
|
||||
| ^^
|
||||
|
|
||||
= help: you can use the `'static` lifetime directly, in place of `'a`
|
||||
|
||||
error: lifetime may not live long enough
|
||||
--> $DIR/implied_lifetime_wf_check3.rs:8:43
|
||||
|
|
||||
LL | fn test<'a>() where Ty<'a>: 'static { assert_static::<'a>() }
|
||||
| -- lifetime `'a` defined here ^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
|
||||
|
||||
error: lifetime may not live long enough
|
||||
--> $DIR/implied_lifetime_wf_check3.rs:17:46
|
||||
|
|
||||
LL | fn test<'a>() where for<'b> Ty<'b>: 'a { assert_static::<'a>() }
|
||||
| -- lifetime `'a` defined here ^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
|
||||
|
||||
error: lifetime may not live long enough
|
||||
--> $DIR/implied_lifetime_wf_check3.rs:24:21
|
||||
|
|
||||
LL | fn test<'a>() { assert_static::<'a>() }
|
||||
| -- ^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
|
||||
| |
|
||||
| lifetime `'a` defined here
|
||||
|
||||
error[E0310]: the parameter type `A` may not live long enough
|
||||
--> $DIR/implied_lifetime_wf_check3.rs:32:41
|
||||
|
|
||||
LL | fn test<A>() where Ty<A>: 'static { assert_static::<A>() }
|
||||
| ^^^^^^^^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds
|
||||
|
|
||||
help: consider adding an explicit lifetime bound...
|
||||
|
|
||||
LL | fn test<A: 'static>() where Ty<A>: 'static { assert_static::<A>() }
|
||||
| +++++++++
|
||||
|
||||
error: aborting due to 4 previous errors; 3 warnings emitted
|
||||
|
||||
For more information about this error, try `rustc --explain E0310`.
|
@ -0,0 +1,11 @@
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
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,14 @@
|
||||
error[E0310]: the parameter type `A` may not live long enough
|
||||
--> $DIR/implied_lifetime_wf_check4_static.rs:4: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
|
||||
|
||||
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() {
|
||||
}
|
14
src/test/ui/type-alias-impl-trait/unbounded_opaque_type.rs
Normal file
14
src/test/ui/type-alias-impl-trait/unbounded_opaque_type.rs
Normal file
@ -0,0 +1,14 @@
|
||||
// check-pass
|
||||
|
||||
#![feature(type_alias_impl_trait)]
|
||||
type Opaque<T> = impl Sized;
|
||||
fn defining<T>() -> Opaque<T> {}
|
||||
struct Ss<'a, T>(&'a Opaque<T>);
|
||||
|
||||
|
||||
fn test<'a, T>(_: Ss<'a, T>) {
|
||||
// test that we have an implied bound `Opaque<T>: 'a` from fn signature
|
||||
None::<&'a Opaque<T>>;
|
||||
}
|
||||
|
||||
fn main() {}
|
Loading…
Reference in New Issue
Block a user