diff options
| author | bors <bors@rust-lang.org> | 2022-09-25 19:15:26 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2022-09-25 19:15:26 +0000 |
| commit | f5193a9fcc73dc09e41a90c5a2c97fc9acc16032 (patch) | |
| tree | 94bef252534bbe09eca9d1fc2253656c54a47136 | |
| parent | f3fafbb006ee98635874f73e480655912b465e65 (diff) | |
| parent | 59e285ff34796585a61a711e11a056c2999368ea (diff) | |
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
34 files changed, 697 insertions, 154 deletions
diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs index f1b1c33a105..e0140e281ee 100644 --- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs +++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs @@ -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)); + } } } } diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 0208c364e43..99469d1e1e7 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -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 { diff --git a/compiler/rustc_infer/src/infer/outlives/components.rs b/compiler/rustc_infer/src/infer/outlives/components.rs index b2d7f4a663a..14ee9f05190 100644 --- a/compiler/rustc_infer/src/infer/outlives/components.rs +++ b/compiler/rustc_infer/src/infer/outlives/components.rs @@ -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(..) | // ... diff --git a/compiler/rustc_infer/src/infer/outlives/env.rs b/compiler/rustc_infer/src/infer/outlives/env.rs index 9922b156ebf..113d4f09066 100644 --- a/compiler/rustc_infer/src/infer/outlives/env.rs +++ b/compiler/rustc_infer/src/infer/outlives/env.rs @@ -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 diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index 5bd1774f6b1..229b69b92e6 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -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,17 +318,69 @@ 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, origin: infer::SubregionOrigin<'tcx>, 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 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. - } - } - } + let needs_infer = substs.needs_infer(); + if approx_env_bounds.is_empty() && trait_bounds.is_empty() && (needs_infer || is_opaque) { + debug!("no declared bounds"); + + 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> { diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs index e344e192a76..f470b2eb8c1 100644 --- a/compiler/rustc_infer/src/infer/outlives/verify.rs +++ b/compiler/rustc_infer/src/infer/outlives/verify.rs @@ -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`. diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs index e43d28ee56e..67b3da68720 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs @@ -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), } } } diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs index f5a1edf6d81..e12c069dcc1 100644 --- a/compiler/rustc_infer/src/traits/util.rs +++ b/compiler/rustc_infer/src/traits/util.rs @@ -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( diff --git a/compiler/rustc_middle/src/traits/query.rs b/compiler/rustc_middle/src/traits/query.rs index 0e6cacb9fd0..fb152b63f63 100644 --- a/compiler/rustc_middle/src/traits/query.rs +++ b/compiler/rustc_middle/src/traits/query.rs @@ -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>), } diff --git a/compiler/rustc_traits/src/implied_outlives_bounds.rs b/compiler/rustc_traits/src/implied_outlives_bounds.rs index 691b79f1053..32aca4a8a3f 100644 --- a/compiler/rustc_traits/src/implied_outlives_bounds.rs +++ b/compiler/rustc_traits/src/implied_outlives_bounds.rs @@ -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 diff --git a/compiler/rustc_typeck/src/mem_categorization.rs b/compiler/rustc_typeck/src/mem_categorization.rs index ced919f66db..39610e3ae38 100644 --- a/compiler/rustc_typeck/src/mem_categorization.rs +++ b/compiler/rustc_typeck/src/mem_categorization.rs @@ -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, diff --git a/compiler/rustc_typeck/src/outlives/utils.rs b/compiler/rustc_typeck/src/outlives/utils.rs index 3e8d023fb55..0409c7081dc 100644 --- a/compiler/rustc_typeck/src/outlives/utils.rs +++ b/compiler/rustc_typeck/src/outlives/utils.rs @@ -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 diff --git a/src/test/ui/generic-associated-types/bugs/issue-86218.stderr b/src/test/ui/generic-associated-types/bugs/issue-86218.stderr deleted file mode 100644 index de1b464a41d..00000000000 --- a/src/test/ui/generic-associated-types/bugs/issue-86218.stderr +++ /dev/null @@ -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`. diff --git a/src/test/ui/generic-associated-types/issue-86218-2.rs b/src/test/ui/generic-associated-types/issue-86218-2.rs new file mode 100644 index 00000000000..63c839ea871 --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-86218-2.rs @@ -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() {} diff --git a/src/test/ui/generic-associated-types/bugs/issue-86218.rs b/src/test/ui/generic-associated-types/issue-86218.rs index 3a2d758e7d6..b2c3071f06b 100644 --- a/src/test/ui/generic-associated-types/bugs/issue-86218.rs +++ b/src/test/ui/generic-associated-types/issue-86218.rs @@ -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() {} diff --git a/src/test/ui/impl-trait/unactionable_diagnostic.fixed b/src/test/ui/impl-trait/unactionable_diagnostic.fixed new file mode 100644 index 00000000000..6c2505177fe --- /dev/null +++ b/src/test/ui/impl-trait/unactionable_diagnostic.fixed @@ -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() {} diff --git a/src/test/ui/impl-trait/unactionable_diagnostic.rs b/src/test/ui/impl-trait/unactionable_diagnostic.rs new file mode 100644 index 00000000000..bce35cbdd0d --- /dev/null +++ b/src/test/ui/impl-trait/unactionable_diagnostic.rs @@ -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() {} diff --git a/src/test/ui/impl-trait/unactionable_diagnostic.stderr b/src/test/ui/impl-trait/unactionable_diagnostic.stderr new file mode 100644 index 00000000000..a32004cda1a --- /dev/null +++ b/src/test/ui/impl-trait/unactionable_diagnostic.stderr @@ -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`. diff --git a/src/test/ui/type-alias-impl-trait/implied_bounds.rs b/src/test/ui/type-alias-impl-trait/implied_bounds.rs new file mode 100644 index 00000000000..53cbf8d2290 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/implied_bounds.rs @@ -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); +} diff --git a/src/test/ui/type-alias-impl-trait/implied_bounds.stderr b/src/test/ui/type-alias-impl-trait/implied_bounds.stderr new file mode 100644 index 00000000000..6f11b66634b --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/implied_bounds.stderr @@ -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 + diff --git a/src/test/ui/type-alias-impl-trait/implied_bounds2.rs b/src/test/ui/type-alias-impl-trait/implied_bounds2.rs new file mode 100644 index 00000000000..b4c4c013cd2 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/implied_bounds2.rs @@ -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() {} diff --git a/src/test/ui/type-alias-impl-trait/implied_bounds3.rs b/src/test/ui/type-alias-impl-trait/implied_bounds3.rs new file mode 100644 index 00000000000..e39c613281d --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/implied_bounds3.rs @@ -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() { +} diff --git a/src/test/ui/type-alias-impl-trait/implied_bounds_closure.rs b/src/test/ui/type-alias-impl-trait/implied_bounds_closure.rs new file mode 100644 index 00000000000..4cf35f95190 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/implied_bounds_closure.rs @@ -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); +} diff --git a/src/test/ui/type-alias-impl-trait/implied_bounds_closure.stderr b/src/test/ui/type-alias-impl-trait/implied_bounds_closure.stderr new file mode 100644 index 00000000000..151564c3b45 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/implied_bounds_closure.stderr @@ -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 + diff --git a/src/test/ui/type-alias-impl-trait/implied_bounds_from_types.rs b/src/test/ui/type-alias-impl-trait/implied_bounds_from_types.rs new file mode 100644 index 00000000000..8023cd24f0b --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/implied_bounds_from_types.rs @@ -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); +} diff --git a/src/test/ui/type-alias-impl-trait/implied_bounds_from_types.stderr b/src/test/ui/type-alias-impl-trait/implied_bounds_from_types.stderr new file mode 100644 index 00000000000..cbc5e607318 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/implied_bounds_from_types.stderr @@ -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 + diff --git a/src/test/ui/type-alias-impl-trait/implied_lifetime_wf_check.rs b/src/test/ui/type-alias-impl-trait/implied_lifetime_wf_check.rs new file mode 100644 index 00000000000..b6a7264a529 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/implied_lifetime_wf_check.rs @@ -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() {} diff --git a/src/test/ui/type-alias-impl-trait/implied_lifetime_wf_check3.rs b/src/test/ui/type-alias-impl-trait/implied_lifetime_wf_check3.rs new file mode 100644 index 00000000000..6e5b8f491ea --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/implied_lifetime_wf_check3.rs @@ -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() {} diff --git a/src/test/ui/type-alias-impl-trait/implied_lifetime_wf_check3.stderr b/src/test/ui/type-alias-impl-trait/implied_lifetime_wf_check3.stderr new file mode 100644 index 00000000000..887620a4d50 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/implied_lifetime_wf_check3.stderr @@ -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`. diff --git a/src/test/ui/type-alias-impl-trait/implied_lifetime_wf_check4_static.rs b/src/test/ui/type-alias-impl-trait/implied_lifetime_wf_check4_static.rs new file mode 100644 index 00000000000..ac32dbde04b --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/implied_lifetime_wf_check4_static.rs @@ -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() {} diff --git a/src/test/ui/type-alias-impl-trait/implied_lifetime_wf_check4_static.stderr b/src/test/ui/type-alias-impl-trait/implied_lifetime_wf_check4_static.stderr new file mode 100644 index 00000000000..47bc31e78c3 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/implied_lifetime_wf_check4_static.stderr @@ -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`. diff --git a/src/test/ui/type-alias-impl-trait/issue-58662-generator-with-lifetime.rs b/src/test/ui/type-alias-impl-trait/issue-58662-generator-with-lifetime.rs index f20ddf02071..477b61390ed 100644 --- a/src/test/ui/type-alias-impl-trait/issue-58662-generator-with-lifetime.rs +++ b/src/test/ui/type-alias-impl-trait/issue-58662-generator-with-lifetime.rs @@ -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 || { diff --git a/src/test/ui/type-alias-impl-trait/issue-58662-simplified.rs b/src/test/ui/type-alias-impl-trait/issue-58662-simplified.rs new file mode 100644 index 00000000000..27ca7d0fdc9 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/issue-58662-simplified.rs @@ -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() { +} diff --git a/src/test/ui/type-alias-impl-trait/unbounded_opaque_type.rs b/src/test/ui/type-alias-impl-trait/unbounded_opaque_type.rs new file mode 100644 index 00000000000..f43ad7dce1d --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/unbounded_opaque_type.rs @@ -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() {} |
