diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index ff29d15f1b525..d10d1b0c73136 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -61,8 +61,8 @@ use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID}; use rustc_hir::definitions::DefPathData; use rustc_hir::{ConstArg, GenericArg, ItemLocalId, ParamName, TraitCandidate}; use rustc_index::vec::{Idx, IndexVec}; +use rustc_middle::span_bug; use rustc_middle::ty::{ResolverAstLowering, TyCtxt}; -use rustc_middle::{bug, span_bug}; use rustc_session::parse::feature_err; use rustc_span::hygiene::MacroKind; use rustc_span::source_map::DesugaringKind; @@ -1457,17 +1457,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // frequently opened issues show. let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::OpaqueTy, span, None); - let opaque_ty_def_id = match origin { - hir::OpaqueTyOrigin::TyAlias => self.create_def( - self.current_hir_id_owner.def_id, - opaque_ty_node_id, - DefPathData::ImplTrait, - ), - hir::OpaqueTyOrigin::FnReturn(fn_def_id) => { - self.create_def(fn_def_id, opaque_ty_node_id, DefPathData::ImplTrait) - } - hir::OpaqueTyOrigin::AsyncFn(..) => bug!("unreachable"), - }; + let opaque_ty_def_id = self.create_def( + self.current_hir_id_owner.def_id, + opaque_ty_node_id, + DefPathData::ImplTrait, + ); debug!(?opaque_ty_def_id); // Contains the new lifetime definitions created for the TAIT (if any). diff --git a/compiler/rustc_borrowck/src/member_constraints.rs b/compiler/rustc_borrowck/src/member_constraints.rs index b48f9f97daad8..b5e00f471d26a 100644 --- a/compiler/rustc_borrowck/src/member_constraints.rs +++ b/compiler/rustc_borrowck/src/member_constraints.rs @@ -11,6 +11,7 @@ use std::ops::Index; /// Compactly stores a set of `R0 member of [R1...Rn]` constraints, /// indexed by the region `R0`. +#[derive(Debug)] pub(crate) struct MemberConstraintSet<'tcx, R> where R: Copy + Eq, @@ -31,6 +32,7 @@ where } /// Represents a `R0 member of [R1..Rn]` constraint +#[derive(Debug)] pub(crate) struct NllMemberConstraint<'tcx> { next_constraint: Option, diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 94e9e05e5d640..b35abbd107b9c 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -128,6 +128,7 @@ pub struct RegionInferenceContext<'tcx> { /// adds a new lower bound to the SCC it is analyzing: so you wind up /// with `'R: 'O` where `'R` is the pick-region and `'O` is the /// minimal viable option. +#[derive(Debug)] pub(crate) struct AppliedMemberConstraint { /// The SCC that was affected. (The "member region".) /// diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index dd222485daf2c..fe49e3a4ba9c8 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -1,4 +1,4 @@ -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; use rustc_data_structures::vec_map::VecMap; use rustc_hir::def_id::LocalDefId; use rustc_hir::OpaqueTyOrigin; @@ -63,17 +63,21 @@ impl<'tcx> RegionInferenceContext<'tcx> { opaque_ty_decls: VecMap, (OpaqueHiddenType<'tcx>, OpaqueTyOrigin)>, ) -> VecMap> { let mut result: VecMap> = VecMap::new(); + + let member_constraints: FxHashMap<_, _> = self + .member_constraints + .all_indices() + .map(|ci| (self.member_constraints[ci].key, ci)) + .collect(); + debug!(?member_constraints); + for (opaque_type_key, (concrete_type, origin)) in opaque_ty_decls { let substs = opaque_type_key.substs; debug!(?concrete_type, ?substs); let mut subst_regions = vec![self.universal_regions.fr_static]; - let universal_substs = infcx.tcx.fold_regions(substs, |region, _| { - if let ty::RePlaceholder(..) = region.kind() { - // Higher kinded regions don't need remapping, they don't refer to anything outside of this the substs. - return region; - } - let vid = self.to_region_vid(region); + + let to_universal_region = |vid, subst_regions: &mut Vec<_>| { trace!(?vid); let scc = self.constraint_sccs.scc(vid); trace!(?scc); @@ -94,10 +98,33 @@ impl<'tcx> RegionInferenceContext<'tcx> { infcx.tcx.lifetimes.re_static } } + }; + + // Start by inserting universal regions from the member_constraint choice regions. + // This will ensure they get precedence when folding the regions in the concrete type. + if let Some(&ci) = member_constraints.get(&opaque_type_key) { + for &vid in self.member_constraints.choice_regions(ci) { + to_universal_region(vid, &mut subst_regions); + } + } + debug!(?subst_regions); + + // Next, insert universal regions from substs, so we can translate regions that appear + // in them but are not subject to member constraints, for instance closure substs. + let universal_substs = infcx.tcx.fold_regions(substs, |region, _| { + if let ty::RePlaceholder(..) = region.kind() { + // Higher kinded regions don't need remapping, they don't refer to anything outside of this the substs. + return region; + } + let vid = self.to_region_vid(region); + to_universal_region(vid, &mut subst_regions) }); + debug!(?universal_substs); + debug!(?subst_regions); - subst_regions.sort(); - subst_regions.dedup(); + // Deduplicate the set of regions while keeping the chosen order. + let subst_regions = subst_regions.into_iter().collect::>(); + debug!(?subst_regions); let universal_concrete_type = infcx.tcx.fold_regions(concrete_type, |region, _| match *region { @@ -108,8 +135,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { .unwrap_or(infcx.tcx.lifetimes.re_erased), _ => region, }); - - debug!(?universal_concrete_type, ?universal_substs); + debug!(?universal_concrete_type); let opaque_type_key = OpaqueTypeKey { def_id: opaque_type_key.def_id, substs: universal_substs }; diff --git a/compiler/rustc_error_codes/src/error_codes/E0760.md b/compiler/rustc_error_codes/src/error_codes/E0760.md index e1dcfefebcd76..85e5faada224e 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0760.md +++ b/compiler/rustc_error_codes/src/error_codes/E0760.md @@ -1,9 +1,11 @@ +#### Note: this error code is no longer emitted by the compiler. + `async fn`/`impl trait` return type cannot contain a projection or `Self` that references lifetimes from a parent scope. Erroneous code example: -```compile_fail,E0760,edition2018 +```compile_fail,edition2018 struct S<'a>(&'a i32); impl<'a> S<'a> { diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index e94e038f9283b..eeae9915993c3 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -419,6 +419,8 @@ declare_features! ( (active, if_let_guard, "1.47.0", Some(51114), None), /// Allows `impl Trait` as output type in `Fn` traits in return position of functions. (active, impl_trait_in_fn_trait_return, "1.64.0", Some(99697), None), + /// Allows referencing `Self` and projections in impl-trait. + (active, impl_trait_projections, "CURRENT_RUSTC_VERSION", Some(103532), None), /// Allows using imported `main` function (active, imported_main, "1.53.0", Some(28937), None), /// Allows associated types in inherent impls. diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 4518cf30acdd5..0f61fc5166183 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -2767,35 +2767,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let substs = InternalSubsts::for_item(tcx, def_id, |param, _| { if let Some(i) = (param.index as usize).checked_sub(generics.parent_count) { // Our own parameters are the resolved lifetimes. - if let GenericParamDefKind::Lifetime = param.kind { - if let hir::GenericArg::Lifetime(lifetime) = &lifetimes[i] { - self.ast_region_to_region(lifetime, None).into() - } else { - bug!() - } - } else { - bug!() - } + let GenericParamDefKind::Lifetime { .. } = param.kind else { bug!() }; + let hir::GenericArg::Lifetime(lifetime) = &lifetimes[i] else { bug!() }; + self.ast_region_to_region(lifetime, None).into() } else { - match param.kind { - // For RPIT (return position impl trait), only lifetimes - // mentioned in the impl Trait predicate are captured by - // the opaque type, so the lifetime parameters from the - // parent item need to be replaced with `'static`. - // - // For `impl Trait` in the types of statics, constants, - // locals and type aliases. These capture all parent - // lifetimes, so they can use their identity subst. - GenericParamDefKind::Lifetime - if matches!( - origin, - hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) - ) => - { - tcx.lifetimes.re_static.into() - } - _ => tcx.mk_param_from_def(param), - } + tcx.mk_param_from_def(param) } }); debug!("impl_trait_ty_to_ty: substs={:?}", substs); @@ -2972,6 +2948,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { Some(tcx.liberate_late_bound_regions(fn_hir_id.expect_owner().to_def_id(), ty)) } + #[instrument(level = "trace", skip(self, generate_err))] fn validate_late_bound_regions( &self, constrained_regions: FxHashSet, diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 0ba5e61510125..e494aef1a744a 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -10,6 +10,7 @@ use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::Visitor; use rustc_hir::{ItemKind, Node, PathSegment}; +use rustc_infer::infer::opaque_types::ConstrainOpaqueTypeRegionVisitor; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::{DefiningAnchor, RegionVariableOrigin, TyCtxtInferExt}; use rustc_infer::traits::Obligation; @@ -231,7 +232,9 @@ fn check_opaque<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) { let substs = InternalSubsts::identity_for_item(tcx, item.owner_id.to_def_id()); let span = tcx.def_span(item.owner_id.def_id); - check_opaque_for_inheriting_lifetimes(tcx, item.owner_id.def_id, span); + if !tcx.features().impl_trait_projections { + check_opaque_for_inheriting_lifetimes(tcx, item.owner_id.def_id, span); + } if tcx.type_of(item.owner_id.def_id).references_error() { return; } @@ -240,6 +243,7 @@ fn check_opaque<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) { } check_opaque_meets_bounds(tcx, item.owner_id.def_id, substs, span, &origin); } + /// Checks that an opaque type does not use `Self` or `T::Foo` projections that would result /// in "inheriting lifetimes". #[instrument(level = "debug", skip(tcx, span))] @@ -251,39 +255,11 @@ pub(super) fn check_opaque_for_inheriting_lifetimes<'tcx>( let item = tcx.hir().expect_item(def_id); debug!(?item, ?span); - struct FoundParentLifetime; - struct FindParentLifetimeVisitor<'tcx>(&'tcx ty::Generics); - impl<'tcx> ty::visit::TypeVisitor<'tcx> for FindParentLifetimeVisitor<'tcx> { - type BreakTy = FoundParentLifetime; - - fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { - debug!("FindParentLifetimeVisitor: r={:?}", r); - if let ty::ReEarlyBound(ty::EarlyBoundRegion { index, .. }) = *r { - if index < self.0.parent_count as u32 { - return ControlFlow::Break(FoundParentLifetime); - } else { - return ControlFlow::CONTINUE; - } - } - - r.super_visit_with(self) - } - - fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow { - if let ty::ConstKind::Unevaluated(..) = c.kind() { - // FIXME(#72219) We currently don't detect lifetimes within substs - // which would violate this check. Even though the particular substitution is not used - // within the const, this should still be fixed. - return ControlFlow::CONTINUE; - } - c.super_visit_with(self) - } - } - struct ProhibitOpaqueVisitor<'tcx> { tcx: TyCtxt<'tcx>, opaque_identity_ty: Ty<'tcx>, - generics: &'tcx ty::Generics, + parent_count: u32, + references_parent_regions: bool, selftys: Vec<(Span, Option)>, } @@ -291,12 +267,25 @@ pub(super) fn check_opaque_for_inheriting_lifetimes<'tcx>( type BreakTy = Ty<'tcx>; fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { - debug!("check_opaque_for_inheriting_lifetimes: (visit_ty) t={:?}", t); + debug!(?t, "root_visit_ty"); if t == self.opaque_identity_ty { ControlFlow::CONTINUE } else { - t.super_visit_with(&mut FindParentLifetimeVisitor(self.generics)) - .map_break(|FoundParentLifetime| t) + t.visit_with(&mut ConstrainOpaqueTypeRegionVisitor { + tcx: self.tcx, + op: |region| { + if let ty::ReEarlyBound(ty::EarlyBoundRegion { index, .. }) = *region + && index < self.parent_count + { + self.references_parent_regions= true; + } + }, + }); + if self.references_parent_regions { + ControlFlow::Break(t) + } else { + ControlFlow::CONTINUE + } } } } @@ -329,15 +318,20 @@ pub(super) fn check_opaque_for_inheriting_lifetimes<'tcx>( if let ItemKind::OpaqueTy(hir::OpaqueTy { origin: hir::OpaqueTyOrigin::AsyncFn(..) | hir::OpaqueTyOrigin::FnReturn(..), + in_trait, .. }) = item.kind { + let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id()); + let opaque_identity_ty = if in_trait { + tcx.mk_projection(def_id.to_def_id(), substs) + } else { + tcx.mk_opaque(def_id.to_def_id(), substs) + }; let mut visitor = ProhibitOpaqueVisitor { - opaque_identity_ty: tcx.mk_opaque( - def_id.to_def_id(), - InternalSubsts::identity_for_item(tcx, def_id.to_def_id()), - ), - generics: tcx.generics_of(def_id), + opaque_identity_ty, + parent_count: tcx.generics_of(def_id).parent_count as u32, + references_parent_regions: false, tcx, selftys: vec![], }; @@ -345,10 +339,6 @@ pub(super) fn check_opaque_for_inheriting_lifetimes<'tcx>( .explicit_item_bounds(def_id) .iter() .try_for_each(|(predicate, _)| predicate.visit_with(&mut visitor)); - debug!( - "check_opaque_for_inheriting_lifetimes: prohibit_opaque={:?}, visitor.opaque_identity_ty={:?}, visitor.generics={:?}", - prohibit_opaque, visitor.opaque_identity_ty, visitor.generics - ); if let Some(ty) = prohibit_opaque.break_value() { visitor.visit_item(&item); @@ -359,15 +349,16 @@ pub(super) fn check_opaque_for_inheriting_lifetimes<'tcx>( _ => unreachable!(), }; - let mut err = struct_span_err!( - tcx.sess, + let mut err = feature_err( + &tcx.sess.parse_sess, + sym::impl_trait_projections, span, - E0760, - "`{}` return type cannot contain a projection or `Self` that references lifetimes from \ - a parent scope", - if is_async { "async fn" } else { "impl Trait" }, + &format!( + "`{}` return type cannot contain a projection or `Self` that references \ + lifetimes from a parent scope", + if is_async { "async fn" } else { "impl Trait" }, + ), ); - for (span, name) in visitor.selftys { err.span_suggestion( span, diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 837ff0bdf3e35..9cd721fb342de 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1538,7 +1538,6 @@ fn check_fn_or_method<'tcx>( check_return_position_impl_trait_in_trait_bounds( tcx, - wfcx, def_id, sig.output(), hir_decl.output.span(), @@ -1574,9 +1573,9 @@ fn check_fn_or_method<'tcx>( /// Basically `check_associated_type_bounds`, but separated for now and should be /// deduplicated when RPITITs get lowered into real associated items. +#[tracing::instrument(level = "trace", skip(tcx))] fn check_return_position_impl_trait_in_trait_bounds<'tcx>( tcx: TyCtxt<'tcx>, - wfcx: &WfCheckingCtxt<'_, 'tcx>, fn_def_id: LocalDefId, fn_output: Ty<'tcx>, span: Span, @@ -1590,18 +1589,22 @@ fn check_return_position_impl_trait_in_trait_bounds<'tcx>( && tcx.def_kind(proj.item_def_id) == DefKind::ImplTraitPlaceholder && tcx.impl_trait_in_trait_parent(proj.item_def_id) == fn_def_id.to_def_id() { - let bounds = wfcx.tcx().explicit_item_bounds(proj.item_def_id); - let wf_obligations = bounds.iter().flat_map(|&(bound, bound_span)| { - let normalized_bound = wfcx.normalize(span, None, bound); - traits::wf::predicate_obligations( - wfcx.infcx, - wfcx.param_env, - wfcx.body_id, - normalized_bound, - bound_span, - ) + // Create a new context, since we want the opaque's ParamEnv and not the parent's. + let span = tcx.def_span(proj.item_def_id); + enter_wf_checking_ctxt(tcx, span, proj.item_def_id.expect_local(), |wfcx| { + let bounds = wfcx.tcx().explicit_item_bounds(proj.item_def_id); + let wf_obligations = bounds.iter().flat_map(|&(bound, bound_span)| { + let normalized_bound = wfcx.normalize(span, None, bound); + traits::wf::predicate_obligations( + wfcx.infcx, + wfcx.param_env, + wfcx.body_id, + normalized_bound, + bound_span, + ) + }); + wfcx.register_obligations(wf_obligations); }); - wfcx.register_obligations(wf_obligations); } } } diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 5d1ca1cbd2389..808391d12c4b4 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -84,60 +84,30 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP Node::ImplItem(item) => item.generics, - Node::Item(item) => { - match item.kind { - ItemKind::Impl(ref impl_) => { - if impl_.defaultness.is_default() { - is_default_impl_trait = tcx.impl_trait_ref(def_id).map(ty::Binder::dummy); - } - &impl_.generics + Node::Item(item) => match item.kind { + ItemKind::Impl(ref impl_) => { + if impl_.defaultness.is_default() { + is_default_impl_trait = tcx.impl_trait_ref(def_id).map(ty::Binder::dummy); } - ItemKind::Fn(.., ref generics, _) - | ItemKind::TyAlias(_, ref generics) - | ItemKind::Enum(_, ref generics) - | ItemKind::Struct(_, ref generics) - | ItemKind::Union(_, ref generics) => *generics, - - ItemKind::Trait(_, _, ref generics, ..) => { - is_trait = Some(ty::TraitRef::identity(tcx, def_id)); - *generics - } - ItemKind::TraitAlias(ref generics, _) => { - is_trait = Some(ty::TraitRef::identity(tcx, def_id)); - *generics - } - ItemKind::OpaqueTy(OpaqueTy { - origin: hir::OpaqueTyOrigin::AsyncFn(..) | hir::OpaqueTyOrigin::FnReturn(..), - .. - }) => { - // return-position impl trait - // - // We don't inherit predicates from the parent here: - // If we have, say `fn f<'a, T: 'a>() -> impl Sized {}` - // then the return type is `f::<'static, T>::{{opaque}}`. - // - // If we inherited the predicates of `f` then we would - // require that `T: 'static` to show that the return - // type is well-formed. - // - // The only way to have something with this opaque type - // is from the return type of the containing function, - // which will ensure that the function's predicates - // hold. - return ty::GenericPredicates { parent: None, predicates: &[] }; - } - ItemKind::OpaqueTy(OpaqueTy { - ref generics, - origin: hir::OpaqueTyOrigin::TyAlias, - .. - }) => { - // type-alias impl trait - generics - } - - _ => NO_GENERICS, + &impl_.generics } - } + ItemKind::Fn(.., ref generics, _) + | ItemKind::TyAlias(_, ref generics) + | ItemKind::Enum(_, ref generics) + | ItemKind::Struct(_, ref generics) + | ItemKind::Union(_, ref generics) => *generics, + + ItemKind::Trait(_, _, ref generics, ..) => { + is_trait = Some(ty::TraitRef::identity(tcx, def_id)); + *generics + } + ItemKind::TraitAlias(ref generics, _) => { + is_trait = Some(ty::TraitRef::identity(tcx, def_id)); + *generics + } + ItemKind::OpaqueTy(OpaqueTy { ref generics, .. }) => generics, + _ => NO_GENERICS, + }, Node::ForeignItem(item) => match item.kind { ForeignItemKind::Static(..) => NO_GENERICS, @@ -181,6 +151,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP trace!(?predicates); trace!(?ast_generics); + trace!(?generics); // Collect the predicates that were written inline by the user on each // type parameter (e.g., ``). @@ -299,6 +270,54 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP ); } + // Opaque types duplicate some of their generic parameters. + // We create bi-directional Outlives predicates between the original + // and the duplicated parameter, to ensure that they do not get out of sync. + if let Node::Item(&Item { kind: ItemKind::OpaqueTy(..), .. }) = node { + let opaque_ty_id = tcx.hir().get_parent_node(hir_id); + let opaque_ty_node = tcx.hir().get(opaque_ty_id); + let Node::Ty(&Ty { kind: TyKind::OpaqueDef(_, lifetimes, _), .. }) = opaque_ty_node else { + bug!("unexpected {opaque_ty_node:?}") + }; + debug!(?lifetimes); + for (arg, duplicate) in std::iter::zip(lifetimes, ast_generics.params) { + let hir::GenericArg::Lifetime(arg) = arg else { bug!() }; + let orig_region = >::ast_region_to_region(&icx, &arg, None); + if !matches!(orig_region.kind(), ty::ReEarlyBound(..)) { + // Only early-bound regions can point to the original generic parameter. + continue; + } + + let hir::GenericParamKind::Lifetime { .. } = duplicate.kind else { continue }; + let dup_def = tcx.hir().local_def_id(duplicate.hir_id).to_def_id(); + + let Some(dup_index) = generics.param_def_id_to_index(tcx, dup_def) else { bug!() }; + + let dup_region = tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion { + def_id: dup_def, + index: dup_index, + name: duplicate.name.ident().name, + })); + predicates.push(( + ty::Binder::dummy(ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate( + orig_region, + dup_region, + ))) + .to_predicate(icx.tcx), + duplicate.span, + )); + predicates.push(( + ty::Binder::dummy(ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate( + dup_region, + orig_region, + ))) + .to_predicate(icx.tcx), + duplicate.span, + )); + } + debug!(?predicates); + } + ty::GenericPredicates { parent: generics.parent, predicates: tcx.arena.alloc_from_iter(predicates), diff --git a/compiler/rustc_hir_analysis/src/variance/mod.rs b/compiler/rustc_hir_analysis/src/variance/mod.rs index 82103c5a03b6e..b6137f89cadaa 100644 --- a/compiler/rustc_hir_analysis/src/variance/mod.rs +++ b/compiler/rustc_hir_analysis/src/variance/mod.rs @@ -5,9 +5,10 @@ use rustc_arena::DroplessArena; use rustc_hir::def::DefKind; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::ty::query::Providers; -use rustc_middle::ty::{self, CrateVariancesMap, TyCtxt}; +use rustc_middle::ty::{self, CrateVariancesMap, TyCtxt, TypeSuperVisitable, TypeVisitable}; +use std::ops::ControlFlow; /// Defines the `TermsContext` basically houses an arena where we can /// allocate terms. @@ -50,6 +51,9 @@ fn variances_of(tcx: TyCtxt<'_>, item_def_id: DefId) -> &[ty::Variance] { | DefKind::Union | DefKind::Variant | DefKind::Ctor(..) => {} + DefKind::OpaqueTy | DefKind::ImplTraitPlaceholder => { + return variance_of_opaque(tcx, item_def_id.expect_local()); + } _ => { // Variance not relevant. span_bug!(tcx.def_span(item_def_id), "asked to compute variance for wrong kind of item") @@ -61,3 +65,89 @@ fn variances_of(tcx: TyCtxt<'_>, item_def_id: DefId) -> &[ty::Variance] { let crate_map = tcx.crate_variances(()); crate_map.variances.get(&item_def_id).copied().unwrap_or(&[]) } + +#[instrument(level = "trace", skip(tcx), ret)] +fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Variance] { + let generics = tcx.generics_of(item_def_id); + + // Opaque types may only use regions that are bound. So for + // ```rust + // type Foo<'a, 'b, 'c> = impl Trait<'a> + 'b; + // ``` + // we may not use `'c` in the hidden type. + struct OpaqueTypeLifetimeCollector { + variances: Vec, + } + + impl<'tcx> ty::TypeVisitor<'tcx> for OpaqueTypeLifetimeCollector { + #[instrument(level = "trace", skip(self), ret)] + fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { + if let ty::RegionKind::ReEarlyBound(ebr) = r.kind() { + self.variances[ebr.index as usize] = ty::Invariant; + } + r.super_visit_with(self) + } + } + + // By default, RPIT are invariant wrt type and const generics, but they are bivariant wrt + // lifetime generics. + let mut variances: Vec<_> = std::iter::repeat(ty::Invariant).take(generics.count()).collect(); + + // Mark all lifetimes from parent generics as unused (Bivariant). + // This will be overridden later if required. + { + let mut generics = generics; + while let Some(def_id) = generics.parent { + generics = tcx.generics_of(def_id); + for param in &generics.params { + match param.kind { + ty::GenericParamDefKind::Lifetime => { + variances[param.index as usize] = ty::Bivariant; + } + ty::GenericParamDefKind::Type { .. } + | ty::GenericParamDefKind::Const { .. } => {} + } + } + } + } + + let mut collector = OpaqueTypeLifetimeCollector { variances }; + let id_substs = ty::InternalSubsts::identity_for_item(tcx, item_def_id.to_def_id()); + for pred in tcx.bound_explicit_item_bounds(item_def_id.to_def_id()).transpose_iter() { + let pred = pred.map_bound(|(pred, _)| *pred).subst(tcx, id_substs); + debug!(?pred); + + // We only ignore opaque type substs if the opaque type is the outermost type. + // The opaque type may be nested within itself via recursion in e.g. + // type Foo<'a> = impl PartialEq>; + // which thus mentions `'a` and should thus accept hidden types that borrow 'a + // instead of requiring an additional `+ 'a`. + match pred.kind().skip_binder() { + ty::PredicateKind::Trait(ty::TraitPredicate { + trait_ref: ty::TraitRef { def_id: _, substs }, + constness: _, + polarity: _, + }) => { + for subst in &substs[1..] { + subst.visit_with(&mut collector); + } + } + ty::PredicateKind::Projection(ty::ProjectionPredicate { + projection_ty: ty::ProjectionTy { substs, item_def_id: _ }, + term, + }) => { + for subst in &substs[1..] { + subst.visit_with(&mut collector); + } + term.visit_with(&mut collector); + } + ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(_, region)) => { + region.visit_with(&mut collector); + } + _ => { + pred.visit_with(&mut collector); + } + } + } + tcx.arena.alloc_from_iter(collector.variances.into_iter()) +} diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs index a973bf54b055e..45972ada6ee5e 100644 --- a/compiler/rustc_infer/src/infer/combine.rs +++ b/compiler/rustc_infer/src/infer/combine.rs @@ -563,6 +563,7 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> { &opt_variances, a_subst, b_subst, + true, ) } } diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 22f32251f6df0..d773aa5f1fce1 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -261,6 +261,7 @@ fn label_msg_span( } } +#[instrument(level = "trace", skip(tcx))] pub fn unexpected_hidden_region_diagnostic<'tcx>( tcx: TyCtxt<'tcx>, span: Span, diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs index a982f11f7187f..d3e216d693fb2 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -332,32 +332,11 @@ impl<'tcx> InferCtxt<'tcx> { concrete_ty: Ty<'tcx>, span: Span, ) { - let def_id = opaque_type_key.def_id; - - let tcx = self.tcx; - let concrete_ty = self.resolve_vars_if_possible(concrete_ty); - debug!(?concrete_ty); - let first_own_region = match self.opaque_ty_origin_unchecked(def_id, span) { - hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => { - // We lower - // - // fn foo<'l0..'ln>() -> impl Trait<'l0..'lm> - // - // into - // - // type foo::<'p0..'pn>::Foo<'q0..'qm> - // fn foo() -> foo::<'static..'static>::Foo<'l0..'lm>. - // - // For these types we only iterate over `'l0..lm` below. - tcx.generics_of(def_id).parent_count - } - // These opaque type inherit all lifetime parameters from their - // parent, so we have to check them all. - hir::OpaqueTyOrigin::TyAlias => 0, - }; + let variances = self.tcx.variances_of(opaque_type_key.def_id); + debug!(?variances); // For a case like `impl Foo<'a, 'b>`, we would generate a constraint // `'r in ['a, 'b, 'static]` for each region `'r` that appears in the @@ -370,9 +349,12 @@ impl<'tcx> InferCtxt<'tcx> { // type can be equal to any of the region parameters of the // opaque type definition. let choice_regions: Lrc>> = Lrc::new( - opaque_type_key.substs[first_own_region..] + opaque_type_key + .substs .iter() - .filter_map(|arg| match arg.unpack() { + .enumerate() + .filter(|(i, _)| variances[*i] == ty::Variance::Invariant) + .filter_map(|(_, arg)| match arg.unpack() { GenericArgKind::Lifetime(r) => Some(r), GenericArgKind::Type(_) | GenericArgKind::Const(_) => None, }) @@ -381,6 +363,7 @@ impl<'tcx> InferCtxt<'tcx> { ); concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor { + tcx: self.tcx, op: |r| self.member_constraint(opaque_type_key, span, concrete_ty, r, &choice_regions), }); } @@ -440,11 +423,12 @@ impl<'tcx> InferCtxt<'tcx> { // // We ignore any type parameters because impl trait values are assumed to // capture all the in-scope type parameters. -struct ConstrainOpaqueTypeRegionVisitor { - op: OP, +pub struct ConstrainOpaqueTypeRegionVisitor<'tcx, OP: FnMut(ty::Region<'tcx>)> { + pub tcx: TyCtxt<'tcx>, + pub op: OP, } -impl<'tcx, OP> TypeVisitor<'tcx> for ConstrainOpaqueTypeRegionVisitor +impl<'tcx, OP> TypeVisitor<'tcx> for ConstrainOpaqueTypeRegionVisitor<'tcx, OP> where OP: FnMut(ty::Region<'tcx>), { @@ -490,6 +474,31 @@ where substs.as_generator().yield_ty().visit_with(self); substs.as_generator().resume_ty().visit_with(self); } + + ty::Opaque(def_id, ref substs) => { + // Skip lifetime paramters that are not captures. + let variances = self.tcx.variances_of(*def_id); + + for (v, s) in std::iter::zip(variances, substs.iter()) { + if *v != ty::Variance::Bivariant { + s.visit_with(self); + } + } + } + + ty::Projection(proj) + if self.tcx.def_kind(proj.item_def_id) == DefKind::ImplTraitPlaceholder => + { + // Skip lifetime paramters that are not captures. + let variances = self.tcx.variances_of(proj.item_def_id); + + for (v, s) in std::iter::zip(variances, proj.substs.iter()) { + if *v != ty::Variance::Bivariant { + s.visit_with(self); + } + } + } + _ => { ty.super_visit_with(self); } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 6a73e14e9f58b..9b95c4a32d7d2 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -928,6 +928,8 @@ fn should_encode_variances(def_kind: DefKind) -> bool { | DefKind::Union | DefKind::Enum | DefKind::Variant + | DefKind::OpaqueTy + | DefKind::ImplTraitPlaceholder | DefKind::Fn | DefKind::Ctor(..) | DefKind::AssocFn => true, @@ -941,8 +943,6 @@ fn should_encode_variances(def_kind: DefKind) -> bool { | DefKind::Const | DefKind::ForeignMod | DefKind::TyAlias - | DefKind::OpaqueTy - | DefKind::ImplTraitPlaceholder | DefKind::Impl | DefKind::Trait | DefKind::TraitAlias diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 18eb06b83c9df..31bdb049e76a5 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1257,7 +1257,7 @@ impl<'tcx> InstantiatedPredicates<'tcx> { } } -#[derive(Copy, Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable, Lift)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable, TyEncodable, TyDecodable, Lift)] #[derive(TypeFoldable, TypeVisitable)] pub struct OpaqueTypeKey<'tcx> { pub def_id: LocalDefId, @@ -1332,6 +1332,9 @@ impl<'tcx> OpaqueHiddenType<'tcx> { let id_substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id()); debug!(?id_substs); + // This zip may have several times the same lifetime in `substs` paired with a different + // lifetime from `id_substs`. Simply `collect`ing the iterator is the correct behaviour: + // it will pick the last one, which is the one we introduced in the impl-trait desugaring. let map = substs.iter().zip(id_substs); let map: FxHashMap, GenericArg<'tcx>> = match origin { @@ -1345,61 +1348,13 @@ impl<'tcx> OpaqueHiddenType<'tcx> { // type Foo<'a, 'b, 'c> = impl Trait<'a> + 'b; // ``` // we may not use `'c` in the hidden type. - struct OpaqueTypeLifetimeCollector<'tcx> { - lifetimes: FxHashSet>, - } - - impl<'tcx> ty::TypeVisitor<'tcx> for OpaqueTypeLifetimeCollector<'tcx> { - fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { - self.lifetimes.insert(r); - r.super_visit_with(self) - } - } + let variances = tcx.variances_of(def_id); + debug!(?variances); - let mut collector = OpaqueTypeLifetimeCollector { lifetimes: Default::default() }; - - for pred in tcx.bound_explicit_item_bounds(def_id.to_def_id()).transpose_iter() { - let pred = pred.map_bound(|(pred, _)| *pred).subst(tcx, id_substs); - - trace!(pred=?pred.kind()); - - // We only ignore opaque type substs if the opaque type is the outermost type. - // The opaque type may be nested within itself via recursion in e.g. - // type Foo<'a> = impl PartialEq>; - // which thus mentions `'a` and should thus accept hidden types that borrow 'a - // instead of requiring an additional `+ 'a`. - match pred.kind().skip_binder() { - ty::PredicateKind::Trait(TraitPredicate { - trait_ref: ty::TraitRef { def_id: _, substs }, - constness: _, - polarity: _, - }) => { - trace!(?substs); - for subst in &substs[1..] { - subst.visit_with(&mut collector); - } - } - ty::PredicateKind::Projection(ty::ProjectionPredicate { - projection_ty: ty::ProjectionTy { substs, item_def_id: _ }, - term, - }) => { - for subst in &substs[1..] { - subst.visit_with(&mut collector); - } - term.visit_with(&mut collector); - } - _ => { - pred.visit_with(&mut collector); - } - } - } - let lifetimes = collector.lifetimes; - trace!(?lifetimes); map.filter(|(_, v)| { - let ty::GenericArgKind::Lifetime(lt) = v.unpack() else { - return true; - }; - lifetimes.contains(<) + let ty::GenericArgKind::Lifetime(lt) = v.unpack() else { return true }; + let ty::ReEarlyBound(ebr) = lt.kind() else { bug!() }; + variances[ebr.index as usize] == ty::Variance::Invariant }) .collect() } diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index c083a405e3cfb..6d02551716e35 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -60,7 +60,7 @@ pub trait TypeRelation<'tcx>: Sized { let tcx = self.tcx(); let opt_variances = tcx.variances_of(item_def_id); - relate_substs_with_variances(self, item_def_id, opt_variances, a_subst, b_subst) + relate_substs_with_variances(self, item_def_id, opt_variances, a_subst, b_subst, true) } /// Switch variance for the purpose of relating `a` and `b`. @@ -151,13 +151,14 @@ pub fn relate_substs_with_variances<'tcx, R: TypeRelation<'tcx>>( variances: &[ty::Variance], a_subst: SubstsRef<'tcx>, b_subst: SubstsRef<'tcx>, + fetch_ty_for_diag: bool, ) -> RelateResult<'tcx, SubstsRef<'tcx>> { let tcx = relation.tcx(); let mut cached_ty = None; let params = iter::zip(a_subst, b_subst).enumerate().map(|(i, (a, b))| { let variance = variances[i]; - let variance_info = if variance == ty::Invariant { + let variance_info = if variance == ty::Invariant && fetch_ty_for_diag { let ty = *cached_ty.get_or_insert_with(|| tcx.bound_type_of(ty_def_id).subst(tcx, a_subst)); ty::VarianceDiagInfo::Invariant { ty, param_index: i.try_into().unwrap() } @@ -561,7 +562,15 @@ pub fn super_relate_tys<'tcx, R: TypeRelation<'tcx>>( (&ty::Opaque(a_def_id, a_substs), &ty::Opaque(b_def_id, b_substs)) if a_def_id == b_def_id => { - let substs = relate_substs(relation, a_substs, b_substs)?; + let opt_variances = tcx.variances_of(a_def_id); + let substs = relate_substs_with_variances( + relation, + a_def_id, + opt_variances, + a_substs, + b_substs, + false, // do not fetch `type_of(a_def_id)`, as it will cause a cycle + )?; Ok(tcx.mk_opaque(a_def_id, substs)) } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 54a61483a11a3..fd7456e8c9d2a 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -816,6 +816,7 @@ symbols! { impl_macros, impl_trait_in_bindings, impl_trait_in_fn_trait_return, + impl_trait_projections, implied_by, import, import_name_type, diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 99d3bda6ebfff..57fe38724b9a9 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -108,12 +108,7 @@ fn adt_sized_constraint(tcx: TyCtxt<'_>, def_id: DefId) -> &[Ty<'_>] { /// See `ParamEnv` struct definition for details. fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> { - // The param_env of an impl Trait type is its defining function's param_env - if let Some(parent) = ty::is_impl_trait_defn(tcx, def_id) { - return param_env(tcx, parent.to_def_id()); - } // Compute the bounds on Self and the type parameters. - let ty::InstantiatedPredicates { mut predicates, .. } = tcx.predicates_of(def_id).instantiate_identity(tcx); diff --git a/src/test/ui/async-await/feature-self-return-type.rs b/src/test/ui/async-await/feature-self-return-type.rs new file mode 100644 index 0000000000000..41f887430c1cb --- /dev/null +++ b/src/test/ui/async-await/feature-self-return-type.rs @@ -0,0 +1,28 @@ +// edition:2018 +#![feature(impl_trait_projections)] + +// This test checks that we emit the correct borrowck error when `Self` is used as a return type. +// See #61949 for context. + +pub struct Foo<'a> { + pub bar: &'a i32, +} + +impl<'a> Foo<'a> { + pub async fn new(_bar: &'a i32) -> Self { + Foo { + bar: &22 + } + } +} + +pub async fn foo() { + let x = { + let bar = 22; + Foo::new(&bar).await + //~^ ERROR `bar` does not live long enough + }; + drop(x); +} + +fn main() { } diff --git a/src/test/ui/async-await/feature-self-return-type.stderr b/src/test/ui/async-await/feature-self-return-type.stderr new file mode 100644 index 0000000000000..8924683684fb4 --- /dev/null +++ b/src/test/ui/async-await/feature-self-return-type.stderr @@ -0,0 +1,15 @@ +error[E0597]: `bar` does not live long enough + --> $DIR/feature-self-return-type.rs:22:18 + | +LL | let x = { + | - borrow later stored here +LL | let bar = 22; +LL | Foo::new(&bar).await + | ^^^^ borrowed value does not live long enough +LL | +LL | }; + | - `bar` dropped here while still borrowed + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/async-await/in-trait/async-associated-types.rs b/src/test/ui/async-await/in-trait/async-associated-types.rs index a6f928f3b1bac..974f5aaff83c3 100644 --- a/src/test/ui/async-await/in-trait/async-associated-types.rs +++ b/src/test/ui/async-await/in-trait/async-associated-types.rs @@ -1,8 +1,8 @@ -// check-fail -// known-bug: #102682 +// check-pass // edition: 2021 #![feature(async_fn_in_trait)] +#![feature(impl_trait_projections)] #![allow(incomplete_features)] use std::fmt::Debug; diff --git a/src/test/ui/async-await/in-trait/async-associated-types.stderr b/src/test/ui/async-await/in-trait/async-associated-types.stderr deleted file mode 100644 index 0985150eee0de..0000000000000 --- a/src/test/ui/async-await/in-trait/async-associated-types.stderr +++ /dev/null @@ -1,57 +0,0 @@ -error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements - --> $DIR/async-associated-types.rs:19:43 - | -LL | async fn foo(&'a self, key: &'b T) -> (&'a U, &'b T) { - | ^^^^^^^^^^^^^^ - | -note: first, the lifetime cannot outlive the lifetime `'a` as defined here... - --> $DIR/async-associated-types.rs:16:6 - | -LL | impl<'a, 'b, T: Debug + Sized + 'b, U: 'a> MyTrait<'a, 'b, T> for U { - | ^^ -note: ...so that the types are compatible - --> $DIR/async-associated-types.rs:19:43 - | -LL | async fn foo(&'a self, key: &'b T) -> (&'a U, &'b T) { - | ^^^^^^^^^^^^^^ - = note: expected `(&'a U, &'b T)` - found `(&U, &T)` - = note: but, the lifetime must be valid for the static lifetime... -note: ...so that the types are compatible - --> $DIR/async-associated-types.rs:19:43 - | -LL | async fn foo(&'a self, key: &'b T) -> (&'a U, &'b T) { - | ^^^^^^^^^^^^^^ - = note: expected `MyTrait<'static, 'static, T>` - found `MyTrait<'_, '_, T>` - -error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'b` due to conflicting requirements - --> $DIR/async-associated-types.rs:19:43 - | -LL | async fn foo(&'a self, key: &'b T) -> (&'a U, &'b T) { - | ^^^^^^^^^^^^^^ - | -note: first, the lifetime cannot outlive the lifetime `'b` as defined here... - --> $DIR/async-associated-types.rs:16:10 - | -LL | impl<'a, 'b, T: Debug + Sized + 'b, U: 'a> MyTrait<'a, 'b, T> for U { - | ^^ -note: ...so that the types are compatible - --> $DIR/async-associated-types.rs:19:43 - | -LL | async fn foo(&'a self, key: &'b T) -> (&'a U, &'b T) { - | ^^^^^^^^^^^^^^ - = note: expected `(&'a U, &'b T)` - found `(&U, &T)` - = note: but, the lifetime must be valid for the static lifetime... -note: ...so that the types are compatible - --> $DIR/async-associated-types.rs:19:43 - | -LL | async fn foo(&'a self, key: &'b T) -> (&'a U, &'b T) { - | ^^^^^^^^^^^^^^ - = note: expected `MyTrait<'static, 'static, T>` - found `MyTrait<'_, '_, T>` - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/async-await/issue-61949-self-return-type.rs b/src/test/ui/async-await/issue-61949-self-return-type.rs index 43429ba2329f9..d73dbc6e828f3 100644 --- a/src/test/ui/async-await/issue-61949-self-return-type.rs +++ b/src/test/ui/async-await/issue-61949-self-return-type.rs @@ -1,4 +1,5 @@ // edition:2018 +// gate-test-impl_trait_projections // This test checks that `Self` is prohibited as a return type. See #61949 for context. @@ -19,6 +20,7 @@ async fn foo() { let x = { let bar = 22; Foo::new(&bar).await + //~^ ERROR `bar` does not live long enough }; drop(x); } diff --git a/src/test/ui/async-await/issue-61949-self-return-type.stderr b/src/test/ui/async-await/issue-61949-self-return-type.stderr index 52b726e186e3a..638b197bc022d 100644 --- a/src/test/ui/async-await/issue-61949-self-return-type.stderr +++ b/src/test/ui/async-await/issue-61949-self-return-type.stderr @@ -1,9 +1,25 @@ -error[E0760]: `async fn` return type cannot contain a projection or `Self` that references lifetimes from a parent scope - --> $DIR/issue-61949-self-return-type.rs:10:40 +error[E0658]: `async fn` return type cannot contain a projection or `Self` that references lifetimes from a parent scope + --> $DIR/issue-61949-self-return-type.rs:11:40 | LL | pub async fn new(_bar: &'a i32) -> Self { | ^^^^ help: consider spelling out the type instead: `Foo<'a>` + | + = note: see issue #103532 for more information + = help: add `#![feature(impl_trait_projections)]` to the crate attributes to enable + +error[E0597]: `bar` does not live long enough + --> $DIR/issue-61949-self-return-type.rs:22:18 + | +LL | let x = { + | - borrow later stored here +LL | let bar = 22; +LL | Foo::new(&bar).await + | ^^^^ borrowed value does not live long enough +LL | +LL | }; + | - `bar` dropped here while still borrowed -error: aborting due to previous error +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0760`. +Some errors have detailed explanations: E0597, E0658. +For more information about an error, try `rustc --explain E0597`. diff --git a/src/test/ui/async-await/issues/issue-78600.stderr b/src/test/ui/async-await/issues/issue-78600.stderr index 92b66147106e1..37eafa996c535 100644 --- a/src/test/ui/async-await/issues/issue-78600.stderr +++ b/src/test/ui/async-await/issues/issue-78600.stderr @@ -1,11 +1,14 @@ -error[E0760]: `async fn` return type cannot contain a projection or `Self` that references lifetimes from a parent scope +error[E0658]: `async fn` return type cannot contain a projection or `Self` that references lifetimes from a parent scope --> $DIR/issue-78600.rs:6:33 | LL | async fn new(i: &'a i32) -> Result { | ^^^^^^^----^^^^^ | | | help: consider spelling out the type instead: `S<'a>` + | + = note: see issue #103532 for more information + = help: add `#![feature(impl_trait_projections)]` to the crate attributes to enable error: aborting due to previous error -For more information about this error, try `rustc --explain E0760`. +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/impl-trait/bound-normalization-fail.stderr b/src/test/ui/impl-trait/bound-normalization-fail.stderr index bd8d3d3d24ece..a9fa2da569f85 100644 --- a/src/test/ui/impl-trait/bound-normalization-fail.stderr +++ b/src/test/ui/impl-trait/bound-normalization-fail.stderr @@ -19,17 +19,20 @@ help: consider constraining the associated type `::Assoc LL | fn foo_fail>() -> impl FooLike { | ++++++++++++ -error[E0760]: `impl Trait` return type cannot contain a projection or `Self` that references lifetimes from a parent scope +error[E0658]: `impl Trait` return type cannot contain a projection or `Self` that references lifetimes from a parent scope --> $DIR/bound-normalization-fail.rs:41:41 | LL | fn foo2_fail<'a, T: Trait<'a>>() -> impl FooLike { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #103532 for more information + = help: add `#![feature(impl_trait_projections)]` to the crate attributes to enable -error[E0271]: type mismatch resolving ` as FooLike>::Output == >::Assoc` +error[E0271]: type mismatch resolving ` as FooLike>::Output == >::Assoc` --> $DIR/bound-normalization-fail.rs:41:41 | LL | fn foo2_fail<'a, T: Trait<'a>>() -> impl FooLike { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type mismatch resolving ` as FooLike>::Output == >::Assoc` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type mismatch resolving ` as FooLike>::Output == >::Assoc` ... LL | Foo(()) | ------- return type was inferred to be `Foo<()>` here @@ -40,13 +43,13 @@ note: expected this to be `()` LL | type Output = T; | ^ = note: expected unit type `()` - found associated type `>::Assoc` -help: consider constraining the associated type `>::Assoc` to `()` + found associated type `>::Assoc` +help: consider constraining the associated type `>::Assoc` to `()` | LL | fn foo2_fail<'a, T: Trait<'a, Assoc = ()>>() -> impl FooLike { | ++++++++++++ error: aborting due to 3 previous errors -Some errors have detailed explanations: E0271, E0760. +Some errors have detailed explanations: E0271, E0658. For more information about an error, try `rustc --explain E0271`. diff --git a/src/test/ui/impl-trait/feature-self-return-type.rs b/src/test/ui/impl-trait/feature-self-return-type.rs new file mode 100644 index 0000000000000..51877e9cc3c43 --- /dev/null +++ b/src/test/ui/impl-trait/feature-self-return-type.rs @@ -0,0 +1,102 @@ +// edition:2018 +#![feature(impl_trait_projections)] + +// This test checks that we emit the correct borrowck error when `Self` or a projection is used as +// a return type. See #61949 for context. + +mod with_self { + pub struct Foo<'a> { + pub bar: &'a i32, + } + + impl<'a> Foo<'a> { + pub fn new(_bar: &'a i32) -> impl Into { + Foo { + bar: &22 + } + } + } + + fn foo() { + let x = { + let bar = 22; + Foo::new(&bar).into() + //~^ ERROR `bar` does not live long enough + }; + drop(x); + } +} + +struct Foo(T); + +trait FooLike { + type Output; +} + +impl FooLike for Foo { + type Output = T; +} + +mod impl_trait { + use super::*; + + trait Trait { + type Assoc; + + fn make_assoc(self) -> Self::Assoc; + } + + /// `T::Assoc` can't be normalized any further here. + fn foo(x: T) -> impl FooLike { + Foo(x.make_assoc()) + } + + impl<'a> Trait for &'a () { + type Assoc = &'a (); + + fn make_assoc(self) -> &'a () { &() } + } + + fn usage() { + let x = { + let y = (); + foo(&y) + //~^ ERROR `y` does not live long enough + }; + drop(x); + } +} + +// Same with lifetimes in the trait + +mod lifetimes { + use super::*; + + trait Trait<'a> { + type Assoc; + + fn make_assoc(self) -> Self::Assoc; + } + + /// Missing bound constraining `Assoc`, `T::Assoc` can't be normalized further. + fn foo<'a, T: Trait<'a>>(x: T) -> impl FooLike { + Foo(x.make_assoc()) + } + + impl<'a> Trait<'a> for &'a () { + type Assoc = &'a (); + + fn make_assoc(self) -> &'a () { &() } + } + + fn usage() { + let x = { + let y = (); + foo(&y) + //~^ ERROR `y` does not live long enough + }; + drop(x); + } +} + +fn main() { } diff --git a/src/test/ui/impl-trait/feature-self-return-type.stderr b/src/test/ui/impl-trait/feature-self-return-type.stderr new file mode 100644 index 0000000000000..601e53b769459 --- /dev/null +++ b/src/test/ui/impl-trait/feature-self-return-type.stderr @@ -0,0 +1,39 @@ +error[E0597]: `bar` does not live long enough + --> $DIR/feature-self-return-type.rs:23:22 + | +LL | let x = { + | - borrow later stored here +LL | let bar = 22; +LL | Foo::new(&bar).into() + | ^^^^ borrowed value does not live long enough +LL | +LL | }; + | - `bar` dropped here while still borrowed + +error[E0597]: `y` does not live long enough + --> $DIR/feature-self-return-type.rs:63:17 + | +LL | let x = { + | - borrow later stored here +LL | let y = (); +LL | foo(&y) + | ^^ borrowed value does not live long enough +LL | +LL | }; + | - `y` dropped here while still borrowed + +error[E0597]: `y` does not live long enough + --> $DIR/feature-self-return-type.rs:95:17 + | +LL | let x = { + | - borrow later stored here +LL | let y = (); +LL | foo(&y) + | ^^ borrowed value does not live long enough +LL | +LL | }; + | - `y` dropped here while still borrowed + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/impl-trait/impl-fn-predefined-lifetimes.stderr b/src/test/ui/impl-trait/impl-fn-predefined-lifetimes.stderr index 7747319c1539b..c19420bbb0ceb 100644 --- a/src/test/ui/impl-trait/impl-fn-predefined-lifetimes.stderr +++ b/src/test/ui/impl-trait/impl-fn-predefined-lifetimes.stderr @@ -14,10 +14,7 @@ error[E0720]: cannot resolve opaque type --> $DIR/impl-fn-predefined-lifetimes.rs:4:35 | LL | fn a<'a>() -> impl Fn(&'a u8) -> (impl Debug + '_) { - | ^^^^^^^^^^^^^^^ recursive opaque type -... -LL | |x| x - | ----- returning here with type `[closure@$DIR/impl-fn-predefined-lifetimes.rs:7:5: 7:8]` + | ^^^^^^^^^^^^^^^ cannot resolve opaque type error: aborting due to 2 previous errors diff --git a/src/test/ui/nll/ty-outlives/impl-trait-captures.stderr b/src/test/ui/nll/ty-outlives/impl-trait-captures.stderr index 737cb35841cf5..7b9ed171d2dbf 100644 --- a/src/test/ui/nll/ty-outlives/impl-trait-captures.stderr +++ b/src/test/ui/nll/ty-outlives/impl-trait-captures.stderr @@ -1,4 +1,4 @@ -error[E0700]: hidden type for `Opaque(DefId(0:13 ~ impl_trait_captures[1afc]::foo::{opaque#0}), [ReStatic, T, ReEarlyBound(0, 'a)])` captures lifetime that does not appear in bounds +error[E0700]: hidden type for `Opaque(DefId(0:13 ~ impl_trait_captures[1afc]::foo::{opaque#0}), [ReEarlyBound(0, 'a), T, ReEarlyBound(0, 'a)])` captures lifetime that does not appear in bounds --> $DIR/impl-trait-captures.rs:11:5 | LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> { diff --git a/src/test/ui/type-alias-impl-trait/missing_lifetime_bound.rs b/src/test/ui/type-alias-impl-trait/missing_lifetime_bound.rs index 428194058c34d..01d1f5db13265 100644 --- a/src/test/ui/type-alias-impl-trait/missing_lifetime_bound.rs +++ b/src/test/ui/type-alias-impl-trait/missing_lifetime_bound.rs @@ -2,6 +2,6 @@ type Opaque<'a, T> = impl Sized; fn defining<'a, T>(x: &'a i32) -> Opaque { x } -//~^ ERROR: non-defining opaque type use in defining scope +//~^ ERROR: hidden type for `Opaque<'a, T>` captures lifetime that does not appear in bounds fn main() {} diff --git a/src/test/ui/type-alias-impl-trait/missing_lifetime_bound.stderr b/src/test/ui/type-alias-impl-trait/missing_lifetime_bound.stderr index df2b3ed1911ed..65a0af0d22fe8 100644 --- a/src/test/ui/type-alias-impl-trait/missing_lifetime_bound.stderr +++ b/src/test/ui/type-alias-impl-trait/missing_lifetime_bound.stderr @@ -1,8 +1,11 @@ -error: non-defining opaque type use in defining scope +error[E0700]: hidden type for `Opaque<'a, T>` captures lifetime that does not appear in bounds --> $DIR/missing_lifetime_bound.rs:4:47 | LL | fn defining<'a, T>(x: &'a i32) -> Opaque { x } - | ^ lifetime `'a` is part of concrete type but not used in parameter list of the `impl Trait` type alias + | -- ^ + | | + | hidden type `&'a i32` captures the lifetime `'a` as defined here error: aborting due to previous error +For more information about this error, try `rustc --explain E0700`.