Change:
<!-- Thank you for filing a bug report! Please provide a short summary of the bug, along with any information you feel relevant to replicating the bug. --I tried this code: I expected to see this happen: compile error that said the return type is wrong. Instead, this happened: compiled without error <!-- If you're using the stable version of the compiler, you should also check if the bug also exists in the beta or nightly versions. --:
cc

Discussion:
// substitutions. use crate::FnCtxt; <del> use hir::def_id::LocalDefId; </del> use rustc_data_structures::unord::ExtendUnord; use rustc_errors::{ErrorGuaranteed, StashKey}; use rustc_hir as hir;

use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282; use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCoercion}; use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; <del> use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt}; </del> <ins> use rustc_middle::ty::visit::TypeVisitableExt; </ins> use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::symbol::sym; use rustc_span::Span; use std::mem; <del> use std::ops::ControlFlow; </del> /////////////////////////////////////////////////////////////////////////// // Entry point

let hidden_type = self.resolve(decl.hidden_type, &decl.hidden_type.span); let opaque_type_key = self.resolve(opaque_type_key, &decl.hidden_type.span); <del> struct RecursionChecker { def_id: LocalDefId, } impl<'tcx> ty::TypeVisitor<TyCtxt<'tcx>> for RecursionChecker { type BreakTy = (); fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = *t.kind() { if def_id == self.def_id.to_def_id() { return ControlFlow::Break(()); } } t.super_visit_with(self) } } if hidden_type .visit_with(&mut RecursionChecker { def_id: opaque_type_key.def_id }) .is_break() </del> <ins> if let ty::Alias(ty::Opaque, alias_ty) = hidden_type.ty.kind() && alias_ty.def_id == opaque_type_key.def_id.to_def_id() && alias_ty.args == opaque_type_key.args </ins> { continue; }

<ins> // issue: 113314 #![feature(type_alias_impl_trait)] type Op = impl std::fmt::Display; fn foo() -> Op { &"hello world" } fn transform<S>() -> impl std::fmt::Display { &0usize } fn bad() -> Op { transform::<Op>() //~^ ERROR concrete type differs from previous defining opaque type use } fn main() { let mut x = foo(); println!("{x}"); x = bad(); println!("{x}"); } </ins>

<ins> error: concrete type differs from previous defining opaque type use --> $DIR/recursive-tait-conflicting-defn-2.rs:12:5 | LL |     transform::<Op>() |     ^^^^^^^^^^^^^^^^^ expected `&'static &'static str`, got `impl std::fmt::Display` | note: previous use here --> $DIR/recursive-tait-conflicting-defn-2.rs:6:18 | LL | fn foo() -> Op { &"hello world" } |                  ^^^^^^^^^^^^^^ error: aborting due to previous error </ins>

<ins> // issue: 113596 #![feature(type_alias_impl_trait)] trait Test {} struct A; impl Test for A {} struct B<T> { inner: T, } impl<T: Test> Test for B<T> {} type TestImpl = impl Test; fn test() -> TestImpl { A } fn make_option() -> Option<TestImpl> { Some(test()) } fn make_option2() -> Option<TestImpl> { let inner = make_option().unwrap(); Some(B { inner }) //~^ ERROR concrete type differs from previous defining opaque type use } fn main() {} </ins>

<ins> error: concrete type differs from previous defining opaque type use --> $DIR/recursive-tait-conflicting-defn.rs:30:3 | LL |   Some(B { inner }) |   ^^^^^^^^^^^^^^^^^ expected `A`, got `B<TestImpl>` | note: previous use here --> $DIR/recursive-tait-conflicting-defn.rs:20:3 | LL |   A |   ^ error: aborting due to previous error </ins>