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:
commit
7fe6f36224
33 changed files with 570 additions and 341 deletions
|
@ -60,8 +60,8 @@ use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
|
||||||
use rustc_hir::definitions::DefPathData;
|
use rustc_hir::definitions::DefPathData;
|
||||||
use rustc_hir::{ConstArg, GenericArg, ItemLocalId, ParamName, TraitCandidate};
|
use rustc_hir::{ConstArg, GenericArg, ItemLocalId, ParamName, TraitCandidate};
|
||||||
use rustc_index::vec::{Idx, IndexVec};
|
use rustc_index::vec::{Idx, IndexVec};
|
||||||
|
use rustc_middle::span_bug;
|
||||||
use rustc_middle::ty::{ResolverAstLowering, TyCtxt};
|
use rustc_middle::ty::{ResolverAstLowering, TyCtxt};
|
||||||
use rustc_middle::{bug, span_bug};
|
|
||||||
use rustc_session::parse::feature_err;
|
use rustc_session::parse::feature_err;
|
||||||
use rustc_span::hygiene::MacroKind;
|
use rustc_span::hygiene::MacroKind;
|
||||||
use rustc_span::source_map::DesugaringKind;
|
use rustc_span::source_map::DesugaringKind;
|
||||||
|
@ -1465,17 +1465,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
// frequently opened issues show.
|
// frequently opened issues show.
|
||||||
let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::OpaqueTy, span, None);
|
let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::OpaqueTy, span, None);
|
||||||
|
|
||||||
let opaque_ty_def_id = match origin {
|
let opaque_ty_def_id = self.create_def(
|
||||||
hir::OpaqueTyOrigin::TyAlias => self.create_def(
|
self.current_hir_id_owner.def_id,
|
||||||
self.current_hir_id_owner.def_id,
|
opaque_ty_node_id,
|
||||||
opaque_ty_node_id,
|
DefPathData::ImplTrait,
|
||||||
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"),
|
|
||||||
};
|
|
||||||
debug!(?opaque_ty_def_id);
|
debug!(?opaque_ty_def_id);
|
||||||
|
|
||||||
// Contains the new lifetime definitions created for the TAIT (if any).
|
// Contains the new lifetime definitions created for the TAIT (if any).
|
||||||
|
|
|
@ -11,6 +11,7 @@ use std::ops::Index;
|
||||||
|
|
||||||
/// Compactly stores a set of `R0 member of [R1...Rn]` constraints,
|
/// Compactly stores a set of `R0 member of [R1...Rn]` constraints,
|
||||||
/// indexed by the region `R0`.
|
/// indexed by the region `R0`.
|
||||||
|
#[derive(Debug)]
|
||||||
pub(crate) struct MemberConstraintSet<'tcx, R>
|
pub(crate) struct MemberConstraintSet<'tcx, R>
|
||||||
where
|
where
|
||||||
R: Copy + Eq,
|
R: Copy + Eq,
|
||||||
|
@ -31,6 +32,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents a `R0 member of [R1..Rn]` constraint
|
/// Represents a `R0 member of [R1..Rn]` constraint
|
||||||
|
#[derive(Debug)]
|
||||||
pub(crate) struct NllMemberConstraint<'tcx> {
|
pub(crate) struct NllMemberConstraint<'tcx> {
|
||||||
next_constraint: Option<NllMemberConstraintIndex>,
|
next_constraint: Option<NllMemberConstraintIndex>,
|
||||||
|
|
||||||
|
|
|
@ -128,6 +128,7 @@ pub struct RegionInferenceContext<'tcx> {
|
||||||
/// adds a new lower bound to the SCC it is analyzing: so you wind up
|
/// 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
|
/// with `'R: 'O` where `'R` is the pick-region and `'O` is the
|
||||||
/// minimal viable option.
|
/// minimal viable option.
|
||||||
|
#[derive(Debug)]
|
||||||
pub(crate) struct AppliedMemberConstraint {
|
pub(crate) struct AppliedMemberConstraint {
|
||||||
/// The SCC that was affected. (The "member region".)
|
/// The SCC that was affected. (The "member region".)
|
||||||
///
|
///
|
||||||
|
|
|
@ -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_data_structures::vec_map::VecMap;
|
||||||
use rustc_hir::def_id::LocalDefId;
|
use rustc_hir::def_id::LocalDefId;
|
||||||
use rustc_hir::OpaqueTyOrigin;
|
use rustc_hir::OpaqueTyOrigin;
|
||||||
|
@ -61,17 +61,21 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||||
opaque_ty_decls: VecMap<OpaqueTypeKey<'tcx>, (OpaqueHiddenType<'tcx>, OpaqueTyOrigin)>,
|
opaque_ty_decls: VecMap<OpaqueTypeKey<'tcx>, (OpaqueHiddenType<'tcx>, OpaqueTyOrigin)>,
|
||||||
) -> VecMap<LocalDefId, OpaqueHiddenType<'tcx>> {
|
) -> VecMap<LocalDefId, OpaqueHiddenType<'tcx>> {
|
||||||
let mut result: VecMap<LocalDefId, OpaqueHiddenType<'tcx>> = VecMap::new();
|
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 {
|
for (opaque_type_key, (concrete_type, origin)) in opaque_ty_decls {
|
||||||
let substs = opaque_type_key.substs;
|
let substs = opaque_type_key.substs;
|
||||||
debug!(?concrete_type, ?substs);
|
debug!(?concrete_type, ?substs);
|
||||||
|
|
||||||
let mut subst_regions = vec![self.universal_regions.fr_static];
|
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() {
|
let to_universal_region = |vid, subst_regions: &mut Vec<_>| {
|
||||||
// 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);
|
|
||||||
trace!(?vid);
|
trace!(?vid);
|
||||||
let scc = self.constraint_sccs.scc(vid);
|
let scc = self.constraint_sccs.scc(vid);
|
||||||
trace!(?scc);
|
trace!(?scc);
|
||||||
|
@ -92,10 +96,33 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||||
infcx.tcx.lifetimes.re_static
|
infcx.tcx.lifetimes.re_static
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
subst_regions.sort();
|
// Start by inserting universal regions from the member_constraint choice regions.
|
||||||
subst_regions.dedup();
|
// 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 =
|
let universal_concrete_type =
|
||||||
infcx.tcx.fold_regions(concrete_type, |region, _| match *region {
|
infcx.tcx.fold_regions(concrete_type, |region, _| match *region {
|
||||||
|
@ -106,8 +133,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||||
.unwrap_or(infcx.tcx.lifetimes.re_erased),
|
.unwrap_or(infcx.tcx.lifetimes.re_erased),
|
||||||
_ => region,
|
_ => region,
|
||||||
});
|
});
|
||||||
|
debug!(?universal_concrete_type);
|
||||||
debug!(?universal_concrete_type, ?universal_substs);
|
|
||||||
|
|
||||||
let opaque_type_key =
|
let opaque_type_key =
|
||||||
OpaqueTypeKey { def_id: opaque_type_key.def_id, substs: universal_substs };
|
OpaqueTypeKey { def_id: opaque_type_key.def_id, substs: universal_substs };
|
||||||
|
|
|
@ -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
|
`async fn`/`impl trait` return type cannot contain a projection
|
||||||
or `Self` that references lifetimes from a parent scope.
|
or `Self` that references lifetimes from a parent scope.
|
||||||
|
|
||||||
Erroneous code example:
|
Erroneous code example:
|
||||||
|
|
||||||
```compile_fail,E0760,edition2018
|
```compile_fail,edition2018
|
||||||
struct S<'a>(&'a i32);
|
struct S<'a>(&'a i32);
|
||||||
|
|
||||||
impl<'a> S<'a> {
|
impl<'a> S<'a> {
|
||||||
|
|
|
@ -419,6 +419,8 @@ declare_features! (
|
||||||
(active, if_let_guard, "1.47.0", Some(51114), None),
|
(active, if_let_guard, "1.47.0", Some(51114), None),
|
||||||
/// Allows `impl Trait` as output type in `Fn` traits in return position of functions.
|
/// 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),
|
(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
|
/// Allows using imported `main` function
|
||||||
(active, imported_main, "1.53.0", Some(28937), None),
|
(active, imported_main, "1.53.0", Some(28937), None),
|
||||||
/// Allows associated types in inherent impls.
|
/// Allows associated types in inherent impls.
|
||||||
|
|
|
@ -2777,35 +2777,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||||
let substs = InternalSubsts::for_item(tcx, def_id, |param, _| {
|
let substs = InternalSubsts::for_item(tcx, def_id, |param, _| {
|
||||||
if let Some(i) = (param.index as usize).checked_sub(generics.parent_count) {
|
if let Some(i) = (param.index as usize).checked_sub(generics.parent_count) {
|
||||||
// Our own parameters are the resolved lifetimes.
|
// Our own parameters are the resolved lifetimes.
|
||||||
if let GenericParamDefKind::Lifetime = param.kind {
|
let GenericParamDefKind::Lifetime { .. } = param.kind else { bug!() };
|
||||||
if let hir::GenericArg::Lifetime(lifetime) = &lifetimes[i] {
|
let hir::GenericArg::Lifetime(lifetime) = &lifetimes[i] else { bug!() };
|
||||||
self.ast_region_to_region(lifetime, None).into()
|
self.ast_region_to_region(lifetime, None).into()
|
||||||
} else {
|
|
||||||
bug!()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
bug!()
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
match param.kind {
|
tcx.mk_param_from_def(param)
|
||||||
// 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),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
debug!("impl_trait_ty_to_ty: substs={:?}", substs);
|
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))
|
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(
|
fn validate_late_bound_regions(
|
||||||
&self,
|
&self,
|
||||||
constrained_regions: FxHashSet<ty::BoundRegionKind>,
|
constrained_regions: FxHashSet<ty::BoundRegionKind>,
|
||||||
|
|
|
@ -10,6 +10,7 @@ use rustc_hir::def::{CtorKind, DefKind, Res};
|
||||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||||
use rustc_hir::intravisit::Visitor;
|
use rustc_hir::intravisit::Visitor;
|
||||||
use rustc_hir::{ItemKind, Node, PathSegment};
|
use rustc_hir::{ItemKind, Node, PathSegment};
|
||||||
|
use rustc_infer::infer::opaque_types::ConstrainOpaqueTypeRegionVisitor;
|
||||||
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
|
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
|
||||||
use rustc_infer::infer::{DefiningAnchor, RegionVariableOrigin, TyCtxtInferExt};
|
use rustc_infer::infer::{DefiningAnchor, RegionVariableOrigin, TyCtxtInferExt};
|
||||||
use rustc_infer::traits::Obligation;
|
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 substs = InternalSubsts::identity_for_item(tcx, item.owner_id.to_def_id());
|
||||||
let span = tcx.def_span(item.owner_id.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() {
|
if tcx.type_of(item.owner_id.def_id).references_error() {
|
||||||
return;
|
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);
|
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
|
/// Checks that an opaque type does not use `Self` or `T::Foo` projections that would result
|
||||||
/// in "inheriting lifetimes".
|
/// in "inheriting lifetimes".
|
||||||
#[instrument(level = "debug", skip(tcx, span))]
|
#[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);
|
let item = tcx.hir().expect_item(def_id);
|
||||||
debug!(?item, ?span);
|
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> {
|
struct ProhibitOpaqueVisitor<'tcx> {
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
opaque_identity_ty: Ty<'tcx>,
|
opaque_identity_ty: Ty<'tcx>,
|
||||||
generics: &'tcx ty::Generics,
|
parent_count: u32,
|
||||||
|
references_parent_regions: bool,
|
||||||
selftys: Vec<(Span, Option<String>)>,
|
selftys: Vec<(Span, Option<String>)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -289,12 +265,25 @@ pub(super) fn check_opaque_for_inheriting_lifetimes<'tcx>(
|
||||||
type BreakTy = Ty<'tcx>;
|
type BreakTy = Ty<'tcx>;
|
||||||
|
|
||||||
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
|
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 {
|
if t == self.opaque_identity_ty {
|
||||||
ControlFlow::CONTINUE
|
ControlFlow::CONTINUE
|
||||||
} else {
|
} else {
|
||||||
t.super_visit_with(&mut FindParentLifetimeVisitor(self.generics))
|
t.visit_with(&mut ConstrainOpaqueTypeRegionVisitor {
|
||||||
.map_break(|FoundParentLifetime| t)
|
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 {
|
if let ItemKind::OpaqueTy(hir::OpaqueTy {
|
||||||
origin: hir::OpaqueTyOrigin::AsyncFn(..) | hir::OpaqueTyOrigin::FnReturn(..),
|
origin: hir::OpaqueTyOrigin::AsyncFn(..) | hir::OpaqueTyOrigin::FnReturn(..),
|
||||||
|
in_trait,
|
||||||
..
|
..
|
||||||
}) = item.kind
|
}) = 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 {
|
let mut visitor = ProhibitOpaqueVisitor {
|
||||||
opaque_identity_ty: tcx.mk_opaque(
|
opaque_identity_ty,
|
||||||
def_id.to_def_id(),
|
parent_count: tcx.generics_of(def_id).parent_count as u32,
|
||||||
InternalSubsts::identity_for_item(tcx, def_id.to_def_id()),
|
references_parent_regions: false,
|
||||||
),
|
|
||||||
generics: tcx.generics_of(def_id),
|
|
||||||
tcx,
|
tcx,
|
||||||
selftys: vec![],
|
selftys: vec![],
|
||||||
};
|
};
|
||||||
|
@ -343,10 +337,6 @@ pub(super) fn check_opaque_for_inheriting_lifetimes<'tcx>(
|
||||||
.explicit_item_bounds(def_id)
|
.explicit_item_bounds(def_id)
|
||||||
.iter()
|
.iter()
|
||||||
.try_for_each(|(predicate, _)| predicate.visit_with(&mut visitor));
|
.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() {
|
if let Some(ty) = prohibit_opaque.break_value() {
|
||||||
visitor.visit_item(&item);
|
visitor.visit_item(&item);
|
||||||
|
@ -357,15 +347,16 @@ pub(super) fn check_opaque_for_inheriting_lifetimes<'tcx>(
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut err = struct_span_err!(
|
let mut err = feature_err(
|
||||||
tcx.sess,
|
&tcx.sess.parse_sess,
|
||||||
|
sym::impl_trait_projections,
|
||||||
span,
|
span,
|
||||||
E0760,
|
&format!(
|
||||||
"`{}` return type cannot contain a projection or `Self` that references lifetimes from \
|
"`{}` return type cannot contain a projection or `Self` that references \
|
||||||
a parent scope",
|
lifetimes from a parent scope",
|
||||||
if is_async { "async fn" } else { "impl Trait" },
|
if is_async { "async fn" } else { "impl Trait" },
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
for (span, name) in visitor.selftys {
|
for (span, name) in visitor.selftys {
|
||||||
err.span_suggestion(
|
err.span_suggestion(
|
||||||
span,
|
span,
|
||||||
|
|
|
@ -1539,7 +1539,6 @@ fn check_fn_or_method<'tcx>(
|
||||||
|
|
||||||
check_return_position_impl_trait_in_trait_bounds(
|
check_return_position_impl_trait_in_trait_bounds(
|
||||||
tcx,
|
tcx,
|
||||||
wfcx,
|
|
||||||
def_id,
|
def_id,
|
||||||
sig.output(),
|
sig.output(),
|
||||||
hir_decl.output.span(),
|
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
|
/// Basically `check_associated_type_bounds`, but separated for now and should be
|
||||||
/// deduplicated when RPITITs get lowered into real associated items.
|
/// 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>(
|
fn check_return_position_impl_trait_in_trait_bounds<'tcx>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
wfcx: &WfCheckingCtxt<'_, 'tcx>,
|
|
||||||
fn_def_id: LocalDefId,
|
fn_def_id: LocalDefId,
|
||||||
fn_output: Ty<'tcx>,
|
fn_output: Ty<'tcx>,
|
||||||
span: Span,
|
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.def_kind(proj.item_def_id) == DefKind::ImplTraitPlaceholder
|
||||||
&& tcx.impl_trait_in_trait_parent(proj.item_def_id) == fn_def_id.to_def_id()
|
&& 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);
|
// Create a new context, since we want the opaque's ParamEnv and not the parent's.
|
||||||
let wf_obligations = bounds.iter().flat_map(|&(bound, bound_span)| {
|
let span = tcx.def_span(proj.item_def_id);
|
||||||
let normalized_bound = wfcx.normalize(span, None, bound);
|
enter_wf_checking_ctxt(tcx, span, proj.item_def_id.expect_local(), |wfcx| {
|
||||||
traits::wf::predicate_obligations(
|
let bounds = wfcx.tcx().explicit_item_bounds(proj.item_def_id);
|
||||||
wfcx.infcx,
|
let wf_obligations = bounds.iter().flat_map(|&(bound, bound_span)| {
|
||||||
wfcx.param_env,
|
let normalized_bound = wfcx.normalize(span, None, bound);
|
||||||
wfcx.body_id,
|
traits::wf::predicate_obligations(
|
||||||
normalized_bound,
|
wfcx.infcx,
|
||||||
bound_span,
|
wfcx.param_env,
|
||||||
)
|
wfcx.body_id,
|
||||||
|
normalized_bound,
|
||||||
|
bound_span,
|
||||||
|
)
|
||||||
|
});
|
||||||
|
wfcx.register_obligations(wf_obligations);
|
||||||
});
|
});
|
||||||
wfcx.register_obligations(wf_obligations);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,60 +84,30 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
|
||||||
|
|
||||||
Node::ImplItem(item) => item.generics,
|
Node::ImplItem(item) => item.generics,
|
||||||
|
|
||||||
Node::Item(item) => {
|
Node::Item(item) => match item.kind {
|
||||||
match item.kind {
|
ItemKind::Impl(ref impl_) => {
|
||||||
ItemKind::Impl(ref impl_) => {
|
if impl_.defaultness.is_default() {
|
||||||
if impl_.defaultness.is_default() {
|
is_default_impl_trait = tcx.impl_trait_ref(def_id).map(ty::Binder::dummy);
|
||||||
is_default_impl_trait = tcx.impl_trait_ref(def_id).map(ty::Binder::dummy);
|
|
||||||
}
|
|
||||||
&impl_.generics
|
|
||||||
}
|
}
|
||||||
ItemKind::Fn(.., ref generics, _)
|
&impl_.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,
|
|
||||||
}
|
}
|
||||||
}
|
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 {
|
Node::ForeignItem(item) => match item.kind {
|
||||||
ForeignItemKind::Static(..) => NO_GENERICS,
|
ForeignItemKind::Static(..) => NO_GENERICS,
|
||||||
|
@ -181,6 +151,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
|
||||||
|
|
||||||
trace!(?predicates);
|
trace!(?predicates);
|
||||||
trace!(?ast_generics);
|
trace!(?ast_generics);
|
||||||
|
trace!(?generics);
|
||||||
|
|
||||||
// Collect the predicates that were written inline by the user on each
|
// Collect the predicates that were written inline by the user on each
|
||||||
// type parameter (e.g., `<T: Foo>`).
|
// 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 {
|
ty::GenericPredicates {
|
||||||
parent: generics.parent,
|
parent: generics.parent,
|
||||||
predicates: tcx.arena.alloc_from_iter(predicates),
|
predicates: tcx.arena.alloc_from_iter(predicates),
|
||||||
|
|
|
@ -5,9 +5,10 @@
|
||||||
|
|
||||||
use rustc_arena::DroplessArena;
|
use rustc_arena::DroplessArena;
|
||||||
use rustc_hir::def::DefKind;
|
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::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
|
/// Defines the `TermsContext` basically houses an arena where we can
|
||||||
/// allocate terms.
|
/// allocate terms.
|
||||||
|
@ -50,6 +51,9 @@ fn variances_of(tcx: TyCtxt<'_>, item_def_id: DefId) -> &[ty::Variance] {
|
||||||
| DefKind::Union
|
| DefKind::Union
|
||||||
| DefKind::Variant
|
| DefKind::Variant
|
||||||
| DefKind::Ctor(..) => {}
|
| DefKind::Ctor(..) => {}
|
||||||
|
DefKind::OpaqueTy | DefKind::ImplTraitPlaceholder => {
|
||||||
|
return variance_of_opaque(tcx, item_def_id.expect_local());
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
// Variance not relevant.
|
// Variance not relevant.
|
||||||
span_bug!(tcx.def_span(item_def_id), "asked to compute variance for wrong kind of item")
|
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(());
|
let crate_map = tcx.crate_variances(());
|
||||||
crate_map.variances.get(&item_def_id).copied().unwrap_or(&[])
|
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())
|
||||||
|
}
|
||||||
|
|
|
@ -564,6 +564,7 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
|
||||||
&opt_variances,
|
&opt_variances,
|
||||||
a_subst,
|
a_subst,
|
||||||
b_subst,
|
b_subst,
|
||||||
|
true,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -261,6 +261,7 @@ fn label_msg_span(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument(level = "trace", skip(tcx))]
|
||||||
pub fn unexpected_hidden_region_diagnostic<'tcx>(
|
pub fn unexpected_hidden_region_diagnostic<'tcx>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
span: Span,
|
span: Span,
|
||||||
|
|
|
@ -332,32 +332,11 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||||
concrete_ty: Ty<'tcx>,
|
concrete_ty: Ty<'tcx>,
|
||||||
span: Span,
|
span: Span,
|
||||||
) {
|
) {
|
||||||
let def_id = opaque_type_key.def_id;
|
|
||||||
|
|
||||||
let tcx = self.tcx;
|
|
||||||
|
|
||||||
let concrete_ty = self.resolve_vars_if_possible(concrete_ty);
|
let concrete_ty = self.resolve_vars_if_possible(concrete_ty);
|
||||||
|
|
||||||
debug!(?concrete_ty);
|
debug!(?concrete_ty);
|
||||||
|
|
||||||
let first_own_region = match self.opaque_ty_origin_unchecked(def_id, span) {
|
let variances = self.tcx.variances_of(opaque_type_key.def_id);
|
||||||
hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => {
|
debug!(?variances);
|
||||||
// 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,
|
|
||||||
};
|
|
||||||
|
|
||||||
// For a case like `impl Foo<'a, 'b>`, we would generate a constraint
|
// 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
|
// `'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
|
// type can be equal to any of the region parameters of the
|
||||||
// opaque type definition.
|
// opaque type definition.
|
||||||
let choice_regions: Lrc<Vec<ty::Region<'tcx>>> = Lrc::new(
|
let choice_regions: Lrc<Vec<ty::Region<'tcx>>> = Lrc::new(
|
||||||
opaque_type_key.substs[first_own_region..]
|
opaque_type_key
|
||||||
|
.substs
|
||||||
.iter()
|
.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::Lifetime(r) => Some(r),
|
||||||
GenericArgKind::Type(_) | GenericArgKind::Const(_) => None,
|
GenericArgKind::Type(_) | GenericArgKind::Const(_) => None,
|
||||||
})
|
})
|
||||||
|
@ -381,6 +363,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||||
);
|
);
|
||||||
|
|
||||||
concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor {
|
concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor {
|
||||||
|
tcx: self.tcx,
|
||||||
op: |r| self.member_constraint(opaque_type_key, span, concrete_ty, r, &choice_regions),
|
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
|
// We ignore any type parameters because impl trait values are assumed to
|
||||||
// capture all the in-scope type parameters.
|
// capture all the in-scope type parameters.
|
||||||
struct ConstrainOpaqueTypeRegionVisitor<OP> {
|
pub struct ConstrainOpaqueTypeRegionVisitor<'tcx, OP: FnMut(ty::Region<'tcx>)> {
|
||||||
op: OP,
|
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
|
where
|
||||||
OP: FnMut(ty::Region<'tcx>),
|
OP: FnMut(ty::Region<'tcx>),
|
||||||
{
|
{
|
||||||
|
@ -490,6 +474,31 @@ where
|
||||||
substs.as_generator().yield_ty().visit_with(self);
|
substs.as_generator().yield_ty().visit_with(self);
|
||||||
substs.as_generator().resume_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);
|
ty.super_visit_with(self);
|
||||||
}
|
}
|
||||||
|
|
|
@ -928,6 +928,8 @@ fn should_encode_variances(def_kind: DefKind) -> bool {
|
||||||
| DefKind::Union
|
| DefKind::Union
|
||||||
| DefKind::Enum
|
| DefKind::Enum
|
||||||
| DefKind::Variant
|
| DefKind::Variant
|
||||||
|
| DefKind::OpaqueTy
|
||||||
|
| DefKind::ImplTraitPlaceholder
|
||||||
| DefKind::Fn
|
| DefKind::Fn
|
||||||
| DefKind::Ctor(..)
|
| DefKind::Ctor(..)
|
||||||
| DefKind::AssocFn => true,
|
| DefKind::AssocFn => true,
|
||||||
|
@ -941,8 +943,6 @@ fn should_encode_variances(def_kind: DefKind) -> bool {
|
||||||
| DefKind::Const
|
| DefKind::Const
|
||||||
| DefKind::ForeignMod
|
| DefKind::ForeignMod
|
||||||
| DefKind::TyAlias
|
| DefKind::TyAlias
|
||||||
| DefKind::OpaqueTy
|
|
||||||
| DefKind::ImplTraitPlaceholder
|
|
||||||
| DefKind::Impl
|
| DefKind::Impl
|
||||||
| DefKind::Trait
|
| DefKind::Trait
|
||||||
| DefKind::TraitAlias
|
| DefKind::TraitAlias
|
||||||
|
|
|
@ -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)]
|
#[derive(TypeFoldable, TypeVisitable)]
|
||||||
pub struct OpaqueTypeKey<'tcx> {
|
pub struct OpaqueTypeKey<'tcx> {
|
||||||
pub def_id: LocalDefId,
|
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());
|
let id_substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
|
||||||
debug!(?id_substs);
|
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 = substs.iter().zip(id_substs);
|
||||||
|
|
||||||
let map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>> = match origin {
|
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;
|
// type Foo<'a, 'b, 'c> = impl Trait<'a> + 'b;
|
||||||
// ```
|
// ```
|
||||||
// we may not use `'c` in the hidden type.
|
// we may not use `'c` in the hidden type.
|
||||||
struct OpaqueTypeLifetimeCollector<'tcx> {
|
let variances = tcx.variances_of(def_id);
|
||||||
lifetimes: FxHashSet<ty::Region<'tcx>>,
|
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)| {
|
map.filter(|(_, v)| {
|
||||||
let ty::GenericArgKind::Lifetime(lt) = v.unpack() else {
|
let ty::GenericArgKind::Lifetime(lt) = v.unpack() else { return true };
|
||||||
return true;
|
let ty::ReEarlyBound(ebr) = lt.kind() else { bug!() };
|
||||||
};
|
variances[ebr.index as usize] == ty::Variance::Invariant
|
||||||
lifetimes.contains(<)
|
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,7 +60,7 @@ pub trait TypeRelation<'tcx>: Sized {
|
||||||
|
|
||||||
let tcx = self.tcx();
|
let tcx = self.tcx();
|
||||||
let opt_variances = tcx.variances_of(item_def_id);
|
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`.
|
/// 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],
|
variances: &[ty::Variance],
|
||||||
a_subst: SubstsRef<'tcx>,
|
a_subst: SubstsRef<'tcx>,
|
||||||
b_subst: SubstsRef<'tcx>,
|
b_subst: SubstsRef<'tcx>,
|
||||||
|
fetch_ty_for_diag: bool,
|
||||||
) -> RelateResult<'tcx, SubstsRef<'tcx>> {
|
) -> RelateResult<'tcx, SubstsRef<'tcx>> {
|
||||||
let tcx = relation.tcx();
|
let tcx = relation.tcx();
|
||||||
|
|
||||||
let mut cached_ty = None;
|
let mut cached_ty = None;
|
||||||
let params = iter::zip(a_subst, b_subst).enumerate().map(|(i, (a, b))| {
|
let params = iter::zip(a_subst, b_subst).enumerate().map(|(i, (a, b))| {
|
||||||
let variance = variances[i];
|
let variance = variances[i];
|
||||||
let variance_info = if variance == ty::Invariant {
|
let variance_info = if variance == ty::Invariant && fetch_ty_for_diag {
|
||||||
let ty =
|
let ty =
|
||||||
*cached_ty.get_or_insert_with(|| tcx.bound_type_of(ty_def_id).subst(tcx, a_subst));
|
*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() }
|
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))
|
(&ty::Opaque(a_def_id, a_substs), &ty::Opaque(b_def_id, b_substs))
|
||||||
if a_def_id == b_def_id =>
|
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))
|
Ok(tcx.mk_opaque(a_def_id, substs))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -787,6 +787,7 @@ symbols! {
|
||||||
impl_lint_pass,
|
impl_lint_pass,
|
||||||
impl_trait_in_bindings,
|
impl_trait_in_bindings,
|
||||||
impl_trait_in_fn_trait_return,
|
impl_trait_in_fn_trait_return,
|
||||||
|
impl_trait_projections,
|
||||||
implied_by,
|
implied_by,
|
||||||
import,
|
import,
|
||||||
import_name_type,
|
import_name_type,
|
||||||
|
|
|
@ -108,12 +108,7 @@ fn adt_sized_constraint(tcx: TyCtxt<'_>, def_id: DefId) -> &[Ty<'_>] {
|
||||||
|
|
||||||
/// See `ParamEnv` struct definition for details.
|
/// See `ParamEnv` struct definition for details.
|
||||||
fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> {
|
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.
|
// Compute the bounds on Self and the type parameters.
|
||||||
|
|
||||||
let ty::InstantiatedPredicates { mut predicates, .. } =
|
let ty::InstantiatedPredicates { mut predicates, .. } =
|
||||||
tcx.predicates_of(def_id).instantiate_identity(tcx);
|
tcx.predicates_of(def_id).instantiate_identity(tcx);
|
||||||
|
|
||||||
|
|
28
src/test/ui/async-await/feature-self-return-type.rs
Normal file
28
src/test/ui/async-await/feature-self-return-type.rs
Normal 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() { }
|
15
src/test/ui/async-await/feature-self-return-type.stderr
Normal file
15
src/test/ui/async-await/feature-self-return-type.stderr
Normal 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`.
|
|
@ -1,8 +1,8 @@
|
||||||
// check-fail
|
// check-pass
|
||||||
// known-bug: #102682
|
|
||||||
// edition: 2021
|
// edition: 2021
|
||||||
|
|
||||||
#![feature(async_fn_in_trait)]
|
#![feature(async_fn_in_trait)]
|
||||||
|
#![feature(impl_trait_projections)]
|
||||||
#![allow(incomplete_features)]
|
#![allow(incomplete_features)]
|
||||||
|
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
|
@ -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`.
|
|
|
@ -1,4 +1,5 @@
|
||||||
// edition:2018
|
// edition:2018
|
||||||
|
// gate-test-impl_trait_projections
|
||||||
|
|
||||||
// This test checks that `Self` is prohibited as a return type. See #61949 for context.
|
// 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 x = {
|
||||||
let bar = 22;
|
let bar = 22;
|
||||||
Foo::new(&bar).await
|
Foo::new(&bar).await
|
||||||
|
//~^ ERROR `bar` does not live long enough
|
||||||
};
|
};
|
||||||
drop(x);
|
drop(x);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,25 @@
|
||||||
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-61949-self-return-type.rs:10:40
|
--> $DIR/issue-61949-self-return-type.rs:11:40
|
||||||
|
|
|
|
||||||
LL | pub async fn new(_bar: &'a i32) -> Self {
|
LL | pub async fn new(_bar: &'a i32) -> Self {
|
||||||
| ^^^^ help: consider spelling out the type instead: `Foo<'a>`
|
| ^^^^ 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`.
|
||||||
|
|
|
@ -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
|
--> $DIR/issue-78600.rs:6:33
|
||||||
|
|
|
|
||||||
LL | async fn new(i: &'a i32) -> Result<Self, ()> {
|
LL | async fn new(i: &'a i32) -> Result<Self, ()> {
|
||||||
| ^^^^^^^----^^^^^
|
| ^^^^^^^----^^^^^
|
||||||
| |
|
| |
|
||||||
| help: consider spelling out the type instead: `S<'a>`
|
| 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
|
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`.
|
||||||
|
|
|
@ -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> {
|
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
|
--> $DIR/bound-normalization-fail.rs:41:41
|
||||||
|
|
|
|
||||||
LL | fn foo2_fail<'a, T: Trait<'a>>() -> impl FooLike<Output = T::Assoc> {
|
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
|
--> $DIR/bound-normalization-fail.rs:41:41
|
||||||
|
|
|
|
||||||
LL | fn foo2_fail<'a, T: Trait<'a>>() -> impl FooLike<Output = T::Assoc> {
|
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(())
|
LL | Foo(())
|
||||||
| ------- return type was inferred to be `Foo<()>` here
|
| ------- return type was inferred to be `Foo<()>` here
|
||||||
|
@ -40,13 +43,13 @@ note: expected this to be `()`
|
||||||
LL | type Output = T;
|
LL | type Output = T;
|
||||||
| ^
|
| ^
|
||||||
= note: expected unit type `()`
|
= note: expected unit type `()`
|
||||||
found associated type `<T as lifetimes::Trait<'static>>::Assoc`
|
found associated type `<T as lifetimes::Trait<'a>>::Assoc`
|
||||||
help: consider constraining the associated type `<T as lifetimes::Trait<'static>>::Assoc` to `()`
|
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> {
|
LL | fn foo2_fail<'a, T: Trait<'a, Assoc = ()>>() -> impl FooLike<Output = T::Assoc> {
|
||||||
| ++++++++++++
|
| ++++++++++++
|
||||||
|
|
||||||
error: aborting due to 3 previous errors
|
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`.
|
For more information about an error, try `rustc --explain E0271`.
|
||||||
|
|
102
src/test/ui/impl-trait/feature-self-return-type.rs
Normal file
102
src/test/ui/impl-trait/feature-self-return-type.rs
Normal 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() { }
|
39
src/test/ui/impl-trait/feature-self-return-type.stderr
Normal file
39
src/test/ui/impl-trait/feature-self-return-type.stderr
Normal 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`.
|
|
@ -14,10 +14,7 @@ error[E0720]: cannot resolve opaque type
|
||||||
--> $DIR/impl-fn-predefined-lifetimes.rs:4:35
|
--> $DIR/impl-fn-predefined-lifetimes.rs:4:35
|
||||||
|
|
|
|
||||||
LL | fn a<'a>() -> impl Fn(&'a u8) -> (impl Debug + '_) {
|
LL | fn a<'a>() -> impl Fn(&'a u8) -> (impl Debug + '_) {
|
||||||
| ^^^^^^^^^^^^^^^ recursive opaque type
|
| ^^^^^^^^^^^^^^^ cannot resolve opaque type
|
||||||
...
|
|
||||||
LL | |x| x
|
|
||||||
| ----- returning here with type `[closure@$DIR/impl-fn-predefined-lifetimes.rs:7:5: 7:8]`
|
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
|
|
@ -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
|
--> $DIR/impl-trait-captures.rs:11:5
|
||||||
|
|
|
|
||||||
LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> {
|
LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> {
|
||||||
|
|
|
@ -2,6 +2,6 @@
|
||||||
|
|
||||||
type Opaque<'a, T> = impl Sized;
|
type Opaque<'a, T> = impl Sized;
|
||||||
fn defining<'a, T>(x: &'a i32) -> Opaque<T> { x }
|
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() {}
|
fn main() {}
|
||||||
|
|
|
@ -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
|
--> $DIR/missing_lifetime_bound.rs:4:47
|
||||||
|
|
|
|
||||||
LL | fn defining<'a, T>(x: &'a i32) -> Opaque<T> { x }
|
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
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0700`.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue