about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDylan DPC <99973273+Dylan-DPC@users.noreply.github.com>2022-07-20 16:17:19 +0530
committerGitHub <noreply@github.com>2022-07-20 16:17:19 +0530
commiteecfdfb8a12367cb292a85b6a30981eb35a56379 (patch)
tree5450ed5b247533c39a063456dbc71de8e2156f78
parent3c3c5da9adfdf308b5189b8034c07e0dc5492a54 (diff)
parent64dc377a103c0d377b3e60e08d29f69fcf7ba2c5 (diff)
downloadrust-eecfdfb8a12367cb292a85b6a30981eb35a56379.tar.gz
rust-eecfdfb8a12367cb292a85b6a30981eb35a56379.zip
Rollup merge of #99383 - ouz-a:issue_57961, r=oli-obk
Formalize defining_use_anchor

This tackles issue #57961

Introduces new enum called `DefiningAnchor` that replaces `Option<LocalDefId>` of `defining_use_anchor`. Now every use of it is explicit and exhaustively matched, catching errors like one in the linked issue. This is not a perfect fix but it's a step in the right direction.

r? `@oli-obk`
-rw-r--r--compiler/rustc_borrowck/src/consumers.rs4
-rw-r--r--compiler/rustc_borrowck/src/lib.rs15
-rw-r--r--compiler/rustc_borrowck/src/region_infer/opaque_types.rs102
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs32
-rw-r--r--compiler/rustc_infer/src/infer/opaque_types.rs85
-rw-r--r--compiler/rustc_trait_selection/src/traits/codegen.rs9
-rw-r--r--compiler/rustc_typeck/src/check/check.rs84
-rw-r--r--compiler/rustc_typeck/src/check/compare_method.rs2
-rw-r--r--src/test/ui/impl-trait/issues/issue-99348-impl-compatibility.rs2
-rw-r--r--src/test/ui/impl-trait/issues/issue-99348-impl-compatibility.stderr22
-rw-r--r--src/test/ui/parser/fn-header-semantic-fail.rs4
-rw-r--r--src/test/ui/parser/fn-header-semantic-fail.stderr46
-rw-r--r--src/test/ui/resolve/issue-70736-async-fn-no-body-def-collector.rs2
-rw-r--r--src/test/ui/resolve/issue-70736-async-fn-no-body-def-collector.stderr23
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-53398-cyclic-types.rs2
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-53398-cyclic-types.stderr4
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-57961.rs18
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-57961.stderr20
18 files changed, 292 insertions, 184 deletions
diff --git a/compiler/rustc_borrowck/src/consumers.rs b/compiler/rustc_borrowck/src/consumers.rs
index 97daad201d9..efc17a173f4 100644
--- a/compiler/rustc_borrowck/src/consumers.rs
+++ b/compiler/rustc_borrowck/src/consumers.rs
@@ -2,7 +2,7 @@
 
 use rustc_hir::def_id::LocalDefId;
 use rustc_index::vec::IndexVec;
-use rustc_infer::infer::TyCtxtInferExt;
+use rustc_infer::infer::{DefiningAnchor, TyCtxtInferExt};
 use rustc_middle::mir::Body;
 use rustc_middle::ty::{self, TyCtxt};
 
@@ -31,7 +31,7 @@ pub fn get_body_with_borrowck_facts<'tcx>(
     def: ty::WithOptConstParam<LocalDefId>,
 ) -> BodyWithBorrowckFacts<'tcx> {
     let (input_body, promoted) = tcx.mir_promoted(def);
-    tcx.infer_ctxt().with_opaque_type_inference(def.did).enter(|infcx| {
+    tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bind(def.did)).enter(|infcx| {
         let input_body: &Body<'_> = &input_body.borrow();
         let promoted: &IndexVec<_, _> = &promoted.borrow();
         *super::do_mir_borrowck(&infcx, input_body, promoted, true).1.unwrap()
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index 15c2a9f7aef..a5a8ded373f 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -24,7 +24,7 @@ use rustc_hir as hir;
 use rustc_hir::def_id::LocalDefId;
 use rustc_index::bit_set::ChunkedBitSet;
 use rustc_index::vec::IndexVec;
-use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
+use rustc_infer::infer::{DefiningAnchor, InferCtxt, TyCtxtInferExt};
 use rustc_middle::mir::{
     traversal, Body, ClearCrossCrate, Local, Location, Mutability, Operand, Place, PlaceElem,
     PlaceRef, VarDebugInfoContents,
@@ -130,11 +130,14 @@ fn mir_borrowck<'tcx>(
     debug!("run query mir_borrowck: {}", tcx.def_path_str(def.did.to_def_id()));
     let hir_owner = tcx.hir().local_def_id_to_hir_id(def.did).owner;
 
-    let opt_closure_req = tcx.infer_ctxt().with_opaque_type_inference(hir_owner).enter(|infcx| {
-        let input_body: &Body<'_> = &input_body.borrow();
-        let promoted: &IndexVec<_, _> = &promoted.borrow();
-        do_mir_borrowck(&infcx, input_body, promoted, false).0
-    });
+    let opt_closure_req = tcx
+        .infer_ctxt()
+        .with_opaque_type_inference(DefiningAnchor::Bind(hir_owner))
+        .enter(|infcx| {
+            let input_body: &Body<'_> = &input_body.borrow();
+            let promoted: &IndexVec<_, _> = &promoted.borrow();
+            do_mir_borrowck(&infcx, input_body, promoted, false).0
+        });
     debug!("mir_borrowck done");
 
     tcx.arena.alloc(opt_closure_req)
diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
index de9da845729..407bbf48813 100644
--- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
+++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
@@ -3,8 +3,8 @@ use rustc_data_structures::vec_map::VecMap;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::OpaqueTyOrigin;
 use rustc_infer::infer::error_reporting::unexpected_hidden_region_diagnostic;
-use rustc_infer::infer::InferCtxt;
 use rustc_infer::infer::TyCtxtInferExt as _;
+use rustc_infer::infer::{DefiningAnchor, InferCtxt};
 use rustc_infer::traits::{Obligation, ObligationCause, TraitEngine};
 use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable};
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts};
@@ -269,59 +269,65 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
             // FIXME(oli-obk): Also do region checks here and then consider removing `check_opaque_meets_bounds` entirely.
             let param_env = self.tcx.param_env(def_id);
             let body_id = self.tcx.local_def_id_to_hir_id(def_id);
-            self.tcx.infer_ctxt().enter(move |infcx| {
-                // Require the hidden type to be well-formed with only the generics of the opaque type.
-                // Defining use functions may have more bounds than the opaque type, which is ok, as long as the
-                // hidden type is well formed even without those bounds.
-                let predicate =
-                    ty::Binder::dummy(ty::PredicateKind::WellFormed(definition_ty.into()))
-                        .to_predicate(infcx.tcx);
-                let mut fulfillment_cx = <dyn TraitEngine<'tcx>>::new(infcx.tcx);
-
-                // Require that the hidden type actually fulfills all the bounds of the opaque type, even without
-                // the bounds that the function supplies.
-                match infcx.register_hidden_type(
-                    OpaqueTypeKey { def_id, substs: id_substs },
-                    ObligationCause::misc(instantiated_ty.span, body_id),
-                    param_env,
-                    definition_ty,
-                    origin,
-                ) {
-                    Ok(infer_ok) => {
-                        for obligation in infer_ok.obligations {
-                            fulfillment_cx.register_predicate_obligation(&infcx, obligation);
+            // HACK This bubble is required for this tests to pass:
+            // type-alias-impl-trait/issue-67844-nested-opaque.rs
+            self.tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bubble).enter(
+                move |infcx| {
+                    // Require the hidden type to be well-formed with only the generics of the opaque type.
+                    // Defining use functions may have more bounds than the opaque type, which is ok, as long as the
+                    // hidden type is well formed even without those bounds.
+                    let predicate =
+                        ty::Binder::dummy(ty::PredicateKind::WellFormed(definition_ty.into()))
+                            .to_predicate(infcx.tcx);
+                    let mut fulfillment_cx = <dyn TraitEngine<'tcx>>::new(infcx.tcx);
+
+                    // Require that the hidden type actually fulfills all the bounds of the opaque type, even without
+                    // the bounds that the function supplies.
+                    match infcx.register_hidden_type(
+                        OpaqueTypeKey { def_id, substs: id_substs },
+                        ObligationCause::misc(instantiated_ty.span, body_id),
+                        param_env,
+                        definition_ty,
+                        origin,
+                    ) {
+                        Ok(infer_ok) => {
+                            for obligation in infer_ok.obligations {
+                                fulfillment_cx.register_predicate_obligation(&infcx, obligation);
+                            }
+                        }
+                        Err(err) => {
+                            infcx
+                                .report_mismatched_types(
+                                    &ObligationCause::misc(instantiated_ty.span, body_id),
+                                    self.tcx.mk_opaque(def_id.to_def_id(), id_substs),
+                                    definition_ty,
+                                    err,
+                                )
+                                .emit();
                         }
                     }
-                    Err(err) => {
-                        infcx
-                            .report_mismatched_types(
-                                &ObligationCause::misc(instantiated_ty.span, body_id),
-                                self.tcx.mk_opaque(def_id.to_def_id(), id_substs),
-                                definition_ty,
-                                err,
-                            )
-                            .emit();
-                    }
-                }
 
-                fulfillment_cx.register_predicate_obligation(
-                    &infcx,
-                    Obligation::misc(instantiated_ty.span, body_id, param_env, predicate),
-                );
+                    fulfillment_cx.register_predicate_obligation(
+                        &infcx,
+                        Obligation::misc(instantiated_ty.span, body_id, param_env, predicate),
+                    );
 
-                // Check that all obligations are satisfied by the implementation's
-                // version.
-                let errors = fulfillment_cx.select_all_or_error(&infcx);
+                    // Check that all obligations are satisfied by the implementation's
+                    // version.
+                    let errors = fulfillment_cx.select_all_or_error(&infcx);
 
-                let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
+                    // This is still required for many(half of the tests in ui/type-alias-impl-trait)
+                    // tests to pass
+                    let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
 
-                if errors.is_empty() {
-                    definition_ty
-                } else {
-                    infcx.report_fulfillment_errors(&errors, None, false);
-                    self.tcx.ty_error()
-                }
-            })
+                    if errors.is_empty() {
+                        definition_ty
+                    } else {
+                        infcx.report_fulfillment_errors(&errors, None, false);
+                        self.tcx.ty_error()
+                    }
+                },
+            )
         } else {
             definition_ty
         }
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index b3dc2e586d2..0e44d4e7c97 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -239,17 +239,31 @@ impl<'tcx> InferCtxtInner<'tcx> {
     }
 }
 
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub enum DefiningAnchor {
+    /// `DefId` of the item.
+    Bind(LocalDefId),
+    /// When opaque types are not resolved, we `Bubble` up, meaning
+    /// return the opaque/hidden type pair from query, for caller of query to handle it.
+    Bubble,
+    /// Used to catch type mismatch errors when handling opaque types.
+    Error,
+}
+
 pub struct InferCtxt<'a, 'tcx> {
     pub tcx: TyCtxt<'tcx>,
 
     /// The `DefId` of the item in whose context we are performing inference or typeck.
     /// It is used to check whether an opaque type use is a defining use.
     ///
-    /// If it is `None`, we can't resolve opaque types here and need to bubble up
+    /// If it is `DefiningAnchor::Bubble`, we can't resolve opaque types here and need to bubble up
     /// the obligation. This frequently happens for
     /// short lived InferCtxt within queries. The opaque type obligations are forwarded
     /// to the outside until the end up in an `InferCtxt` for typeck or borrowck.
-    pub defining_use_anchor: Option<LocalDefId>,
+    ///
+    /// It is default value is `DefiningAnchor::Error`, this way it is easier to catch errors that
+    /// might come up during inference or typeck.
+    pub defining_use_anchor: DefiningAnchor,
 
     /// During type-checking/inference of a body, `in_progress_typeck_results`
     /// contains a reference to the typeck results being built up, which are
@@ -526,7 +540,7 @@ impl<'tcx> fmt::Display for FixupError<'tcx> {
 pub struct InferCtxtBuilder<'tcx> {
     tcx: TyCtxt<'tcx>,
     fresh_typeck_results: Option<RefCell<ty::TypeckResults<'tcx>>>,
-    defining_use_anchor: Option<LocalDefId>,
+    defining_use_anchor: DefiningAnchor,
 }
 
 pub trait TyCtxtInferExt<'tcx> {
@@ -535,7 +549,11 @@ pub trait TyCtxtInferExt<'tcx> {
 
 impl<'tcx> TyCtxtInferExt<'tcx> for TyCtxt<'tcx> {
     fn infer_ctxt(self) -> InferCtxtBuilder<'tcx> {
-        InferCtxtBuilder { tcx: self, defining_use_anchor: None, fresh_typeck_results: None }
+        InferCtxtBuilder {
+            tcx: self,
+            defining_use_anchor: DefiningAnchor::Error,
+            fresh_typeck_results: None,
+        }
     }
 }
 
