about summary refs log tree commit diff
path: root/compiler/rustc_ty_utils/src
diff options
context:
space:
mode:
authorOli Scherer <git-spam-no-reply9815368754983@oli-obk.de>2023-04-25 08:07:44 +0000
committerOli Scherer <git-spam-no-reply9815368754983@oli-obk.de>2023-05-12 10:26:50 +0000
commit4e92f761fe54fc602ec2bf63819e8c973d1facd5 (patch)
treead4824e716785fd097f0c53e5ff4ce74c61770eb /compiler/rustc_ty_utils/src
parent6ae803eedfeb57944cd0d2930d9a8b7a606baf4a (diff)
downloadrust-4e92f761fe54fc602ec2bf63819e8c973d1facd5.tar.gz
rust-4e92f761fe54fc602ec2bf63819e8c973d1facd5.zip
Use the opaque_types_defined_by query to cheaply check for whether a hidden type may be registered for an opaque type
Diffstat (limited to 'compiler/rustc_ty_utils/src')
-rw-r--r--compiler/rustc_ty_utils/src/errors.rs24
-rw-r--r--compiler/rustc_ty_utils/src/opaque_types.rs165
2 files changed, 164 insertions, 25 deletions
diff --git a/compiler/rustc_ty_utils/src/errors.rs b/compiler/rustc_ty_utils/src/errors.rs
index 3d3fc50e6e5..553bf40ef3a 100644
--- a/compiler/rustc_ty_utils/src/errors.rs
+++ b/compiler/rustc_ty_utils/src/errors.rs
@@ -1,7 +1,7 @@
 //! Errors emitted by ty_utils
 
 use rustc_macros::{Diagnostic, Subdiagnostic};
-use rustc_middle::ty::Ty;
+use rustc_middle::ty::{GenericArg, Ty};
 use rustc_span::Span;
 
 #[derive(Diagnostic)]
@@ -100,3 +100,25 @@ pub struct NonPrimitiveSimdType<'tcx> {
     pub ty: Ty<'tcx>,
     pub e_ty: Ty<'tcx>,
 }
+
+#[derive(Diagnostic)]
+#[diag(ty_utils_impl_trait_duplicate_arg)]
+pub struct DuplicateArg<'tcx> {
+    pub arg: GenericArg<'tcx>,
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    #[note]
+    pub opaque_span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(ty_utils_impl_trait_not_param)]
+pub struct NotParam<'tcx> {
+    pub arg: GenericArg<'tcx>,
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    #[note]
+    pub opaque_span: Span,
+}
diff --git a/compiler/rustc_ty_utils/src/opaque_types.rs b/compiler/rustc_ty_utils/src/opaque_types.rs
index cdb8e4a439d..25ebb333bf7 100644
--- a/compiler/rustc_ty_utils/src/opaque_types.rs
+++ b/compiler/rustc_ty_utils/src/opaque_types.rs
@@ -1,46 +1,165 @@
+use rustc_data_structures::fx::FxHashSet;
+use rustc_errors::ErrorGuaranteed;
 use rustc_hir::{def::DefKind, def_id::LocalDefId};
-use rustc_middle::ty::util::CheckRegions;
+use rustc_middle::ty::util::{CheckRegions, NotUniqueParam};
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_middle::ty::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
+use rustc_span::Span;
 use rustc_type_ir::AliasKind;
 use std::ops::ControlFlow;
 
+use crate::errors::{DuplicateArg, NotParam};
+
 struct OpaqueTypeCollector<'tcx> {
     tcx: TyCtxt<'tcx>,
     opaques: Vec<LocalDefId>,
+    /// The `DefId` of the item which we are collecting opaque types for.
+    item: LocalDefId,
+
+    /// Avoid infinite recursion due to recursive declarations.
+    seen: FxHashSet<LocalDefId>,
+}
+
+impl<'tcx> OpaqueTypeCollector<'tcx> {
+    fn collect(
+        tcx: TyCtxt<'tcx>,
+        item: LocalDefId,
+        val: ty::Binder<'tcx, impl TypeVisitable<TyCtxt<'tcx>>>,
+    ) -> Vec<LocalDefId> {
+        let mut collector = Self { tcx, opaques: Vec::new(), item, seen: Default::default() };
+        val.skip_binder().visit_with(&mut collector);
+        collector.opaques
+    }
+
+    fn span(&self) -> Span {
+        self.tcx.def_span(self.item)
+    }
+
+    fn parent(&self) -> Option<LocalDefId> {
+        match self.tcx.def_kind(self.item) {
+            DefKind::Fn => None,
+            DefKind::AssocFn | DefKind::AssocTy | DefKind::AssocConst => {
+                Some(self.tcx.local_parent(self.item))
+            }
+            other => span_bug!(
+                self.tcx.def_span(self.item),
+                "unhandled item with opaque types: {other:?}"
+            ),
+        }
+    }
 }
 
 impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for OpaqueTypeCollector<'tcx> {
