about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-10-25 22:17:11 +0000
committerbors <bors@rust-lang.org>2023-10-25 22:17:11 +0000
commit7ac9a3a124da8f15ef53b70ff7a60b890abe83a6 (patch)
tree1bb3553ca0223662c1f552bef123f79f828f5640
parentab5c841a1f3c09edc5ea07722519627c960aed17 (diff)
parent4e4e5619af3693c194b85e787300492bc04b2d47 (diff)
Auto merge of #117193 - matthiaskrgr:rollup-bygfdcd, r=matthiaskrgr
Rollup of 6 pull requests

Successful merges:

 - #116401 (Return multiple object-safety violation errors and code improvements to the object-safety check)
 - #116553 (Do not suggest 'Trait<Assoc=arg>' when in trait impl)
 - #116931 (Improve the warning messages for the `#[diagnostic::on_unimplemented]`)
 - #117008 (Uplift `Canonical` to `rustc_type_ir`)
 - #117009 (On unresolved imports, suggest a disambiguated path if necessary to avoid collision with local items)
 - #117175 (Rename AsyncCoroutineKind to CoroutineSource)

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs6
-rw-r--r--compiler/rustc_ast_lowering/src/item.rs2
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs6
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_name.rs6
-rw-r--r--compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs8
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/ops.rs6
-rw-r--r--compiler/rustc_hir/src/hir.rs51
-rw-r--r--compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs70
-rw-r--r--compiler/rustc_hir_typeck/src/callee.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/closure.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs3
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs6
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs21
-rw-r--r--compiler/rustc_middle/src/infer/canonical.rs80
-rw-r--r--compiler/rustc_middle/src/ty/context.rs3
-rw-r--r--compiler/rustc_middle/src/ty/error.rs8
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs4
-rw-r--r--compiler/rustc_middle/src/ty/structural_impls.rs1
-rw-r--r--compiler/rustc_middle/src/ty/typeck_results.rs34
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs58
-rw-r--r--compiler/rustc_smir/src/rustc_smir/mod.rs8
-rw-r--r--compiler/rustc_trait_selection/messages.ftl5
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs57
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs12
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/object_safety.rs84
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/normalize.rs2
-rw-r--r--compiler/rustc_type_ir/src/canonical.rs169
-rw-r--r--compiler/rustc_type_ir/src/interner.rs1
-rw-r--r--compiler/rustc_type_ir/src/lib.rs2
-rw-r--r--compiler/rustc_type_ir/src/macros.rs1
-rw-r--r--compiler/rustc_type_ir/src/region_kind.rs2
-rw-r--r--compiler/rustc_type_ir/src/ty_kind.rs2
-rw-r--r--compiler/stable_mir/src/mir/body.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/async_yields_async.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/await_holding_invalid.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_async_fn.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_question_mark.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_async_block.rs4
-rw-r--r--tests/ui/async-await/async-await-let-else.stderr4
-rw-r--r--tests/ui/async-await/issue-68112.stderr2
-rw-r--r--tests/ui/async-await/issue-70935-complex-spans.stderr2
-rw-r--r--tests/ui/async-await/issues/issue-67893.stderr2
-rw-r--r--tests/ui/async-await/partial-drop-partial-reinit.rs2
-rw-r--r--tests/ui/async-await/partial-drop-partial-reinit.stderr2
-rw-r--r--tests/ui/const-generics/generic_const_exprs/object-safety-err-ret.stderr7
-rw-r--r--tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.rs8
-rw-r--r--tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.stderr77
-rw-r--r--tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.rs10
-rw-r--r--tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.stderr36
-rw-r--r--tests/ui/imports/issue-56125.stderr12
-rw-r--r--tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.rs43
-rw-r--r--tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.stderr109
-rw-r--r--tests/ui/unresolved/auxiliary/library.rs1
-rw-r--r--tests/ui/unresolved/unresolved-import-avoid-suggesting-global-path.rs31
-rw-r--r--tests/ui/unresolved/unresolved-import-avoid-suggesting-global-path.stderr25
-rw-r--r--tests/ui/unresolved/unresolved-import-suggest-disambiguated-crate-name.fixed19
-rw-r--r--tests/ui/unresolved/unresolved-import-suggest-disambiguated-crate-name.rs19
-rw-r--r--tests/ui/unresolved/unresolved-import-suggest-disambiguated-crate-name.stderr14
59 files changed, 857 insertions, 320 deletions
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index 4f1b13870fd..b82f878ea87 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -188,7 +188,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     e.id,
                     None,
                     e.span,
-                    hir::AsyncCoroutineKind::Block,
+                    hir::CoroutineSource::Block,
                     |this| this.with_new_scopes(|this| this.lower_block_expr(block)),
                 ),
                 ExprKind::Await(expr, await_kw_span) => self.lower_expr_await(*await_kw_span, expr),
@@ -598,7 +598,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
         closure_node_id: NodeId,
         ret_ty: Option<hir::FnRetTy<'hir>>,
         span: Span,
-        async_gen_kind: hir::AsyncCoroutineKind,
+        async_gen_kind: hir::CoroutineSource,
         body: impl FnOnce(&mut Self) -> hir::Expr<'hir>,
     ) -> hir::ExprKind<'hir> {
         let output = ret_ty.unwrap_or_else(|| hir::FnRetTy::DefaultReturn(self.lower_span(span)));
@@ -1005,7 +1005,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     inner_closure_id,
                     async_ret_ty,
                     body.span,
-                    hir::AsyncCoroutineKind::Closure,
+                    hir::CoroutineSource::Closure,
                     |this| this.with_new_scopes(|this| this.lower_expr_mut(body)),
                 );
                 let hir_id = this.lower_node_id(inner_closure_id);
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index 3c165f87dbf..ca851bd4d35 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -1206,7 +1206,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 closure_id,
                 None,
                 body.span,
-                hir::AsyncCoroutineKind::Fn,
+                hir::CoroutineSource::Fn,
                 |this| {
                     // Create a block from the user's function body:
                     let user_body = this.lower_block_expr(body);
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index b5ad02dc688..928c25d1061 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -8,7 +8,7 @@ use rustc_errors::{
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::intravisit::{walk_block, walk_expr, Visitor};
-use rustc_hir::{AsyncCoroutineKind, CoroutineKind, LangItem};
+use rustc_hir::{CoroutineKind, CoroutineSource, LangItem};
 use rustc_infer::traits::ObligationCause;
 use rustc_middle::hir::nested_filter::OnlyBodies;
 use rustc_middle::mir::tcx::PlaceTy;
@@ -2506,8 +2506,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         let kind = match use_span.coroutine_kind() {
             Some(coroutine_kind) => match coroutine_kind {
                 CoroutineKind::Async(async_kind) => match async_kind {
-                    AsyncCoroutineKind::Block => "async block",
-                    AsyncCoroutineKind::Closure => "async closure",
+                    CoroutineSource::Block => "async block",
+                    CoroutineSource::Closure => "async closure",
                     _ => bug!("async block/closure expected, but async function found."),
                 },
                 CoroutineKind::Coroutine => "coroutine",
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
index de9ece3faba..e630ac7c4fa 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
@@ -682,9 +682,9 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
                 };
                 let mir_description = match hir.body(body).coroutine_kind {
                     Some(hir::CoroutineKind::Async(gen)) => match gen {
-                        hir::AsyncCoroutineKind::Block => " of async block",
-                        hir::AsyncCoroutineKind::Closure => " of async closure",
-                        hir::AsyncCoroutineKind::Fn => {
+                        hir::CoroutineSource::Block => " of async block",
+                        hir::CoroutineSource::Closure => " of async closure",
+                        hir::CoroutineSource::Fn => {
                             let parent_item =
                                 hir.get_by_def_id(hir.get_parent_item(mir_hir_id).def_id);
                             let output = &parent_item
diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
index e401f6bbcbf..5900c764073 100644
--- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
+++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
@@ -15,7 +15,7 @@ use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::stable_hasher::{Hash64, HashStable, StableHasher};
 use rustc_hir::def_id::DefId;
 use rustc_hir::definitions::{DefPathData, DefPathDataName, DisambiguatedDefPathData};
-use rustc_hir::{AsyncCoroutineKind, CoroutineKind, Mutability};
+use rustc_hir::{CoroutineKind, CoroutineSource, Mutability};
 use rustc_middle::ty::layout::{IntegerExt, TyAndLayout};
 use rustc_middle::ty::{self, ExistentialProjection, ParamEnv, Ty, TyCtxt};
 use rustc_middle::ty::{GenericArgKind, GenericArgsRef};
@@ -560,9 +560,9 @@ pub fn push_item_name(tcx: TyCtxt<'_>, def_id: DefId, qualified: bool, output: &
 
 fn coroutine_kind_label(coroutine_kind: Option<CoroutineKind>) -> &'static str {
     match coroutine_kind {
-        Some(CoroutineKind::Async(AsyncCoroutineKind::Block)) => "async_block",
-        Some(CoroutineKind::Async(AsyncCoroutineKind::Closure)) => "async_closure",
-        Some(CoroutineKind::Async(AsyncCoroutineKind::Fn)) => "async_fn",
+        Some(CoroutineKind::Async(CoroutineSource::Block)) => "async_block",
+        Some(CoroutineKind::Async(CoroutineSource::Closure)) => "async_closure",
+        Some(CoroutineKind::Async(CoroutineSource::Fn)) => "async_fn",
         Some(CoroutineKind::Coroutine) => "coroutine",
         None => "closure",
     }
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
index 616fab8fe7d..40183baccf8 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
@@ -360,7 +360,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallUnstable {
 pub struct Coroutine(pub hir::CoroutineKind);
 impl<'tcx> NonConstOp<'tcx> for Coroutine {
     fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status {
-        if let hir::CoroutineKind::Async(hir::AsyncCoroutineKind::Block) = self.0 {
+        if let hir::CoroutineKind::Async(hir::CoroutineSource::Block) = self.0 {
             Status::Unstable(sym::const_async_blocks)
         } else {
             Status::Forbidden
@@ -372,8 +372,8 @@ impl<'tcx> NonConstOp<'tcx> for Coroutine {
         ccx: &ConstCx<'_, 'tcx>,
         span: Span,
     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
-        let msg = format!("{}s are not allowed in {}s", self.0.descr(), ccx.const_kind());
-        if let hir::CoroutineKind::Async(hir::AsyncCoroutineKind::Block) = self.0 {
+        let msg = format!("{:#}s are not allowed in {}s", self.0, ccx.const_kind());
+        if let hir::CoroutineKind::Async(hir::CoroutineSource::Block) = self.0 {
             ccx.tcx.sess.create_feature_err(
                 errors::UnallowedOpInConstContext { span, msg },
                 sym::const_async_blocks,
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 63711f5804d..259af4f565b 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -1511,7 +1511,7 @@ impl<'hir> Body<'hir> {
 #[derive(HashStable_Generic, Encodable, Decodable)]
 pub enum CoroutineKind {
     /// An explicit `async` block or the body of an async function.
-    Async(AsyncCoroutineKind),
+    Async(CoroutineSource),
 
     /// A coroutine literal created via a `yield` inside a closure.
     Coroutine,
@@ -1520,56 +1520,45 @@ pub enum CoroutineKind {
 impl fmt::Display for CoroutineKind {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self {
-            CoroutineKind::Async(k) => fmt::Display::fmt(k, f),
+            CoroutineKind::Async(k) => {
+                if f.alternate() {
+                    f.write_str("`async` ")?;
+                } else {
+                    f.write_str("async ")?
+                }
+                k.fmt(f)
+            }
             CoroutineKind::Coroutine => f.write_str("coroutine"),
         }
     }
 }
 
-impl CoroutineKind {
-    pub fn descr(&self) -> &'static str {
-        match self {
-            CoroutineKind::Async(ask) => ask.descr(),
-            CoroutineKind::Coroutine => "coroutine",
-        }
-    }
-}
-
-/// In the case of a coroutine created as part of an async construct,
-/// which kind of async construct caused it to be created?
+/// In the case of a coroutine created as part of an async/gen construct,
+/// which kind of async/gen construct caused it to be created?
 ///
 /// This helps error messages but is also used to drive coercions in
 /// type-checking (see #60424).
 #[derive(Clone, PartialEq, Eq, Hash, Debug, Copy)]
 #[derive(HashStable_Generic, Encodable, Decodable)]
-pub enum AsyncCoroutineKind {
-    /// An explicit `async` block written by the user.
+pub enum CoroutineSource {
+    /// An explicit `async`/`gen` block written by the user.
     Block,
 
-    /// An explicit `async` closure written by the user.
+    /// An explicit `async`/`gen` closure written by the user.
     Closure,
 
-    /// The `async` block generated as the body of an async function.
+    /// The `async`/`gen` block generated as the body of an async/gen function.
     Fn,
 }
 
-impl fmt::Display for AsyncCoroutineKind {
+impl fmt::Display for CoroutineSource {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.write_str(match self {
-            AsyncCoroutineKind::Block => "async block",
-            AsyncCoroutineKind::Closure => "async closure body",
-            AsyncCoroutineKind::Fn => "async fn body",
-        })
-    }
-}
-
-impl AsyncCoroutineKind {
-    pub fn descr(&self) -> &'static str {
         match self {
-            AsyncCoroutineKind::Block => "`async` block",
-            AsyncCoroutineKind::Closure => "`async` closure body",
-            AsyncCoroutineKind::Fn => "`async fn` body",
+            CoroutineSource::Block => "block",
+            CoroutineSource::Closure => "closure body",
+            CoroutineSource::Fn => "fn body",
         }
+        .fmt(f)
     }
 }
 
diff --git a/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs b/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs
index 2b5f6fd214c..76bd370a641 100644
--- a/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs
+++ b/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs
@@ -129,6 +129,44 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
         if self.missing_lifetimes() { "lifetime" } else { "generic" }
     }
 
+    /// Returns true if the generic type is a trait
+    /// and is being referred to from one of its trait impls
+    fn is_in_trait_impl(&self) -> bool {
+        if self.tcx.is_trait(self.def_id) {
+            // Here we check if the reference to the generic type
+            // is from the 'of_trait' field of the enclosing impl
+
+            let parent = self.tcx.hir().get_parent(self.path_segment.hir_id);
+            let parent_item = self
+                .tcx
+                .hir()
+                .get_by_def_id(self.tcx.hir().get_parent_item(self.path_segment.hir_id).def_id);
+
+            // Get the HIR id of the trait ref
+            let hir::Node::TraitRef(hir::TraitRef { hir_ref_id: trait_ref_id, .. }) = parent else {
+                return false;
+            };
+
+            // Get the HIR id of the 'of_trait' field of the impl
+            let hir::Node::Item(hir::Item {
+                kind:
+                    hir::ItemKind::Impl(hir::Impl {
+                        of_trait: Some(hir::TraitRef { hir_ref_id: id_in_of_trait, .. }),
+                        ..
+                    }),
+                ..
+            }) = parent_item
+            else {
+                return false;
+            };
+
+            // Check that trait is referred to from the of_trait field of impl
+            trait_ref_id == id_in_of_trait
+        } else {
+            false
+        }
+    }
+
     fn num_provided_args(&self) -> usize {
         if self.missing_lifetimes() {
             self.num_provided_lifetime_args()
@@ -955,20 +993,26 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
         // If there is a single unbound associated type and a single excess generic param
         // suggest replacing the generic param with the associated type bound
         if provided_args_matches_unbound_traits && !unbound_types.is_empty() {
-            let unused_generics = &self.gen_args.args[self.num_expected_type_or_const_args()..];
-            let suggestions = iter::zip(unused_generics, &unbound_types)
-                .map(|(potential, name)| (potential.span().shrink_to_lo(), format!("{name} = ")))
-                .collect::<Vec<_>>();
+            // Don't suggest if we're in a trait impl as
+            // that would result in invalid syntax (fixes #116464)
+            if !self.is_in_trait_impl() {
+                let unused_generics = &self.gen_args.args[self.num_expected_type_or_const_args()..];
+                let suggestions = iter::zip(unused_generics, &unbound_types)
+                    .map(|(potential, name)| {
+                        (potential.span().shrink_to_lo(), format!("{name} = "))
+                    })
+                    .collect::<Vec<_>>();
 
-            if !suggestions.is_empty() {
-                err.multipart_suggestion_verbose(
-                    format!(
-                        "replace the generic bound{s} with the associated type{s}",
-                        s = pluralize!(unbound_types.len())
-                    ),
-                    suggestions,
-                    Applicability::MaybeIncorrect,
-                );
+                if !suggestions.is_empty() {
+                    err.multipart_suggestion_verbose(
+                        format!(
+                            "replace the generic bound{s} with the associated type{s}",
+                            s = pluralize!(unbound_types.len())
+                        ),
+                        suggestions,
+                        Applicability::MaybeIncorrect,
+                    );
+                }
             }
         } else if remove_entire_generics {
             let span = self
diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs
index 5eb68cf6b28..6b6d1574b2b 100644
--- a/compiler/rustc_hir_typeck/src/callee.rs
+++ b/compiler/rustc_hir_typeck/src/callee.rs
@@ -305,7 +305,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         ) = (parent_node, callee_node)
         {
             let fn_decl_span = if hir.body(body).coroutine_kind
-                == Some(hir::CoroutineKind::Async(hir::AsyncCoroutineKind::Closure))
+                == Some(hir::CoroutineKind::Async(hir::CoroutineSource::Closure))
             {
                 // Actually need to unwrap one more layer of HIR to get to
                 // the _real_ closure...
diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs
index cf8a4cafbb6..47bde21ceb2 100644
--- a/compiler/rustc_hir_typeck/src/closure.rs
+++ b/compiler/rustc_hir_typeck/src/closure.rs
@@ -636,7 +636,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 // In the case of the async block that we create for a function body,
                 // we expect the return type of the block to match that of the enclosing
                 // function.
-                Some(hir::CoroutineKind::Async(hir::AsyncCoroutineKind::Fn)) => {
+                Some(hir::CoroutineKind::Async(hir::CoroutineSource::Fn)) => {
                     debug!("closure is async fn body");
                     let def_id = self.tcx.hir().body_owner_def_id(body.id());
                     self.deduce_future_output_from_obligations(expr_def_id, def_id).unwrap_or_else(
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index afa5a3b9379..b5a07f0d3e9 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -26,7 +26,7 @@ use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt};
 use rustc_middle::ty::{
-    self, AdtKind, CanonicalUserType, GenericParamDefKind, Ty, TyCtxt, UserType,
+    self, AdtKind, CanonicalUserType, GenericParamDefKind, IsIdentity, Ty, TyCtxt, UserType,
 };
 use rustc_middle::ty::{GenericArgKind, GenericArgsRef, UserArgs, UserSelfTy};
 use rustc_session::lint;
@@ -207,6 +207,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     ) {
         debug!("fcx {}", self.tag());
 
+        // FIXME: is_identity being on `UserType` and not `Canonical<UserType>` is awkward
         if !canonical_user_type_annotation.is_identity() {
             self.typeck_results
                 .borrow_mut()
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
index e1dbf37743f..ca7dc298de6 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
@@ -10,8 +10,8 @@ use rustc_hir::def::Res;
 use rustc_hir::def::{CtorKind, CtorOf, DefKind};
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{
-    AsyncCoroutineKind, CoroutineKind, Expr, ExprKind, GenericBound, HirId, Node, Path, QPath,
-    Stmt, StmtKind, TyKind, WherePredicate,
+    CoroutineKind, CoroutineSource, Expr, ExprKind, GenericBound, HirId, Node, Path, QPath, Stmt,
+    StmtKind, TyKind, WherePredicate,
 };
 use rustc_hir_analysis::astconv::AstConv;
 use rustc_infer::traits::{self, StatementAsExpression};
@@ -536,7 +536,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 ty::Coroutine(def_id, ..)
                     if matches!(
                         self.tcx.coroutine_kind(def_id),
-                        Some(CoroutineKind::Async(AsyncCoroutineKind::Closure))
+                        Some(CoroutineKind::Async(CoroutineSource::Closure))
                     ) =>
                 {
                     errors::SuggestBoxing::AsyncBody
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index ba118f8110f..e4be435fded 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -1584,14 +1584,13 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                 target: &str,
                 types: &FxIndexMap<TyCategory, FxIndexSet<Span>>,
             ) {
-                for (key, values) in types.iter() {
+                for (kind, values) in types.iter() {
                     let count = values.len();
-                    let kind = key.descr();
                     for &sp in values {
                         err.span_label(
                             sp,
                             format!(
-                                "{}{} {}{}",
+                                "{}{} {:#}{}",
                                 if count == 1 { "the " } else { "one of the " },
                                 target,
                                 kind,
@@ -2952,17 +2951,19 @@ pub enum TyCategory {
     Foreign,
 }
 
-impl TyCategory {
-    fn descr(&self) -> &'static str {
+impl fmt::Display for TyCategory {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self {
-            Self::Closure => "closure",
-            Self::Opaque => "opaque type",
-            Self::OpaqueFuture => "future",
-            Self::Coroutine(gk) => gk.descr(),
-            Self::Foreign => "foreign type",
+            Self::Closure => "closure".fmt(f),
+            Self::Opaque => "opaque type".fmt(f),
+            Self::OpaqueFuture => "future".fmt(f),
+            Self::Coroutine(gk) => gk.fmt(f),
+            Self::Foreign => "foreign type".fmt(f),
         }
     }
+}
 
+impl TyCategory {
     pub fn from_ty(tcx: TyCtxt<'_>, ty: Ty<'_>) -> Option<(Self, DefId)> {
         match *ty.kind() {
             ty::Closure(def_id, _) => Some((Self::Closure, def_id)),
diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs
index c8f3c2a20a6..0b5426c3bb1 100644
--- a/compiler/rustc_middle/src/infer/canonical.rs
+++ b/compiler/rustc_middle/src/infer/canonical.rs
@@ -21,35 +21,17 @@
 //!
 //! [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html
 
-use crate::infer::MemberConstraint;
-use crate::mir::ConstraintCategory;
-use crate::ty::GenericArg;
-use crate::ty::{self, BoundVar, List, Region, Ty, TyCtxt};
 use rustc_macros::HashStable;
+use rustc_type_ir::Canonical as IrCanonical;
 use smallvec::SmallVec;
-use std::fmt::Display;
 use std::ops::Index;
 
-/// A "canonicalized" type `V` is one where all free inference
-/// variables have been rewritten to "canonical vars". These are
-/// numbered starting from 0 in order of first appearance.
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyDecodable, TyEncodable)]
-#[derive(HashStable, TypeFoldable, TypeVisitable)]
-pub struct Canonical<'tcx, V> {
-    pub value: V,
-    pub max_universe: ty::UniverseIndex,
-    pub variables: CanonicalVarInfos<'tcx>,
-}
+use crate::infer::MemberConstraint;
+use crate::mir::ConstraintCategory;
+use crate::ty::GenericArg;
+use crate::ty::{self, BoundVar, List, Region, Ty, TyCtxt};
 
-impl<'tcx, V: Display> std::fmt::Display for Canonical<'tcx, V> {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        write!(
-            f,
-            "Canonical {{ value: {}, max_universe: {:?}, variables: {:?} }}",
-            self.value, self.max_universe, self.variables
-        )
-    }
-}
+pub type Canonical<'tcx, V> = IrCanonical<TyCtxt<'tcx>, V>;
 
 pub type CanonicalVarInfos<'tcx> = &'tcx List<CanonicalVarInfo<'tcx>>;
 
@@ -379,56 +361,6 @@ impl<'tcx, R> QueryResponse<'tcx, R> {
     }
 }
 
-impl<'tcx, R> Canonical<'tcx, QueryResponse<'tcx, R>> {
-    pub fn is_proven(&self) -> bool {
-        self.value.is_proven()
-    }
-
-    pub fn is_ambiguous(&self) -> bool {
-        !self.is_proven()
-    }
-}
-
-impl<'tcx, V> Canonical<'tcx, V> {
-    /// Allows you to map the `value` of a canonical while keeping the
-    /// same set of bound variables.
-    ///
-    /// **WARNING:** This function is very easy to mis-use, hence the
-    /// name!  In particular, the new value `W` must use all **the
-    /// same type/region variables** in **precisely the same order**
-    /// as the original! (The ordering is defined by the
-    /// `TypeFoldable` implementation of the type in question.)
-    ///
-    /// An example of a **correct** use of this:
-    ///
-    /// ```rust,ignore (not real code)
-    /// let a: Canonical<'_, T> = ...;
-    /// let b: Canonical<'_, (T,)> = a.unchecked_map(|v| (v, ));
-    /// ```
-    ///
-    /// An example of an **incorrect** use of this:
-    ///
-    /// ```rust,ignore (not real code)
-    /// let a: Canonical<'tcx, T> = ...;
-    /// let ty: Ty<'tcx> = ...;
-    /// let b: Canonical<'tcx, (T, Ty<'tcx>)> = a.unchecked_map(|v| (v, ty));
-    /// ```
-    pub fn unchecked_map<W>(self, map_op: impl FnOnce(V) -> W) -> Canonical<'tcx, W> {
-        let Canonical { max_universe, variables, value } = self;
-        Canonical { max_universe, variables, value: map_op(value) }
-    }
-
-    /// Allows you to map the `value` of a canonical while keeping the same set of
-    /// bound variables.
-    ///
-    /// **WARNING:** This function is very easy to mis-use, hence the name! See
-    /// the comment of [Canonical::unchecked_map] for more details.
-    pub fn unchecked_rebind<W>(self, value: W) -> Canonical<'tcx, W> {
-        let Canonical { max_universe, variables, value: _ } = self;
-        Canonical { max_universe, variables, value }
-    }
-}
-
 pub type QueryOutlivesConstraint<'tcx> =
     (ty::OutlivesPredicate<GenericArg<'tcx>, Region<'tcx>>, ConstraintCategory<'tcx>);
 
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 6a9a8bcdc06..a669ff8d961 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -6,7 +6,7 @@ pub mod tls;
 
 use crate::arena::Arena;
 use crate::dep_graph::{DepGraph, DepKindStruct};
-use crate::infer::canonical::CanonicalVarInfo;
+use crate::infer::canonical::{CanonicalVarInfo, CanonicalVarInfos};
 use crate::lint::struct_lint_level;
 use crate::metadata::ModChild;
 use crate::middle::codegen_fn_attrs::CodegenFnAttrs;
@@ -88,6 +88,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
 
     type Binder<T> = Binder<'tcx, T>;
     type TypeAndMut = TypeAndMut<'tcx>;
+    type CanonicalVars = CanonicalVarInfos<'tcx>;
 
     type Ty = Ty<'tcx>;
     type Tys = &'tcx List<Ty<'tcx>>;
diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs
index 184a70ed4cb..738bb5e8b19 100644
--- a/compiler/rustc_middle/src/ty/error.rs
+++ b/compiler/rustc_middle/src/ty/error.rs
@@ -241,7 +241,9 @@ impl<'tcx> Ty<'tcx> {
             }
             ty::Dynamic(..) => "trait object".into(),
             ty::Closure(..) => "closure".into(),
-            ty::Coroutine(def_id, ..) => tcx.coroutine_kind(def_id).unwrap().descr().into(),
+            ty::Coroutine(def_id, ..) => {
+                format!("{:#}", tcx.coroutine_kind(def_id).unwrap()).into()
+            }
             ty::CoroutineWitness(..) => "coroutine witness".into(),
             ty::Infer(ty::TyVar(_)) => "inferred type".into(),
             ty::Infer(ty::IntVar(_)) => "integer".into(),
@@ -299,7 +301,9 @@ impl<'tcx> Ty<'tcx> {
             ty::FnPtr(_) => "fn pointer".into(),
             ty::Dynamic(..) => "trait object".into(),
             ty::Closure(..) => "closure".into(),
-            ty::Coroutine(def_id, ..) => tcx.coroutine_kind(def_id).unwrap().descr().into(),
+            ty::Coroutine(def_id, ..) => {
+                format!("{:#}", tcx.coroutine_kind(def_id).unwrap()).into()
+            }
             ty::CoroutineWitness(..) => "coroutine witness".into(),
             ty::Tuple(..) => "tuple".into(),
             ty::Placeholder(..) => "higher-ranked type".into(),
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index cc0db39ac57..5d6d46e16b7 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -106,8 +106,8 @@ pub use self::sty::{
 };
 pub use self::trait_def::TraitDef;
 pub use self::typeck_results::{
-    CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, TypeckResults,
-    UserType, UserTypeAnnotationIndex,
+    CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, IsIdentity,
+    TypeckResults, UserType, UserTypeAnnotationIndex,
 };
 
 pub mod _match;
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index 7f86acd4bf5..6af68bc5dba 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -449,7 +449,6 @@ TrivialTypeTraversalImpls! {
     crate::ty::IntVarValue,
     crate::ty::adjustment::PointerCoercion,
     crate::ty::RegionVid,
-    crate::ty::UniverseIndex,
     crate::ty::Variance,
     ::rustc_span::Span,
     ::rustc_span::symbol::Ident,
diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs
index 7d516410b20..58ad1eb900f 100644
--- a/compiler/rustc_middle/src/ty/typeck_results.rs
+++ b/compiler/rustc_middle/src/ty/typeck_results.rs
@@ -594,10 +594,27 @@ pub struct CanonicalUserTypeAnnotation<'tcx> {
 /// Canonical user type annotation.
 pub type CanonicalUserType<'tcx> = Canonical<'tcx, UserType<'tcx>>;
 
-impl<'tcx> CanonicalUserType<'tcx> {
+/// A user-given type annotation attached to a constant. These arise
+/// from constants that are named via paths, like `Foo::<A>::new` and
+/// so forth.
+#[derive(Copy, Clone, Debug, PartialEq, TyEncodable, TyDecodable)]
+#[derive(Eq, Hash, HashStable, TypeFoldable, TypeVisitable)]
+pub enum UserType<'tcx> {
+    Ty(Ty<'tcx>),
+
+    /// The canonical type is the result of `type_of(def_id)` with the
+    /// given substitutions applied.
+    TypeOf(DefId, UserArgs<'tcx>),
+}
+
+pub trait IsIdentity {
+    fn is_identity(&self) -> bool;
+}
+
+impl<'tcx> IsIdentity for CanonicalUserType<'tcx> {
     /// Returns `true` if this represents a substitution of the form `[?0, ?1, ?2]`,
     /// i.e., each thing is mapped to a canonical variable with the same index.
-    pub fn is_identity(&self) -> bool {
+    fn is_identity(&self) -> bool {
         match self.value {
             UserType::Ty(_) => false,
             UserType::TypeOf(_, user_args) => {
@@ -640,19 +657,6 @@ impl<'tcx> CanonicalUserType<'tcx> {
     }
 }
 
-/// A user-given type annotation attached to a constant. These arise
-/// from constants that are named via paths, like `Foo::<A>::new` and
-/// so forth.
-#[derive(Copy, Clone, Debug, PartialEq, TyEncodable, TyDecodable)]
-#[derive(Eq, Hash, HashStable, TypeFoldable, TypeVisitable)]
-pub enum UserType<'tcx> {
-    Ty(Ty<'tcx>),
-
-    /// The canonical type is the result of `type_of(def_id)` with the
-    /// given substitutions applied.
-    TypeOf(DefId, UserArgs<'tcx>),
-}
-
 impl<'tcx> std::fmt::Display for UserType<'tcx> {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         match self {
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index 4ad838e5aed..edcc22d56c6 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -25,7 +25,7 @@ use rustc_span::hygiene::MacroKind;
 use rustc_span::source_map::SourceMap;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{BytePos, Span, SyntaxContext};
-use thin_vec::ThinVec;
+use thin_vec::{thin_vec, ThinVec};
 
 use crate::errors::{
     AddedMacroUse, ChangeImportBinding, ChangeImportBindingSuggestion, ConsiderAddingADerive,
@@ -1147,7 +1147,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         namespace: Namespace,
         parent_scope: &ParentScope<'a>,
         start_module: Module<'a>,
-        crate_name: Ident,
+        crate_path: ThinVec<ast::PathSegment>,
         filter_fn: FilterFn,
     ) -> Vec<ImportSuggestion>
     where
@@ -1163,8 +1163,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             Some(x) => Some(x),
         } {
             let in_module_is_extern = !in_module.def_id().is_local();
-            // We have to visit module children in deterministic order to avoid
-            // instabilities in reported imports (#43552).
             in_module.for_each_child(self, |this, ident, ns, name_binding| {
                 // avoid non-importable candidates
                 if !name_binding.is_importable() {
@@ -1214,12 +1212,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     let res = name_binding.res();
                     if filter_fn(res) {
                         // create the path
-                        let mut segms = path_segments.clone();
-                        if lookup_ident.span.at_least_rust_2018() {
+                        let mut segms = if lookup_ident.span.at_least_rust_2018() {
                             // crate-local absolute paths start with `crate::` in edition 2018
                             // FIXME: may also be stabilized for Rust 2015 (Issues #45477, #44660)
-                            segms.insert(0, ast::PathSegment::from_ident(crate_name));
-                        }
+                            crate_path.clone()
+                        } else {
+                            ThinVec::new()
+                        };
+                        segms.append(&mut path_segments.clone());
 
                         segms.push(ast::PathSegment::from_ident(ident));
                         let path = Path { span: name_binding.span, segments: segms, tokens: None };
@@ -1318,18 +1318,18 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
     where
         FilterFn: Fn(Res) -> bool,
     {
+        let crate_path = thin_vec![ast::PathSegment::from_ident(Ident::with_dummy_span(kw::Crate))];
         let mut suggestions = self.lookup_import_candidates_from_module(
             lookup_ident,
             namespace,
             parent_scope,
             self.graph_root,
-            Ident::with_dummy_span(kw::Crate),
+            crate_path,
             &filter_fn,
         );
 
         if lookup_ident.span.at_least_rust_2018() {
-            let extern_prelude_names = self.extern_prelude.clone();
-            for (ident, _) in extern_prelude_names.into_iter() {
+            for ident in self.extern_prelude.clone().into_keys() {
                 if ident.span.from_expansion() {
                     // Idents are adjusted to the root context before being
                     // resolved in the extern prelude, so reporting this to the
@@ -1340,13 +1340,43 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 }
                 let crate_id = self.crate_loader(|c| c.maybe_process_path_extern(ident.name));
                 if let Some(crate_id) = crate_id {
-                    let crate_root = self.expect_module(crate_id.as_def_id());
+                    let crate_def_id = crate_id.as_def_id();
+                    let crate_root = self.expect_module(crate_def_id);
+
+                    // Check if there's already an item in scope with the same name as the crate.
+                    // If so, we have to disambiguate the potential import suggestions by making
+                    // the paths *global* (i.e., by prefixing them with `::`).
+                    let needs_disambiguation =
+                        self.resolutions(parent_scope.module).borrow().iter().any(
+                            |(key, name_resolution)| {
+                                if key.ns == TypeNS
+                                    && key.ident == ident
+                                    && let Some(binding) = name_resolution.borrow().binding
+                                {
+                                    match binding.res() {
+                                        // No disambiguation needed if the identically named item we
+                                        // found in scope actually refers to the crate in question.
+                                        Res::Def(_, def_id) => def_id != crate_def_id,
+                                        Res::PrimTy(_) => true,
+                                        _ => false,
+                                    }
+                                } else {
+                                    false
+                                }
+                            },
+                        );
+                    let mut crate_path = ThinVec::new();
+                    if needs_disambiguation {
+                        crate_path.push(ast::PathSegment::path_root(rustc_span::DUMMY_SP));
+                    }
+                    crate_path.push(ast::PathSegment::from_ident(ident));
+
                     suggestions.extend(self.lookup_import_candidates_from_module(
                         lookup_ident,
                         namespace,
                         parent_scope,
                         crate_root,
-                        ident,
+                        crate_path,
                         &filter_fn,
                     ));
                 }
@@ -2554,7 +2584,7 @@ fn show_candidates(
 
     candidates.iter().for_each(|c| {
         (if c.accessible { &mut accessible_path_strings } else { &mut inaccessible_path_strings })
-            .push((path_names_to_string(&c.path), c.descr, c.did, &c.note, c.via_import))
+            .push((pprust::path_to_string(&c.path), c.descr, c.did, &c.note, c.via_import))
     });
 
     // we want consistent results across executions, but candidates are produced
diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs
index e772ae942fa..928536721c9 100644
--- a/compiler/rustc_smir/src/rustc_smir/mod.rs
+++ b/compiler/rustc_smir/src/rustc_smir/mod.rs
@@ -883,13 +883,13 @@ impl<'tcx> Stable<'tcx> for mir::AggregateKind<'tcx> {
 impl<'tcx> Stable<'tcx> for rustc_hir::CoroutineKind {
     type T = stable_mir::mir::CoroutineKind;
     fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
-        use rustc_hir::{AsyncCoroutineKind, CoroutineKind};
+        use rustc_hir::{CoroutineKind, CoroutineSource};
         match self {
             CoroutineKind::Async(async_gen) => {
                 let async_gen = match async_gen {
-                    AsyncCoroutineKind::Block => stable_mir::mir::AsyncCoroutineKind::Block,
-                    AsyncCoroutineKind::Closure => stable_mir::mir::AsyncCoroutineKind::Closure,
-                    AsyncCoroutineKind::Fn => stable_mir::mir::AsyncCoroutineKind::Fn,
+                    CoroutineSource::Block => stable_mir::mir::CoroutineSource::Block,
+                    CoroutineSource::Closure => stable_mir::mir::CoroutineSource::Closure,
+                    CoroutineSource::Fn => stable_mir::mir::CoroutineSource::Fn,
                 };
                 stable_mir::mir::CoroutineKind::Async(async_gen)
             }
diff --git a/compiler/rustc_trait_selection/messages.ftl b/compiler/rustc_trait_selection/messages.ftl
index 20253b32add..a9792ca2795 100644
--- a/compiler/rustc_trait_selection/messages.ftl
+++ b/compiler/rustc_trait_selection/messages.ftl
@@ -28,6 +28,11 @@ trait_selection_invalid_on_clause_in_rustc_on_unimplemented = invalid `on`-claus
     .label = invalid on-clause here
 
 trait_selection_malformed_on_unimplemented_attr = malformed `on_unimplemented` attribute
+    .help = only `message`, `note` and `label` are allowed as options
+    .label = invalid option found here
+
+trait_selection_missing_options_for_on_unimplemented_attr = missing options for `on_unimplemented` attribute
+    .help = at least one of the `message`, `note` and `label` options are expected
 
 trait_selection_negative_positive_conflict = found both positive and negative implementation of trait `{$trait_desc}`{$self_desc ->
         [none] {""}
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
index 016c44c20f6..c96e41b88bd 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
@@ -1,5 +1,8 @@
 use super::{ObligationCauseCode, PredicateObligation};
 use crate::infer::error_reporting::TypeErrCtxt;
+use rustc_ast::AttrArgs;
+use rustc_ast::AttrArgsEq;
+use rustc_ast::AttrKind;
 use rustc_ast::{Attribute, MetaItem, NestedMetaItem};
 use rustc_attr as attr;
 use rustc_data_structures::fx::FxHashMap;
@@ -342,7 +345,22 @@ pub enum AppendConstMessage {
 
 #[derive(LintDiagnostic)]
 #[diag(trait_selection_malformed_on_unimplemented_attr)]
-pub struct NoValueInOnUnimplementedLint;
+#[help]
+pub struct MalformedOnUnimplementedAttrLint {
+    #[label]
+    pub span: Span,
+}
+
+impl MalformedOnUnimplementedAttrLint {
+    fn new(span: Span) -> Self {
+        Self { span }
+    }
+}
+
+#[derive(LintDiagnostic)]
+#[diag(trait_selection_missing_options_for_on_unimplemented_attr)]
+#[help]
+pub struct MissingOptionsForOnUnimplementedAttr;
 
 impl<'tcx> OnUnimplementedDirective {
     fn parse(
@@ -453,7 +471,7 @@ impl<'tcx> OnUnimplementedDirective {
                     UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
                     tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local()),
                     vec![item.span()],
-                    NoValueInOnUnimplementedLint,
+                    MalformedOnUnimplementedAttrLint::new(item.span()),
                 );
             } else {
                 // nothing found
@@ -530,21 +548,40 @@ impl<'tcx> OnUnimplementedDirective {
                     append_const_msg: None,
                 }))
             } else {
+                let item = attr.get_normal_item();
+                let report_span = match &item.args {
+                    AttrArgs::Empty => item.path.span,
+                    AttrArgs::Delimited(args) => args.dspan.entire(),
+                    AttrArgs::Eq(eq_span, AttrArgsEq::Ast(expr)) => eq_span.to(expr.span),
+                    AttrArgs::Eq(span, AttrArgsEq::Hir(expr)) => span.to(expr.span),
+                };
+
                 tcx.emit_spanned_lint(
                     UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
                     tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local()),
-                    attr.span,
-                    NoValueInOnUnimplementedLint,
+                    report_span,
+                    MalformedOnUnimplementedAttrLint::new(report_span),
                 );
                 Ok(None)
             }
         } else if is_diagnostic_namespace_variant {
-            tcx.emit_spanned_lint(
-                UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
-                tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local()),
-                attr.span,
-                NoValueInOnUnimplementedLint,
-            );
+            match &attr.kind {
+                AttrKind::Normal(p) if !matches!(p.item.args, AttrArgs::Empty) => {
+                    tcx.emit_spanned_lint(
+                        UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
+                        tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local()),
+                        attr.span,
+                        MalformedOnUnimplementedAttrLint::new(attr.span),
+                    );
+                }
+                _ => tcx.emit_spanned_lint(
+                    UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
+                    tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local()),
+                    attr.span,
+                    MissingOptionsForOnUnimplementedAttr,
+                ),
+            };
+
             Ok(None)
         } else {
             let reported =
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index 78b466907b3..b9a08056ad1 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -22,7 +22,7 @@ use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::is_range_literal;
 use rustc_hir::lang_items::LangItem;
-use rustc_hir::{AsyncCoroutineKind, CoroutineKind, Node};
+use rustc_hir::{CoroutineKind, CoroutineSource, Node};
 use rustc_hir::{Expr, HirId};
 use rustc_infer::infer::error_reporting::TypeErrCtxt;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
@@ -2410,7 +2410,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                 .and_then(|coroutine_did| {
                     Some(match self.tcx.coroutine_kind(coroutine_did).unwrap() {
                         CoroutineKind::Coroutine => format!("coroutine is not {trait_name}"),
-                        CoroutineKind::Async(AsyncCoroutineKind::Fn) => self
+                        CoroutineKind::Async(CoroutineSource::Fn) => self
                             .tcx
                             .parent(coroutine_did)
                             .as_local()
@@ -2419,10 +2419,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                             .map(|name| {
                                 format!("future returned by `{name}` is not {trait_name}")
                             })?,
-                        CoroutineKind::Async(AsyncCoroutineKind::Block) => {
+                        CoroutineKind::Async(CoroutineSource::Block) => {
                             format!("future created by async block is not {trait_name}")
                         }
-                        CoroutineKind::Async(AsyncCoroutineKind::Closure) => {
+                        CoroutineKind::Async(CoroutineSource::Closure) => {
                             format!("future created by async closure is not {trait_name}")
                         }
                     })
@@ -2995,11 +2995,11 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                                 let sp = self.tcx.def_span(def_id);
 
                                 // Special-case this to say "async block" instead of `[static coroutine]`.
-                                let kind = tcx.coroutine_kind(def_id).unwrap().descr();
+                                let kind = tcx.coroutine_kind(def_id).unwrap();
                                 err.span_note(
                                     sp,
                                     with_forced_trimmed_paths!(format!(
-                                        "required because it's used within this {kind}",
+                                        "required because it's used within this {kind:#}",
                                     )),
                                 )
                             }
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
index 1245b4a7756..353a69ef6d3 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
@@ -1611,9 +1611,9 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
     fn describe_coroutine(&self, body_id: hir::BodyId) -> Option<&'static str> {
         self.tcx.hir().body(body_id).coroutine_kind.map(|gen_kind| match gen_kind {
             hir::CoroutineKind::Coroutine => "a coroutine",
-            hir::CoroutineKind::Async(hir::AsyncCoroutineKind::Block) => "an async block",
-            hir::CoroutineKind::Async(hir::AsyncCoroutineKind::Fn) => "an async function",
-            hir::CoroutineKind::Async(hir::AsyncCoroutineKind::Closure) => "an async closure",
+            hir::CoroutineKind::Async(hir::CoroutineSource::Block) => "an async block",
+            hir::CoroutineKind::Async(hir::CoroutineSource::Fn) => "an async function",
+            hir::CoroutineKind::Async(hir::CoroutineSource::Closure) => "an async closure",
         })
     }
 
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index 2d05f934393..dfc4bdf1484 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -97,6 +97,10 @@ fn check_is_object_safe(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool {
 /// object. Note that object-safe traits can have some
 /// non-vtable-safe methods, so long as they require `Self: Sized` or
 /// otherwise ensure that they cannot be used when `Self = Trait`.
+///
+/// [`MethodViolationCode::WhereClauseReferencesSelf`] is considered object safe due to backwards
+/// compatibility, see <https://github.com/rust-lang/rust/issues/51443> and
+/// [`WHERE_CLAUSES_OBJECT_SAFETY`].
 pub fn is_vtable_safe_method(tcx: TyCtxt<'_>, trait_def_id: DefId, method: ty::AssocItem) -> bool {
     debug_assert!(tcx.generics_of(trait_def_id).has_self);
     debug!("is_vtable_safe_method({:?}, {:?})", trait_def_id, method);
@@ -105,10 +109,9 @@ pub fn is_vtable_safe_method(tcx: TyCtxt<'_>, trait_def_id: DefId, method: ty::A
         return false;
     }
 
-    match virtual_call_violation_for_method(tcx, trait_def_id, method) {
-        None | Some(MethodViolationCode::WhereClauseReferencesSelf) => true,
-        Some(_) => false,
-    }
+    virtual_call_violations_for_method(tcx, trait_def_id, method)
+        .iter()
+        .all(|v| matches!(v, MethodViolationCode::WhereClauseReferencesSelf))
 }
 
 fn object_safety_violations_for_trait(
@@ -119,7 +122,7 @@ fn object_safety_violations_for_trait(
     let mut violations: Vec<_> = tcx
         .associated_items(trait_def_id)
         .in_definition_order()
-        .filter_map(|&item| object_safety_violation_for_assoc_item(tcx, trait_def_id, item))
+        .flat_map(|&item| object_safety_violations_for_assoc_item(tcx, trait_def_id, item))
         .collect();
 
     // Check the trait itself.
@@ -357,49 +360,52 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
 
 /// Returns `Some(_)` if this item makes the containing trait not object safe.
 #[instrument(level = "debug", skip(tcx), ret)]
-fn object_safety_violation_for_assoc_item(
+fn object_safety_violations_for_assoc_item(
     tcx: TyCtxt<'_>,
     trait_def_id: DefId,
     item: ty::AssocItem,
-) -> Option<ObjectSafetyViolation> {
+) -> Vec<ObjectSafetyViolation> {
     // Any item that has a `Self : Sized` requisite is otherwise
     // exempt from the regulations.
     if tcx.generics_require_sized_self(item.def_id) {
-        return None;
+        return Vec::new();
     }
 
     match item.kind {
         // Associated consts are never object safe, as they can't have `where` bounds yet at all,
         // and associated const bounds in trait objects aren't a thing yet either.
         ty::AssocKind::Const => {
-            Some(ObjectSafetyViolation::AssocConst(item.name, item.ident(tcx).span))
+            vec![ObjectSafetyViolation::AssocConst(item.name, item.ident(tcx).span)]
         }
-        ty::AssocKind::Fn => virtual_call_violation_for_method(tcx, trait_def_id, item).map(|v| {
-            let node = tcx.hir().get_if_local(item.def_id);
-            // Get an accurate span depending on the violation.
-            let span = match (&v, node) {
-                (MethodViolationCode::ReferencesSelfInput(Some(span)), _) => *span,
-                (MethodViolationCode::UndispatchableReceiver(Some(span)), _) => *span,
-                (MethodViolationCode::ReferencesImplTraitInTrait(span), _) => *span,
-                (MethodViolationCode::ReferencesSelfOutput, Some(node)) => {
-                    node.fn_decl().map_or(item.ident(tcx).span, |decl| decl.output.span())
-                }
-                _ => item.ident(tcx).span,
-            };
+        ty::AssocKind::Fn => virtual_call_violations_for_method(tcx, trait_def_id, item)
+            .into_iter()
+            .map(|v| {
+                let node = tcx.hir().get_if_local(item.def_id);
+                // Get an accurate span depending on the violation.
+                let span = match (&v, node) {
+                    (MethodViolationCode::ReferencesSelfInput(Some(span)), _) => *span,
+                    (MethodViolationCode::UndispatchableReceiver(Some(span)), _) => *span,
+                    (MethodViolationCode::ReferencesImplTraitInTrait(span), _) => *span,
+                    (MethodViolationCode::ReferencesSelfOutput, Some(node)) => {
+                        node.fn_decl().map_or(item.ident(tcx).span, |decl| decl.output.span())
+                    }
+                    _ => item.ident(tcx).span,
+                };
 
-            ObjectSafetyViolation::Method(item.name, v, span)
-        }),
+                ObjectSafetyViolation::Method(item.name, v, span)
+            })
+            .collect(),
         // Associated types can only be object safe if they have `Self: Sized` bounds.
         ty::AssocKind::Type => {
             if !tcx.features().generic_associated_types_extended
                 && !tcx.generics_of(item.def_id).params.is_empty()
                 && !item.is_impl_trait_in_trait()
             {
-                Some(ObjectSafetyViolation::GAT(item.name, item.ident(tcx).span))
+                vec![ObjectSafetyViolation::GAT(item.name, item.ident(tcx).span)]
             } else {
                 // We will permit associated types if they are explicitly mentioned in the trait object.
                 // We can't check this here, as here we only check if it is guaranteed to not be possible.
-                None
+                Vec::new()
             }
         }
     }
@@ -409,11 +415,11 @@ fn object_safety_violation_for_assoc_item(
 /// object; this does not necessarily imply that the enclosing trait
 /// is not object safe, because the method might have a where clause
 /// `Self:Sized`.
-fn virtual_call_violation_for_method<'tcx>(
+fn virtual_call_violations_for_method<'tcx>(
     tcx: TyCtxt<'tcx>,
     trait_def_id: DefId,
     method: ty::AssocItem,
-) -> Option<MethodViolationCode> {
+) -> Vec<MethodViolationCode> {
     let sig = tcx.fn_sig(method.def_id).instantiate_identity();
 
     // The method's first parameter must be named `self`
@@ -438,9 +444,14 @@ fn virtual_call_violation_for_method<'tcx>(
         } else {
             None
         };
-        return Some(MethodViolationCode::StaticMethod(sugg));
+
+        // Not having `self` parameter messes up the later checks,
+        // so we need to return instead of pushing
+        return vec![MethodViolationCode::StaticMethod(sugg)];
     }
 
+    let mut errors = Vec::new();
+
     for (i, &input_ty) in sig.skip_binder().inputs().iter().enumerate().skip(1) {
         if contains_illegal_self_type_reference(tcx, trait_def_id, sig.rebind(input_ty)) {
             let span = if let Some(hir::Node::TraitItem(hir::TraitItem {
@@ -452,20 +463,20 @@ fn virtual_call_violation_for_method<'tcx>(
             } else {
                 None
             };
-            return Some(MethodViolationCode::ReferencesSelfInput(span));
+            errors.push(MethodViolationCode::ReferencesSelfInput(span));
         }
     }
     if contains_illegal_self_type_reference(tcx, trait_def_id, sig.output()) {
-        return Some(MethodViolationCode::ReferencesSelfOutput);
+        errors.push(MethodViolationCode::ReferencesSelfOutput);
     }
     if let Some(code) = contains_illegal_impl_trait_in_trait(tcx, method.def_id, sig.output()) {
-        return Some(code);
+        errors.push(code);
     }
 
     // We can't monomorphize things like `fn foo<A>(...)`.
     let own_counts = tcx.generics_of(method.def_id).own_counts();
-    if own_counts.types + own_counts.consts != 0 {
-        return Some(MethodViolationCode::Generic);
+    if own_counts.types > 0 || own_counts.consts > 0 {
+        errors.push(MethodViolationCode::Generic);
     }
 
     let receiver_ty = tcx.liberate_late_bound_regions(method.def_id, sig.input(0));
@@ -485,7 +496,7 @@ fn virtual_call_violation_for_method<'tcx>(
             } else {
                 None
             };
-            return Some(MethodViolationCode::UndispatchableReceiver(span));
+            errors.push(MethodViolationCode::UndispatchableReceiver(span));
         } else {
             // Do sanity check to make sure the receiver actually has the layout of a pointer.
 
@@ -593,10 +604,10 @@ fn virtual_call_violation_for_method<'tcx>(
 
         contains_illegal_self_type_reference(tcx, trait_def_id, pred)
     }) {
-        return Some(MethodViolationCode::WhereClauseReferencesSelf);
+        errors.push(MethodViolationCode::WhereClauseReferencesSelf);
     }
 
-    None
+    errors
 }
 
 /// Performs a type substitution to produce the version of `receiver_ty` when `Self = self_ty`.
@@ -709,7 +720,6 @@ fn object_ty_for_trait<'tcx>(
 // FIXME(mikeyhew) when unsized receivers are implemented as part of unsized rvalues, add this
 // fallback query: `Receiver: Unsize<Receiver[Self => U]>` to support receivers like
 // `self: Wrapper<Self>`.
-#[allow(dead_code)]
 fn receiver_is_dispatchable<'tcx>(
     tcx: TyCtxt<'tcx>,
     method: ty::AssocItem,
diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
index 349741a698c..c761d0d103e 100644
--- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
@@ -293,7 +293,7 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx>
                     _ => unreachable!(),
                 }?;
                 // We don't expect ambiguity.
-                if result.is_ambiguous() {
+                if !result.value.is_proven() {
                     // Rustdoc normalizes possibly not well-formed types, so only
                     // treat this as a bug if we're not in rustdoc.
                     if !tcx.sess.opts.actually_rustdoc {
diff --git a/compiler/rustc_type_ir/src/canonical.rs b/compiler/rustc_type_ir/src/canonical.rs
new file mode 100644
index 00000000000..c0b6aed98ef
--- /dev/null
+++ b/compiler/rustc_type_ir/src/canonical.rs
@@ -0,0 +1,169 @@
+use std::fmt;
+use std::hash;
+use std::ops::ControlFlow;
+
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_serialize::{Decodable, Encodable};
+
+use crate::fold::{FallibleTypeFolder, TypeFoldable};
+use crate::visit::{TypeVisitable, TypeVisitor};
+use crate::TyDecoder;
+use crate::{HashStableContext, Interner, TyEncoder, UniverseIndex};
+
+/// A "canonicalized" type `V` is one where all free inference
+/// variables have been rewritten to "canonical vars". These are
+/// numbered starting from 0 in order of first appearance.
+pub struct Canonical<I: Interner, V> {
+    pub value: V,
+    pub max_universe: UniverseIndex,
+    pub variables: I::CanonicalVars,
+}
+
+impl<I: Interner, V> Canonical<I, V> {
+    /// Allows you to map the `value` of a canonical while keeping the
+    /// same set of bound variables.
+    ///
+    /// **WARNING:** This function is very easy to mis-use, hence the
+    /// name!  In particular, the new value `W` must use all **the
+    /// same type/region variables** in **precisely the same order**
+    /// as the original! (The ordering is defined by the
+    /// `TypeFoldable` implementation of the type in question.)
+    ///
+    /// An example of a **correct** use of this:
+    ///
+    /// ```rust,ignore (not real code)
+    /// let a: Canonical<I, T> = ...;
+    /// let b: Canonical<I, (T,)> = a.unchecked_map(|v| (v, ));
+    /// ```
+    ///
+    /// An example of an **incorrect** use of this:
+    ///
+    /// ```rust,ignore (not real code)
+    /// let a: Canonical<I, T> = ...;
+    /// let ty: Ty<I> = ...;
+    /// let b: Canonical<I, (T, Ty<I>)> = a.unchecked_map(|v| (v, ty));
+    /// ```
+    pub fn unchecked_map<W>(self, map_op: impl FnOnce(V) -> W) -> Canonical<I, W> {
+        let Canonical { max_universe, variables, value } = self;
+        Canonical { max_universe, variables, value: map_op(value) }
+    }
+
+    /// Allows you to map the `value` of a canonical while keeping the same set of
+    /// bound variables.
+    ///
+    /// **WARNING:** This function is very easy to mis-use, hence the name! See
+    /// the comment of [Canonical::unchecked_map] for more details.
+    pub fn unchecked_rebind<W>(self, value: W) -> Canonical<I, W> {
+        let Canonical { max_universe, variables, value: _ } = self;
+        Canonical { max_universe, variables, value }
+    }
+}
+
+impl<I: Interner, V: hash::Hash> hash::Hash for Canonical<I, V> {
+    fn hash<H: hash::Hasher>(&self, state: &mut H) {
+        self.value.hash(state);
+        self.max_universe.hash(state);
+        self.variables.hash(state);
+    }
+}
+
+impl<CTX: HashStableContext, I: Interner, V: HashStable<CTX>> HashStable<CTX> for Canonical<I, V>
+where
+    I::CanonicalVars: HashStable<CTX>,
+{
+    fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
+        self.value.hash_stable(hcx, hasher);
+        self.max_universe.hash_stable(hcx, hasher);
+        self.variables.hash_stable(hcx, hasher);
+    }
+}
+
+impl<I: Interner, V: Eq> Eq for Canonical<I, V> {}
+
+impl<I: Interner, V: PartialEq> PartialEq for Canonical<I, V> {
+    fn eq(&self, other: &Self) -> bool {
+        self.value == other.value
+            && self.max_universe == other.max_universe
+            && self.variables == other.variables
+    }
+}
+
+impl<I: Interner, V: fmt::Display> fmt::Display for Canonical<I, V> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(
+            f,
+            "Canonical {{ value: {}, max_universe: {:?}, variables: {:?} }}",
+            self.value, self.max_universe, self.variables
+        )
+    }
+}
+
+impl<I: Interner, V: fmt::Debug> fmt::Debug for Canonical<I, V> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("Canonical")
+            .field("value", &self.value)
+            .field("max_universe", &self.max_universe)
+            .field("variables", &self.variables)
+            .finish()
+    }
+}
+
+impl<I: Interner, V: Clone> Clone for Canonical<I, V> {
+    fn clone(&self) -> Self {
+        Canonical {
+            value: self.value.clone(),
+            max_universe: self.max_universe.clone(),
+            variables: self.variables.clone(),
+        }
+    }
+}
+
+impl<I: Interner, V: Copy> Copy for Canonical<I, V> where I::CanonicalVars: Copy {}
+
+impl<I: Interner, V: TypeFoldable<I>> TypeFoldable<I> for Canonical<I, V>
+where
+    I::CanonicalVars: TypeFoldable<I>,
+{
+    fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
+        Ok(Canonical {
+            value: self.value.try_fold_with(folder)?,
+            max_universe: self.max_universe.try_fold_with(folder)?,
+            variables: self.variables.try_fold_with(folder)?,
+        })
+    }
+}
+
+impl<I: Interner, V: TypeVisitable<I>> TypeVisitable<I> for Canonical<I, V>
+where
+    I::CanonicalVars: TypeVisitable<I>,
+{
+    fn visit_with<F: TypeVisitor<I>>(&self, folder: &mut F) -> ControlFlow<F::BreakTy> {
+        self.value.visit_with(folder)?;
+        self.max_universe.visit_with(folder)?;
+        self.variables.visit_with(folder)
+    }
+}
+
+impl<I: Interner, E: TyEncoder<I = I>, V: Encodable<E>> Encodable<E> for Canonical<I, V>
+where
+    I::CanonicalVars: Encodable<E>,
+{
+    fn encode(&self, s: &mut E) {
+        self.value.encode(s);
+        self.max_universe.encode(s);
+        self.variables.encode(s);
+    }
+}
+
+impl<I: Interner, D: TyDecoder<I = I>, V: Decodable<D>> Decodable<D> for Canonical<I, V>
+where
+    I::CanonicalVars: Decodable<D>,
+{
+    fn decode(d: &mut D) -> Self {
+        Canonical {
+            value: Decodable::decode(d),
+            max_universe: Decodable::decode(d),
+            variables: Decodable::decode(d),
+        }
+    }
+}
diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs
index 6e5d3ee0b6d..7f75e5b35a2 100644
--- a/compiler/rustc_type_ir/src/interner.rs
+++ b/compiler/rustc_type_ir/src/interner.rs
@@ -18,6 +18,7 @@ pub trait Interner: Sized {
 
     type Binder<T>;
     type TypeAndMut: Clone + Debug + Hash + Ord;
+    type CanonicalVars: Clone + Debug + Hash + Eq;
 
     // Kinds of tys
     type Ty: Clone + DebugWithInfcx<Self> + Hash + Ord;
diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs
index 3494b24f060..a056fbeda98 100644
--- a/compiler/rustc_type_ir/src/lib.rs
+++ b/compiler/rustc_type_ir/src/lib.rs
@@ -26,6 +26,7 @@ pub mod visit;
 
 #[macro_use]
 mod macros;
+mod canonical;
 mod const_kind;
 mod debug;
 mod flags;
@@ -33,6 +34,7 @@ mod interner;
 mod predicate_kind;
 mod region_kind;
 
+pub use canonical::*;
 pub use codec::*;
 pub use const_kind::*;
 pub use debug::{DebugWithInfcx, InferCtxtLike, WithInfcx};
diff --git a/compiler/rustc_type_ir/src/macros.rs b/compiler/rustc_type_ir/src/macros.rs
index 88314aca6f3..cfed84a35c6 100644
--- a/compiler/rustc_type_ir/src/macros.rs
+++ b/compiler/rustc_type_ir/src/macros.rs
@@ -50,4 +50,5 @@ TrivialTypeTraversalImpls! {
     String,
     crate::DebruijnIndex,
     crate::AliasRelationDirection,
+    crate::UniverseIndex,
 }
diff --git a/compiler/rustc_type_ir/src/region_kind.rs b/compiler/rustc_type_ir/src/region_kind.rs
index 60b90f4fae3..19576ea58f1 100644
--- a/compiler/rustc_type_ir/src/region_kind.rs
+++ b/compiler/rustc_type_ir/src/region_kind.rs
@@ -307,7 +307,7 @@ impl<I: Interner> fmt::Debug for RegionKind<I> {
 }
 
 // This is manually implemented because a derive would require `I: Encodable`
-impl<I: Interner, E: TyEncoder> Encodable<E> for RegionKind<I>
+impl<I: Interner, E: TyEncoder<I = I>> Encodable<E> for RegionKind<I>
 where
     I::EarlyBoundRegion: Encodable<E>,
     I::BoundRegion: Encodable<E>,
diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs
index 2128666c2a4..b542547589a 100644
--- a/compiler/rustc_type_ir/src/ty_kind.rs
+++ b/compiler/rustc_type_ir/src/ty_kind.rs
@@ -622,7 +622,7 @@ impl<I: Interner> fmt::Debug for TyKind<I> {
 }
 
 // This is manually implemented because a derive would require `I: Encodable`
-impl<I: Interner, E: TyEncoder> Encodable<E> for TyKind<I>
+impl<I: Interner, E: TyEncoder<I = I>> Encodable<E> for TyKind<I>
 where
     I::ErrorGuaranteed: Encodable<E>,
     I::AdtDef: Encodable<E>,
diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs
index fc617513aee..c2e79eaaf3f 100644
--- a/compiler/stable_mir/src/mir/body.rs
+++ b/compiler/stable_mir/src/mir/body.rs
@@ -135,12 +135,12 @@ pub enum UnOp {
 
 #[derive(Clone, Debug)]
 pub enum CoroutineKind {
-    Async(AsyncCoroutineKind),
+    Async(CoroutineSource),
     Coroutine,
 }
 
 #[derive(Clone, Debug)]
-pub enum AsyncCoroutineKind {
+pub enum CoroutineSource {
     Block,
     Closure,
     Fn,
diff --git a/src/tools/clippy/clippy_lints/src/async_yields_async.rs b/src/tools/clippy/clippy_lints/src/async_yields_async.rs
index 56f56fff1e7..050df68a0fa 100644
--- a/src/tools/clippy/clippy_lints/src/async_yields_async.rs
+++ b/src/tools/clippy/clippy_lints/src/async_yields_async.rs
@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_hir_and_then;
 use clippy_utils::source::snippet;
 use clippy_utils::ty::implements_trait;
 use rustc_errors::Applicability;
-use rustc_hir::{AsyncCoroutineKind, Body, BodyId, CoroutineKind, ExprKind, QPath};
+use rustc_hir::{CoroutineSource, Body, BodyId, CoroutineKind, ExprKind, QPath};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 
@@ -45,7 +45,7 @@ declare_lint_pass!(AsyncYieldsAsync => [ASYNC_YIELDS_ASYNC]);
 
 impl<'tcx> LateLintPass<'tcx> for AsyncYieldsAsync {
     fn check_body(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'_>) {
-        use AsyncCoroutineKind::{Block, Closure};
+        use CoroutineSource::{Block, Closure};
         // For functions, with explicitly defined types, don't warn.
         // XXXkhuey maybe we should?
         if let Some(CoroutineKind::Async(Block | Closure)) = body.coroutine_kind {
diff --git a/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs b/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs
index ae8618dcaa0..0c356934992 100644
--- a/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs
+++ b/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs
@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::{match_def_path, paths};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::def_id::DefId;
-use rustc_hir::{AsyncCoroutineKind, Body, CoroutineKind};
+use rustc_hir::{CoroutineSource, Body, CoroutineKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::mir::CoroutineLayout;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
@@ -195,7 +195,7 @@ impl LateLintPass<'_> for AwaitHolding {
     }
 
     fn check_body(&mut self, cx: &LateContext<'_>, body: &'_ Body<'_>) {
-        use AsyncCoroutineKind::{Block, Closure, Fn};
+        use CoroutineSource::{Block, Closure, Fn};
         if let Some(CoroutineKind::Async(Block | Closure | Fn)) = body.coroutine_kind {
             let def_id = cx.tcx.hir().body_owner_def_id(body.id());
             if let Some(coroutine_layout) = cx.tcx.mir_coroutine_witnesses(def_id) {
diff --git a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs
index 5a87e75722d..a75c76d6fe0 100644
--- a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs
@@ -4,7 +4,7 @@ use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::{
-    AsyncCoroutineKind, Block, Body, Closure, CoroutineKind, Expr, ExprKind, FnDecl, FnRetTy, GenericArg, GenericBound,
+    CoroutineSource, Block, Body, Closure, CoroutineKind, Expr, ExprKind, FnDecl, FnRetTy, GenericArg, GenericBound,
     ImplItem, Item, ItemKind, LifetimeName, Node, Term, TraitRef, Ty, TyKind, TypeBindingKind,
 };
 use rustc_lint::{LateContext, LateLintPass};
@@ -188,7 +188,7 @@ fn desugared_async_block<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>)
             ..
         } = block_expr;
         let closure_body = cx.tcx.hir().body(body);
-        if closure_body.coroutine_kind == Some(CoroutineKind::Async(AsyncCoroutineKind::Block));
+        if closure_body.coroutine_kind == Some(CoroutineKind::Async(CoroutineSource::Block));
         then {
             return Some(closure_body);
         }
diff --git a/src/tools/clippy/clippy_lints/src/needless_question_mark.rs b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs
index ed279a3813d..b3a2060d6ac 100644
--- a/src/tools/clippy/clippy_lints/src/needless_question_mark.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs
@@ -4,7 +4,7 @@ use clippy_utils::source::snippet;
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::{AsyncCoroutineKind, Block, Body, CoroutineKind, Expr, ExprKind, LangItem, MatchSource, QPath};
+use rustc_hir::{CoroutineSource, Block, Body, CoroutineKind, Expr, ExprKind, LangItem, MatchSource, QPath};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 
@@ -87,7 +87,7 @@ impl LateLintPass<'_> for NeedlessQuestionMark {
     }
 
     fn check_body(&mut self, cx: &LateContext<'_>, body: &'_ Body<'_>) {
-        if let Some(CoroutineKind::Async(AsyncCoroutineKind::Fn)) = body.coroutine_kind {
+        if let Some(CoroutineKind::Async(CoroutineSource::Fn)) = body.coroutine_kind {
             if let ExprKind::Block(
                 Block {
                     expr:
diff --git a/src/tools/clippy/clippy_lints/src/redundant_async_block.rs b/src/tools/clippy/clippy_lints/src/redundant_async_block.rs
index 2e895d5f236..bf9bdacba5b 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_async_block.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_async_block.rs
@@ -5,7 +5,7 @@ use clippy_utils::peel_blocks;
 use clippy_utils::source::{snippet, walk_span_to_context};
 use clippy_utils::visitors::for_each_expr;
 use rustc_errors::Applicability;
-use rustc_hir::{AsyncCoroutineKind, Closure, CoroutineKind, Expr, ExprKind, MatchSource};
+use rustc_hir::{CoroutineSource, Closure, CoroutineKind, Expr, ExprKind, MatchSource};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::UpvarCapture;
@@ -71,7 +71,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantAsyncBlock {
 fn desugar_async_block<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
     if let ExprKind::Closure(Closure { body, def_id, .. }) = expr.kind &&
         let body = cx.tcx.hir().body(*body) &&
-        matches!(body.coroutine_kind, Some(CoroutineKind::Async(AsyncCoroutineKind::Block)))
+        matches!(body.coroutine_kind, Some(CoroutineKind::Async(CoroutineSource::Block)))
     {
         cx
             .typeck_results()
diff --git a/tests/ui/async-await/async-await-let-else.stderr b/tests/ui/async-await/async-await-let-else.stderr
index c3b4e761824..b360aab6b59 100644
--- a/tests/ui/async-await/async-await-let-else.stderr
+++ b/tests/ui/async-await/async-await-let-else.stderr
@@ -30,7 +30,7 @@ LL |     is_send(foo2(Some(true)));
    |     required by a bound introduced by this call
    |
    = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>`
-note: required because it's used within this `async fn` body
+note: required because it's used within this `async` fn body
   --> $DIR/async-await-let-else.rs:24:29
    |
 LL |   async fn bar2<T>(_: T) -> ! {
@@ -39,7 +39,7 @@ LL | |     panic!()
 LL | | }
    | |_^
    = note: required because it captures the following types: `impl Future<Output = !>`
-note: required because it's used within this `async fn` body
+note: required because it's used within this `async` fn body
   --> $DIR/async-await-let-else.rs:18:32
    |
 LL |   async fn foo2(x: Option<bool>) {
diff --git a/tests/ui/async-await/issue-68112.stderr b/tests/ui/async-await/issue-68112.stderr
index 17b619ebee3..1cd8beac260 100644
--- a/tests/ui/async-await/issue-68112.stderr
+++ b/tests/ui/async-await/issue-68112.stderr
@@ -45,7 +45,7 @@ LL |     require_send(send_fut);
    = help: the trait `Sync` is not implemented for `RefCell<i32>`
    = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead
    = note: required for `Arc<RefCell<i32>>` to implement `Send`
-note: required because it's used within this `async fn` body
+note: required because it's used within this `async` fn body
   --> $DIR/issue-68112.rs:47:31
    |
 LL |   async fn ready2<T>(t: T) -> T {
diff --git a/tests/ui/async-await/issue-70935-complex-spans.stderr b/tests/ui/async-await/issue-70935-complex-spans.stderr
index ab834daa85d..d0605d7e1a6 100644
--- a/tests/ui/async-await/issue-70935-complex-spans.stderr
+++ b/tests/ui/async-await/issue-70935-complex-spans.stderr
@@ -18,7 +18,7 @@ note: required because it's used within this closure
    |
 LL |         baz(|| async {
    |             ^^
-note: required because it's used within this `async fn` body
+note: required because it's used within this `async` fn body
   --> $DIR/issue-70935-complex-spans.rs:12:67
    |
 LL |   async fn baz<T>(_c: impl FnMut() -> T) where T: Future<Output=()> {
diff --git a/tests/ui/async-await/issues/issue-67893.stderr b/tests/ui/async-await/issues/issue-67893.stderr
index 3d6d1fb5c09..2a712aee9c4 100644
--- a/tests/ui/async-await/issues/issue-67893.stderr
+++ b/tests/ui/async-await/issues/issue-67893.stderr
@@ -13,7 +13,7 @@ LL | pub async fn run() {
    |
    = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `MutexGuard<'_, ()>`
    = note: required because it captures the following types: `Arc<Mutex<()>>`, `MutexGuard<'_, ()>`, `impl Future<Output = ()>`
-note: required because it's used within this `async fn` body
+note: required because it's used within this `async` fn body
   --> $DIR/auxiliary/issue_67893.rs:9:20
    |
 LL |   pub async fn run() {
diff --git a/tests/ui/async-await/partial-drop-partial-reinit.rs b/tests/ui/async-await/partial-drop-partial-reinit.rs
index 75acb442e7a..815cc916b41 100644
--- a/tests/ui/async-await/partial-drop-partial-reinit.rs
+++ b/tests/ui/async-await/partial-drop-partial-reinit.rs
@@ -26,7 +26,7 @@ impl Drop for NotSend {
 impl !Send for NotSend {}
 
 async fn foo() {
-    //~^ NOTE used within this `async fn` body
+    //~^ NOTE used within this `async` fn body
     //~| NOTE within this `impl Future
     let mut x = (NotSend {},);
     drop(x.0);
diff --git a/tests/ui/async-await/partial-drop-partial-reinit.stderr b/tests/ui/async-await/partial-drop-partial-reinit.stderr
index d115c1b1cc4..310a2923955 100644
--- a/tests/ui/async-await/partial-drop-partial-reinit.stderr
+++ b/tests/ui/async-await/partial-drop-partial-reinit.stderr
@@ -12,7 +12,7 @@ LL | async fn foo() {
    = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `NotSend`
    = note: required because it appears within the type `(NotSend,)`
    = note: required because it captures the following types: `(NotSend,)`, `impl Future<Output = ()>`
-note: required because it's used within this `async fn` body
+note: required because it's used within this `async` fn body
   --> $DIR/partial-drop-partial-reinit.rs:28:16
    |
 LL |   async fn foo() {
diff --git a/tests/ui/const-generics/generic_const_exprs/object-safety-err-ret.stderr b/tests/ui/const-generics/generic_const_exprs/object-safety-err-ret.stderr
index 4e1d71f1545..7ce2b9ac95a 100644
--- a/tests/ui/const-generics/generic_const_exprs/object-safety-err-ret.stderr
+++ b/tests/ui/const-generics/generic_const_exprs/object-safety-err-ret.stderr
@@ -5,12 +5,15 @@ LL | fn use_dyn(v: &dyn Foo) {
    |                ^^^^^^^ `Foo` cannot be made into an object
    |
 note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
-  --> $DIR/object-safety-err-ret.rs:8:23
+  --> $DIR/object-safety-err-ret.rs:8:8
    |
 LL | trait Foo {
    |       --- this trait cannot be made into an object...
 LL |     fn test(&self) -> [u8; bar::<Self>()];
-   |                       ^^^^^^^^^^^^^^^^^^^ ...because method `test` references the `Self` type in its return type
+   |        ^^^^           ^^^^^^^^^^^^^^^^^^^ ...because method `test` references the `Self` type in its return type
+   |        |
+   |        ...because method `test` references the `Self` type in its `where` clause
+   = help: consider moving `test` to another trait
    = help: consider moving `test` to another trait
 
 error: aborting due to previous error
diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.rs b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.rs
index 00fb59d14d7..346d8373f73 100644
--- a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.rs
+++ b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.rs
@@ -23,9 +23,15 @@ trait Boom {}
 //~^WARN malformed `on_unimplemented` attribute
 trait Doom {}
 
+#[diagnostic::on_unimplemented]
+//~^WARN missing options for `on_unimplemented` attribute
+//~|WARN missing options for `on_unimplemented` attribute
+trait Whatever {}
+
 fn take_foo(_: impl Foo) {}
 fn take_baz(_: impl Baz) {}
 fn take_boom(_: impl Boom) {}
+fn take_whatever(_: impl Whatever) {}
 
 fn main() {
     take_foo(1_i32);
@@ -34,4 +40,6 @@ fn main() {
     //~^ERROR Boom
     take_boom(1_i32);
     //~^ERROR Boom
+    take_whatever(1_i32);
+    //~^ERROR the trait bound `i32: Whatever` is not satisfied
 }
diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.stderr
index bd39c91ffe8..162ddd79fbb 100644
--- a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.stderr
+++ b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.stderr
@@ -10,36 +10,53 @@ warning: malformed `on_unimplemented` attribute
   --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:3:32
    |
 LL | #[diagnostic::on_unimplemented(unsupported = "foo")]
-   |                                ^^^^^^^^^^^^^^^^^^^
+   |                                ^^^^^^^^^^^^^^^^^^^ invalid option found here
+   |
+   = help: only `message`, `note` and `label` are allowed as options
 
 warning: malformed `on_unimplemented` attribute
   --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:12:50
    |
 LL | #[diagnostic::on_unimplemented(message = "Boom", unsupported = "Bar")]
-   |                                                  ^^^^^^^^^^^^^^^^^^^
+   |                                                  ^^^^^^^^^^^^^^^^^^^ invalid option found here
+   |
+   = help: only `message`, `note` and `label` are allowed as options
 
 warning: malformed `on_unimplemented` attribute
   --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:17:50
    |
 LL | #[diagnostic::on_unimplemented(message = "Boom", on(_Self = "i32", message = "whatever"))]
-   |                                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid option found here
+   |
+   = help: only `message`, `note` and `label` are allowed as options
 
 warning: malformed `on_unimplemented` attribute
-  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:22:1
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:22:32
    |
 LL | #[diagnostic::on_unimplemented = "boom"]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                                ^^^^^^^^ invalid option found here
+   |
+   = help: only `message`, `note` and `label` are allowed as options
+
+warning: missing options for `on_unimplemented` attribute
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:26:1
+   |
+LL | #[diagnostic::on_unimplemented]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: at least one of the `message`, `note` and `label` options are expected
 
 warning: malformed `on_unimplemented` attribute
   --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:3:32
    |
 LL | #[diagnostic::on_unimplemented(unsupported = "foo")]
-   |                                ^^^^^^^^^^^^^^^^^^^
+   |                                ^^^^^^^^^^^^^^^^^^^ invalid option found here
    |
+   = help: only `message`, `note` and `label` are allowed as options
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0277]: the trait bound `i32: Foo` is not satisfied
-  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:31:14
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:37:14
    |
 LL |     take_foo(1_i32);
    |     -------- ^^^^^ the trait `Foo` is not implemented for `i32`
@@ -52,7 +69,7 @@ help: this trait has no implementations, consider adding one
 LL | trait Foo {}
    | ^^^^^^^^^
 note: required by a bound in `take_foo`
-  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:26:21
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:31:21
    |
 LL | fn take_foo(_: impl Foo) {}
    |                     ^^^ required by this bound in `take_foo`
@@ -61,12 +78,13 @@ warning: malformed `on_unimplemented` attribute
   --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:12:50
    |
 LL | #[diagnostic::on_unimplemented(message = "Boom", unsupported = "Bar")]
-   |                                                  ^^^^^^^^^^^^^^^^^^^
+   |                                                  ^^^^^^^^^^^^^^^^^^^ invalid option found here
    |
+   = help: only `message`, `note` and `label` are allowed as options
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0277]: Boom
-  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:33:14
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:39:14
    |
 LL |     take_baz(1_i32);
    |     -------- ^^^^^ the trait `Baz` is not implemented for `i32`
@@ -79,7 +97,7 @@ help: this trait has no implementations, consider adding one
 LL | trait Baz {}
    | ^^^^^^^^^
 note: required by a bound in `take_baz`
-  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:27:21
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:32:21
    |
 LL | fn take_baz(_: impl Baz) {}
    |                     ^^^ required by this bound in `take_baz`
@@ -88,12 +106,13 @@ warning: malformed `on_unimplemented` attribute
   --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:17:50
    |
 LL | #[diagnostic::on_unimplemented(message = "Boom", on(_Self = "i32", message = "whatever"))]
-   |                                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid option found here
    |
+   = help: only `message`, `note` and `label` are allowed as options
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0277]: Boom
-  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:35:15
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:41:15
    |
 LL |     take_boom(1_i32);
    |     --------- ^^^^^ the trait `Boom` is not implemented for `i32`
@@ -106,11 +125,39 @@ help: this trait has no implementations, consider adding one
 LL | trait Boom {}
    | ^^^^^^^^^^
 note: required by a bound in `take_boom`
-  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:28:22
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:33:22
    |
 LL | fn take_boom(_: impl Boom) {}
    |                      ^^^^ required by this bound in `take_boom`
 
-error: aborting due to 3 previous errors; 8 warnings emitted
+warning: missing options for `on_unimplemented` attribute
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:26:1
+   |
+LL | #[diagnostic::on_unimplemented]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: at least one of the `message`, `note` and `label` options are expected
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0277]: the trait bound `i32: Whatever` is not satisfied
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:43:19
+   |
+LL |     take_whatever(1_i32);
+   |     ------------- ^^^^^ the trait `Whatever` is not implemented for `i32`
+   |     |
+   |     required by a bound introduced by this call
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:29:1
+   |
+LL | trait Whatever {}
+   | ^^^^^^^^^^^^^^
+note: required by a bound in `take_whatever`
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:34:26
+   |
+LL | fn take_whatever(_: impl Whatever) {}
+   |                          ^^^^^^^^ required by this bound in `take_whatever`
+
+error: aborting due to 4 previous errors; 10 warnings emitted
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.rs b/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.rs
index 35307586391..8410b3eb105 100644
--- a/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.rs
+++ b/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.rs
@@ -1,22 +1,20 @@
 #![feature(diagnostic_namespace)]
 
 #[diagnostic::on_unimplemented(
+    if(Self = "()"),
     //~^WARN malformed `on_unimplemented` attribute
     //~|WARN malformed `on_unimplemented` attribute
-    if(Self = ()),
-    message = "not used yet",
-    label = "not used yet",
-    note = "not used yet"
+    message = "custom message",
+    note = "custom note"
 )]
 #[diagnostic::on_unimplemented(message = "fallback!!")]
 #[diagnostic::on_unimplemented(label = "fallback label")]
 #[diagnostic::on_unimplemented(note = "fallback note")]
-#[diagnostic::on_unimplemented(message = "fallback2!!")]
 trait Foo {}
 
 fn takes_foo(_: impl Foo) {}
 
 fn main() {
     takes_foo(());
-    //~^ERROR fallback!!
+    //~^ERROR custom message
 }
diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.stderr
index 6a83d8e39c6..7860e540589 100644
--- a/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.stderr
+++ b/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.stderr
@@ -1,33 +1,23 @@
 warning: malformed `on_unimplemented` attribute
-  --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:3:1
+  --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:4:5
    |
-LL | / #[diagnostic::on_unimplemented(
-LL | |
-LL | |
-LL | |     if(Self = ()),
-...  |
-LL | |     note = "not used yet"
-LL | | )]
-   | |__^
+LL |     if(Self = "()"),
+   |     ^^^^^^^^^^^^^^^ invalid option found here
    |
+   = help: only `message`, `note` and `label` are allowed as options
    = note: `#[warn(unknown_or_malformed_diagnostic_attributes)]` on by default
 
 warning: malformed `on_unimplemented` attribute
-  --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:3:1
+  --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:4:5
    |
-LL | / #[diagnostic::on_unimplemented(
-LL | |
-LL | |
-LL | |     if(Self = ()),
-...  |
-LL | |     note = "not used yet"
-LL | | )]
-   | |__^
+LL |     if(Self = "()"),
+   |     ^^^^^^^^^^^^^^^ invalid option found here
    |
+   = help: only `message`, `note` and `label` are allowed as options
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
-error[E0277]: fallback!!
-  --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:20:15
+error[E0277]: custom message
+  --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:18:15
    |
 LL |     takes_foo(());
    |     --------- ^^ fallback label
@@ -35,14 +25,14 @@ LL |     takes_foo(());
    |     required by a bound introduced by this call
    |
    = help: the trait `Foo` is not implemented for `()`
-   = note: fallback note
+   = note: custom note
 help: this trait has no implementations, consider adding one
-  --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:15:1
+  --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:13:1
    |
 LL | trait Foo {}
    | ^^^^^^^^^
 note: required by a bound in `takes_foo`
-  --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:17:22
+  --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:15:22
    |
 LL | fn takes_foo(_: impl Foo) {}
    |                      ^^^ required by this bound in `takes_foo`
diff --git a/tests/ui/imports/issue-56125.stderr b/tests/ui/imports/issue-56125.stderr
index 15477fb6f10..d2a0f436c42 100644
--- a/tests/ui/imports/issue-56125.stderr
+++ b/tests/ui/imports/issue-56125.stderr
@@ -6,14 +6,14 @@ LL |     use empty::issue_56125;
    |
 help: consider importing one of these items instead
    |
+LL |     use ::issue_56125::issue_56125;
+   |         ~~~~~~~~~~~~~~~~~~~~~~~~~~
+LL |     use ::issue_56125::last_segment::issue_56125;
+   |         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+LL |     use ::issue_56125::non_last_segment::non_last_segment::issue_56125;
+   |         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 LL |     use crate::m3::last_segment::issue_56125;
    |         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-LL |     use crate::m3::non_last_segment::non_last_segment::issue_56125;
-   |         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-LL |     use issue_56125::issue_56125;
-   |         ~~~~~~~~~~~~~~~~~~~~~~~~
-LL |     use issue_56125::last_segment::issue_56125;
-   |         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      and 1 other candidate
 
 error[E0659]: `issue_56125` is ambiguous
diff --git a/tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.rs b/tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.rs
new file mode 100644
index 00000000000..e0edd522431
--- /dev/null
+++ b/tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.rs
@@ -0,0 +1,43 @@
+// Regression test for #116464
+// Checks that we do not suggest Trait<..., Assoc=arg> when the trait
+// is referred to from one of its impls but do so at all other places
+
+pub trait Trait<T> {
+    type Assoc;
+}
+
+impl<T, S> Trait<T> for i32 {
+    type Assoc = String;
+}
+
+// Should not not trigger suggestion here...
+impl<T, S> Trait<T, S> for () {}
+//~^ ERROR trait takes 1 generic argument but 2 generic arguments were supplied
+
+//... but should do so in all of the below cases except the last one
+fn func<T: Trait<u32, String>>(t: T) -> impl Trait<(), i32> {
+//~^ ERROR trait takes 1 generic argument but 2 generic arguments were supplied
+//~| ERROR trait takes 1 generic argument but 2 generic arguments were supplied
+    3
+}
+
+struct Struct<T: Trait<u32, String>> {
+//~^ ERROR trait takes 1 generic argument but 2 generic arguments were supplied
+    a: T
+}
+
+trait AnotherTrait<T: Trait<T, i32>> {}
+//~^ ERROR trait takes 1 generic argument but 2 generic arguments were supplied
+
+impl<T: Trait<u32, String>> Struct<T> {}
+//~^ ERROR trait takes 1 generic argument but 2 generic arguments were supplied
+
+// Test for self type. Should not trigger suggestion as it doesn't have an
+// associated type
+trait YetAnotherTrait {}
+impl<T: Trait<u32, Assoc=String>, U> YetAnotherTrait for Struct<T, U> {}
+//~^ ERROR struct takes 1 generic argument but 2 generic arguments were supplied
+
+
+fn main() {
+}
diff --git a/tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.stderr b/tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.stderr
new file mode 100644
index 00000000000..711ccf1b668
--- /dev/null
+++ b/tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.stderr
@@ -0,0 +1,109 @@
+error[E0107]: trait takes 1 generic argument but 2 generic arguments were supplied
+  --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:14:12
+   |
+LL | impl<T, S> Trait<T, S> for () {}
+   |            ^^^^^ expected 1 generic argument
+   |
+note: trait defined here, with 1 generic parameter: `T`
+  --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:5:11
+   |
+LL | pub trait Trait<T> {
+   |           ^^^^^ -
+
+error[E0107]: trait takes 1 generic argument but 2 generic arguments were supplied
+  --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:18:12
+   |
+LL | fn func<T: Trait<u32, String>>(t: T) -> impl Trait<(), i32> {
+   |            ^^^^^ expected 1 generic argument
+   |
+note: trait defined here, with 1 generic parameter: `T`
+  --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:5:11
+   |
+LL | pub trait Trait<T> {
+   |           ^^^^^ -
+help: replace the generic bound with the associated type
+   |
+LL | fn func<T: Trait<u32, Assoc = String>>(t: T) -> impl Trait<(), i32> {
+   |                       +++++++
+
+error[E0107]: trait takes 1 generic argument but 2 generic arguments were supplied
+  --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:18:46
+   |
+LL | fn func<T: Trait<u32, String>>(t: T) -> impl Trait<(), i32> {
+   |                                              ^^^^^ expected 1 generic argument
+   |
+note: trait defined here, with 1 generic parameter: `T`
+  --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:5:11
+   |
+LL | pub trait Trait<T> {
+   |           ^^^^^ -
+help: replace the generic bound with the associated type
+   |
+LL | fn func<T: Trait<u32, String>>(t: T) -> impl Trait<(), Assoc = i32> {
+   |                                                        +++++++
+
+error[E0107]: trait takes 1 generic argument but 2 generic arguments were supplied
+  --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:24:18
+   |
+LL | struct Struct<T: Trait<u32, String>> {
+   |                  ^^^^^ expected 1 generic argument
+   |
+note: trait defined here, with 1 generic parameter: `T`
+  --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:5:11
+   |
+LL | pub trait Trait<T> {
+   |           ^^^^^ -
+help: replace the generic bound with the associated type
+   |
+LL | struct Struct<T: Trait<u32, Assoc = String>> {
+   |                             +++++++
+
+error[E0107]: trait takes 1 generic argument but 2 generic arguments were supplied
+  --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:29:23
+   |
+LL | trait AnotherTrait<T: Trait<T, i32>> {}
+   |                       ^^^^^ expected 1 generic argument
+   |
+note: trait defined here, with 1 generic parameter: `T`
+  --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:5:11
+   |
+LL | pub trait Trait<T> {
+   |           ^^^^^ -
+help: replace the generic bound with the associated type
+   |
+LL | trait AnotherTrait<T: Trait<T, Assoc = i32>> {}
+   |                                +++++++
+
+error[E0107]: trait takes 1 generic argument but 2 generic arguments were supplied
+  --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:32:9
+   |
+LL | impl<T: Trait<u32, String>> Struct<T> {}
+   |         ^^^^^ expected 1 generic argument
+   |
+note: trait defined here, with 1 generic parameter: `T`
+  --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:5:11
+   |
+LL | pub trait Trait<T> {
+   |           ^^^^^ -
+help: replace the generic bound with the associated type
+   |
+LL | impl<T: Trait<u32, Assoc = String>> Struct<T> {}
+   |                    +++++++
+
+error[E0107]: struct takes 1 generic argument but 2 generic arguments were supplied
+  --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:38:58
+   |
+LL | impl<T: Trait<u32, Assoc=String>, U> YetAnotherTrait for Struct<T, U> {}
+   |                                                          ^^^^^^    - help: remove this generic argument
+   |                                                          |
+   |                                                          expected 1 generic argument
+   |
+note: struct defined here, with 1 generic parameter: `T`
+  --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:24:8
+   |
+LL | struct Struct<T: Trait<u32, String>> {
+   |        ^^^^^^ -
+
+error: aborting due to 7 previous errors
+
+For more information about this error, try `rustc --explain E0107`.
diff --git a/tests/ui/unresolved/auxiliary/library.rs b/tests/ui/unresolved/auxiliary/library.rs
new file mode 100644
index 00000000000..1169ed96225
--- /dev/null
+++ b/tests/ui/unresolved/auxiliary/library.rs
@@ -0,0 +1 @@
+pub struct SomeUsefulType;
diff --git a/tests/ui/unresolved/unresolved-import-avoid-suggesting-global-path.rs b/tests/ui/unresolved/unresolved-import-avoid-suggesting-global-path.rs
new file mode 100644
index 00000000000..af8207aaadd
--- /dev/null
+++ b/tests/ui/unresolved/unresolved-import-avoid-suggesting-global-path.rs
@@ -0,0 +1,31 @@
+// Test that we don't prepend `::` to paths referencing crates from the extern prelude
+// when it can be avoided[^1] since it's more idiomatic to do so.
+//
+// [^1]: Counterexample: `unresolved-import-suggest-disambiguated-crate-name.rs`
+#![feature(decl_macro)] // allows us to create items with hygienic names
+
+// aux-crate:library=library.rs
+// edition: 2021
+
+mod hygiene {
+    make!();
+    macro make() {
+        // This won't conflict with the suggested *non-global* path as the syntax context differs.
+        mod library {}
+    }
+
+    mod module {}
+    use module::SomeUsefulType; //~ ERROR unresolved import `module::SomeUsefulType`
+}
+
+mod glob {
+    use inner::*;
+    mod inner {
+        mod library {}
+    }
+
+    mod module {}
+    use module::SomeUsefulType; //~ ERROR unresolved import `module::SomeUsefulType`
+}
+
+fn main() {}
diff --git a/tests/ui/unresolved/unresolved-import-avoid-suggesting-global-path.stderr b/tests/ui/unresolved/unresolved-import-avoid-suggesting-global-path.stderr
new file mode 100644
index 00000000000..b0352ab6754
--- /dev/null
+++ b/tests/ui/unresolved/unresolved-import-avoid-suggesting-global-path.stderr
@@ -0,0 +1,25 @@
+error[E0432]: unresolved import `module::SomeUsefulType`
+  --> $DIR/unresolved-import-avoid-suggesting-global-path.rs:18:9
+   |
+LL |     use module::SomeUsefulType;
+   |         ^^^^^^^^^^^^^^^^^^^^^^ no `SomeUsefulType` in `hygiene::module`
+   |
+help: consider importing this struct instead
+   |
+LL |     use library::SomeUsefulType;
+   |         ~~~~~~~~~~~~~~~~~~~~~~~
+
+error[E0432]: unresolved import `module::SomeUsefulType`
+  --> $DIR/unresolved-import-avoid-suggesting-global-path.rs:28:9
+   |
+LL |     use module::SomeUsefulType;
+   |         ^^^^^^^^^^^^^^^^^^^^^^ no `SomeUsefulType` in `glob::module`
+   |
+help: consider importing this struct instead
+   |
+LL |     use library::SomeUsefulType;
+   |         ~~~~~~~~~~~~~~~~~~~~~~~
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0432`.
diff --git a/tests/ui/unresolved/unresolved-import-suggest-disambiguated-crate-name.fixed b/tests/ui/unresolved/unresolved-import-suggest-disambiguated-crate-name.fixed
new file mode 100644
index 00000000000..2b20d3f106b
--- /dev/null
+++ b/tests/ui/unresolved/unresolved-import-suggest-disambiguated-crate-name.fixed
@@ -0,0 +1,19 @@
+// Regression test for issue #116970.
+//
+// When we suggest importing an item from a crate found in the extern prelude and there
+// happens to exist a module or type in the current scope with the same name as the crate,
+// disambiguate the suggested path by making it global (i.e., by prefixing it with `::`).
+//
+// For context, when it can be avoided we don't prepend `::` to paths referencing crates
+// from the extern prelude. See also `unresolved-import-avoid-suggesting-global-path.rs`.
+
+// run-rustfix
+
+// compile-flags: --crate-type=lib
+// aux-crate:library=library.rs
+// edition: 2021
+
+mod library {} // this module shares the same name as the external crate!
+
+mod module {}
+pub use ::library::SomeUsefulType; //~ ERROR unresolved import `module::SomeUsefulType`
diff --git a/tests/ui/unresolved/unresolved-import-suggest-disambiguated-crate-name.rs b/tests/ui/unresolved/unresolved-import-suggest-disambiguated-crate-name.rs
new file mode 100644
index 00000000000..b810a7f5296
--- /dev/null
+++ b/tests/ui/unresolved/unresolved-import-suggest-disambiguated-crate-name.rs
@@ -0,0 +1,19 @@
+// Regression test for issue #116970.
+//
+// When we suggest importing an item from a crate found in the extern prelude and there
+// happens to exist a module or type in the current scope with the same name as the crate,
+// disambiguate the suggested path by making it global (i.e., by prefixing it with `::`).
+//
+// For context, when it can be avoided we don't prepend `::` to paths referencing crates
+// from the extern prelude. See also `unresolved-import-avoid-suggesting-global-path.rs`.
+
+// run-rustfix
+
+// compile-flags: --crate-type=lib
+// aux-crate:library=library.rs
+// edition: 2021
+
+mod library {} // this module shares the same name as the external crate!
+
+mod module {}
+pub use module::SomeUsefulType; //~ ERROR unresolved import `module::SomeUsefulType`
diff --git a/tests/ui/unresolved/unresolved-import-suggest-disambiguated-crate-name.stderr b/tests/ui/unresolved/unresolved-import-suggest-disambiguated-crate-name.stderr
new file mode 100644
index 00000000000..f139c0f3cf1
--- /dev/null
+++ b/tests/ui/unresolved/unresolved-import-suggest-disambiguated-crate-name.stderr
@@ -0,0 +1,14 @@
+error[E0432]: unresolved import `module::SomeUsefulType`
+  --> $DIR/unresolved-import-suggest-disambiguated-crate-name.rs:19:9
+   |
+LL | pub use module::SomeUsefulType;
+   |         ^^^^^^^^^^^^^^^^^^^^^^ no `SomeUsefulType` in `module`
+   |
+help: consider importing this struct instead
+   |
+LL | pub use ::library::SomeUsefulType;
+   |         ~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0432`.