Auto merge of #103491 - cjgillot:self-rpit, r=oli-obk

Support using `Self` or projections inside an RPIT/async fn

I reuse the same idea as https://github.com/rust-lang/rust/pull/103449 to use variances to encode whether a lifetime parameter is captured by impl-trait.

The current implementation of async and RPIT replace all lifetimes from the parent generics by `'static`.  This PR changes the scheme
```rust
impl<'a> Foo<'a> {
    fn foo<'b, T>() -> impl Into<Self> + 'b { ... }
}

opaque Foo::<'_a>::foo::<'_b, T>::opaque<'b>: Into<Foo<'_a>> + 'b;
impl<'a> Foo<'a> {
    // OLD
    fn foo<'b, T>() -> Foo::<'static>::foo::<'static, T>::opaque::<'b> { ... }
                             ^^^^^^^ the `Self` becomes `Foo<'static>`

    // NEW
    fn foo<'b, T>() -> Foo::<'a>::foo::<'b, T>::opaque::<'b> { ... }
                             ^^ the `Self` stays `Foo<'a>`
}
```

There is the same issue with projections. In the example, substitute `Self` by `<T as Trait<'b>>::Assoc` in the sugared version, and `Foo<'_a>` by `<T as Trait<'_b>>::Assoc` in the desugared one.

This allows to support `Self` in impl-trait, since we do not replace lifetimes by `'static` any more.  The same trick allows to use projections like `T::Assoc` where `Self` is allowed.  The feature is gated behind a `impl_trait_projections` feature gate.

The implementation relies on 2 tweaking rules for opaques in 2 places:
- we only relate substs that correspond to captured lifetimes during TypeRelation;
- we only list captured lifetimes in choice region computation.

For simplicity, I encoded the "capturedness" of lifetimes as a variance, `Bivariant` vs `Invariant` for unused vs captured lifetimes. The `variances_of` query used to ICE for opaques.

Impl-trait that do not reference `Self` or projections will have their variances as:
- `o` (invariant) for each parent type or const;
- `*` (bivariant) for each parent lifetime --> will not participate in borrowck;
- `o` (invariant) for each own lifetime.

Impl-trait that does reference `Self` and/or projections will have some parent lifetimes marked as `o` (as the example above), and participate in type relation and borrowck.  In the example above, `variances_of(opaque) = ['_a: o, '_b: *, T: o, 'b: o]`.

r? types
cc `@compiler-errors` , as you asked about the issue with `Self` and projections.
This commit is contained in:
bors 2022-11-21 12:17:03 +00:00
commit 7fe6f36224
33 changed files with 570 additions and 341 deletions

View File

@ -60,8 +60,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;
@ -1465,17 +1465,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).

View File

@ -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<NllMemberConstraintIndex>,

View File

@ -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".)
///

View File

@ -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;
@ -61,17 +61,21 @@ impl<'tcx> RegionInferenceContext<'tcx> {
opaque_ty_decls: VecMap<OpaqueTypeKey<'tcx>, (OpaqueHiddenType<'tcx>, OpaqueTyOrigin)>,
) -> VecMap<LocalDefId, OpaqueHiddenType<'tcx>> {
let mut result: VecMap<LocalDefId, OpaqueHiddenType<'tcx>> = 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);
@ -92,10 +96,33 @@ impl<'tcx> RegionInferenceContext<'tcx> {
infcx.tcx.lifetimes.re_static
}
}
});
};
subst_regions.sort();
subst_regions.dedup();
// 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);
// Deduplicate the set of regions while keeping the chosen order.
let subst_regions = subst_regions.into_iter().collect::<FxIndexSet<_>>();
debug!(?subst_regions);
let universal_concrete_type =
infcx.tcx.fold_regions(concrete_type, |region, _| match *region {
@ -106,8 +133,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 };

View File

@ -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> {

View File

@ -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.

View File

@ -2777,35 +2777,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);
@ -2982,6 +2958,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<ty::BoundRegionKind>,

View File

@ -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;
@ -229,7 +230,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;
}
@ -238,6 +241,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))]
@ -249,39 +253,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<Self::BreakTy> {
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<Self::BreakTy> {
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<String>)>,
}
@ -289,12 +265,25 @@ pub(super) fn check_opaque_for_inheriting_lifetimes<'tcx>(
type BreakTy = Ty<'tcx>;
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
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
}
}
}
}
@ -327,15 +316,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![],
};
@ -343,10 +337,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);
@ -357,15 +347,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,

View File

@ -1539,7 +1539,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(),
@ -1575,9 +1574,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,
@ -1591,18 +1590,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);
}
}
}

