about summary refs log tree commit diff
diff options
context:
space:
mode:
authorOli Scherer <git-spam-no-reply9815368754983@oli-obk.de>2023-04-17 10:19:41 +0000
committerOli Scherer <git-spam-no-reply9815368754983@oli-obk.de>2023-05-12 10:24:03 +0000
commitf08b51759763e44fc59b56584b640c2d2ccff0a0 (patch)
treea92628d0ba91c465c0ba55e98da3d76f073d94f7
parent699a862a3d4e4a2d5603c93297c0c44021ea72f5 (diff)
downloadrust-f08b51759763e44fc59b56584b640c2d2ccff0a0.tar.gz
rust-f08b51759763e44fc59b56584b640c2d2ccff0a0.zip
Require `impl Trait` in associated types to appear in method signatures
-rw-r--r--compiler/rustc_ast_lowering/src/item.rs10
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs36
-rw-r--r--compiler/rustc_borrowck/src/region_infer/opaque_types.rs4
-rw-r--r--compiler/rustc_hir/src/hir.rs5
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs13
-rw-r--r--compiler/rustc_hir_analysis/src/collect.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/collect/generics_of.rs5
-rw-r--r--compiler/rustc_hir_analysis/src/collect/predicates_of.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs5
-rw-r--r--compiler/rustc_hir_analysis/src/collect/type_of.rs7
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs2
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs13
-rw-r--r--compiler/rustc_infer/src/infer/opaque_types.rs132
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs7
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs2
-rw-r--r--compiler/rustc_middle/src/ty/normalize_erasing_regions.rs2
-rw-r--r--src/librustdoc/visit_ast.rs3
-rw-r--r--tests/ui/type-alias-impl-trait/associated-type-impl-trait-lifetime.rs7
-rw-r--r--tests/ui/type-alias-impl-trait/invalid_impl_trait_in_assoc_ty.rs16
-rw-r--r--tests/ui/type-alias-impl-trait/invalid_impl_trait_in_assoc_ty.stderr22
20 files changed, 242 insertions, 53 deletions
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index 3d154a93fb2..08ee3761bac 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -305,7 +305,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
                             );
                             this.arena.alloc(this.ty(span, hir::TyKind::Err(guar)))
                         }
-                        Some(ty) => this.lower_ty(ty, &ImplTraitContext::TypeAliasesOpaqueTy),
+                        Some(ty) => this.lower_ty(
+                            ty,
+                            &ImplTraitContext::TypeAliasesOpaqueTy { in_assoc_ty: false },
+                        ),
                     },
                 );
                 hir::ItemKind::TyAlias(ty, generics)
@@ -852,7 +855,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
                             hir::ImplItemKind::Type(ty)
                         }
                         Some(ty) => {
-                            let ty = this.lower_ty(ty, &ImplTraitContext::TypeAliasesOpaqueTy);
+                            let ty = this.lower_ty(
+                                ty,
+                                &ImplTraitContext::TypeAliasesOpaqueTy { in_assoc_ty: true },
+                            );
                             hir::ImplItemKind::Type(ty)
                         }
                     },
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 1fd7cc66470..cd6614a54a4 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -247,7 +247,7 @@ enum ImplTraitContext {
         in_trait: bool,
     },
     /// Impl trait in type aliases.
-    TypeAliasesOpaqueTy,
+    TypeAliasesOpaqueTy { in_assoc_ty: bool },
     /// `impl Trait` is unstably accepted in this position.
     FeatureGated(ImplTraitPosition, Symbol),
     /// `impl Trait` is not accepted in this position.
@@ -1407,14 +1407,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                             *in_trait,
                             itctx,
                         ),