@@ -545,7 +563,7 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
     /// Will also change the scope for opaque type defining use checks to the given owner.
     pub fn with_fresh_in_progress_typeck_results(mut self, table_owner: LocalDefId) -> Self {
         self.fresh_typeck_results = Some(RefCell::new(ty::TypeckResults::new(table_owner)));
-        self.with_opaque_type_inference(table_owner)
+        self.with_opaque_type_inference(DefiningAnchor::Bind(table_owner))
     }
 
     /// Whenever the `InferCtxt` should be able to handle defining uses of opaque types,
@@ -554,8 +572,8 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
     /// It is only meant to be called in two places, for typeck
     /// (via `with_fresh_in_progress_typeck_results`) and for the inference context used
     /// in mir borrowck.
-    pub fn with_opaque_type_inference(mut self, defining_use_anchor: LocalDefId) -> Self {
-        self.defining_use_anchor = Some(defining_use_anchor);
+    pub fn with_opaque_type_inference(mut self, defining_use_anchor: DefiningAnchor) -> Self {
+        self.defining_use_anchor = defining_use_anchor;
         self
     }
 
diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs
index 81c3bf5d441..7b0ff9552a3 100644
--- a/compiler/rustc_infer/src/infer/opaque_types.rs
+++ b/compiler/rustc_infer/src/infer/opaque_types.rs
@@ -1,4 +1,4 @@
-use crate::infer::{InferCtxt, InferOk};
+use crate::infer::{DefiningAnchor, InferCtxt, InferOk};
 use crate::traits;
 use hir::def_id::{DefId, LocalDefId};
 use hir::{HirId, OpaqueTyOrigin};
@@ -101,44 +101,46 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         let process = |a: Ty<'tcx>, b: Ty<'tcx>| match *a.kind() {
             ty::Opaque(def_id, substs) if def_id.is_local() => {
                 let def_id = def_id.expect_local();
-                let origin = if self.defining_use_anchor.is_some() {
-                    // Check that this is `impl Trait` type is
-                    // declared by `parent_def_id` -- i.e., one whose
-                    // value we are inferring.  At present, this is
-                    // always true during the first phase of
-                    // type-check, but not always true later on during
-                    // NLL. Once we support named opaque types more fully,
-                    // this same scenario will be able to arise during all phases.
-                    //
-                    // Here is an example using type alias `impl Trait`
-                    // that indicates the distinction we are checking for:
-                    //
-                    // ```rust
-                    // mod a {
-                    //   pub type Foo = impl Iterator;
-                    //   pub fn make_foo() -> Foo { .. }
-                    // }
-                    //
-                    // mod b {
-                    //   fn foo() -> a::Foo { a::make_foo() }
-                    // }
-                    // ```
-                    //
-                    // Here, the return type of `foo` references an
-                    // `Opaque` indeed, but not one whose value is
-                    // presently being inferred. You can get into a
-                    // similar situation with closure return types
-                    // today:
-                    //
-                    // ```rust
-                    // fn foo() -> impl Iterator { .. }
-                    // fn bar() {
-                    //     let x = || foo(); // returns the Opaque assoc with `foo`
-                    // }
-                    // ```
-                    self.opaque_type_origin(def_id, cause.span)?
-                } else {
-                    self.opaque_ty_origin_unchecked(def_id, cause.span)
+                let origin = match self.defining_use_anchor {
+                    DefiningAnchor::Bind(_) => {
+                        // Check that this is `impl Trait` type is
+                        // declared by `parent_def_id` -- i.e., one whose
+                        // value we are inferring.  At present, this is
+                        // always true during the first phase of
+                        // type-check, but not always true later on during
+                        // NLL. Once we support named opaque types more fully,
+                        // this same scenario will be able to arise during all phases.
+                        //
+                        // Here is an example using type alias `impl Trait`
+                        // that indicates the distinction we are checking for:
+                        //
+                        // ```rust
+                        // mod a {
+                        //   pub type Foo = impl Iterator;
+                        //   pub fn make_foo() -> Foo { .. }
+                        // }
+                        //
+                        // mod b {
+                        //   fn foo() -> a::Foo { a::make_foo() }
+                        // }
+                        // ```
+                        //
+                        // Here, the return type of `foo` references an
+                        // `Opaque` indeed, but not one whose value is
+                        // presently being inferred. You can get into a
+                        // similar situation with closure return types
+                        // today:
+                        //
+                        // ```rust
+                        // fn foo() -> impl Iterator { .. }
+                        // fn bar() {
+                        //     let x = || foo(); // returns the Opaque assoc with `foo`
+                        // }
+                        // ```
+                        self.opaque_type_origin(def_id, cause.span)?
+                    }
+                    DefiningAnchor::Bubble => self.opaque_ty_origin_unchecked(def_id, cause.span),
+                    DefiningAnchor::Error => return None,
                 };
                 if let ty::Opaque(did2, _) = *b.kind() {
                     // We could accept this, but there are various ways to handle this situation, and we don't
@@ -407,7 +409,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
     #[instrument(skip(self), level = "trace")]
     pub fn opaque_type_origin(&self, def_id: LocalDefId, span: Span) -> Option<OpaqueTyOrigin> {
         let opaque_hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
-        let parent_def_id = self.defining_use_anchor?;
+        let parent_def_id = match self.defining_use_anchor {
+            DefiningAnchor::Bubble | DefiningAnchor::Error => return None,
+            DefiningAnchor::Bind(bind) => bind,
+        };
         let item_kind = &self.tcx.hir().expect_item(def_id).kind;
 
         let hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, ..  }) = item_kind else {
diff --git a/compiler/rustc_trait_selection/src/traits/codegen.rs b/compiler/rustc_trait_selection/src/traits/codegen.rs
index 6ca630b74cc..c2b2e319951 100644
--- a/compiler/rustc_trait_selection/src/traits/codegen.rs
+++ b/compiler/rustc_trait_selection/src/traits/codegen.rs
@@ -3,7 +3,7 @@
 // seems likely that they should eventually be merged into more
 // general routines.
 
-use crate::infer::TyCtxtInferExt;
+use crate::infer::{DefiningAnchor, TyCtxtInferExt};
 use crate::traits::{
     FulfillmentContext, ImplSource, Obligation, ObligationCause, SelectionContext, TraitEngine,
     Unimplemented,
@@ -30,7 +30,9 @@ pub fn codegen_fulfill_obligation<'tcx>(
 
     // Do the initial selection for the obligation. This yields the
     // shallow result we are looking for -- that is, what specific impl.
-    tcx.infer_ctxt().enter(|infcx| {
+    tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bubble).enter(|infcx| {
+        //~^ HACK `Bubble` is required for
+        // this test to pass: type-alias-impl-trait/assoc-projection-ice.rs
         let mut selcx = SelectionContext::new(&infcx);
 
         let obligation_cause = ObligationCause::dummy();
@@ -69,7 +71,8 @@ pub fn codegen_fulfill_obligation<'tcx>(
 
         // Opaque types may have gotten their hidden types constrained, but we can ignore them safely
         // as they will get constrained elsewhere, too.
-        let _opaque_types = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
+        // (ouz-a) This is required for `type-alias-impl-trait/assoc-projection-ice.rs` to pass
+        let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
 
         debug!("Cache miss: {trait_ref:?} => {impl_source:?}");
         Ok(&*tcx.arena.alloc(impl_source))
diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs
index 69f3f03cfa9..9497d5c4528 100644
--- a/compiler/rustc_typeck/src/check/check.rs
+++ b/compiler/rustc_typeck/src/check/check.rs
@@ -14,7 +14,7 @@ use rustc_hir::lang_items::LangItem;
 use rustc_hir::{ItemKind, Node, PathSegment};
 use rustc_infer::infer::outlives::env::OutlivesEnvironment;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt};
+use rustc_infer::infer::{DefiningAnchor, RegionVariableOrigin, TyCtxtInferExt};
 use rustc_infer::traits::Obligation;
 use rustc_lint::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS;
 use rustc_middle::hir::nested_filter;
@@ -731,52 +731,52 @@ fn check_opaque_meets_bounds<'tcx>(
     };
     let param_env = tcx.param_env(defining_use_anchor);
 
-    tcx.infer_ctxt().with_opaque_type_inference(defining_use_anchor).enter(move |infcx| {
-        let ocx = ObligationCtxt::new(&infcx);
-        let opaque_ty = tcx.mk_opaque(def_id.to_def_id(), substs);
+    tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bind(defining_use_anchor)).enter(
+        move |infcx| {
+            let ocx = ObligationCtxt::new(&infcx);
+            let opaque_ty = tcx.mk_opaque(def_id.to_def_id(), substs);
 
-        let misc_cause = traits::ObligationCause::misc(span, hir_id);
+            let misc_cause = traits::ObligationCause::misc(span, hir_id);
 
-        match infcx.at(&misc_cause, param_env).eq(opaque_ty, hidden_type) {
-            Ok(infer_ok) => ocx.register_infer_ok_obligations(infer_ok),
-            Err(ty_err) => {
-                tcx.sess.delay_span_bug(
-                    span,
-                    &format!("could not unify `{hidden_type}` with revealed type:\n{ty_err}"),
-                );
+            match infcx.at(&misc_cause, param_env).eq(opaque_ty, hidden_type) {
+                Ok(infer_ok) => ocx.register_infer_ok_obligations(infer_ok),
+                Err(ty_err) => {
+                    tcx.sess.delay_span_bug(
+                        span,
+                        &format!("could not unify `{hidden_type}` with revealed type:\n{ty_err}"),
+                    );
+                }
             }
-        }
 
-        // Additionally require the hidden type to be well-formed with only the generics of the opaque type.
-        // Defining use functions may have more bounds than the opaque type, which is ok, as long as the
-        // hidden type is well formed even without those bounds.
-        let predicate =
-            ty::Binder::dummy(ty::PredicateKind::WellFormed(hidden_type.into())).to_predicate(tcx);
-        ocx.register_obligation(Obligation::new(misc_cause, param_env, predicate));
-
-        // Check that all obligations are satisfied by the implementation's
-        // version.
-        let errors = ocx.select_all_or_error();
-        if !errors.is_empty() {
-            infcx.report_fulfillment_errors(&errors, None, false);
-        }
-
-        match origin {
-            // Checked when type checking the function containing them.
-            hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => {}
-            // Can have different predicates to their defining use
-            hir::OpaqueTyOrigin::TyAlias => {
-                let outlives_environment = OutlivesEnvironment::new(param_env);
-                infcx.check_region_obligations_and_report_errors(
-                    defining_use_anchor,
-                    &outlives_environment,
-                );
+            // Additionally require the hidden type to be well-formed with only the generics of the opaque type.
+            // Defining use functions may have more bounds than the opaque type, which is ok, as long as the
+            // hidden type is well formed even without those bounds.
+            let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(hidden_type.into()))
+                .to_predicate(tcx);
+            ocx.register_obligation(Obligation::new(misc_cause, param_env, predicate));
+
+            // Check that all obligations are satisfied by the implementation's
+            // version.
+            let errors = ocx.select_all_or_error();
+            if !errors.is_empty() {
+                infcx.report_fulfillment_errors(&errors, None, false);
             }
-        }
-
-        // Clean up after ourselves
-        let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
-    });
+            match origin {
+                // Checked when type checking the function containing them.
+                hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => {}
+                // Can have different predicates to their defining use
+                hir::OpaqueTyOrigin::TyAlias => {
+                    let outlives_environment = OutlivesEnvironment::new(param_env);
+                    infcx.check_region_obligations_and_report_errors(
+                        defining_use_anchor,
+                        &outlives_environment,
+                    );
+                }
+            }
+            // Clean up after ourselves
+            let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
+        },
+    );
 }
 
 fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) {
diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs
index 3fb8e5080f3..020aa95d0be 100644
--- a/compiler/rustc_typeck/src/check/compare_method.rs
+++ b/compiler/rustc_typeck/src/check/compare_method.rs
@@ -1460,6 +1460,7 @@ pub fn check_type_bounds<'tcx>(
             .map(|e| e.map_bound(|e| *e).transpose_tuple2())
             .map(|(bound, span)| {
                 debug!(?bound);
+                // this is where opaque type is found
                 let concrete_ty_bound = bound.subst(tcx, rebased_substs);
                 debug!("check_type_bounds: concrete_ty_bound = {:?}", concrete_ty_bound);
 
@@ -1481,7 +1482,6 @@ pub fn check_type_bounds<'tcx>(
             ocx.register_obligations(obligations);
             ocx.register_obligation(obligation);
         }
-
         // Check that all obligations are satisfied by the implementation's
         // version.
         let errors = ocx.select_all_or_error();
diff --git a/src/test/ui/impl-trait/issues/issue-99348-impl-compatibility.rs b/src/test/ui/impl-trait/issues/issue-99348-impl-compatibility.rs
index d29a82f76a7..b05579f2166 100644
--- a/src/test/ui/impl-trait/issues/issue-99348-impl-compatibility.rs
+++ b/src/test/ui/impl-trait/issues/issue-99348-impl-compatibility.rs
@@ -6,7 +6,7 @@ type Tait = impl Sized;
 
 impl Foo for Concrete {
     type Item = Concrete;
-    //~^ mismatched types
+    //~^ type mismatch resolving
 }
 
 impl Bar for Concrete {
diff --git a/src/test/ui/impl-trait/issues/issue-99348-impl-compatibility.stderr b/src/test/ui/impl-trait/issues/issue-99348-impl-compatibility.stderr
index a25f0cd8761..f0dceb1b11a 100644
--- a/src/test/ui/impl-trait/issues/issue-99348-impl-compatibility.stderr
+++ b/src/test/ui/impl-trait/issues/issue-99348-impl-compatibility.stderr
@@ -1,15 +1,25 @@
-error[E0308]: mismatched types
+error[E0271]: type mismatch resolving `<Concrete as Bar>::Other == Concrete`
   --> $DIR/issue-99348-impl-compatibility.rs:8:17
    |
 LL | type Tait = impl Sized;
-   |             ---------- the expected opaque type
+   |             ---------- the found opaque type
 ...
 LL |     type Item = Concrete;
-   |                 ^^^^^^^^ types differ
+   |                 ^^^^^^^^ type mismatch resolving `<Concrete as Bar>::Other == Concrete`
    |
-   = note: expected opaque type `Tait`
-                   found struct `Concrete`
+note: expected this to be `Concrete`
+  --> $DIR/issue-99348-impl-compatibility.rs:13:18
+   |
+LL |     type Other = Tait;
+   |                  ^^^^
+   = note:   expected struct `Concrete`
+           found opaque type `Tait`
+note: required by a bound in `Foo::Item`
+  --> $DIR/issue-99348-impl-compatibility.rs:17:20
+   |
+LL |     type Item: Bar<Other = Self>;
+   |                    ^^^^^^^^^^^^ required by this bound in `Foo::Item`
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0308`.
+For more information about this error, try `rustc --explain E0271`.
diff --git a/src/test/ui/parser/fn-header-semantic-fail.rs b/src/test/ui/parser/fn-header-semantic-fail.rs
index c2954868f78..8ff14fb1f30 100644
--- a/src/test/ui/parser/fn-header-semantic-fail.rs
+++ b/src/test/ui/parser/fn-header-semantic-fail.rs
@@ -27,7 +27,7 @@ fn main() {
     struct Y;
     impl X for Y {
         async fn ft1() {} //~ ERROR functions in traits cannot be declared `async`
-        //~^ ERROR impl has stricter requirements than trait
+        //~^ ERROR has an incompatible type for trait
         unsafe fn ft2() {} // OK.
         const fn ft3() {} //~ ERROR functions in traits cannot be declared const
         extern "C" fn ft4() {}
@@ -36,7 +36,7 @@ fn main() {
         //~| ERROR functions in traits cannot be declared const
         //~| ERROR functions cannot be both `const` and `async`
         //~| ERROR cycle detected
-        //~| ERROR impl has stricter requirements than trait
+        //~| ERROR has an incompatible type for trait
     }
 
     impl Y {
diff --git a/src/test/ui/parser/fn-header-semantic-fail.stderr b/src/test/ui/parser/fn-header-semantic-fail.stderr
index 75d27c614e2..bc51ba8b8c5 100644
--- a/src/test/ui/parser/fn-header-semantic-fail.stderr
+++ b/src/test/ui/parser/fn-header-semantic-fail.stderr
@@ -216,23 +216,41 @@ LL | |     }
 LL | | }
    | |_^
 
-error[E0276]: impl has stricter requirements than trait
-  --> $DIR/fn-header-semantic-fail.rs:29:9
+error[E0053]: method `ft1` has an incompatible type for trait
+  --> $DIR/fn-header-semantic-fail.rs:29:24
    |
-LL |         async fn ft1();
-   |         --------------- definition of `ft1` from trait
-...
 LL |         async fn ft1() {}
-   |         ^^^^^^^^^^^^^^ impl has extra requirement `(): Future`
+   |                        ^
+   |                        |
+   |                        checked the `Output` of this `async fn`, found opaque type
+   |                        expected `()`, found opaque type
+   |
+   = note: while checking the return type of the `async fn`
+note: type in trait
+  --> $DIR/fn-header-semantic-fail.rs:17:23
+   |
+LL |         async fn ft1();
+   |                       ^
+   = note: expected fn pointer `fn()`
+              found fn pointer `fn() -> impl Future<Output = ()>`
 
-error[E0276]: impl has stricter requirements than trait
-  --> $DIR/fn-header-semantic-fail.rs:34:9
+error[E0053]: method `ft5` has an incompatible type for trait
+  --> $DIR/fn-header-semantic-fail.rs:34:48
    |
-LL |         const async unsafe extern "C" fn ft5();
-   |         --------------------------------------- definition of `ft5` from trait
-...
 LL |         const async unsafe extern "C" fn ft5() {}
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `(): Future`
+   |                                                ^
+   |                                                |
+   |                                                checked the `Output` of this `async fn`, found opaque type
+   |                                                expected `()`, found opaque type
+   |
+   = note: while checking the return type of the `async fn`
+note: type in trait
+  --> $DIR/fn-header-semantic-fail.rs:21:47
+   |
+LL |         const async unsafe extern "C" fn ft5();
+   |                                               ^
+   = note: expected fn pointer `unsafe extern "C" fn()`
+              found fn pointer `unsafe extern "C" fn() -> impl Future<Output = ()>`
 
 error[E0391]: cycle detected when computing type of `main::<impl at $DIR/fn-header-semantic-fail.rs:28:5: 28:17>::ft5::{opaque#0}`
   --> $DIR/fn-header-semantic-fail.rs:34:48
@@ -308,5 +326,5 @@ LL | | }
 
 error: aborting due to 23 previous errors
 
-Some errors have detailed explanations: E0276, E0379, E0391, E0706.
-For more information about an error, try `rustc --explain E0276`.
+Some errors have detailed explanations: E0053, E0379, E0391, E0706.
+For more information about an error, try `rustc --explain E0053`.
diff --git a/src/test/ui/resolve/issue-70736-async-fn-no-body-def-collector.rs b/src/test/ui/resolve/issue-70736-async-fn-no-body-def-collector.rs
index 6facc467f7a..aaf0f7eaef0 100644
--- a/src/test/ui/resolve/issue-70736-async-fn-no-body-def-collector.rs
+++ b/src/test/ui/resolve/issue-70736-async-fn-no-body-def-collector.rs
@@ -14,7 +14,7 @@ trait B {
 impl B for A {
     async fn associated(); //~ ERROR without body
     //~^ ERROR cannot be declared `async`
-    //~| ERROR impl has stricter requirements than trait
+    //~| ERROR has an incompatible type for trait
 }
 
 fn main() {}
diff --git a/src/test/ui/resolve/issue-70736-async-fn-no-body-def-collector.stderr b/src/test/ui/resolve/issue-70736-async-fn-no-body-def-collector.stderr
index c144060a859..d3214458eac 100644
--- a/src/test/ui/resolve/issue-70736-async-fn-no-body-def-collector.stderr
+++ b/src/test/ui/resolve/issue-70736-async-fn-no-body-def-collector.stderr
@@ -44,16 +44,25 @@ LL |     async fn associated();
    = note: `async` trait functions are not currently supported
    = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
 
-error[E0276]: impl has stricter requirements than trait
-  --> $DIR/issue-70736-async-fn-no-body-def-collector.rs:15:5
+error[E0053]: method `associated` has an incompatible type for trait
+  --> $DIR/issue-70736-async-fn-no-body-def-collector.rs:15:26
    |
 LL |     async fn associated();
-   |     ---------------------- definition of `associated` from trait
-...
+   |                          ^
+   |                          |
+   |                          checked the `Output` of this `async fn`, found opaque type
+   |                          expected `()`, found opaque type
+   |
+   = note: while checking the return type of the `async fn`
+note: type in trait
+  --> $DIR/issue-70736-async-fn-no-body-def-collector.rs:11:26
+   |
 LL |     async fn associated();
-   |     ^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `(): Future`
+   |                          ^
+   = note: expected fn pointer `fn()`
+              found fn pointer `fn() -> impl Future<Output = ()>`
 
 error: aborting due to 6 previous errors
 
-Some errors have detailed explanations: E0276, E0706.
-For more information about an error, try `rustc --explain E0276`.
+Some errors have detailed explanations: E0053, E0706.
+For more information about an error, try `rustc --explain E0053`.
diff --git a/src/test/ui/type-alias-impl-trait/issue-53398-cyclic-types.rs b/src/test/ui/type-alias-impl-trait/issue-53398-cyclic-types.rs
index 377ce85e8b2..4a11bb5020e 100644
--- a/src/test/ui/type-alias-impl-trait/issue-53398-cyclic-types.rs
+++ b/src/test/ui/type-alias-impl-trait/issue-53398-cyclic-types.rs
@@ -3,7 +3,7 @@
 type Foo = impl Fn() -> Foo;
 
 fn foo() -> Foo {
-//~^ ERROR: overflow evaluating the requirement `fn() -> Foo {foo}: Sized`
+//~^ ERROR: overflow evaluating the requirement
     foo
 }
 
diff --git a/src/test/ui/type-alias-impl-trait/issue-53398-cyclic-types.stderr b/src/test/ui/type-alias-impl-trait/issue-53398-cyclic-types.stderr
index d20b1cc6d85..00c682b2193 100644
--- a/src/test/ui/type-alias-impl-trait/issue-53398-cyclic-types.stderr
+++ b/src/test/ui/type-alias-impl-trait/issue-53398-cyclic-types.stderr
@@ -1,10 +1,8 @@
-error[E0275]: overflow evaluating the requirement `fn() -> Foo {foo}: Sized`
+error[E0275]: overflow evaluating the requirement `<fn() -> Foo {foo} as FnOnce<()>>::Output == fn() -> Foo {foo}`
   --> $DIR/issue-53398-cyclic-types.rs:5:13
    |
 LL | fn foo() -> Foo {
    |             ^^^
-   |
-   = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_53398_cyclic_types`)
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/type-alias-impl-trait/issue-57961.rs b/src/test/ui/type-alias-impl-trait/issue-57961.rs
new file mode 100644
index 00000000000..472886c9caa
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/issue-57961.rs
@@ -0,0 +1,18 @@
+#![feature(type_alias_impl_trait)]
+
+type X = impl Sized;
+
+trait Foo {
+    type Bar: Iterator<Item = X>;
+}
+
+impl Foo for () {
+    type Bar = std::vec::IntoIter<u32>;
+    //~^ ERROR type mismatch resolving `<std::vec::IntoIter<u32> as Iterator>::Item == X
+}
+
+fn incoherent() {
+    let f: X = 22_i32;
+}
+
+fn main() {}
diff --git a/src/test/ui/type-alias-impl-trait/issue-57961.stderr b/src/test/ui/type-alias-impl-trait/issue-57961.stderr
new file mode 100644
index 00000000000..ed4caf6ce68
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/issue-57961.stderr
@@ -0,0 +1,20 @@
+error[E0271]: type mismatch resolving `<std::vec::IntoIter<u32> as Iterator>::Item == X`
+  --> $DIR/issue-57961.rs:10:16
+   |
+LL | type X = impl Sized;
+   |          ---------- the expected opaque type
+...
+LL |     type Bar = std::vec::IntoIter<u32>;
+   |                ^^^^^^^^^^^^^^^^^^^^^^^ expected opaque type, found `u32`
+   |
+   = note: expected opaque type `X`
+                     found type `u32`
+note: required by a bound in `Foo::Bar`
+  --> $DIR/issue-57961.rs:6:24
+   |
+LL |     type Bar: Iterator<Item = X>;
+   |                        ^^^^^^^^ required by this bound in `Foo::Bar`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0271`.