Auto merge of #113704 - compiler-errors:rpitit-assumed-wf-inherit, r=spastorino
Make RPITITs inherit the `assumed_wf_types` of their parent method ... and then move the RPITIT well-formedness check to just use the regular logic of wfchecking an associated type. --- We need to inherit the `assumed_wf_types` of the RPITIT's parent function in order for the given code to be considered well-formed: ```rust trait Foo { fn bar<'a, T>(_: &'a T) -> impl Iterator<Output = &'a T>; } ``` Since for `&'a T` to be WF, we need `T: 'a`. In order for this to work for late-bound lifetimes, we need to do some additional mapping of any late-bound lifetimes captured by these assumed wf types. This is because within the body of the function (and thus in the `assumed_wf_types`), they're represented as `ReFree` variants of the original late-bound lifetimes declared in the function's generics, but in the RPITIT's GAT, they're represented as "reified" `ReEarlyBound` vars (duplicated during opaque type lowering). Luckily, the mapping between these two is already [stored in the opaque](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/struct.OpaqueTy.html#structfield.lifetime_mapping). Fixes #113796
This commit is contained in:
commit
b969b830aa
@ -284,6 +284,17 @@ fn check_trait_item(tcx: TyCtxt<'_>, trait_item: &hir::TraitItem<'_>) {
|
|||||||
};
|
};
|
||||||
check_object_unsafe_self_trait_by_name(tcx, trait_item);
|
check_object_unsafe_self_trait_by_name(tcx, trait_item);
|
||||||
check_associated_item(tcx, def_id, span, method_sig);
|
check_associated_item(tcx, def_id, span, method_sig);
|
||||||
|
|
||||||
|
if matches!(trait_item.kind, hir::TraitItemKind::Fn(..)) {
|
||||||
|
for &assoc_ty_def_id in tcx.associated_types_for_impl_traits_in_associated_fn(def_id) {
|
||||||
|
check_associated_item(
|
||||||
|
tcx,
|
||||||
|
assoc_ty_def_id.expect_local(),
|
||||||
|
tcx.def_span(assoc_ty_def_id),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Require that the user writes where clauses on GATs for the implicit
|
/// Require that the user writes where clauses on GATs for the implicit
|
||||||
@ -1466,13 +1477,6 @@ fn check_fn_or_method<'tcx>(
|
|||||||
|
|
||||||
check_where_clauses(wfcx, span, def_id);
|
check_where_clauses(wfcx, span, def_id);
|
||||||
|
|
||||||
check_return_position_impl_trait_in_trait_bounds(
|
|
||||||
wfcx,
|
|
||||||
def_id,
|
|
||||||
sig.output(),
|
|
||||||
hir_decl.output.span(),
|
|
||||||
);
|
|
||||||
|
|
||||||
if sig.abi == Abi::RustCall {
|
if sig.abi == Abi::RustCall {
|
||||||
let span = tcx.def_span(def_id);
|
let span = tcx.def_span(def_id);
|
||||||
let has_implicit_self = hir_decl.implicit_self != hir::ImplicitSelfKind::None;
|
let has_implicit_self = hir_decl.implicit_self != hir::ImplicitSelfKind::None;
|
||||||
@ -1507,87 +1511,6 @@ 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(wfcx))]
|
|
||||||
fn check_return_position_impl_trait_in_trait_bounds<'tcx>(
|
|
||||||
wfcx: &WfCheckingCtxt<'_, 'tcx>,
|
|
||||||
fn_def_id: LocalDefId,
|
|
||||||
fn_output: Ty<'tcx>,
|
|
||||||
span: Span,
|
|
||||||
) {
|
|
||||||
let tcx = wfcx.tcx();
|
|
||||||
let Some(assoc_item) = tcx.opt_associated_item(fn_def_id.to_def_id()) else {
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
if assoc_item.container != ty::AssocItemContainer::TraitContainer {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
fn_output.visit_with(&mut ImplTraitInTraitFinder {
|
|
||||||
wfcx,
|
|
||||||
fn_def_id,
|
|
||||||
depth: ty::INNERMOST,
|
|
||||||
seen: FxHashSet::default(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty): Even with the new lowering
|
|
||||||
// strategy, we can't just call `check_associated_item` on the new RPITITs,
|
|
||||||
// because tests like `tests/ui/async-await/in-trait/implied-bounds.rs` will fail.
|
|
||||||
// That's because we need to check that the bounds of the RPITIT hold using
|
|
||||||
// the special args that we create during opaque type lowering, otherwise we're
|
|
||||||
// getting a bunch of early bound and free regions mixed up... Haven't looked too
|
|
||||||
// deep into this, though.
|
|
||||||
struct ImplTraitInTraitFinder<'a, 'tcx> {
|
|
||||||
wfcx: &'a WfCheckingCtxt<'a, 'tcx>,
|
|
||||||
fn_def_id: LocalDefId,
|
|
||||||
depth: ty::DebruijnIndex,
|
|
||||||
seen: FxHashSet<DefId>,
|
|
||||||
}
|
|
||||||
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ImplTraitInTraitFinder<'_, 'tcx> {
|
|
||||||
type BreakTy = !;
|
|
||||||
|
|
||||||
fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<!> {
|
|
||||||
let tcx = self.wfcx.tcx();
|
|
||||||
if let ty::Alias(ty::Opaque, unshifted_opaque_ty) = *ty.kind()
|
|
||||||
&& self.seen.insert(unshifted_opaque_ty.def_id)
|
|
||||||
&& let Some(opaque_def_id) = unshifted_opaque_ty.def_id.as_local()
|
|
||||||
&& let origin = tcx.opaque_type_origin(opaque_def_id)
|
|
||||||
&& let hir::OpaqueTyOrigin::FnReturn(source) | hir::OpaqueTyOrigin::AsyncFn(source) = origin
|
|
||||||
&& source == self.fn_def_id
|
|
||||||
{
|
|
||||||
let opaque_ty = tcx.fold_regions(unshifted_opaque_ty, |re, _depth| {
|
|
||||||
match re.kind() {
|
|
||||||
ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReError(_) | ty::ReStatic => re,
|
|
||||||
r => bug!("unexpected region: {r:?}"),
|
|
||||||
}
|
|
||||||
});
|
|
||||||
for (bound, bound_span) in tcx
|
|
||||||
.explicit_item_bounds(opaque_ty.def_id)
|
|
||||||
.iter_instantiated_copied(tcx, opaque_ty.args)
|
|
||||||
{
|
|
||||||
let bound = self.wfcx.normalize(bound_span, None, bound);
|
|
||||||
self.wfcx.register_obligations(traits::wf::predicate_obligations(
|
|
||||||
self.wfcx.infcx,
|
|
||||||
self.wfcx.param_env,
|
|
||||||
self.wfcx.body_def_id,
|
|
||||||
bound.as_predicate(),
|
|
||||||
bound_span,
|
|
||||||
));
|
|
||||||
// Set the debruijn index back to innermost here, since we already eagerly
|
|
||||||
// shifted the args that we use to generate these bounds. This is unfortunately
|
|
||||||
// subtly different behavior than the `ImplTraitInTraitFinder` we use in `param_env`,
|
|
||||||
// but that function doesn't actually need to normalize the bound it's visiting
|
|
||||||
// (whereas we have to do so here)...
|
|
||||||
let old_depth = std::mem::replace(&mut self.depth, ty::INNERMOST);
|
|
||||||
bound.visit_with(self);
|
|
||||||
self.depth = old_depth;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ty.super_visit_with(self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const HELP_FOR_SELF_TYPE: &str = "consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, \
|
const HELP_FOR_SELF_TYPE: &str = "consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, \
|
||||||
`self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one \
|
`self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one \
|
||||||
of the previous types except `Self`)";
|
of the previous types except `Self`)";
|
||||||
|
@ -246,6 +246,7 @@ fn into_args(self) -> (DefId, SimplifiedType) {
|
|||||||
debug_assert_eq!(tcx.def_kind(def_id), DefKind::OpaqueTy);
|
debug_assert_eq!(tcx.def_kind(def_id), DefKind::OpaqueTy);
|
||||||
cdata.root.tables.is_type_alias_impl_trait.get(cdata, def_id.index)
|
cdata.root.tables.is_type_alias_impl_trait.get(cdata, def_id.index)
|
||||||
}
|
}
|
||||||
|
assumed_wf_types_for_rpitit => { table }
|
||||||
collect_return_position_impl_trait_in_trait_tys => {
|
collect_return_position_impl_trait_in_trait_tys => {
|
||||||
Ok(cdata
|
Ok(cdata
|
||||||
.root
|
.root
|
||||||
|
@ -1560,6 +1560,12 @@ fn encode_info_for_assoc_item(&mut self, def_id: DefId) {
|
|||||||
}
|
}
|
||||||
if let Some(rpitit_info) = item.opt_rpitit_info {
|
if let Some(rpitit_info) = item.opt_rpitit_info {
|
||||||
record!(self.tables.opt_rpitit_info[def_id] <- rpitit_info);
|
record!(self.tables.opt_rpitit_info[def_id] <- rpitit_info);
|
||||||
|
if matches!(rpitit_info, ty::ImplTraitInTraitData::Trait { .. }) {
|
||||||
|
record_array!(
|
||||||
|
self.tables.assumed_wf_types_for_rpitit[def_id]
|
||||||
|
<- self.tcx.assumed_wf_types_for_rpitit(def_id)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -457,6 +457,7 @@ fn encode(&self, buf: &mut FileEncoder) -> LazyTables {
|
|||||||
trait_impl_trait_tys: Table<DefIndex, LazyValue<FxHashMap<DefId, ty::EarlyBinder<Ty<'static>>>>>,
|
trait_impl_trait_tys: Table<DefIndex, LazyValue<FxHashMap<DefId, ty::EarlyBinder<Ty<'static>>>>>,
|
||||||
doc_link_resolutions: Table<DefIndex, LazyValue<DocLinkResMap>>,
|
doc_link_resolutions: Table<DefIndex, LazyValue<DocLinkResMap>>,
|
||||||
doc_link_traits_in_scope: Table<DefIndex, LazyArray<DefId>>,
|
doc_link_traits_in_scope: Table<DefIndex, LazyArray<DefId>>,
|
||||||
|
assumed_wf_types_for_rpitit: Table<DefIndex, LazyArray<(Ty<'static>, Span)>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(TyEncodable, TyDecodable)]
|
#[derive(TyEncodable, TyDecodable)]
|
||||||
|
@ -885,6 +885,13 @@
|
|||||||
desc { |tcx| "computing the implied bounds of `{}`", tcx.def_path_str(key) }
|
desc { |tcx| "computing the implied bounds of `{}`", tcx.def_path_str(key) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// We need to store the assumed_wf_types for an RPITIT so that impls of foreign
|
||||||
|
/// traits with return-position impl trait in traits can inherit the right wf types.
|
||||||
|
query assumed_wf_types_for_rpitit(key: DefId) -> &'tcx [(Ty<'tcx>, Span)] {
|
||||||
|
desc { |tcx| "computing the implied bounds of `{}`", tcx.def_path_str(key) }
|
||||||
|
separate_provide_extern
|
||||||
|
}
|
||||||
|
|
||||||
/// Computes the signature of the function.
|
/// Computes the signature of the function.
|
||||||
query fn_sig(key: DefId) -> ty::EarlyBinder<ty::PolyFnSig<'tcx>> {
|
query fn_sig(key: DefId) -> ty::EarlyBinder<ty::PolyFnSig<'tcx>> {
|
||||||
desc { |tcx| "computing function signature of `{}`", tcx.def_path_str(key) }
|
desc { |tcx| "computing function signature of `{}`", tcx.def_path_str(key) }
|
||||||
|
@ -1,13 +1,22 @@
|
|||||||
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def::DefKind;
|
use rustc_hir::def::DefKind;
|
||||||
use rustc_hir::def_id::LocalDefId;
|
use rustc_hir::def_id::LocalDefId;
|
||||||
|
use rustc_middle::middle::resolve_bound_vars as rbv;
|
||||||
use rustc_middle::query::Providers;
|
use rustc_middle::query::Providers;
|
||||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
use std::iter;
|
use std::iter;
|
||||||
|
|
||||||
pub fn provide(providers: &mut Providers) {
|
pub fn provide(providers: &mut Providers) {
|
||||||
*providers = Providers { assumed_wf_types, ..*providers };
|
*providers = Providers {
|
||||||
|
assumed_wf_types,
|
||||||
|
assumed_wf_types_for_rpitit: |tcx, def_id| {
|
||||||
|
assert!(tcx.is_impl_trait_in_trait(def_id.to_def_id()));
|
||||||
|
tcx.assumed_wf_types(def_id)
|
||||||
|
},
|
||||||
|
..*providers
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn assumed_wf_types<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx [(Ty<'tcx>, Span)] {
|
fn assumed_wf_types<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx [(Ty<'tcx>, Span)] {
|
||||||
@ -42,6 +51,81 @@ fn assumed_wf_types<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx [(Ty<'
|
|||||||
let mut impl_spans = impl_spans(tcx, def_id);
|
let mut impl_spans = impl_spans(tcx, def_id);
|
||||||
tcx.arena.alloc_from_iter(tys.into_iter().map(|ty| (ty, impl_spans.next().unwrap())))
|
tcx.arena.alloc_from_iter(tys.into_iter().map(|ty| (ty, impl_spans.next().unwrap())))
|
||||||
}
|
}
|
||||||
|
DefKind::AssocTy if let Some(data) = tcx.opt_rpitit_info(def_id.to_def_id()) => match data {
|
||||||
|
ty::ImplTraitInTraitData::Trait { fn_def_id, opaque_def_id } => {
|
||||||
|
let hir::OpaqueTy { lifetime_mapping, .. } =
|
||||||
|
*tcx.hir().expect_item(opaque_def_id.expect_local()).expect_opaque_ty();
|
||||||
|
// We need to remap all of the late-bound lifetimes in theassumed wf types
|
||||||
|
// of the fn (which are represented as ReFree) to the early-bound lifetimes
|
||||||
|
// of the RPITIT (which are represented by ReEarlyBound owned by the opaque).
|
||||||
|
// Luckily, this is very easy to do because we already have that mapping
|
||||||
|
// stored in the HIR of this RPITIT.
|
||||||
|
//
|
||||||
|
// Side-note: We don't really need to do this remapping for early-bound
|
||||||
|
// lifetimes because they're already "linked" by the bidirectional outlives
|
||||||
|
// predicates we insert in the `explicit_predicates_of` query for RPITITs.
|
||||||
|
let mut mapping = FxHashMap::default();
|
||||||
|
let generics = tcx.generics_of(def_id);
|
||||||
|
for &(lifetime, new_early_bound_def_id) in
|
||||||
|
lifetime_mapping.expect("expected lifetime mapping for RPITIT")
|
||||||
|
{
|
||||||
|
if let Some(rbv::ResolvedArg::LateBound(_, _, def_id)) =
|
||||||
|
tcx.named_bound_var(lifetime.hir_id)
|
||||||
|
{
|
||||||
|
let name = tcx.hir().name(lifetime.hir_id);
|
||||||
|
let index = generics
|
||||||
|
.param_def_id_to_index(tcx, new_early_bound_def_id.to_def_id())
|
||||||
|
.unwrap();
|
||||||
|
mapping.insert(
|
||||||
|
ty::Region::new_free(
|
||||||
|
tcx,
|
||||||
|
fn_def_id,
|
||||||
|
ty::BoundRegionKind::BrNamed(def_id, name),
|
||||||
|
),
|
||||||
|
ty::Region::new_early_bound(
|
||||||
|
tcx,
|
||||||
|
ty::EarlyBoundRegion {
|
||||||
|
def_id: new_early_bound_def_id.to_def_id(),
|
||||||
|
index,
|
||||||
|
name,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// FIXME: This could use a real folder, I guess.
|
||||||
|
let remapped_wf_tys = tcx.fold_regions(
|
||||||
|
tcx.assumed_wf_types(fn_def_id.expect_local()).to_vec(),
|
||||||
|
|region, _| {
|
||||||
|
// If `region` is a `ReFree` that is captured by the
|
||||||
|
// opaque, remap it to its corresponding the early-
|
||||||
|
// bound region.
|
||||||
|
if let Some(remapped_region) = mapping.get(®ion) {
|
||||||
|
*remapped_region
|
||||||
|
} else {
|
||||||
|
region
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
tcx.arena.alloc_from_iter(remapped_wf_tys)
|
||||||
|
}
|
||||||
|
// Assumed wf types for RPITITs in an impl just inherit (and instantiate)
|
||||||
|
// the assumed wf types of the trait's RPITIT GAT.
|
||||||
|
ty::ImplTraitInTraitData::Impl { .. } => {
|
||||||
|
let impl_def_id = tcx.local_parent(def_id);
|
||||||
|
let rpitit_def_id = tcx.associated_item(def_id).trait_item_def_id.unwrap();
|
||||||
|
let args = ty::GenericArgs::identity_for_item(tcx, def_id).rebase_onto(
|
||||||
|
tcx,
|
||||||
|
impl_def_id.to_def_id(),
|
||||||
|
tcx.impl_trait_ref(impl_def_id).unwrap().instantiate_identity().args,
|
||||||
|
);
|
||||||
|
tcx.arena.alloc_from_iter(
|
||||||
|
ty::EarlyBinder::bind(tcx.assumed_wf_types_for_rpitit(rpitit_def_id))
|
||||||
|
.iter_instantiated_copied(tcx, args)
|
||||||
|
.chain(tcx.assumed_wf_types(impl_def_id).into_iter().copied()),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
DefKind::AssocConst | DefKind::AssocTy => tcx.assumed_wf_types(tcx.local_parent(def_id)),
|
DefKind::AssocConst | DefKind::AssocTy => tcx.assumed_wf_types(tcx.local_parent(def_id)),
|
||||||
DefKind::OpaqueTy => match tcx.def_kind(tcx.local_parent(def_id)) {
|
DefKind::OpaqueTy => match tcx.def_kind(tcx.local_parent(def_id)) {
|
||||||
DefKind::TyAlias => ty::List::empty(),
|
DefKind::TyAlias => ty::List::empty(),
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#![feature(assert_matches)]
|
#![feature(assert_matches)]
|
||||||
#![feature(iterator_try_collect)]
|
#![feature(iterator_try_collect)]
|
||||||
#![feature(let_chains)]
|
#![feature(let_chains)]
|
||||||
|
#![feature(if_let_guard)]
|
||||||
#![feature(never_type)]
|
#![feature(never_type)]
|
||||||
#![feature(box_patterns)]
|
#![feature(box_patterns)]
|
||||||
#![recursion_limit = "256"]
|
#![recursion_limit = "256"]
|
||||||
|
@ -4,11 +4,11 @@ error[E0311]: the parameter type `U` may not live long enough
|
|||||||
LL | async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash;
|
LL | async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash;
|
||||||
| ^^^^^^^
|
| ^^^^^^^
|
||||||
|
|
|
|
||||||
note: the parameter type `U` must be valid for the anonymous lifetime defined here...
|
note: the parameter type `U` must be valid for the anonymous lifetime as defined here...
|
||||||
--> $DIR/async-generics-and-bounds.rs:12:18
|
--> $DIR/async-generics-and-bounds.rs:12:18
|
||||||
|
|
|
|
||||||
LL | async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash;
|
LL | async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash;
|
||||||
| ^^^^^
|
| ^
|
||||||
note: ...so that the reference type `&(T, U)` does not outlive the data it points at
|
note: ...so that the reference type `&(T, U)` does not outlive the data it points at
|
||||||
--> $DIR/async-generics-and-bounds.rs:12:28
|
--> $DIR/async-generics-and-bounds.rs:12:28
|
||||||
|
|
|
|
||||||
@ -21,11 +21,11 @@ error[E0311]: the parameter type `T` may not live long enough
|
|||||||
LL | async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash;
|
LL | async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash;
|
||||||
| ^^^^^^^
|
| ^^^^^^^
|
||||||
|
|
|
|
||||||
note: the parameter type `T` must be valid for the anonymous lifetime defined here...
|
note: the parameter type `T` must be valid for the anonymous lifetime as defined here...
|
||||||
--> $DIR/async-generics-and-bounds.rs:12:18
|
--> $DIR/async-generics-and-bounds.rs:12:18
|
||||||
|
|
|
|
||||||
LL | async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash;
|
LL | async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash;
|
||||||
| ^^^^^
|
| ^
|
||||||
note: ...so that the reference type `&(T, U)` does not outlive the data it points at
|
note: ...so that the reference type `&(T, U)` does not outlive the data it points at
|
||||||
--> $DIR/async-generics-and-bounds.rs:12:28
|
--> $DIR/async-generics-and-bounds.rs:12:28
|
||||||
|
|
|
|
||||||
|
@ -4,11 +4,11 @@ error[E0311]: the parameter type `U` may not live long enough
|
|||||||
LL | async fn foo(&self) -> &(T, U);
|
LL | async fn foo(&self) -> &(T, U);
|
||||||
| ^^^^^^^
|
| ^^^^^^^
|
||||||
|
|
|
|
||||||
note: the parameter type `U` must be valid for the anonymous lifetime defined here...
|
note: the parameter type `U` must be valid for the anonymous lifetime as defined here...
|
||||||
--> $DIR/async-generics.rs:9:18
|
--> $DIR/async-generics.rs:9:18
|
||||||
|
|
|
|
||||||
LL | async fn foo(&self) -> &(T, U);
|
LL | async fn foo(&self) -> &(T, U);
|
||||||
| ^^^^^
|
| ^
|
||||||
note: ...so that the reference type `&(T, U)` does not outlive the data it points at
|
note: ...so that the reference type `&(T, U)` does not outlive the data it points at
|
||||||
--> $DIR/async-generics.rs:9:28
|
--> $DIR/async-generics.rs:9:28
|
||||||
|
|
|
|
||||||
@ -21,11 +21,11 @@ error[E0311]: the parameter type `T` may not live long enough
|
|||||||
LL | async fn foo(&self) -> &(T, U);
|
LL | async fn foo(&self) -> &(T, U);
|
||||||
| ^^^^^^^
|
| ^^^^^^^
|
||||||
|
|
|
|
||||||
note: the parameter type `T` must be valid for the anonymous lifetime defined here...
|
note: the parameter type `T` must be valid for the anonymous lifetime as defined here...
|
||||||
--> $DIR/async-generics.rs:9:18
|
--> $DIR/async-generics.rs:9:18
|
||||||
|
|
|
|
||||||
LL | async fn foo(&self) -> &(T, U);
|
LL | async fn foo(&self) -> &(T, U);
|
||||||
| ^^^^^
|
| ^
|
||||||
note: ...so that the reference type `&(T, U)` does not outlive the data it points at
|
note: ...so that the reference type `&(T, U)` does not outlive the data it points at
|
||||||
--> $DIR/async-generics.rs:9:28
|
--> $DIR/async-generics.rs:9:28
|
||||||
|
|
|
|
||||||
|
29
tests/ui/impl-trait/in-trait/assumed-wf-bounds-in-impl.rs
Normal file
29
tests/ui/impl-trait/in-trait/assumed-wf-bounds-in-impl.rs
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
// check-pass
|
||||||
|
// edition: 2021
|
||||||
|
// issue: 113796
|
||||||
|
|
||||||
|
#![feature(async_fn_in_trait)]
|
||||||
|
|
||||||
|
trait AsyncLendingIterator {
|
||||||
|
type Item<'a>
|
||||||
|
where
|
||||||
|
Self: 'a;
|
||||||
|
|
||||||
|
async fn next(&mut self) -> Option<Self::Item<'_>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Lend<I>(I);
|
||||||
|
impl<I> AsyncLendingIterator for Lend<I> {
|
||||||
|
type Item<'a> = &'a I
|
||||||
|
where
|
||||||
|
Self: 'a;
|
||||||
|
|
||||||
|
// Checking that the synthetic `<Self as AsyncLendingIterator>::next()` GAT
|
||||||
|
// is well-formed requires being able to assume the WF types of `next`.
|
||||||
|
|
||||||
|
async fn next(&mut self) -> Option<Self::Item<'_>> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
@ -17,7 +17,6 @@ impl<'a, I: 'a + Iterable> Iterable for &'a I {
|
|||||||
//~^ ERROR impl has stricter requirements than trait
|
//~^ ERROR impl has stricter requirements than trait
|
||||||
|
|
||||||
fn iter(&self) -> impl 'a + Iterator<Item = I::Item<'a>> {
|
fn iter(&self) -> impl 'a + Iterator<Item = I::Item<'a>> {
|
||||||
//~^ ERROR the type `&'a I` does not fulfill the required lifetime
|
|
||||||
(*self).iter()
|
(*self).iter()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,19 +12,6 @@ help: copy the `where` clause predicates from the trait
|
|||||||
LL | where Self: 'b;
|
LL | where Self: 'b;
|
||||||
| ~~~~~~~~~~~~~~
|
| ~~~~~~~~~~~~~~
|
||||||
|
|
||||||
error[E0477]: the type `&'a I` does not fulfill the required lifetime
|
error: aborting due to previous error
|
||||||
--> $DIR/bad-item-bound-within-rpitit.rs:19:23
|
|
||||||
|
|
|
||||||
LL | fn iter(&self) -> impl 'a + Iterator<Item = I::Item<'a>> {
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
|
||||||
note: type must outlive the anonymous lifetime as defined here
|
|
||||||
--> $DIR/bad-item-bound-within-rpitit.rs:10:28
|
|
||||||
|
|
|
||||||
LL | fn iter(&self) -> impl '_ + Iterator<Item = Self::Item<'_>>;
|
|
||||||
| ^^
|
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
For more information about this error, try `rustc --explain E0276`.
|
||||||
|
|
||||||
Some errors have detailed explanations: E0276, E0477.
|
|
||||||
For more information about an error, try `rustc --explain E0276`.
|
|
||||||
|
@ -47,10 +47,6 @@ note: required by a bound in `NeedsDisplay`
|
|||||||
|
|
|
|
||||||
LL | struct NeedsDisplay<T: Display>(T);
|
LL | struct NeedsDisplay<T: Display>(T);
|
||||||
| ^^^^^^^ required by this bound in `NeedsDisplay`
|
| ^^^^^^^ required by this bound in `NeedsDisplay`
|
||||||
help: consider restricting type parameter `T`
|
|
||||||
|
|
|
||||||
LL | fn nya4<T: std::fmt::Display>() -> impl Wf<NeedsDisplay<T>>;
|
|
||||||
| +++++++++++++++++++
|
|
||||||
|
|
||||||
error: aborting due to 4 previous errors
|
error: aborting due to 4 previous errors
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user