-                    ImplTraitContext::TypeAliasesOpaqueTy => self.lower_opaque_impl_trait(
-                        span,
-                        hir::OpaqueTyOrigin::TyAlias,
-                        *def_node_id,
-                        bounds,
-                        false,
-                        itctx,
-                    ),
+                    &ImplTraitContext::TypeAliasesOpaqueTy { in_assoc_ty } => self
+                        .lower_opaque_impl_trait(
+                            span,
+                            hir::OpaqueTyOrigin::TyAlias { in_assoc_ty },
+                            *def_node_id,
+                            bounds,
+                            false,
+                            itctx,
+                        ),
                     ImplTraitContext::Universal => {
                         let span = t.span;
                         self.create_def(
@@ -1534,13 +1535,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         // If this came from a TAIT (as opposed to a function that returns an RPIT), we only want
         // to capture the lifetimes that appear in the bounds. So visit the bounds to find out
         // exactly which ones those are.
-        let lifetimes_to_remap = if origin == hir::OpaqueTyOrigin::TyAlias {
-            // in a TAIT like `type Foo<'a> = impl Foo<'a>`, we don't keep all the lifetime parameters
-            Vec::new()
-        } else {
-            // in fn return position, like the `fn test<'a>() -> impl Debug + 'a` example,
-            // we only keep the lifetimes that appear in the `impl Debug` itself:
-            lifetime_collector::lifetimes_in_bounds(&self.resolver, bounds)
+        let lifetimes_to_remap = match origin {
+            hir::OpaqueTyOrigin::TyAlias { .. } => {
+                // in a TAIT like `type Foo<'a> = impl Foo<'a>`, we don't keep all the lifetime parameters
+                Vec::new()
+            }
+            hir::OpaqueTyOrigin::AsyncFn(..) | hir::OpaqueTyOrigin::FnReturn(..) => {
+                // in fn return position, like the `fn test<'a>() -> impl Debug + 'a` example,
+                // we only keep the lifetimes that appear in the `impl Debug` itself:
+                lifetime_collector::lifetimes_in_bounds(&self.resolver, bounds)
+            }
         };
         debug!(?lifetimes_to_remap);
 
diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
index 4970ece5e7d..309f23d9226 100644
--- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
+++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
@@ -265,7 +265,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
 
         // Only check this for TAIT. RPIT already supports `tests/ui/impl-trait/nested-return-type2.rs`
         // on stable and we'd break that.
-        let OpaqueTyOrigin::TyAlias = origin else {
+        let OpaqueTyOrigin::TyAlias { .. } = origin else {
             return definition_ty;
         };
         let def_id = opaque_type_key.def_id;
@@ -360,7 +360,7 @@ fn check_opaque_type_parameter_valid(
         // which would error here on all of the `'static` args.
         OpaqueTyOrigin::FnReturn(..) | OpaqueTyOrigin::AsyncFn(..) => return Ok(()),
         // Check these
-        OpaqueTyOrigin::TyAlias => {}
+        OpaqueTyOrigin::TyAlias { .. } => {}
     }
     let opaque_generics = tcx.generics_of(opaque_type_key.def_id);
     let mut seen_params: FxIndexMap<_, Vec<_>> = FxIndexMap::default();
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 38cd5865cc3..932f0396282 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -2662,7 +2662,10 @@ pub enum OpaqueTyOrigin {
     /// `async fn`
     AsyncFn(LocalDefId),
     /// type aliases: `type Foo = impl Trait;`
-    TyAlias,
+    TyAlias {
+        /// associated types in impl blocks for traits.
+        in_assoc_ty: bool,
+    },
 }
 
 /// The various kinds of types recognized by the compiler.
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index 5187e63f8e3..b16860907eb 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -397,7 +397,14 @@ fn check_opaque_meets_bounds<'tcx>(
 ) {
     let defining_use_anchor = match *origin {
         hir::OpaqueTyOrigin::FnReturn(did) | hir::OpaqueTyOrigin::AsyncFn(did) => did,
-        hir::OpaqueTyOrigin::TyAlias => def_id,
+        hir::OpaqueTyOrigin::TyAlias { .. } => {
+            let mut def_id = def_id;
+            // Find the surrounding item (type alias or assoc type)
+            while let DefKind::OpaqueTy = tcx.def_kind(def_id) {
+                def_id = tcx.local_parent(def_id);
+            }
+            def_id
+        }
     };
     let param_env = tcx.param_env(defining_use_anchor);
 
@@ -455,10 +462,10 @@ fn check_opaque_meets_bounds<'tcx>(
         // They can only be referenced as `<Opaque<T> as Trait<&'static T>>::AssocTy`.
         // We don't have to check them here because their well-formedness follows from the WF of
         // the projection input types in the defining- and use-sites.
-        hir::OpaqueTyOrigin::TyAlias
+        hir::OpaqueTyOrigin::TyAlias { .. }
             if tcx.def_kind(tcx.parent(def_id.to_def_id())) == DefKind::OpaqueTy => {}
         // Can have different predicates to their defining use
-        hir::OpaqueTyOrigin::TyAlias => {
+        hir::OpaqueTyOrigin::TyAlias { .. } => {
             let wf_tys = ocx.assumed_wf_types(param_env, span, def_id);
             let implied_bounds = infcx.implied_bounds_tys(param_env, def_id, wf_tys);
             let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds);
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index b65817ee95e..2f808d4ce73 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -1483,7 +1483,7 @@ fn generator_kind(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<hir::GeneratorK
 fn is_type_alias_impl_trait<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> bool {
     match tcx.hir().get_by_def_id(def_id) {
         Node::Item(hir::Item { kind: hir::ItemKind::OpaqueTy(opaque), .. }) => {
-            matches!(opaque.origin, hir::OpaqueTyOrigin::TyAlias)
+            matches!(opaque.origin, hir::OpaqueTyOrigin::TyAlias { .. })
         }
         _ => bug!("tried getting opaque_ty_origin for non-opaque: {:?}", def_id),
     }
diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
index ab2932bf969..ed60998ec8d 100644
--- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
@@ -159,7 +159,10 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
                 }
                 Some(fn_def_id.to_def_id())
             }
-            ItemKind::OpaqueTy(hir::OpaqueTy { origin: hir::OpaqueTyOrigin::TyAlias, .. }) => {
+            ItemKind::OpaqueTy(hir::OpaqueTy {
+                origin: hir::OpaqueTyOrigin::TyAlias { .. },
+                ..
+            }) => {
                 let parent_id = tcx.hir().get_parent_item(hir_id);
                 assert_ne!(parent_id, hir::CRATE_OWNER_ID);
                 debug!("generics_of: parent of opaque ty {:?} is {:?}", def_id, parent_id);
diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
index e04658c8e77..a33990813b8 100644
--- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
@@ -721,7 +721,7 @@ pub(super) fn type_param_predicates(
                 | ItemKind::TyAlias(_, generics)
                 | ItemKind::OpaqueTy(OpaqueTy {
                     generics,
-                    origin: hir::OpaqueTyOrigin::TyAlias,
+                    origin: hir::OpaqueTyOrigin::TyAlias { .. },
                     ..
                 })
                 | ItemKind::Enum(_, generics)
diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
index 5c7f7f10b17..92ae93cf4cc 100644
--- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
+++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
@@ -526,7 +526,8 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
                 });
             }
             hir::ItemKind::OpaqueTy(hir::OpaqueTy {
-                origin: hir::OpaqueTyOrigin::TyAlias, ..
+                origin: hir::OpaqueTyOrigin::TyAlias { .. },
+                ..
             }) => {
                 // Opaque types are visited when we visit the
                 // `TyKind::OpaqueDef`, so that they have the lifetimes from
@@ -707,7 +708,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
                 let opaque_ty = self.tcx.hir().item(item_id);
                 match &opaque_ty.kind {
                     hir::ItemKind::OpaqueTy(hir::OpaqueTy {
-                        origin: hir::OpaqueTyOrigin::TyAlias,
+                        origin: hir::OpaqueTyOrigin::TyAlias { .. },
                         ..
                     }) => {
                         intravisit::walk_ty(self, ty);
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs
index 8df0166f76b..6c7c2b9eea2 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs
@@ -426,9 +426,10 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty
                     let substs = InternalSubsts::identity_for_item(tcx, def_id);
                     tcx.mk_adt(def, substs)
                 }
-                ItemKind::OpaqueTy(OpaqueTy { origin: hir::OpaqueTyOrigin::TyAlias, .. }) => {
-                    find_opaque_ty_constraints_for_tait(tcx, def_id)
-                }
+                ItemKind::OpaqueTy(OpaqueTy {
+                    origin: hir::OpaqueTyOrigin::TyAlias { .. },
+                    ..
+                }) => find_opaque_ty_constraints_for_tait(tcx, def_id),
                 // Opaque types desugared from `impl Trait`.
                 ItemKind::OpaqueTy(OpaqueTy {
                     origin:
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index 9e78e6acba5..b7253957edc 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -735,7 +735,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 if let ty::subst::GenericArgKind::Type(ty) = ty.unpack()
                     && let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = *ty.kind()
                     && let Some(def_id) = def_id.as_local()
-                    && self.opaque_type_origin(def_id).is_some() {
+                    && self.opaque_type_origin(def_id, self.param_env).is_some() {
                     return None;
                 }
             }
diff --git a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs
index 064811bd29d..e9c3726f8c3 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs
@@ -1,8 +1,10 @@
+use crate::infer::opaque_types::may_define_impl_trait_in_assoc_ty_modulo_sig;
+
 use super::TypeErrCtxt;
 use rustc_errors::Applicability::{MachineApplicable, MaybeIncorrect};
 use rustc_errors::{pluralize, Diagnostic, MultiSpan};
 use rustc_hir as hir;
-use rustc_middle::traits::ObligationCauseCode;
+use rustc_middle::traits::ObligationCauseCode::{self, MiscObligation};
 use rustc_middle::ty::error::ExpectedFound;
 use rustc_middle::ty::print::Printer;
 use rustc_middle::{
@@ -256,6 +258,15 @@ impl<T> Trait<T> for X {
                             );
                         }
                     }
+                    (ty::Alias(ty::Opaque, alias), _) | (_, ty::Alias(ty::Opaque, alias)) if matches!(cause.code(), MiscObligation) => {
+                        if let Some(def_id) = alias.def_id.as_local() {
+                            if may_define_impl_trait_in_assoc_ty_modulo_sig(tcx, body_owner_def_id.expect_local(), def_id).is_some() {
+                                diag.span_note(tcx.def_span(body_owner_def_id), "\
+                                    this item must have the opaque type in its signature \
+                                    in order to be able to register hidden types");
+                            }
+                        }
+                    }
                     (ty::FnPtr(_), ty::FnDef(def, _))
                     if let hir::def::DefKind::Fn = tcx.def_kind(def) => {
                         diag.note(
diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs
index 362b22b23a8..0b6f51652fd 100644
--- a/compiler/rustc_infer/src/infer/opaque_types.rs
+++ b/compiler/rustc_infer/src/infer/opaque_types.rs
@@ -3,9 +3,10 @@ use super::{DefineOpaqueTypes, InferResult};
 use crate::errors::OpaqueHiddenTypeDiag;
 use crate::infer::{DefiningAnchor, InferCtxt, InferOk};
 use crate::traits;
+use hir::def::DefKind;
 use hir::def_id::{DefId, LocalDefId};
 use hir::OpaqueTyOrigin;
-use rustc_data_structures::fx::FxIndexMap;
+use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
 use rustc_data_structures::sync::Lrc;
 use rustc_hir as hir;
 use rustc_middle::traits::ObligationCause;
@@ -53,7 +54,9 @@ impl<'tcx> InferCtxt<'tcx> {
         }
         let mut obligations = vec![];
         let replace_opaque_type = |def_id: DefId| {
-            def_id.as_local().map_or(false, |def_id| self.opaque_type_origin(def_id).is_some())
+            def_id
+                .as_local()
+                .map_or(false, |def_id| self.opaque_type_origin(def_id, param_env).is_some())
         };
         let value = value.fold_with(&mut BottomUpFolder {
             tcx: self.tcx,
@@ -138,7 +141,7 @@ impl<'tcx> InferCtxt<'tcx> {
                         //     let x = || foo(); // returns the Opaque assoc with `foo`
                         // }
                         // ```
-                        self.opaque_type_origin(def_id)?
+                        self.opaque_type_origin(def_id, param_env)?
                     }
                     DefiningAnchor::Bubble => self.opaque_type_origin_unchecked(def_id),
                     DefiningAnchor::Error => return None,
@@ -149,8 +152,9 @@ impl<'tcx> InferCtxt<'tcx> {
                     // no one encounters it in practice.
                     // It does occur however in `fn fut() -> impl Future<Output = i32> { async { 42 } }`,
                     // where it is of no concern, so we only check for TAITs.
-                    if let Some(OpaqueTyOrigin::TyAlias) =
-                        b_def_id.as_local().and_then(|b_def_id| self.opaque_type_origin(b_def_id))
+                    if let Some(OpaqueTyOrigin::TyAlias { .. }) = b_def_id
+                        .as_local()
+                        .and_then(|b_def_id| self.opaque_type_origin(b_def_id, param_env))
                     {
                         self.tcx.sess.emit_err(OpaqueHiddenTypeDiag {
                             span: cause.span,
@@ -366,8 +370,12 @@ impl<'tcx> InferCtxt<'tcx> {
 
     /// Returns the origin of the opaque type `def_id` if we're currently
     /// in its defining scope.
-    #[instrument(skip(self), level = "trace", ret)]
-    pub fn opaque_type_origin(&self, def_id: LocalDefId) -> Option<OpaqueTyOrigin> {
+    #[instrument(skip(self, param_env), level = "trace", ret)]
+    pub fn opaque_type_origin(
+        &self,
+        def_id: LocalDefId,
+        param_env: ty::ParamEnv<'tcx>,
+    ) -> Option<OpaqueTyOrigin> {
         let opaque_hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
         let parent_def_id = match self.defining_use_anchor {
             DefiningAnchor::Bubble | DefiningAnchor::Error => return None,
@@ -381,8 +389,12 @@ impl<'tcx> InferCtxt<'tcx> {
             // Anonymous `impl Trait`
             hir::OpaqueTyOrigin::FnReturn(parent) => parent == parent_def_id,
             // Named `type Foo = impl Bar;`
-            hir::OpaqueTyOrigin::TyAlias => {
-                may_define_opaque_type(self.tcx, parent_def_id, opaque_hir_id)
+            hir::OpaqueTyOrigin::TyAlias { in_assoc_ty } => {
+                if in_assoc_ty {
+                    may_define_impl_trait_in_assoc_ty(self.tcx, parent_def_id, def_id, param_env)
+                } else {
+                    may_define_opaque_type(self.tcx, parent_def_id, opaque_hir_id)
+                }
             }
         };
         in_definition_scope.then_some(origin)
@@ -642,3 +654,105 @@ fn may_define_opaque_type(tcx: TyCtxt<'_>, def_id: LocalDefId, opaque_hir_id: hi
     );
     res
 }
+
+#[derive(Debug, TypeVisitable, Clone)]
+/// Helper datastructure containing the signature
+/// that the opaque type extraction logic uses for determining
+/// whether an opaque type may have its hidden types registered
+/// by an item.
+enum FnSigOrTy<'tcx> {
+    FnSig(ty::PolyFnSig<'tcx>),
+    Ty(Ty<'tcx>),
+}
+
+/// Checks that the item may register hidden types for the
+/// opaque type, if the opaque type shows up in its signature.
+#[instrument(level = "debug", skip(tcx), ret)]
+pub fn may_define_impl_trait_in_assoc_ty_modulo_sig<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    def_id: LocalDefId,
+    opaque_def_id: LocalDefId,
+) -> Option<impl TypeVisitable<TyCtxt<'tcx>>> {
+    let sig = match tcx.def_kind(def_id) {
+        DefKind::AssocFn => FnSigOrTy::FnSig(tcx.fn_sig(def_id).subst_identity()),
+        DefKind::AssocConst | DefKind::AssocTy => {
+            FnSigOrTy::Ty(tcx.type_of(def_id).subst_identity())
+        }
+        _ => return None,
+    };
+    let impl_id = tcx.local_parent(def_id);
+    trace!(?impl_id);
+    let mut assoc_id = opaque_def_id;
+    // Peel nested opaque types.
+    while let DefKind::OpaqueTy = tcx.def_kind(assoc_id) {
+        trace!(?assoc_id);
+        assoc_id = tcx.local_parent(assoc_id);
+    }
+    trace!(?assoc_id);
+    if !matches!(tcx.def_kind(assoc_id), DefKind::AssocTy) {
+        tcx.sess
+            .delay_span_bug(tcx.def_span(opaque_def_id), format!("{:?}", tcx.def_kind(assoc_id)));
+    }
+    let assoc_impl_id = tcx.local_parent(assoc_id);
+    trace!(?assoc_impl_id);
+
+    if impl_id != assoc_impl_id {
+        return None;
+    }
+
+    Some(sig)
+}
+
+#[instrument(level = "debug", skip(tcx, param_env), ret)]
+fn may_define_impl_trait_in_assoc_ty<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    def_id: LocalDefId,
+    opaque_def_id: LocalDefId,
+    param_env: ty::ParamEnv<'tcx>,
+) -> bool {
+    let Some(sig) = may_define_impl_trait_in_assoc_ty_modulo_sig(tcx, def_id, opaque_def_id) else {
+        return false;
+    };
+
+    struct Visitor<'tcx> {
+        opaque_def_id: LocalDefId,
+        param_env: ty::ParamEnv<'tcx>,
+        tcx: TyCtxt<'tcx>,
+        seen: FxHashSet<LocalDefId>,
+    }
+
+    impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for Visitor<'tcx> {
+        type BreakTy = ();
+        #[instrument(level = "trace", skip(self), ret)]
+        fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<()> {
+            // FIXME(oli-obk): We should be checking if the associated type
+            // is mentioned instead of normalizing to find the opaque type.
+            // But that requires a way to figure out that a projection refers
+            // to a specific opaque type. That is probably doable by checking for
+            // `Self` as the `substs[0]`.
+            let normalized_ty = self.tcx.normalize_erasing_regions(self.param_env, ty);
+            if let ty::Alias(ty::Opaque, alias) = normalized_ty.kind() {
+                if let Some(def_id) = alias.def_id.as_local() {
+                    trace!(?alias.def_id);
+                    if def_id == self.opaque_def_id {
+                        return ControlFlow::Break(());
+                    }
+
+                    if self.seen.insert(def_id) {
+                        // Look into nested obligations like `impl Trait<Assoc = impl OtherTrait>`.
+                        for (pred, _) in self
+                            .tcx
+                            .explicit_item_bounds(alias.def_id)
+                            .subst_iter_copied(self.tcx, alias.substs)
+                        {
+                            pred.visit_with(self)?;
+                        }
+                    }
+                }
+            }
+            normalized_ty.super_visit_with(self)
+        }
+    }
+    sig.visit_with(&mut Visitor { opaque_def_id, param_env, tcx, seen: Default::default() })
+        .is_break()
+}
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 29cf432b8f9..043410c47e0 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -1641,9 +1641,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             }
             hir::ItemKind::OpaqueTy(ref opaque) => {
                 self.encode_explicit_item_bounds(def_id);
-                self.tables
-                    .is_type_alias_impl_trait
-                    .set(def_id.index, matches!(opaque.origin, hir::OpaqueTyOrigin::TyAlias));
+                self.tables.is_type_alias_impl_trait.set(
+                    def_id.index,
+                    matches!(opaque.origin, hir::OpaqueTyOrigin::TyAlias { .. }),
+                );
             }
             hir::ItemKind::Impl(hir::Impl { defaultness, constness, .. }) => {
                 self.tables.impl_defaultness.set_some(def_id.index, *defaultness);
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index f882f54d628..2952217f267 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -2520,7 +2520,7 @@ pub fn is_impl_trait_defn(tcx: TyCtxt<'_>, def_id: DefId) -> Option<LocalDefId>
                 hir::OpaqueTyOrigin::FnReturn(parent) | hir::OpaqueTyOrigin::AsyncFn(parent) => {
                     Some(parent)
                 }
-                hir::OpaqueTyOrigin::TyAlias => None,
+                hir::OpaqueTyOrigin::TyAlias { .. } => None,
             };
         }
     }
diff --git a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
index 9332b0430ff..a0c8d299f48 100644
--- a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
+++ b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
@@ -32,7 +32,7 @@ impl<'tcx> TyCtxt<'tcx> {
     ///
     /// This should only be used outside of type inference. For example,
     /// it assumes that normalization will succeed.
-    #[tracing::instrument(level = "debug", skip(self, param_env))]
+    #[tracing::instrument(level = "debug", skip(self, param_env), ret)]
     pub fn normalize_erasing_regions<T>(self, param_env: ty::ParamEnv<'tcx>, value: T) -> T
     where
         T: TypeFoldable<TyCtxt<'tcx>>,
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index deb29b1e7a9..ff13daa6db4 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -455,7 +455,8 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
             | hir::ItemKind::Union(..)
             | hir::ItemKind::TyAlias(..)
             | hir::ItemKind::OpaqueTy(hir::OpaqueTy {
-                origin: hir::OpaqueTyOrigin::TyAlias, ..
+                origin: hir::OpaqueTyOrigin::TyAlias { .. },
+                ..
             })
             | hir::ItemKind::Static(..)
             | hir::ItemKind::Trait(..)
diff --git a/tests/ui/type-alias-impl-trait/associated-type-impl-trait-lifetime.rs b/tests/ui/type-alias-impl-trait/associated-type-impl-trait-lifetime.rs
index 551815d021a..21c1d8bcc98 100644
--- a/tests/ui/type-alias-impl-trait/associated-type-impl-trait-lifetime.rs
+++ b/tests/ui/type-alias-impl-trait/associated-type-impl-trait-lifetime.rs
@@ -5,15 +5,14 @@
 trait Trait {
     type Opaque1;
     type Opaque2;
-    fn constrain(self);
+    fn constrain(self) -> (Self::Opaque1, Self::Opaque2);
 }
 
 impl<'a> Trait for &'a () {
     type Opaque1 = impl Sized;
     type Opaque2 = impl Sized + 'a;
-    fn constrain(self) {
-        let _: Self::Opaque1 = ();
-        let _: Self::Opaque2 = self;
+    fn constrain(self) -> (Self::Opaque1, Self::Opaque2) {
+        ((), self)
     }
 }
 
diff --git a/tests/ui/type-alias-impl-trait/invalid_impl_trait_in_assoc_ty.rs b/tests/ui/type-alias-impl-trait/invalid_impl_trait_in_assoc_ty.rs
new file mode 100644
index 00000000000..93c52126d69
--- /dev/null
+++ b/tests/ui/type-alias-impl-trait/invalid_impl_trait_in_assoc_ty.rs
@@ -0,0 +1,16 @@
+#![feature(impl_trait_in_assoc_type)]
+
+trait Foo {
+    type Foo;
+    fn bar();
+}
+
+impl Foo for () {
+    type Foo = impl std::fmt::Debug;
+    fn bar() {
+        let x: Self::Foo = ();
+        //~^ ERROR: mismatched types
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/type-alias-impl-trait/invalid_impl_trait_in_assoc_ty.stderr b/tests/ui/type-alias-impl-trait/invalid_impl_trait_in_assoc_ty.stderr
new file mode 100644
index 00000000000..2beed73cb85
--- /dev/null
+++ b/tests/ui/type-alias-impl-trait/invalid_impl_trait_in_assoc_ty.stderr
@@ -0,0 +1,22 @@
+error[E0308]: mismatched types
+  --> $DIR/invalid_impl_trait_in_assoc_ty.rs:11:28
+   |
+LL |     type Foo = impl std::fmt::Debug;
+   |                -------------------- the expected opaque type
+LL |     fn bar() {
+LL |         let x: Self::Foo = ();
+   |                ---------   ^^ expected opaque type, found `()`
+   |                |
+   |                expected due to this
+   |
+   = note: expected opaque type `<() as Foo>::Foo`
+                found unit type `()`
+note: this item must have the opaque type in its signature in order to be able to register hidden types
+  --> $DIR/invalid_impl_trait_in_assoc_ty.rs:10:5
+   |
+LL |     fn bar() {
+   |     ^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.