View File

@ -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., `<T: Foo>`).
@ -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 = <dyn AstConv<'_>>::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),

View File

@ -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<ty::Variance>,
}
impl<'tcx> ty::TypeVisitor<'tcx> for OpaqueTypeLifetimeCollector {
#[instrument(level = "trace", skip(self), ret)]
fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
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<Foo<'a>>;
// 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())
}

View File

@ -564,6 +564,7 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
&opt_variances,
a_subst,
b_subst,
true,
)
}
}

View File

@ -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,

View File

@ -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<l0..'ln>() -> 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<Vec<ty::Region<'tcx>>> = 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: OP,
pub struct ConstrainOpaqueTypeRegionVisitor<'tcx, OP: FnMut(ty::Region<'tcx>)> {
pub tcx: TyCtxt<'tcx>,
pub op: OP,
}
impl<'tcx, OP> TypeVisitor<'tcx> for ConstrainOpaqueTypeRegionVisitor<OP>
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);
}

View File

@ -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

View File

@ -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>, 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<ty::Region<'tcx>>,
}
let variances = tcx.variances_of(def_id);
debug!(?variances);
impl<'tcx> ty::TypeVisitor<'tcx> for OpaqueTypeLifetimeCollector<'tcx> {
fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
self.lifetimes.insert(r);
r.super_visit_with(self)
}
}
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<Foo<'a>>;
// 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(&lt)
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()
}

View File

@ -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))
}

View File

@ -787,6 +787,7 @@ symbols! {
impl_lint_pass,
impl_trait_in_bindings,
impl_trait_in_fn_trait_return,
impl_trait_projections,
implied_by,
import,
import_name_type,

View File

@ -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);

View File

@ -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() { }

View File

@ -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`.

View File

@ -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;

View File

@ -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`.

View File

@ -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);
}

View File

@ -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 <https://github.com/rust-lang/rust/issues/103532> for more information
= help: add `#![feature(impl_trait_projections)]` to the crate attributes to enable
error: aborting due to previous error
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
For more information about this error, try `rustc --explain E0760`.
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0597, E0658.
For more information about an error, try `rustc --explain E0597`.

View File

@ -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<Self, ()> {
| ^^^^^^^----^^^^^
| |
| help: consider spelling out the type instead: `S<'a>`
|
= note: see issue #103532 <https://github.com/rust-lang/rust/issues/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`.

View File

@ -19,17 +19,20 @@ help: consider constraining the associated type `<T as impl_trait::Trait>::Assoc
LL | fn foo_fail<T: Trait<Assoc = ()>>() -> impl FooLike<Output = T::Assoc> {
| ++++++++++++
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<Output = T::Assoc> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #103532 <https://github.com/rust-lang/rust/issues/103532> for more information
= help: add `#![feature(impl_trait_projections)]` to the crate attributes to enable
error[E0271]: type mismatch resolving `<Foo<()> as FooLike>::Output == <T as lifetimes::Trait<'static>>::Assoc`
error[E0271]: type mismatch resolving `<Foo<()> as FooLike>::Output == <T as lifetimes::Trait<'a>>::Assoc`
--> $DIR/bound-normalization-fail.rs:41:41
|
LL | fn foo2_fail<'a, T: Trait<'a>>() -> impl FooLike<Output = T::Assoc> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type mismatch resolving `<Foo<()> as FooLike>::Output == <T as lifetimes::Trait<'static>>::Assoc`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type mismatch resolving `<Foo<()> as FooLike>::Output == <T as lifetimes::Trait<'a>>::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 `<T as lifetimes::Trait<'static>>::Assoc`
help: consider constraining the associated type `<T as lifetimes::Trait<'static>>::Assoc` to `()`
found associated type `<T as lifetimes::Trait<'a>>::Assoc`
help: consider constraining the associated type `<T as lifetimes::Trait<'a>>::Assoc` to `()`
|
LL | fn foo2_fail<'a, T: Trait<'a, Assoc = ()>>() -> impl FooLike<Output = T::Assoc> {
| ++++++++++++
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`.

View File

@ -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<Self> {
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>(T);
trait FooLike {
type Output;
}
impl<T> FooLike for Foo<T> {
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<T: Trait>(x: T) -> impl FooLike<Output = T::Assoc> {
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<Output = T::Assoc> {
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() { }

View File

@ -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`.

View File

@ -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

View File

@ -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> {

View File

@ -2,6 +2,6 @@
type Opaque<'a, T> = impl Sized;
fn defining<'a, T>(x: &'a i32) -> Opaque<T> { 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() {}

View File

@ -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<T> { 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`.