diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 0e99df4f581..4df572f6199 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -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_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 @@ -1466,13 +1477,6 @@ fn check_fn_or_method<'tcx>( 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 { let span = tcx.def_span(def_id); 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, -} -impl<'tcx> TypeVisitor> 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: Rc`, `self: Arc`, or `self: Pin

` (where P is one \ of the previous types except `Self`)"; diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index a8815ee0908..7dbfe0e0cb0 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -246,6 +246,7 @@ fn into_args(self) -> (DefId, SimplifiedType) { debug_assert_eq!(tcx.def_kind(def_id), DefKind::OpaqueTy); 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 => { Ok(cdata .root diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 8f065dd6b58..0025dc9033c 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1560,6 +1560,12 @@ fn encode_info_for_assoc_item(&mut self, def_id: DefId) { } if let Some(rpitit_info) = item.opt_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) + ); + } } } diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 0bc16fc64ff..09e21fd4455 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -457,6 +457,7 @@ fn encode(&self, buf: &mut FileEncoder) -> LazyTables { trait_impl_trait_tys: Table>>>>, doc_link_resolutions: Table>, doc_link_traits_in_scope: Table>, + assumed_wf_types_for_rpitit: Table, Span)>>, } #[derive(TyEncodable, TyDecodable)] diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index fb796587352..0cdb7714729 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -885,6 +885,13 @@ 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. query fn_sig(key: DefId) -> ty::EarlyBinder> { desc { |tcx| "computing function signature of `{}`", tcx.def_path_str(key) } diff --git a/compiler/rustc_ty_utils/src/implied_bounds.rs b/compiler/rustc_ty_utils/src/implied_bounds.rs index fa1976510cf..7eb1042d2f8 100644 --- a/compiler/rustc_ty_utils/src/implied_bounds.rs +++ b/compiler/rustc_ty_utils/src/implied_bounds.rs @@ -1,13 +1,22 @@ +use rustc_data_structures::fx::FxHashMap; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; +use rustc_middle::middle::resolve_bound_vars as rbv; use rustc_middle::query::Providers; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::Span; use std::iter; 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)] { @@ -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); 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::OpaqueTy => match tcx.def_kind(tcx.local_parent(def_id)) { DefKind::TyAlias => ty::List::empty(), diff --git a/compiler/rustc_ty_utils/src/lib.rs b/compiler/rustc_ty_utils/src/lib.rs index 55b8857ed39..147b600f7ba 100644 --- a/compiler/rustc_ty_utils/src/lib.rs +++ b/compiler/rustc_ty_utils/src/lib.rs @@ -8,6 +8,7 @@ #![feature(assert_matches)] #![feature(iterator_try_collect)] #![feature(let_chains)] +#![feature(if_let_guard)] #![feature(never_type)] #![feature(box_patterns)] #![recursion_limit = "256"] diff --git a/tests/ui/async-await/in-trait/async-generics-and-bounds.stderr b/tests/ui/async-await/in-trait/async-generics-and-bounds.stderr index f1f0d7e5907..5c8d64fc6cb 100644 --- a/tests/ui/async-await/in-trait/async-generics-and-bounds.stderr +++ b/tests/ui/async-await/in-trait/async-generics-and-bounds.stderr @@ -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; | ^^^^^^^ | -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 | 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 --> $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; | ^^^^^^^ | -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 | 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 --> $DIR/async-generics-and-bounds.rs:12:28 | diff --git a/tests/ui/async-await/in-trait/async-generics.stderr b/tests/ui/async-await/in-trait/async-generics.stderr index 2f05564564c..6ae73d9e3a6 100644 --- a/tests/ui/async-await/in-trait/async-generics.stderr +++ b/tests/ui/async-await/in-trait/async-generics.stderr @@ -4,11 +4,11 @@ error[E0311]: the parameter type `U` may not live long enough 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 | LL | async fn foo(&self) -> &(T, U); - | ^^^^^ + | ^ note: ...so that the reference type `&(T, U)` does not outlive the data it points at --> $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); | ^^^^^^^ | -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 | LL | async fn foo(&self) -> &(T, U); - | ^^^^^ + | ^ note: ...so that the reference type `&(T, U)` does not outlive the data it points at --> $DIR/async-generics.rs:9:28 | diff --git a/tests/ui/impl-trait/in-trait/assumed-wf-bounds-in-impl.rs b/tests/ui/impl-trait/in-trait/assumed-wf-bounds-in-impl.rs new file mode 100644 index 00000000000..2a61c5cc8df --- /dev/null +++ b/tests/ui/impl-trait/in-trait/assumed-wf-bounds-in-impl.rs @@ -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>; +} + +struct Lend(I); +impl AsyncLendingIterator for Lend { + type Item<'a> = &'a I + where + Self: 'a; + + // Checking that the synthetic `::next()` GAT + // is well-formed requires being able to assume the WF types of `next`. + + async fn next(&mut self) -> Option> { + todo!() + } +} + +fn main() {} diff --git a/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit.rs b/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit.rs index 8b97336fe0c..ff7ad4bf389 100644 --- a/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit.rs +++ b/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit.rs @@ -17,7 +17,6 @@ impl<'a, I: 'a + Iterable> Iterable for &'a I { //~^ ERROR impl has stricter requirements than trait fn iter(&self) -> impl 'a + Iterator> { - //~^ ERROR the type `&'a I` does not fulfill the required lifetime (*self).iter() } } diff --git a/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit.stderr b/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit.stderr index 54a08c5b516..106b8a7c804 100644 --- a/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit.stderr +++ b/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit.stderr @@ -12,19 +12,6 @@ help: copy the `where` clause predicates from the trait LL | where Self: 'b; | ~~~~~~~~~~~~~~ -error[E0477]: the type `&'a I` does not fulfill the required lifetime - --> $DIR/bad-item-bound-within-rpitit.rs:19:23 - | -LL | fn iter(&self) -> impl 'a + Iterator> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -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>; - | ^^ +error: aborting due to previous error -error: aborting due to 2 previous errors - -Some errors have detailed explanations: E0276, E0477. -For more information about an error, try `rustc --explain E0276`. +For more information about this error, try `rustc --explain E0276`. diff --git a/tests/ui/impl-trait/in-trait/wf-bounds.stderr b/tests/ui/impl-trait/in-trait/wf-bounds.stderr index beac6620911..4d60b133048 100644 --- a/tests/ui/impl-trait/in-trait/wf-bounds.stderr +++ b/tests/ui/impl-trait/in-trait/wf-bounds.stderr @@ -47,10 +47,6 @@ note: required by a bound in `NeedsDisplay` | LL | struct NeedsDisplay(T); | ^^^^^^^ required by this bound in `NeedsDisplay` -help: consider restricting type parameter `T` - | -LL | fn nya4() -> impl Wf>; - | +++++++++++++++++++ error: aborting due to 4 previous errors