-    fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<!> {
+    type BreakTy = ErrorGuaranteed;
+
+    #[instrument(skip(self), ret, level = "trace")]
+    fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<ErrorGuaranteed> {
         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:?}");
+            ty::Alias(AliasKind::Opaque, alias_ty) if alias_ty.def_id.is_local() => {
+                if !self.seen.insert(alias_ty.def_id.expect_local()) {
+                    return ControlFlow::Continue(());
+                }
+                match self.tcx.uses_unique_generic_params(alias_ty.substs, CheckRegions::Bound) {
+                    Ok(()) => {
+                        // FIXME: implement higher kinded lifetime bounds on nested opaque types. They are not
+                        // supported at all, so this is sound to do, but once we want to support them, you'll
+                        // start seeing the error below.
+
+                        self.opaques.push(alias_ty.def_id.expect_local());
+
+                        // Collect opaque types nested within the associated type bounds of this opaque type.
+                        for (pred, _span) in self
+                            .tcx
+                            .explicit_item_bounds(alias_ty.def_id)
+                            .subst_iter_copied(self.tcx, alias_ty.substs)
+                        {
+                            trace!(?pred);
+                            pred.visit_with(self)?;
+                        }
+
+                        ControlFlow::Continue(())
+                    }
+                    Err(NotUniqueParam::NotParam(arg)) => {
+                        let err = self.tcx.sess.emit_err(NotParam {
+                            arg,
+                            span: self.span(),
+                            opaque_span: self.tcx.def_span(alias_ty.def_id),
+                        });
+                        ControlFlow::Break(err)
+                    }
+                    Err(NotUniqueParam::DuplicateParam(arg)) => {
+                        let err = self.tcx.sess.emit_err(DuplicateArg {
+                            arg,
+                            span: self.span(),
+                            opaque_span: self.tcx.def_span(alias_ty.def_id),
+                        });
+                        ControlFlow::Break(err)
                     }
                 }
             }
-            _ => {}
+            ty::Alias(AliasKind::Projection, alias_ty) => {
+                if let Some(parent) = self.parent() {
+                    trace!(?alias_ty);
+                    let (trait_ref, own_substs) = alias_ty.trait_ref_and_own_substs(self.tcx);
+
+                    trace!(?trait_ref, ?own_substs);
+                    // This avoids having to do normalization of `Self::AssocTy` by only
+                    // supporting the case of a method defining opaque types from assoc types
+                    // in the same impl block.
+                    if trait_ref.self_ty() == self.tcx.type_of(parent).subst_identity() {
+                        for assoc in self.tcx.associated_items(parent).in_definition_order() {
+                            trace!(?assoc);
+                            if assoc.trait_item_def_id == Some(alias_ty.def_id) {
+                                // We reconstruct the generic args of the associated type within the impl
+                                // from the impl's generics and the generic args passed to the type via the
+                                // projection.
+                                let substs = ty::InternalSubsts::identity_for_item(
+                                    self.tcx,
+                                    parent.to_def_id(),
+                                );
+                                trace!(?substs);
+                                let substs: Vec<_> =
+                                    substs.iter().chain(own_substs.iter().copied()).collect();
+                                trace!(?substs);
+                                // Find opaque types in this associated type.
+                                return self
+                                    .tcx
+                                    .type_of(assoc.def_id)
+                                    .subst(self.tcx, &substs)
+                                    .visit_with(self);
+                            }
+                        }
+                    }
+                }
+                t.super_visit_with(self)
+            }
+            _ => t.super_visit_with(self),
         }
-        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)
+    let kind = tcx.def_kind(item);
+    trace!(?kind);
+    // FIXME(type_alias_impl_trait): This is definitely still wrong except for RPIT and impl trait in assoc types.
+    match kind {
+        // We're also doing this for `AssocTy` for the wf checks in `check_opaque_meets_bounds`
+        DefKind::Fn | DefKind::AssocFn | DefKind::AssocTy | DefKind::AssocConst => {
+            let defined_opaques = match kind {
+                DefKind::Fn => {
+                    OpaqueTypeCollector::collect(tcx, item, tcx.fn_sig(item).subst_identity())
+                }
+                DefKind::AssocFn => {
+                    OpaqueTypeCollector::collect(tcx, item, tcx.fn_sig(item).subst_identity())
+                }
+                DefKind::AssocTy | DefKind::AssocConst => OpaqueTypeCollector::collect(
+                    tcx,
+                    item,
+                    ty::Binder::dummy(tcx.type_of(item).subst_identity()),
+                ),
+                _ => unreachable!(),
+            };
+            tcx.arena.alloc_from_iter(defined_opaques)
         }
         DefKind::Mod
         | DefKind::Struct
@@ -51,13 +170,11 @@ fn opaque_types_defined_by<'tcx>(tcx: TyCtxt<'tcx>, item: LocalDefId) -> &'tcx [
         | 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