From 50d21091ee39319b4819b2c7e8ea6e8e78c75fb9 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 17 Jul 2023 18:12:49 +0000 Subject: [PATCH] Implement assumed_wf_types for RPITITs' implementations --- .../src/rmeta/decoder/cstore_impl.rs | 1 + compiler/rustc_metadata/src/rmeta/encoder.rs | 6 ++ compiler/rustc_metadata/src/rmeta/mod.rs | 1 + compiler/rustc_middle/src/query/mod.rs | 7 ++ compiler/rustc_ty_utils/src/implied_bounds.rs | 91 ++++++++++++------- .../in-trait/assumed-wf-bounds-in-impl.rs | 29 ++++++ 6 files changed, 102 insertions(+), 33 deletions(-) create mode 100644 tests/ui/impl-trait/in-trait/assumed-wf-bounds-in-impl.rs 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 @@ provide! { tcx, def_id, other, cdata, 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 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } 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 @@ define_tables! { 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 @@ rustc_queries! { 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 2c1687f10cc..815550a49e1 100644 --- a/compiler/rustc_ty_utils/src/implied_bounds.rs +++ b/compiler/rustc_ty_utils/src/implied_bounds.rs @@ -9,7 +9,11 @@ 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| tcx.assumed_wf_types(def_id), + ..*providers + }; } fn assumed_wf_types<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx [(Ty<'tcx>, Span)] { @@ -44,41 +48,62 @@ 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(ty::ImplTraitInTraitData::Trait { fn_def_id, opaque_def_id }) = tcx.opt_rpitit_info(def_id.to_def_id()) => { - let hir::OpaqueTy { lifetime_mapping, .. } = - *tcx.hir().expect_item(opaque_def_id.expect_local()).expect_opaque_ty(); - let mut mapping = FxHashMap::default(); - let generics = tcx.generics_of(def_id); - for &(lifetime, new_early_bound_def_id) in lifetime_mapping { - if let Some(rbv::ResolvedArg::LateBound(_, _, def_id)) = - tcx.named_bound_var(lifetime.hir_id) + 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(); + 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") { - 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, - }, - ), - ); + 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, + }, + ), + ); + } } + let a = tcx.fold_regions( + tcx.assumed_wf_types(fn_def_id.expect_local()).to_vec(), + |re, _| { + if let Some(re) = mapping.get(&re) { *re } else { re } + }, + ); + tcx.arena.alloc_from_iter(a) } - let a = tcx.fold_regions(tcx.assumed_wf_types(fn_def_id.expect_local()).to_vec(), |re, _| { - if let Some(re) = mapping.get(&re) { *re } else { re } - }); - tcx.arena.alloc_from_iter(a) - } + 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/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() {}