diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 9fad2816b0d..5acdd68e60e 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -236,6 +236,15 @@ cache_on_disk_if { key.is_local() } } + query opaque_types_defined_by( + key: LocalDefId + ) -> &'tcx [LocalDefId] { + desc { + |tcx| "computing the opaque types defined by `{}`", + tcx.def_path_str(key.to_def_id()) + } + } + /// Returns the list of bounds that can be used for /// `SelectionCandidate::ProjectionCandidate(_)` and /// `ProjectionTyCandidate::TraitDef`. diff --git a/compiler/rustc_ty_utils/src/lib.rs b/compiler/rustc_ty_utils/src/lib.rs index 73a2f6af579..8306c5ae493 100644 --- a/compiler/rustc_ty_utils/src/lib.rs +++ b/compiler/rustc_ty_utils/src/lib.rs @@ -33,6 +33,7 @@ mod layout; mod layout_sanity_check; mod needs_drop; +mod opaque_types; pub mod representability; mod structural_match; mod ty; @@ -47,6 +48,7 @@ pub fn provide(providers: &mut Providers) { implied_bounds::provide(providers); layout::provide(providers); needs_drop::provide(providers); + opaque_types::provide(providers); representability::provide(providers); ty::provide(providers); instance::provide(providers); diff --git a/compiler/rustc_ty_utils/src/opaque_types.rs b/compiler/rustc_ty_utils/src/opaque_types.rs new file mode 100644 index 00000000000..cdb8e4a439d --- /dev/null +++ b/compiler/rustc_ty_utils/src/opaque_types.rs @@ -0,0 +1,80 @@ +use rustc_hir::{def::DefKind, def_id::LocalDefId}; +use rustc_middle::ty::util::CheckRegions; +use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{TypeSuperVisitable, TypeVisitable, TypeVisitor}; +use rustc_type_ir::AliasKind; +use std::ops::ControlFlow; + +struct OpaqueTypeCollector<'tcx> { + tcx: TyCtxt<'tcx>, + opaques: Vec, +} + +impl<'tcx> TypeVisitor> for OpaqueTypeCollector<'tcx> { + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { + match t.kind() { + ty::Alias(AliasKind::Opaque, alias_ty) => { + if let Some(def_id) = alias_ty.def_id.as_local() { + if self + .tcx + .uses_unique_generic_params(alias_ty.substs, CheckRegions::OnlyEarlyBound) + .is_ok() + { + self.opaques.push(def_id); + return ControlFlow::Continue(()); + } else { + warn!(?t, "opaque types with non-unique params in sig: {t:?}"); + } + } + } + _ => {} + } + t.super_visit_with(self) + } +} + +fn opaque_types_defined_by<'tcx>(tcx: TyCtxt<'tcx>, item: LocalDefId) -> &'tcx [LocalDefId] { + // FIXME(type_alias_impl_trait): This is definitely still wrong except for RPIT. + match tcx.def_kind(item) { + DefKind::Fn | DefKind::AssocFn => { + let sig = tcx.fn_sig(item).subst_identity(); + let mut collector = OpaqueTypeCollector { tcx, opaques: Vec::new() }; + sig.visit_with(&mut collector); + tcx.arena.alloc_from_iter(collector.opaques) + } + DefKind::Mod + | DefKind::Struct + | DefKind::Union + | DefKind::Enum + | DefKind::Variant + | DefKind::Trait + | DefKind::TyAlias + | DefKind::ForeignTy + | DefKind::TraitAlias + | DefKind::AssocTy + | DefKind::TyParam + | DefKind::Const + | DefKind::ConstParam + | DefKind::Static(_) + | DefKind::Ctor(_, _) + | DefKind::AssocConst + | DefKind::Macro(_) + | DefKind::ExternCrate + | DefKind::Use + | DefKind::ForeignMod + | DefKind::AnonConst + | DefKind::InlineConst + | DefKind::OpaqueTy + | DefKind::ImplTraitPlaceholder + | DefKind::Field + | DefKind::LifetimeParam + | DefKind::GlobalAsm + | DefKind::Impl { .. } + | DefKind::Closure + | DefKind::Generator => &[], + } +} + +pub(super) fn provide(providers: &mut ty::query::Providers) { + *providers = ty::query::Providers { opaque_types_defined_by, ..*providers }; +}