about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-12-15 01:24:40 +0000
committerbors <bors@rust-lang.org>2024-12-15 01:24:40 +0000
commit7caf35b2e5401d7740fdc567fdc388059208150b (patch)
tree49b11fbac4bfebbc02a0950ec196e20a12f87654
parentb57d93d8b9525fa261404b4cd9c0670eeb1264b8 (diff)
parent0f828022dbc8e57696b624914082713ce7b447c5 (diff)
downloadrust-7caf35b2e5401d7740fdc567fdc388059208150b.tar.gz
rust-7caf35b2e5401d7740fdc567fdc388059208150b.zip
Auto merge of #134318 - matthiaskrgr:rollup-jda0jkx, r=matthiaskrgr
Rollup of 7 pull requests

Successful merges:

 - #132939 (Suggest using deref in patterns)
 - #133293 (Updates Solaris target information, adds Solaris maintainer)
 - #133392 (Fix ICE when multiple supertrait substitutions need assoc but only one is provided)
 - #133986 (Add documentation for anonymous pipe module)
 - #134022 (Doc: Extend for tuples to be stabilized in 1.85.0)
 - #134259 (Clean up `infer_return_ty_for_fn_sig`)
 - #134264 (Arbitrary self types v2: Weak & NonNull diagnostics)

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--compiler/rustc_hir/src/hir.rs16
-rw-r--r--compiler/rustc_hir_analysis/messages.ftl6
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs14
-rw-r--r--compiler/rustc_hir_analysis/src/collect.rs179
-rw-r--r--compiler/rustc_hir_analysis/src/errors.rs10
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs52
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs244
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs17
-rw-r--r--compiler/rustc_hir_typeck/src/pat.rs30
-rw-r--r--compiler/rustc_middle/src/traits/mod.rs23
-rw-r--r--compiler/rustc_target/src/spec/targets/sparcv9_sun_solaris.rs2
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_pc_solaris.rs2
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs115
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs2
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs11
-rw-r--r--library/core/src/iter/traits/collect.rs63
-rw-r--r--library/std/src/pipe.rs140
-rw-r--r--src/doc/rustc/src/SUMMARY.md2
-rw-r--r--src/doc/rustc/src/platform-support.md4
-rw-r--r--src/doc/rustc/src/platform-support/solaris.md32
-rw-r--r--tests/ui/associated-types/missing-associated-types.stderr4
-rw-r--r--tests/ui/closures/2229_closure_analysis/issue-118144.stderr5
-rw-r--r--tests/ui/dyn-compatibility/assoc_type_bounds.rs4
-rw-r--r--tests/ui/dyn-compatibility/assoc_type_bounds.stderr4
-rw-r--r--tests/ui/dyn-compatibility/assoc_type_bounds2.rs4
-rw-r--r--tests/ui/dyn-compatibility/assoc_type_bounds2.stderr4
-rw-r--r--tests/ui/dyn-compatibility/require-assoc-for-all-super-substs.rs15
-rw-r--r--tests/ui/dyn-compatibility/require-assoc-for-all-super-substs.stderr12
-rw-r--r--tests/ui/issues/issue-28344.stderr4
-rw-r--r--tests/ui/issues/issue-57741-dereference-boxed-value/issue-57741.stderr36
-rw-r--r--tests/ui/let-else/let-else-deref-coercion.stderr10
-rw-r--r--tests/ui/self/arbitrary_self_types_nonnull.rs13
-rw-r--r--tests/ui/self/arbitrary_self_types_nonnull.stderr23
-rw-r--r--tests/ui/self/arbitrary_self_types_weak.rs13
-rw-r--r--tests/ui/self/arbitrary_self_types_weak.stderr23
-rw-r--r--tests/ui/suggestions/suggest-deref-in-match-issue-132784.rs84
-rw-r--r--tests/ui/suggestions/suggest-deref-in-match-issue-132784.stderr259
37 files changed, 1152 insertions, 329 deletions
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 357033a9e18..2e795d84559 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -2025,6 +2025,22 @@ pub fn is_range_literal(expr: &Expr<'_>) -> bool {
     }
 }
 
+/// Checks if the specified expression needs parentheses for prefix
+/// or postfix suggestions to be valid.
+/// For example, `a + b` requires parentheses to suggest `&(a + b)`,
+/// but just `a` does not.
+/// Similarly, `(a + b).c()` also requires parentheses.
+/// This should not be used for other types of suggestions.
+pub fn expr_needs_parens(expr: &Expr<'_>) -> bool {
+    match expr.kind {
+        // parenthesize if needed (Issue #46756)
+        ExprKind::Cast(_, _) | ExprKind::Binary(_, _, _) => true,
+        // parenthesize borrows of range literals (Issue #54505)
+        _ if is_range_literal(expr) => true,
+        _ => false,
+    }
+}
+
 #[derive(Debug, Clone, Copy, HashStable_Generic)]
 pub enum ExprKind<'hir> {
     /// Allow anonymous constants from an inline `const` block
diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl
index a2df0ba265c..0c3ed9b5c60 100644
--- a/compiler/rustc_hir_analysis/messages.ftl
+++ b/compiler/rustc_hir_analysis/messages.ftl
@@ -249,6 +249,12 @@ hir_analysis_invalid_receiver_ty_help =
 hir_analysis_invalid_receiver_ty_help_no_arbitrary_self_types =
     consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
 
+hir_analysis_invalid_receiver_ty_help_nonnull_note =
+    `NonNull` does not implement `Receiver` because it has methods that may shadow the referent; consider wrapping your `NonNull` in a newtype wrapper for which you implement `Receiver`
+
+hir_analysis_invalid_receiver_ty_help_weak_note =
+    `Weak` does not implement `Receiver` because it has methods that may shadow the referent; consider wrapping your `Weak` in a newtype wrapper for which you implement `Receiver`
+
 hir_analysis_invalid_receiver_ty_no_arbitrary_self_types = invalid `self` parameter type: `{$receiver_ty}`
     .note = type of `self` must be `Self` or a type that dereferences to it
 
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index e6ef29de965..95ad8225f61 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -44,6 +44,7 @@ use {rustc_ast as ast, rustc_hir as hir};
 use crate::autoderef::Autoderef;
 use crate::collect::CollectItemTypesVisitor;
 use crate::constrained_generic_params::{Parameter, identify_constrained_generic_params};
+use crate::errors::InvalidReceiverTyHint;
 use crate::{errors, fluent_generated as fluent};
 
 pub(super) struct WfCheckingCtxt<'a, 'tcx> {
@@ -1749,7 +1750,18 @@ fn check_method_receiver<'tcx>(
             {
                 match receiver_validity_err {
                     ReceiverValidityError::DoesNotDeref if arbitrary_self_types_level.is_some() => {
-                        tcx.dcx().emit_err(errors::InvalidReceiverTy { span, receiver_ty })
+                        let hint = match receiver_ty
+                            .builtin_deref(false)
+                            .unwrap_or(receiver_ty)
+                            .ty_adt_def()
+                            .and_then(|adt_def| tcx.get_diagnostic_name(adt_def.did()))
+                        {
+                            Some(sym::RcWeak | sym::ArcWeak) => Some(InvalidReceiverTyHint::Weak),
+                            Some(sym::NonNull) => Some(InvalidReceiverTyHint::NonNull),
+                            _ => None,
+                        };
+
+                        tcx.dcx().emit_err(errors::InvalidReceiverTy { span, receiver_ty, hint })
                     }
                     ReceiverValidityError::DoesNotDeref => {
                         tcx.dcx().emit_err(errors::InvalidReceiverTyNoArbitrarySelfTypes {
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index 7fb024cce5a..8c9da78a659 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -1340,7 +1340,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, ty::PolyFn
             ..
         })
         | Item(hir::Item { kind: ItemKind::Fn(sig, generics, _), .. }) => {
-            infer_return_ty_for_fn_sig(sig, generics, def_id, &icx)
+            lower_fn_sig_recovering_infer_ret_ty(&icx, sig, generics, def_id)
         }
 
         ImplItem(hir::ImplItem { kind: ImplItemKind::Fn(sig, _), generics, .. }) => {
@@ -1357,7 +1357,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, ty::PolyFn
                     None,
                 )
             } else {
-                infer_return_ty_for_fn_sig(sig, generics, def_id, &icx)
+                lower_fn_sig_recovering_infer_ret_ty(&icx, sig, generics, def_id)
             }
         }
 
@@ -1407,99 +1407,108 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, ty::PolyFn
     ty::EarlyBinder::bind(output)
 }
 
-fn infer_return_ty_for_fn_sig<'tcx>(
-    sig: &hir::FnSig<'tcx>,
-    generics: &hir::Generics<'_>,
+fn lower_fn_sig_recovering_infer_ret_ty<'tcx>(
+    icx: &ItemCtxt<'tcx>,
+    sig: &'tcx hir::FnSig<'tcx>,
+    generics: &'tcx hir::Generics<'tcx>,
     def_id: LocalDefId,
+) -> ty::PolyFnSig<'tcx> {
+    if let Some(infer_ret_ty) = sig.decl.output.get_infer_ret_ty() {
+        return recover_infer_ret_ty(icx, infer_ret_ty, generics, def_id);
+    }
+
+    icx.lowerer().lower_fn_ty(
+        icx.tcx().local_def_id_to_hir_id(def_id),
+        sig.header.safety,
+        sig.header.abi,
+        sig.decl,
+        Some(generics),
+        None,
+    )
+}
+
+fn recover_infer_ret_ty<'tcx>(
     icx: &ItemCtxt<'tcx>,
+    infer_ret_ty: &'tcx hir::Ty<'tcx>,
+    generics: &'tcx hir::Generics<'tcx>,
+    def_id: LocalDefId,
 ) -> ty::PolyFnSig<'tcx> {
     let tcx = icx.tcx;
     let hir_id = tcx.local_def_id_to_hir_id(def_id);
 
-    match sig.decl.output.get_infer_ret_ty() {
-        Some(ty) => {
-            let fn_sig = tcx.typeck(def_id).liberated_fn_sigs()[hir_id];
-            // Typeck doesn't expect erased regions to be returned from `type_of`.
-            // This is a heuristic approach. If the scope has region parameters,
-            // we should change fn_sig's lifetime from `ReErased` to `ReError`,
-            // otherwise to `ReStatic`.
-            let has_region_params = generics.params.iter().any(|param| match param.kind {
-                GenericParamKind::Lifetime { .. } => true,
-                _ => false,
-            });
-            let fn_sig = fold_regions(tcx, fn_sig, |r, _| match *r {
-                ty::ReErased => {
-                    if has_region_params {
-                        ty::Region::new_error_with_message(
-                            tcx,
-                            DUMMY_SP,
-                            "erased region is not allowed here in return type",
-                        )
-                    } else {
-                        tcx.lifetimes.re_static
-                    }
-                }
-                _ => r,
-            });
+    let fn_sig = tcx.typeck(def_id).liberated_fn_sigs()[hir_id];
 
-            let mut visitor = HirPlaceholderCollector::default();
-            visitor.visit_ty(ty);
-
-            let mut diag = bad_placeholder(icx.lowerer(), visitor.0, "return type");
-            let ret_ty = fn_sig.output();
-            // Don't leak types into signatures unless they're nameable!
-            // For example, if a function returns itself, we don't want that
-            // recursive function definition to leak out into the fn sig.
-            let mut recovered_ret_ty = None;
-
-            if let Some(suggestable_ret_ty) = ret_ty.make_suggestable(tcx, false, None) {
-                diag.span_suggestion(
-                    ty.span,
-                    "replace with the correct return type",
-                    suggestable_ret_ty,
-                    Applicability::MachineApplicable,
-                );
-                recovered_ret_ty = Some(suggestable_ret_ty);
-            } else if let Some(sugg) = suggest_impl_trait(
-                &tcx.infer_ctxt().build(TypingMode::non_body_analysis()),
-                tcx.param_env(def_id),
-                ret_ty,
-            ) {
-                diag.span_suggestion(
-                    ty.span,
-                    "replace with an appropriate return type",
-                    sugg,
-                    Applicability::MachineApplicable,
-                );
-            } else if ret_ty.is_closure() {
-                diag.help("consider using an `Fn`, `FnMut`, or `FnOnce` trait bound");
-            }
-            // Also note how `Fn` traits work just in case!
-            if ret_ty.is_closure() {
-                diag.note(
-                    "for more information on `Fn` traits and closure types, see \
-                     https://doc.rust-lang.org/book/ch13-01-closures.html",
-                );
+    // Typeck doesn't expect erased regions to be returned from `type_of`.
+    // This is a heuristic approach. If the scope has region parameters,
+    // we should change fn_sig's lifetime from `ReErased` to `ReError`,
+    // otherwise to `ReStatic`.
+    let has_region_params = generics.params.iter().any(|param| match param.kind {
+        GenericParamKind::Lifetime { .. } => true,
+        _ => false,
+    });
+    let fn_sig = fold_regions(tcx, fn_sig, |r, _| match *r {
+        ty::ReErased => {
+            if has_region_params {
+                ty::Region::new_error_with_message(
+                    tcx,
+                    DUMMY_SP,
+                    "erased region is not allowed here in return type",
+                )
+            } else {
+                tcx.lifetimes.re_static
             }
-
-            let guar = diag.emit();
-            ty::Binder::dummy(tcx.mk_fn_sig(
-                fn_sig.inputs().iter().copied(),
-                recovered_ret_ty.unwrap_or_else(|| Ty::new_error(tcx, guar)),
-                fn_sig.c_variadic,
-                fn_sig.safety,
-                fn_sig.abi,
-            ))
         }
-        None => icx.lowerer().lower_fn_ty(
-            hir_id,
-            sig.header.safety,
-            sig.header.abi,
-            sig.decl,
-            Some(generics),
-            None,
-        ),
+        _ => r,
+    });
+
+    let mut visitor = HirPlaceholderCollector::default();
+    visitor.visit_ty(infer_ret_ty);
+
+    let mut diag = bad_placeholder(icx.lowerer(), visitor.0, "return type");
+    let ret_ty = fn_sig.output();
+
+    // Don't leak types into signatures unless they're nameable!
+    // For example, if a function returns itself, we don't want that
+    // recursive function definition to leak out into the fn sig.
+    let mut recovered_ret_ty = None;
+    if let Some(suggestable_ret_ty) = ret_ty.make_suggestable(tcx, false, None) {
+        diag.span_suggestion(
+            infer_ret_ty.span,
+            "replace with the correct return type",
+            suggestable_ret_ty,
+            Applicability::MachineApplicable,
+        );
+        recovered_ret_ty = Some(suggestable_ret_ty);
+    } else if let Some(sugg) = suggest_impl_trait(
+        &tcx.infer_ctxt().build(TypingMode::non_body_analysis()),
+        tcx.param_env(def_id),
+        ret_ty,
+    ) {
+        diag.span_suggestion(
+            infer_ret_ty.span,
+            "replace with an appropriate return type",
+            sugg,
+            Applicability::MachineApplicable,
+        );
+    } else if ret_ty.is_closure() {
+        diag.help("consider using an `Fn`, `FnMut`, or `FnOnce` trait bound");
+    }
+
+    // Also note how `Fn` traits work just in case!
+    if ret_ty.is_closure() {
+        diag.note(
+            "for more information on `Fn` traits and closure types, see \
+                     https://doc.rust-lang.org/book/ch13-01-closures.html",
+        );
     }
+    let guar = diag.emit();
+    ty::Binder::dummy(tcx.mk_fn_sig(
+        fn_sig.inputs().iter().copied(),
+        recovered_ret_ty.unwrap_or_else(|| Ty::new_error(tcx, guar)),
+        fn_sig.c_variadic,
+        fn_sig.safety,
+        fn_sig.abi,
+    ))
 }
 
 pub fn suggest_impl_trait<'tcx>(
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index 5ab6faf3b7c..d46f60b16f5 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -1655,6 +1655,14 @@ pub(crate) struct NonConstRange {
     pub span: Span,
 }
 
+#[derive(Subdiagnostic)]
+pub(crate) enum InvalidReceiverTyHint {
+    #[note(hir_analysis_invalid_receiver_ty_help_weak_note)]
+    Weak,
+    #[note(hir_analysis_invalid_receiver_ty_help_nonnull_note)]
+    NonNull,
+}
+
 #[derive(Diagnostic)]
 #[diag(hir_analysis_invalid_receiver_ty_no_arbitrary_self_types, code = E0307)]
 #[note]
@@ -1673,6 +1681,8 @@ pub(crate) struct InvalidReceiverTy<'tcx> {
     #[primary_span]
     pub span: Span,
     pub receiver_ty: Ty<'tcx>,
+    #[subdiagnostic]
+    pub hint: Option<InvalidReceiverTyHint>,
 }
 
 #[derive(Diagnostic)]
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
index d3c86989440..71a5727ed6c 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
@@ -1,9 +1,8 @@
-use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
+use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
 use rustc_errors::codes::*;
 use rustc_errors::struct_span_code_err;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::DefId;
 use rustc_lint_defs::builtin::UNUSED_ASSOCIATED_TYPE_BOUNDS;
 use rustc_middle::span_bug;
 use rustc_middle::ty::fold::BottomUpFolder;
@@ -11,7 +10,7 @@ use rustc_middle::ty::{
     self, DynKind, ExistentialPredicateStableCmpExt as _, Ty, TyCtxt, TypeFoldable,
     TypeVisitableExt, Upcast,
 };
-use rustc_span::{ErrorGuaranteed, Span};
+use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span};
 use rustc_trait_selection::error_reporting::traits::report_dyn_incompatibility;
 use rustc_trait_selection::traits::{self, hir_ty_lowering_dyn_compatibility_violations};
 use rustc_type_ir::elaborate::ClauseWithSupertraitSpan;
@@ -128,8 +127,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             }
         }
 
-        let mut associated_types: FxIndexMap<Span, FxIndexSet<DefId>> = FxIndexMap::default();
+        let mut needed_associated_types = FxIndexSet::default();
 
+        let principal_span = regular_traits.first().map_or(DUMMY_SP, |info| info.bottom().1);
         let regular_traits_refs_spans = trait_bounds
             .into_iter()
             .filter(|(trait_ref, _)| !tcx.trait_is_auto(trait_ref.def_id()));
@@ -145,13 +145,18 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 let bound_predicate = pred.kind();
                 match bound_predicate.skip_binder() {
                     ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => {
-                        let pred = bound_predicate.rebind(pred);
-                        associated_types.entry(original_span).or_default().extend(
-                            tcx.associated_items(pred.def_id())
+                        // FIXME(negative_bounds): Handle this correctly...
+                        let trait_ref =
+                            tcx.anonymize_bound_vars(bound_predicate.rebind(pred.trait_ref));
+                        needed_associated_types.extend(
+                            tcx.associated_items(trait_ref.def_id())
                                 .in_definition_order()
                                 .filter(|item| item.kind == ty::AssocKind::Type)
                                 .filter(|item| !item.is_impl_trait_in_trait())
-                                .map(|item| item.def_id),
+                                // If the associated type has a `where Self: Sized` bound,
+                                // we do not need to constrain the associated type.
+                                .filter(|item| !tcx.generics_require_sized_self(item.def_id))
+                                .map(|item| (item.def_id, trait_ref)),
                         );
                     }
                     ty::PredicateKind::Clause(ty::ClauseKind::Projection(pred)) => {
@@ -201,26 +206,25 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         // So every `Projection` clause is an `Assoc = Foo` bound. `associated_types` contains all associated
         // types's `DefId`, so the following loop removes all the `DefIds` of the associated types that have a
         // corresponding `Projection` clause
-        for def_ids in associated_types.values_mut() {
-            for (projection_bound, span) in &projection_bounds {
-                let def_id = projection_bound.item_def_id();
-                def_ids.swap_remove(&def_id);
-                if tcx.generics_require_sized_self(def_id) {
-                    tcx.emit_node_span_lint(
-                        UNUSED_ASSOCIATED_TYPE_BOUNDS,
-                        hir_id,
-                        *span,
-                        crate::errors::UnusedAssociatedTypeBounds { span: *span },
-                    );
-                }
+        for (projection_bound, span) in &projection_bounds {
+            let def_id = projection_bound.item_def_id();
+            let trait_ref = tcx.anonymize_bound_vars(
+                projection_bound.map_bound(|p| p.projection_term.trait_ref(tcx)),
+            );
+            needed_associated_types.swap_remove(&(def_id, trait_ref));
+            if tcx.generics_require_sized_self(def_id) {
+                tcx.emit_node_span_lint(
+                    UNUSED_ASSOCIATED_TYPE_BOUNDS,
+                    hir_id,
+                    *span,
+                    crate::errors::UnusedAssociatedTypeBounds { span: *span },
+                );
             }
-            // If the associated type has a `where Self: Sized` bound, we do not need to constrain the associated
-            // type in the `dyn Trait`.
-            def_ids.retain(|def_id| !tcx.generics_require_sized_self(def_id));
         }
 
         if let Err(guar) = self.check_for_required_assoc_tys(
-            associated_types,
+            principal_span,
+            needed_associated_types,
             potential_assoc_types,
             hir_trait_bounds,
         ) {
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
index 6e10450313c..00c1f9b332b 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
@@ -721,51 +721,42 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
     /// emit a generic note suggesting using a `where` clause to constraint instead.
     pub(crate) fn check_for_required_assoc_tys(
         &self,
-        associated_types: FxIndexMap<Span, FxIndexSet<DefId>>,
+        principal_span: Span,
+        missing_assoc_types: FxIndexSet<(DefId, ty::PolyTraitRef<'tcx>)>,
         potential_assoc_types: Vec<usize>,
         trait_bounds: &[hir::PolyTraitRef<'_>],
     ) -> Result<(), ErrorGuaranteed> {
-        if associated_types.values().all(|v| v.is_empty()) {
+        if missing_assoc_types.is_empty() {
             return Ok(());
         }
 
         let tcx = self.tcx();
-        // FIXME: Marked `mut` so that we can replace the spans further below with a more
-        // appropriate one, but this should be handled earlier in the span assignment.
-        let associated_types: FxIndexMap<Span, Vec<_>> = associated_types
+        // FIXME: This logic needs some more care w.r.t handling of conflicts
+        let missing_assoc_types: Vec<_> = missing_assoc_types
             .into_iter()
-            .map(|(span, def_ids)| {
-                (span, def_ids.into_iter().map(|did| tcx.associated_item(did)).collect())
-            })
+            .map(|(def_id, trait_ref)| (tcx.associated_item(def_id), trait_ref))
             .collect();
-        let mut names: FxIndexMap<String, Vec<Symbol>> = Default::default();
+        let mut names: FxIndexMap<_, Vec<Symbol>> = Default::default();
         let mut names_len = 0;
 
         // Account for things like `dyn Foo + 'a`, like in tests `issue-22434.rs` and
         // `issue-22560.rs`.
-        let mut trait_bound_spans: Vec<Span> = vec![];
         let mut dyn_compatibility_violations = Ok(());
-        for (span, items) in &associated_types {
-            if !items.is_empty() {
-                trait_bound_spans.push(*span);
-            }
-            for assoc_item in items {
-                let trait_def_id = assoc_item.container_id(tcx);
-                names.entry(tcx.def_path_str(trait_def_id)).or_default().push(assoc_item.name);
-                names_len += 1;
-
-                let violations =
-                    dyn_compatibility_violations_for_assoc_item(tcx, trait_def_id, *assoc_item);
-                if !violations.is_empty() {
-                    dyn_compatibility_violations = Err(report_dyn_incompatibility(
-                        tcx,
-                        *span,
-                        None,
-                        trait_def_id,
-                        &violations,
-                    )
-                    .emit());
-                }
+        for (assoc_item, trait_ref) in &missing_assoc_types {
+            names.entry(trait_ref).or_default().push(assoc_item.name);
+            names_len += 1;
+
+            let violations =
+                dyn_compatibility_violations_for_assoc_item(tcx, trait_ref.def_id(), *assoc_item);
+            if !violations.is_empty() {
+                dyn_compatibility_violations = Err(report_dyn_incompatibility(
+                    tcx,
+                    principal_span,
+                    None,
+                    trait_ref.def_id(),
+                    &violations,
+                )
+                .emit());
             }
         }
 
@@ -813,6 +804,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             .into_iter()
             .map(|(trait_, mut assocs)| {
                 assocs.sort();
+                let trait_ = trait_.print_trait_sugared();
                 format!("{} in `{trait_}`", match &assocs[..] {
                     [] => String::new(),
                     [only] => format!("`{only}`"),
@@ -826,10 +818,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         names.sort();
         let names = names.join(", ");
 
-        trait_bound_spans.sort();
         let mut err = struct_span_code_err!(
             self.dcx(),
-            trait_bound_spans,
+            principal_span,
             E0191,
             "the value of the associated type{} {} must be specified",
             pluralize!(names_len),
@@ -839,81 +830,83 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         let mut types_count = 0;
         let mut where_constraints = vec![];
         let mut already_has_generics_args_suggestion = false;
-        for (span, assoc_items) in &associated_types {
-            let mut names: UnordMap<_, usize> = Default::default();
-            for item in assoc_items {
-                types_count += 1;
-                *names.entry(item.name).or_insert(0) += 1;
-            }
-            let mut dupes = false;
-            let mut shadows = false;
-            for item in assoc_items {
-                let prefix = if names[&item.name] > 1 {
-                    let trait_def_id = item.container_id(tcx);
-                    dupes = true;
-                    format!("{}::", tcx.def_path_str(trait_def_id))
-                } else if bound_names.get(&item.name).is_some_and(|x| x != &item) {
-                    let trait_def_id = item.container_id(tcx);
-                    shadows = true;
-                    format!("{}::", tcx.def_path_str(trait_def_id))
-                } else {
-                    String::new()
-                };
 
-                let mut is_shadowed = false;
-
-                if let Some(assoc_item) = bound_names.get(&item.name)
-                    && assoc_item != &item
-                {
-                    is_shadowed = true;
+        let mut names: UnordMap<_, usize> = Default::default();
+        for (item, _) in &missing_assoc_types {
+            types_count += 1;
+            *names.entry(item.name).or_insert(0) += 1;
+        }
+        let mut dupes = false;
+        let mut shadows = false;
+        for (item, trait_ref) in &missing_assoc_types {
+            let prefix = if names[&item.name] > 1 {
+                let trait_def_id = trait_ref.def_id();
+                dupes = true;
+                format!("{}::", tcx.def_path_str(trait_def_id))
+            } else if bound_names.get(&item.name).is_some_and(|x| *x != item) {
+                let trait_def_id = trait_ref.def_id();
+                shadows = true;
+                format!("{}::", tcx.def_path_str(trait_def_id))
+            } else {
+                String::new()
+            };
 
-                    let rename_message =
-                        if assoc_item.def_id.is_local() { ", consider renaming it" } else { "" };
-                    err.span_label(
-                        tcx.def_span(assoc_item.def_id),
-                        format!("`{}{}` shadowed here{}", prefix, item.name, rename_message),
-                    );
-                }
+            let mut is_shadowed = false;
 
-                let rename_message = if is_shadowed { ", consider renaming it" } else { "" };
+            if let Some(assoc_item) = bound_names.get(&item.name)
+                && *assoc_item != item
+            {
+                is_shadowed = true;
 
-                if let Some(sp) = tcx.hir().span_if_local(item.def_id) {
-                    err.span_label(
-                        sp,
-                        format!("`{}{}` defined here{}", prefix, item.name, rename_message),
-                    );
-                }
+                let rename_message =
+                    if assoc_item.def_id.is_local() { ", consider renaming it" } else { "" };
+                err.span_label(
+                    tcx.def_span(assoc_item.def_id),
+                    format!("`{}{}` shadowed here{}", prefix, item.name, rename_message),
+                );
             }
-            if potential_assoc_types.len() == assoc_items.len() {
-                // When the amount of missing associated types equals the number of
-                // extra type arguments present. A suggesting to replace the generic args with
-                // associated types is already emitted.
-                already_has_generics_args_suggestion = true;
-            } else if let (Ok(snippet), false, false) =
-                (tcx.sess.source_map().span_to_snippet(*span), dupes, shadows)
-            {
-                let types: Vec<_> =
-                    assoc_items.iter().map(|item| format!("{} = Type", item.name)).collect();
-                let code = if snippet.ends_with('>') {
-                    // The user wrote `Trait<'a>` or similar and we don't have a type we can
-                    // suggest, but at least we can clue them to the correct syntax
-                    // `Trait<'a, Item = Type>` while accounting for the `<'a>` in the
-                    // suggestion.
-                    format!("{}, {}>", &snippet[..snippet.len() - 1], types.join(", "))
-                } else if in_expr_or_pat {
-                    // The user wrote `Iterator`, so we don't have a type we can suggest, but at
-                    // least we can clue them to the correct syntax `Iterator::<Item = Type>`.
-                    format!("{}::<{}>", snippet, types.join(", "))
-                } else {
-                    // The user wrote `Iterator`, so we don't have a type we can suggest, but at
-                    // least we can clue them to the correct syntax `Iterator<Item = Type>`.
-                    format!("{}<{}>", snippet, types.join(", "))
-                };
-                suggestions.push((*span, code));
-            } else if dupes {
-                where_constraints.push(*span);
+
+            let rename_message = if is_shadowed { ", consider renaming it" } else { "" };
+
+            if let Some(sp) = tcx.hir().span_if_local(item.def_id) {
+                err.span_label(
+                    sp,
+                    format!("`{}{}` defined here{}", prefix, item.name, rename_message),
+                );
             }
         }
+        if potential_assoc_types.len() == missing_assoc_types.len() {
+            // When the amount of missing associated types equals the number of
+            // extra type arguments present. A suggesting to replace the generic args with
+            // associated types is already emitted.
+            already_has_generics_args_suggestion = true;
+        } else if let (Ok(snippet), false, false) =
+            (tcx.sess.source_map().span_to_snippet(principal_span), dupes, shadows)
+        {
+            let types: Vec<_> = missing_assoc_types
+                .iter()
+                .map(|(item, _)| format!("{} = Type", item.name))
+                .collect();
+            let code = if snippet.ends_with('>') {
+                // The user wrote `Trait<'a>` or similar and we don't have a type we can
+                // suggest, but at least we can clue them to the correct syntax
+                // `Trait<'a, Item = Type>` while accounting for the `<'a>` in the
+                // suggestion.
+                format!("{}, {}>", &snippet[..snippet.len() - 1], types.join(", "))
+            } else if in_expr_or_pat {
+                // The user wrote `Iterator`, so we don't have a type we can suggest, but at
+                // least we can clue them to the correct syntax `Iterator::<Item = Type>`.
+                format!("{}::<{}>", snippet, types.join(", "))
+            } else {
+                // The user wrote `Iterator`, so we don't have a type we can suggest, but at
+                // least we can clue them to the correct syntax `Iterator<Item = Type>`.
+                format!("{}<{}>", snippet, types.join(", "))
+            };
+            suggestions.push((principal_span, code));
+        } else if dupes {
+            where_constraints.push(principal_span);
+        }
+
         let where_msg = "consider introducing a new type parameter, adding `where` constraints \
                          using the fully-qualified path to the associated types";
         if !where_constraints.is_empty() && suggestions.is_empty() {
@@ -924,32 +917,29 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         }
         if suggestions.len() != 1 || already_has_generics_args_suggestion {
             // We don't need this label if there's an inline suggestion, show otherwise.
-            for (span, assoc_items) in &associated_types {
-                let mut names: FxIndexMap<_, usize> = FxIndexMap::default();
-                for item in assoc_items {
-                    types_count += 1;
-                    *names.entry(item.name).or_insert(0) += 1;
-                }
-                let mut label = vec![];
-                for item in assoc_items {
-                    let postfix = if names[&item.name] > 1 {
-                        let trait_def_id = item.container_id(tcx);
-                        format!(" (from trait `{}`)", tcx.def_path_str(trait_def_id))
-                    } else {
-                        String::new()
-                    };
-                    label.push(format!("`{}`{}", item.name, postfix));
-                }
-                if !label.is_empty() {
-                    err.span_label(
-                        *span,
-                        format!(
-                            "associated type{} {} must be specified",
-                            pluralize!(label.len()),
-                            label.join(", "),
-                        ),
-                    );
-                }
+            let mut names: FxIndexMap<_, usize> = FxIndexMap::default();
+            for (item, _) in &missing_assoc_types {
+                types_count += 1;
+                *names.entry(item.name).or_insert(0) += 1;
+            }
+            let mut label = vec![];
+            for (item, trait_ref) in &missing_assoc_types {
+                let postfix = if names[&item.name] > 1 {
+                    format!(" (from trait `{}`)", trait_ref.print_trait_sugared())
+                } else {
+                    String::new()
+                };
+                label.push(format!("`{}`{}", item.name, postfix));
+            }
+            if !label.is_empty() {
+                err.span_label(
+                    principal_span,
+                    format!(
+                        "associated type{} {} must be specified",
+                        pluralize!(label.len()),
+                        label.join(", "),
+                    ),
+                );
             }
         }
         suggestions.sort_by_key(|&(span, _)| span);
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
index ddcd90a2a9d..21b1768ae6f 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
@@ -10,7 +10,7 @@ use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{
     Arm, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind, GenericBound, HirId,
-    Node, Path, QPath, Stmt, StmtKind, TyKind, WherePredicateKind,
+    Node, Path, QPath, Stmt, StmtKind, TyKind, WherePredicateKind, expr_needs_parens,
 };
 use rustc_hir_analysis::collect::suggest_impl_trait;
 use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer;
@@ -35,7 +35,6 @@ use tracing::{debug, instrument};
 
 use super::FnCtxt;
 use crate::fn_ctxt::rustc_span::BytePos;
-use crate::hir::is_range_literal;
 use crate::method::probe;
 use crate::method::probe::{IsSuggestion, Mode, ProbeScope};
 use crate::{errors, fluent_generated as fluent};
@@ -2648,7 +2647,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     }
 
                     let make_sugg = |expr: &Expr<'_>, span: Span, sugg: &str| {
-                        if self.needs_parentheses(expr) {
+                        if expr_needs_parens(expr) {
                             (
                                 vec![
                                     (span.shrink_to_lo(), format!("{prefix}{sugg}(")),
@@ -2861,7 +2860,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             return None;
                         }
 
-                        if self.needs_parentheses(expr) {
+                        if expr_needs_parens(expr) {
                             return Some((
                                 vec![
                                     (span, format!("{suggestion}(")),
@@ -2902,16 +2901,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         false
     }
 
-    fn needs_parentheses(&self, expr: &hir::Expr<'_>) -> bool {
-        match expr.kind {
-            // parenthesize if needed (Issue #46756)
-            hir::ExprKind::Cast(_, _) | hir::ExprKind::Binary(_, _, _) => true,
-            // parenthesize borrows of range literals (Issue #54505)
-            _ if is_range_literal(expr) => true,
-            _ => false,
-        }
-    }
-
     pub(crate) fn suggest_cast(
         &self,
         err: &mut Diag<'_>,
diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs
index 2a8ed26aa2b..e7726845652 100644
--- a/compiler/rustc_hir_typeck/src/pat.rs
+++ b/compiler/rustc_hir_typeck/src/pat.rs
@@ -10,8 +10,12 @@ use rustc_errors::{
 };
 use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::pat_util::EnumerateAndAdjustIterator;
-use rustc_hir::{self as hir, BindingMode, ByRef, HirId, LangItem, Mutability, Pat, PatKind};
+use rustc_hir::{
+    self as hir, BindingMode, ByRef, ExprKind, HirId, LangItem, Mutability, Pat, PatKind,
+    expr_needs_parens,
+};
 use rustc_infer::infer;
+use rustc_middle::traits::PatternOriginExpr;
 use rustc_middle::ty::{self, Ty, TypeVisitableExt};
 use rustc_middle::{bug, span_bug};
 use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS;
@@ -94,10 +98,32 @@ struct PatInfo<'a, 'tcx> {
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     fn pattern_cause(&self, ti: &TopInfo<'tcx>, cause_span: Span) -> ObligationCause<'tcx> {
+        // If origin_expr exists, then expected represents the type of origin_expr.
+        // If span also exists, then span == origin_expr.span (although it doesn't need to exist).
+        // In that case, we can peel away references from both and treat them
+        // as the same.
+        let origin_expr_info = ti.origin_expr.map(|mut cur_expr| {
+            let mut count = 0;
+
+            // cur_ty may have more layers of references than cur_expr.
+            // We can only make suggestions about cur_expr, however, so we'll
+            // use that as our condition for stopping.
+            while let ExprKind::AddrOf(.., inner) = &cur_expr.kind {
+                cur_expr = inner;
+                count += 1;
+            }
+
+            PatternOriginExpr {
+                peeled_span: cur_expr.span,
+                peeled_count: count,
+                peeled_prefix_suggestion_parentheses: expr_needs_parens(cur_expr),
+            }
+        });
+
         let code = ObligationCauseCode::Pattern {
             span: ti.span,
             root_ty: ti.expected,
-            origin_expr: ti.origin_expr.is_some(),
+            origin_expr: origin_expr_info,
         };
         self.cause(cause_span, code)
     }
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index 0a77c3bc42f..8c434265d27 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -316,8 +316,8 @@ pub enum ObligationCauseCode<'tcx> {
         span: Option<Span>,
         /// The root expected type induced by a scrutinee or type expression.
         root_ty: Ty<'tcx>,
-        /// Whether the `Span` came from an expression or a type expression.
-        origin_expr: bool,
+        /// Information about the `Span`, if it came from an expression, otherwise `None`.
+        origin_expr: Option<PatternOriginExpr>,
     },
 
     /// Computing common supertype in an if expression
@@ -530,6 +530,25 @@ pub struct MatchExpressionArmCause<'tcx> {
     pub tail_defines_return_position_impl_trait: Option<LocalDefId>,
 }
 
+/// Information about the origin expression of a pattern, relevant to diagnostics.
+/// Fields here refer to the scrutinee of a pattern.
+/// If the scrutinee isn't given in the diagnostic, then this won't exist.
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+#[derive(TypeFoldable, TypeVisitable, HashStable, TyEncodable, TyDecodable)]
+pub struct PatternOriginExpr {
+    /// A span representing the scrutinee expression, with all leading references
+    /// peeled from the expression.
+    /// Only references in the expression are peeled - if the expression refers to a variable
+    /// whose type is a reference, then that reference is kept because it wasn't created
+    /// in the expression.
+    pub peeled_span: Span,
+    /// The number of references that were peeled to produce `peeled_span`.
+    pub peeled_count: usize,
+    /// Does the peeled expression need to be wrapped in parentheses for
+    /// a prefix suggestion (i.e., dereference) to be valid.
+    pub peeled_prefix_suggestion_parentheses: bool,
+}
+
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
 #[derive(TypeFoldable, TypeVisitable, HashStable, TyEncodable, TyDecodable)]
 pub struct IfExpressionCause<'tcx> {
diff --git a/compiler/rustc_target/src/spec/targets/sparcv9_sun_solaris.rs b/compiler/rustc_target/src/spec/targets/sparcv9_sun_solaris.rs
index fdc9628f78e..770da60da9e 100644
--- a/compiler/rustc_target/src/spec/targets/sparcv9_sun_solaris.rs
+++ b/compiler/rustc_target/src/spec/targets/sparcv9_sun_solaris.rs
@@ -13,7 +13,7 @@ pub(crate) fn target() -> Target {
     Target {
         llvm_target: "sparcv9-sun-solaris".into(),
         metadata: crate::spec::TargetMetadata {
-            description: Some("SPARC Solaris 11, illumos".into()),
+            description: Some("SPARC Solaris 11.4".into()),
             tier: Some(2),
             host_tools: Some(false),
             std: Some(true),
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_pc_solaris.rs b/compiler/rustc_target/src/spec/targets/x86_64_pc_solaris.rs
index 28dd3c426c7..843568a4792 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_pc_solaris.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_pc_solaris.rs
@@ -13,7 +13,7 @@ pub(crate) fn target() -> Target {
     Target {
         llvm_target: "x86_64-pc-solaris".into(),
         metadata: crate::spec::TargetMetadata {
-            description: Some("64-bit Solaris 11, illumos".into()),
+            description: Some("64-bit Solaris 11.4".into()),
             tier: Some(2),
             host_tools: Some(false),
             std: Some(true),
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
index f856a8d7abb..5a62a4c3bd5 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
@@ -63,10 +63,11 @@ use rustc_hir::{self as hir};
 use rustc_macros::extension;
 use rustc_middle::bug;
 use rustc_middle::dep_graph::DepContext;
+use rustc_middle::traits::PatternOriginExpr;
 use rustc_middle::ty::error::{ExpectedFound, TypeError, TypeErrorToStringExt};
 use rustc_middle::ty::print::{PrintError, PrintTraitRefExt as _, with_forced_trimmed_paths};
 use rustc_middle::ty::{
-    self, List, Region, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable,
+    self, List, ParamEnv, Region, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable,
     TypeVisitableExt,
 };
 use rustc_span::def_id::LOCAL_CRATE;
@@ -77,7 +78,7 @@ use crate::error_reporting::TypeErrCtxt;
 use crate::errors::{ObligationCauseFailureCode, TypeErrorAdditionalDiags};
 use crate::infer;
 use crate::infer::relate::{self, RelateResult, TypeRelation};
-use crate::infer::{InferCtxt, TypeTrace, ValuePairs};
+use crate::infer::{InferCtxt, InferCtxtExt as _, TypeTrace, ValuePairs};
 use crate::solve::deeply_normalize_for_diagnostics;
 use crate::traits::{
     IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode,
@@ -433,15 +434,22 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         cause: &ObligationCause<'tcx>,
         exp_found: Option<ty::error::ExpectedFound<Ty<'tcx>>>,
         terr: TypeError<'tcx>,
+        param_env: Option<ParamEnv<'tcx>>,
     ) {
         match *cause.code() {
-            ObligationCauseCode::Pattern { origin_expr: true, span: Some(span), root_ty } => {
-                let ty = self.resolve_vars_if_possible(root_ty);
-                if !matches!(ty.kind(), ty::Infer(ty::InferTy::TyVar(_) | ty::InferTy::FreshTy(_)))
-                {
+            ObligationCauseCode::Pattern {
+                origin_expr: Some(origin_expr),
+                span: Some(span),
+                root_ty,
+            } => {
+                let expected_ty = self.resolve_vars_if_possible(root_ty);
+                if !matches!(
+                    expected_ty.kind(),
+                    ty::Infer(ty::InferTy::TyVar(_) | ty::InferTy::FreshTy(_))
+                ) {
                     // don't show type `_`
                     if span.desugaring_kind() == Some(DesugaringKind::ForLoop)
-                        && let ty::Adt(def, args) = ty.kind()
+                        && let ty::Adt(def, args) = expected_ty.kind()
                         && Some(def.did()) == self.tcx.get_diagnostic_item(sym::Option)
                     {
                         err.span_label(
@@ -449,22 +457,48 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                             format!("this is an iterator with items of type `{}`", args.type_at(0)),
                         );
                     } else {
-                        err.span_label(span, format!("this expression has type `{ty}`"));
+                        err.span_label(span, format!("this expression has type `{expected_ty}`"));
                     }
                 }
                 if let Some(ty::error::ExpectedFound { found, .. }) = exp_found
-                    && ty.boxed_ty() == Some(found)
-                    && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
+                    && let Ok(mut peeled_snippet) =
+                        self.tcx.sess.source_map().span_to_snippet(origin_expr.peeled_span)
                 {
-                    err.span_suggestion(
-                        span,
-                        "consider dereferencing the boxed value",
-                        format!("*{snippet}"),
-                        Applicability::MachineApplicable,
-                    );
+                    // Parentheses are needed for cases like as casts.
+                    // We use the peeled_span for deref suggestions.
+                    // It's also safe to use for box, since box only triggers if there
+                    // wasn't a reference to begin with.
+                    if origin_expr.peeled_prefix_suggestion_parentheses {
+                        peeled_snippet = format!("({peeled_snippet})");
+                    }
+
+                    // Try giving a box suggestion first, as it is a special case of the
+                    // deref suggestion.
+                    if expected_ty.boxed_ty() == Some(found) {
+                        err.span_suggestion_verbose(
+                            span,
+                            "consider dereferencing the boxed value",
+                            format!("*{peeled_snippet}"),
+                            Applicability::MachineApplicable,
+                        );
+                    } else if let Some(param_env) = param_env
+                        && let Some(prefix) = self.should_deref_suggestion_on_mismatch(
+                            param_env,
+                            found,
+                            expected_ty,
+                            origin_expr,
+                        )
+                    {
+                        err.span_suggestion_verbose(
+                            span,
+                            "consider dereferencing to access the inner value using the Deref trait",
+                            format!("{prefix}{peeled_snippet}"),
+                            Applicability::MaybeIncorrect,
+                        );
+                    }
                 }
             }
-            ObligationCauseCode::Pattern { origin_expr: false, span: Some(span), .. } => {
+            ObligationCauseCode::Pattern { origin_expr: None, span: Some(span), .. } => {
                 err.span_label(span, "expected due to this");
             }
             ObligationCauseCode::BlockTailExpression(
@@ -618,6 +652,45 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         }
     }
 
+    /// Determines whether deref_to == <deref_from as Deref>::Target, and if so,
+    /// returns a prefix that should be added to deref_from as a suggestion.
+    fn should_deref_suggestion_on_mismatch(
+        &self,
+        param_env: ParamEnv<'tcx>,
+        deref_to: Ty<'tcx>,
+        deref_from: Ty<'tcx>,
+        origin_expr: PatternOriginExpr,
+    ) -> Option<String> {
+        // origin_expr contains stripped away versions of our expression.
+        // We'll want to use that to avoid suggesting things like *&x.
+        // However, the type that we have access to hasn't been stripped away,
+        // so we need to ignore the first n dereferences, where n is the number
+        // that's been stripped away in origin_expr.
+
+        // Find a way to autoderef from deref_from to deref_to.
+        let Some((num_derefs, (after_deref_ty, _))) = (self.autoderef_steps)(deref_from)
+            .into_iter()
+            .enumerate()
+            .find(|(_, (ty, _))| self.infcx.can_eq(param_env, *ty, deref_to))
+        else {
+            return None;
+        };
+
+        if num_derefs <= origin_expr.peeled_count {
+            return None;
+        }
+
+        let deref_part = "*".repeat(num_derefs - origin_expr.peeled_count);
+
+        // If the user used a reference in the original expression, they probably
+        // want the suggestion to still give a reference.
+        if deref_from.is_ref() && !after_deref_ty.is_ref() {
+            Some(format!("&{deref_part}"))
+        } else {
+            Some(deref_part)
+        }
+    }
+
     /// Given that `other_ty` is the same as a type argument for `name` in `sub`, populate `value`
     /// highlighting `name` and every type argument that isn't at `pos` (which is `other_ty`), and
     /// populate `other_value` with `other_ty`.
@@ -1406,8 +1479,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             Variable(ty::error::ExpectedFound<Ty<'a>>),
             Fixed(&'static str),
         }
-        let (expected_found, exp_found, is_simple_error, values) = match values {
-            None => (None, Mismatch::Fixed("type"), false, None),
+        let (expected_found, exp_found, is_simple_error, values, param_env) = match values {
+            None => (None, Mismatch::Fixed("type"), false, None, None),
             Some(ty::ParamEnvAnd { param_env, value: values }) => {
                 let mut values = self.resolve_vars_if_possible(values);
                 if self.next_trait_solver() {
@@ -1459,7 +1532,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     diag.downgrade_to_delayed_bug();
                     return;
                 };
-                (Some(vals), exp_found, is_simple_error, Some(values))
+                (Some(vals), exp_found, is_simple_error, Some(values), Some(param_env))
             }
         };
 
@@ -1791,7 +1864,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
 
         // It reads better to have the error origin as the final
         // thing.
-        self.note_error_origin(diag, cause, exp_found, terr);
+        self.note_error_origin(diag, cause, exp_found, terr, param_env);
 
         debug!(?diag);
     }
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs
index fc2d0ba36f0..08775df5ac9 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs
@@ -210,7 +210,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             (Some(ty), _) if self.same_type_modulo_infer(ty, exp_found.found) => match cause.code()
             {
                 ObligationCauseCode::Pattern { span: Some(then_span), origin_expr, .. } => {
-                    origin_expr.then_some(ConsiderAddingAwait::FutureSugg {
+                    origin_expr.is_some().then_some(ConsiderAddingAwait::FutureSugg {
                         span: then_span.shrink_to_hi(),
                     })
                 }
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
index 94682f501a8..cc8941b9224 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
@@ -20,7 +20,8 @@ use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{
-    CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, HirId, Node, is_range_literal,
+    CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, HirId, Node, expr_needs_parens,
+    is_range_literal,
 };
 use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferCtxt, InferOk};
 use rustc_middle::hir::map;
@@ -1391,13 +1392,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                         let Some(expr) = expr_finder.result else {
                             return false;
                         };
-                        let needs_parens = match expr.kind {
-                            // parenthesize if needed (Issue #46756)
-                            hir::ExprKind::Cast(_, _) | hir::ExprKind::Binary(_, _, _) => true,
-                            // parenthesize borrows of range literals (Issue #54505)
-                            _ if is_range_literal(expr) => true,
-                            _ => false,
-                        };
+                        let needs_parens = expr_needs_parens(expr);
 
                         let span = if needs_parens { span } else { span.shrink_to_lo() };
                         let suggestions = if !needs_parens {
diff --git a/library/core/src/iter/traits/collect.rs b/library/core/src/iter/traits/collect.rs
index c3c7288e389..8ab1c26f95e 100644
--- a/library/core/src/iter/traits/collect.rs
+++ b/library/core/src/iter/traits/collect.rs
@@ -493,15 +493,64 @@ impl Extend<()> for () {
 }
 
 macro_rules! spec_tuple_impl {
-    ( ($ty_name:ident, $var_name:ident, $extend_ty_name: ident, $trait_name:ident, $default_fn_name:ident, $cnt:tt), ) => {
-        spec_tuple_impl!($trait_name, $default_fn_name, #[doc(fake_variadic)] #[doc = "This trait is implemented for tuples up to twelve items long. The `impl`s for 1- and 3- through 12-ary tuples were stabilized after 2-tuples, in RUSTC_CURRENT_VERSION."] => ($ty_name, $var_name, $extend_ty_name, $cnt),);
+    (
+        (
+            $ty_name:ident, $var_name:ident, $extend_ty_name: ident,
+            $trait_name:ident, $default_fn_name:ident, $cnt:tt
+        ),
+    ) => {
+        spec_tuple_impl!(
+            $trait_name,
+            $default_fn_name,
+            #[doc(fake_variadic)]
+            #[doc = "This trait is implemented for tuples up to twelve items long. The `impl`s for \
+                     1- and 3- through 12-ary tuples were stabilized after 2-tuples, in \
+                     CURRENT_RUSTC_VERSION."]
+            => ($ty_name, $var_name, $extend_ty_name, $cnt),
+        );
     };
-    ( ($ty_name:ident, $var_name:ident, $extend_ty_name: ident, $trait_name:ident, $default_fn_name:ident, $cnt:tt), $(($ty_names:ident, $var_names:ident,  $extend_ty_names:ident, $trait_names:ident, $default_fn_names:ident, $cnts:tt),)*) => {
-
-        spec_tuple_impl!($(($ty_names, $var_names, $extend_ty_names, $trait_names, $default_fn_names, $cnts),)*);
-        spec_tuple_impl!($trait_name, $default_fn_name, #[doc(hidden)] => ($ty_name, $var_name, $extend_ty_name, $cnt), $(($ty_names, $var_names, $extend_ty_names, $cnts),)*);
+    (
+        (
+            $ty_name:ident, $var_name:ident, $extend_ty_name: ident,
+            $trait_name:ident, $default_fn_name:ident, $cnt:tt
+        ),
+        $(
+            (
+                $ty_names:ident, $var_names:ident,  $extend_ty_names:ident,
+                $trait_names:ident, $default_fn_names:ident, $cnts:tt
+            ),
+        )*
+    ) => {
+        spec_tuple_impl!(
+            $(
+                (
+                    $ty_names, $var_names, $extend_ty_names,
+                    $trait_names, $default_fn_names, $cnts
+                ),
+            )*
+        );
+        spec_tuple_impl!(
+            $trait_name,
+            $default_fn_name,
+            #[doc(hidden)]
+            => (
+                $ty_name, $var_name, $extend_ty_name, $cnt
+            ),
+            $(
+                (
+                    $ty_names, $var_names, $extend_ty_names, $cnts
+                ),
+            )*
+        );
     };
-    ($trait_name:ident, $default_fn_name:ident, #[$meta:meta] $(#[$doctext:meta])? => $(($ty_names:ident, $var_names:ident, $extend_ty_names:ident, $cnts:tt),)*) => {
+    (
+        $trait_name:ident, $default_fn_name:ident, #[$meta:meta]
+        $(#[$doctext:meta])? => $(
+            (
+                $ty_names:ident, $var_names:ident, $extend_ty_names:ident, $cnts:tt
+            ),
+        )*
+    ) => {
         #[$meta]
         $(#[$doctext])?
         #[stable(feature = "extend_for_tuple", since = "1.56.0")]
diff --git a/library/std/src/pipe.rs b/library/std/src/pipe.rs
index 891032e94a6..06f3fd9fdff 100644
--- a/library/std/src/pipe.rs
+++ b/library/std/src/pipe.rs
@@ -1,20 +1,66 @@
-//! Module for anonymous pipe
+//!  A cross-platform anonymous pipe.
 //!
-//! ```
-//! #![feature(anonymous_pipe)]
+//! This module provides support for anonymous OS pipes, like [pipe] on Linux or [CreatePipe] on
+//! Windows.
+//!
+//! # Behavior
+//!
+//! A pipe is a synchronous, unidirectional data channel between two or more processes, like an
+//! interprocess [`mpsc`](crate::sync::mpsc) provided by the OS. In particular:
+//!
+//! * A read on a [`PipeReader`] blocks until the pipe is non-empty.
+//! * A write on a [`PipeWriter`] blocks when the pipe is full.
+//! * When all copies of a [`PipeWriter`] are closed, a read on the corresponding [`PipeReader`]
+//!   returns EOF.
+//! * [`PipeReader`] can be shared, but only one process will consume the data in the pipe.
+//!
+//! # Capacity
+//!
+//! Pipe capacity is platform dependent. To quote the Linux [man page]:
+//!
+//! > Different implementations have different limits for the pipe capacity. Applications should
+//! > not rely on a particular capacity: an application should be designed so that a reading process
+//! > consumes data as soon as it is available, so that a writing process does not remain blocked.
 //!
+//! # Examples
+//!
+//! ```no_run
+//! #![feature(anonymous_pipe)]
 //! # #[cfg(miri)] fn main() {}
 //! # #[cfg(not(miri))]
 //! # fn main() -> std::io::Result<()> {
-//! let (reader, writer) = std::pipe::pipe()?;
+//! # use std::process::Command;
+//! # use std::io::{Read, Write};
+//! let (ping_rx, mut ping_tx) = std::pipe::pipe()?;
+//! let (mut pong_rx, pong_tx) = std::pipe::pipe()?;
+//!
+//! // Spawn a process that echoes its input.
+//! let mut echo_server = Command::new("cat").stdin(ping_rx).stdout(pong_tx).spawn()?;
+//!
+//! ping_tx.write_all(b"hello")?;
+//! // Close to unblock echo_server's reader.
+//! drop(ping_tx);
+//!
+//! let mut buf = String::new();
+//! // Block until echo_server's writer is closed.
+//! pong_rx.read_to_string(&mut buf)?;
+//! assert_eq!(&buf, "hello");
+//!
+//! echo_server.wait()?;
 //! # Ok(())
 //! # }
 //! ```
-
+//! [pipe]: https://man7.org/linux/man-pages/man2/pipe.2.html
+//! [CreatePipe]: https://learn.microsoft.com/en-us/windows/win32/api/namedpipeapi/nf-namedpipeapi-createpipe
+//! [man page]: https://man7.org/linux/man-pages/man7/pipe.7.html
 use crate::io;
 use crate::sys::anonymous_pipe::{AnonPipe, pipe as pipe_inner};
 
 /// Create anonymous pipe that is close-on-exec and blocking.
+///
+/// # Examples
+///
+/// See the [module-level](crate::pipe) documentation for examples.
 #[unstable(feature = "anonymous_pipe", issue = "127154")]
 #[inline]
 pub fn pipe() -> io::Result<(PipeReader, PipeWriter)> {
@@ -33,6 +79,58 @@ pub struct PipeWriter(pub(crate) AnonPipe);
 
 impl PipeReader {
     /// Create a new [`PipeReader`] instance that shares the same underlying file description.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// #![feature(anonymous_pipe)]
+    /// # #[cfg(miri)] fn main() {}
+    /// # #[cfg(not(miri))]
+    /// # fn main() -> std::io::Result<()> {
+    /// # use std::fs;
+    /// # use std::io::Write;
+    /// # use std::process::Command;
+    /// const NUM_SLOT: u8 = 2;
+    /// const NUM_PROC: u8 = 5;
+    /// const OUTPUT: &str = "work.txt";
+    ///
+    /// let mut jobs = vec![];
+    /// let (reader, mut writer) = std::pipe::pipe()?;
+    ///
+    /// // Write NUM_SLOT characters the the pipe.
+    /// writer.write_all(&[b'|'; NUM_SLOT as usize])?;
+    ///
+    /// // Spawn several processes that read a character from the pipe, do some work, then
+    /// // write back to the pipe. When the pipe is empty, the processes block, so only
+    /// // NUM_SLOT processes can be working at any given time.
+    /// for _ in 0..NUM_PROC {
+    ///     jobs.push(
+    ///         Command::new("bash")
+    ///             .args(["-c",
+    ///                 &format!(
+    ///                      "read -n 1\n\
+    ///                       echo -n 'x' >> '{OUTPUT}'\n\
+    ///                       echo -n '|'",
+    ///                 ),
+    ///             ])
+    ///             .stdin(reader.try_clone()?)
+    ///             .stdout(writer.try_clone()?)
+    ///             .spawn()?,
+    ///     );
+    /// }
+    ///
+    /// // Wait for all jobs to finish.
+    /// for mut job in jobs {
+    ///     job.wait()?;
+    /// }
+    ///
+    /// // Check our work and clean up.
+    /// let xs = fs::read_to_string(OUTPUT)?;
+    /// fs::remove_file(OUTPUT)?;
+    /// assert_eq!(xs, "x".repeat(NUM_PROC.into()));
+    /// # Ok(())
+    /// # }
+    /// ```
     #[unstable(feature = "anonymous_pipe", issue = "127154")]
     pub fn try_clone(&self) -> io::Result<Self> {
         self.0.try_clone().map(Self)
@@ -41,6 +139,38 @@ impl PipeReader {
 
 impl PipeWriter {
     /// Create a new [`PipeWriter`] instance that shares the same underlying file description.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// #![feature(anonymous_pipe)]
+    /// # #[cfg(miri)] fn main() {}
+    /// # #[cfg(not(miri))]
+    /// # fn main() -> std::io::Result<()> {
+    /// # use std::process::Command;
+    /// # use std::io::Read;
+    /// let (mut reader, writer) = std::pipe::pipe()?;
+    ///
+    /// // Spawn a process that writes to stdout and stderr.
+    /// let mut peer = Command::new("bash")
+    ///     .args([
+    ///         "-c",
+    ///         "echo -n foo\n\
+    ///          echo -n bar >&2"
+    ///     ])
+    ///     .stdout(writer.try_clone()?)
+    ///     .stderr(writer)
+    ///     .spawn()?;
+    ///
+    /// // Read and check the result.
+    /// let mut msg = String::new();
+    /// reader.read_to_string(&mut msg)?;
+    /// assert_eq!(&msg, "foobar");
+    ///
+    /// peer.wait()?;
+    /// # Ok(())
+    /// # }
+    /// ```
     #[unstable(feature = "anonymous_pipe", issue = "127154")]
     pub fn try_clone(&self) -> io::Result<Self> {
         self.0.try_clone().map(Self)
diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md
index f3d8a4edd6c..2341d25ff09 100644
--- a/src/doc/rustc/src/SUMMARY.md
+++ b/src/doc/rustc/src/SUMMARY.md
@@ -75,6 +75,7 @@
     - [s390x-unknown-linux-gnu](platform-support/s390x-unknown-linux-gnu.md)
     - [s390x-unknown-linux-musl](platform-support/s390x-unknown-linux-musl.md)
     - [sparc-unknown-none-elf](./platform-support/sparc-unknown-none-elf.md)
+    - [sparcv9-sun-solaris](platform-support/solaris.md)
     - [*-pc-windows-gnullvm](platform-support/pc-windows-gnullvm.md)
     - [\*-nto-qnx-\*](platform-support/nto-qnx.md)
     - [*-unikraft-linux-musl](platform-support/unikraft-linux-musl.md)
@@ -93,6 +94,7 @@
     - [wasm64-unknown-unknown](platform-support/wasm64-unknown-unknown.md)
     - [\*-win7-windows-msvc](platform-support/win7-windows-msvc.md)
     - [x86_64-fortanix-unknown-sgx](platform-support/x86_64-fortanix-unknown-sgx.md)
+    - [x86_64-pc-solaris](platform-support/solaris.md)
     - [x86_64-unknown-linux-none.md](platform-support/x86_64-unknown-linux-none.md)
     - [x86_64-unknown-none](platform-support/x86_64-unknown-none.md)
     - [xtensa-\*-none-elf](platform-support/xtensa.md)
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index 3dbcfe97036..c4efe27efc2 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -180,7 +180,7 @@ target | std | notes
 `riscv64gc-unknown-none-elf` | * | Bare RISC-V (RV64IMAFDC ISA)
 `riscv64imac-unknown-none-elf` | * | Bare RISC-V (RV64IMAC ISA)
 `sparc64-unknown-linux-gnu` | ✓ | SPARC Linux (kernel 4.4, glibc 2.23)
-`sparcv9-sun-solaris` | ✓ | SPARC Solaris 11, illumos
+[`sparcv9-sun-solaris`](platform-support/solaris.md) | ✓ | SPARC V9 Solaris 11.4
 [`thumbv6m-none-eabi`](platform-support/thumbv6m-none-eabi.md) | * | Bare Armv6-M
 [`thumbv7em-none-eabi`](platform-support/thumbv7em-none-eabi.md) | * | Bare Armv7E-M
 [`thumbv7em-none-eabihf`](platform-support/thumbv7em-none-eabi.md) | * | Bare Armv7E-M, hardfloat
@@ -201,7 +201,7 @@ target | std | notes
 [`x86_64-fortanix-unknown-sgx`](platform-support/x86_64-fortanix-unknown-sgx.md) | ✓ | [Fortanix ABI] for 64-bit Intel SGX
 [`x86_64-unknown-fuchsia`](platform-support/fuchsia.md) | ✓ | 64-bit x86 Fuchsia
 [`x86_64-linux-android`](platform-support/android.md) | ✓ | 64-bit x86 Android
-`x86_64-pc-solaris` | ✓ | 64-bit Solaris 11, illumos
+[`x86_64-pc-solaris`](platform-support/solaris.md) | ✓ | 64-bit x86 Solaris 11.4
 [`x86_64-pc-windows-gnullvm`](platform-support/pc-windows-gnullvm.md) | ✓ | 64-bit x86 MinGW (Windows 10+), LLVM ABI
 `x86_64-unknown-linux-gnux32` | ✓ | 64-bit Linux (x32 ABI) (kernel 4.15, glibc 2.27)
 [`x86_64-unknown-linux-ohos`](platform-support/openharmony.md) | ✓ | x86_64 OpenHarmony
diff --git a/src/doc/rustc/src/platform-support/solaris.md b/src/doc/rustc/src/platform-support/solaris.md
new file mode 100644
index 00000000000..1e0a241f840
--- /dev/null
+++ b/src/doc/rustc/src/platform-support/solaris.md
@@ -0,0 +1,32 @@
+# sparcv9-sun-solaris
+# x86_64-pc-solaris
+
+**Tier: 2**
+
+Rust for Solaris operating system.
+
+## Target maintainers
+
+- Petr Sumbera `sumbera@volny.cz`, https://github.com/psumbera
+
+## Requirements
+
+Binary built for this target is expected to run on sparcv9 or x86_64, and Solaris 11.4.
+
+## Testing
+
+For testing you can download Oracle Solaris 11.4 CBE release from:
+
+  https://www.oracle.com/uk/solaris/solaris11/downloads/solaris-downloads.html
+
+Solaris CBE release is also available for GitHub CI:
+
+  https://github.com/vmactions/solaris-vm
+
+Latest Solaris 11.4 SRU can be tested at Compile farm project:
+
+  https://portal.cfarm.net/machines/list/ (cfarm215, cfarm215)
+
+There are no official Rust binaries for Solaris available for Rustup yet. But you can eventually download unofficial from:
+
+  https://github.com/psumbera/solaris-rust
diff --git a/tests/ui/associated-types/missing-associated-types.stderr b/tests/ui/associated-types/missing-associated-types.stderr
index ce4b57e8af8..3a56c55896e 100644
--- a/tests/ui/associated-types/missing-associated-types.stderr
+++ b/tests/ui/associated-types/missing-associated-types.stderr
@@ -42,11 +42,11 @@ LL | type Bat<Rhs> = dyn Add<Rhs> + Sub<Rhs> + Fine<Rhs>;
    = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Add<Rhs> + Sub<Rhs> + Fine<Rhs> {}`
    = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
 
-error[E0191]: the value of the associated types `Output` in `Div`, `Output` in `Mul` must be specified
+error[E0191]: the value of the associated types `Output` in `Div<Rhs>`, `Output` in `Mul<Rhs>` must be specified
   --> $DIR/missing-associated-types.rs:20:21
    |
 LL | type Bal<Rhs> = dyn X<Rhs>;
-   |                     ^^^^^^ associated types `Output` (from trait `Div`), `Output` (from trait `Mul`) must be specified
+   |                     ^^^^^^ associated types `Output` (from trait `Div<Rhs>`), `Output` (from trait `Mul<Rhs>`) must be specified
    |
    = help: consider introducing a new type parameter, adding `where` constraints using the fully-qualified path to the associated types
 
diff --git a/tests/ui/closures/2229_closure_analysis/issue-118144.stderr b/tests/ui/closures/2229_closure_analysis/issue-118144.stderr
index 85cb5adc07e..87084e60237 100644
--- a/tests/ui/closures/2229_closure_analysis/issue-118144.stderr
+++ b/tests/ui/closures/2229_closure_analysis/issue-118144.stderr
@@ -5,6 +5,11 @@ LL |         V(x) = func_arg;
    |         ^^^^   -------- this expression has type `&mut V`
    |         |
    |         expected `&mut V`, found `V`
+   |
+help: consider dereferencing to access the inner value using the Deref trait
+   |
+LL |         V(x) = &*func_arg;
+   |                ~~~~~~~~~~
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/dyn-compatibility/assoc_type_bounds.rs b/tests/ui/dyn-compatibility/assoc_type_bounds.rs
index 8634ba626a1..6e2076a4822 100644
--- a/tests/ui/dyn-compatibility/assoc_type_bounds.rs
+++ b/tests/ui/dyn-compatibility/assoc_type_bounds.rs
@@ -7,7 +7,7 @@ trait Foo<T> {
 trait Cake {}
 impl Cake for () {}
 
-fn foo(_: &dyn Foo<()>) {} //~ ERROR: the value of the associated type `Bar` in `Foo` must be specified
-fn bar(_: &dyn Foo<i32>) {} //~ ERROR: the value of the associated type `Bar` in `Foo` must be specified
+fn foo(_: &dyn Foo<()>) {} //~ ERROR: the value of the associated type `Bar` in `Foo<()>` must be specified
+fn bar(_: &dyn Foo<i32>) {} //~ ERROR: the value of the associated type `Bar` in `Foo<i32>` must be specified
 
 fn main() {}
diff --git a/tests/ui/dyn-compatibility/assoc_type_bounds.stderr b/tests/ui/dyn-compatibility/assoc_type_bounds.stderr
index 3d5482625af..21ba9030117 100644
--- a/tests/ui/dyn-compatibility/assoc_type_bounds.stderr
+++ b/tests/ui/dyn-compatibility/assoc_type_bounds.stderr
@@ -1,4 +1,4 @@
-error[E0191]: the value of the associated type `Bar` in `Foo` must be specified
+error[E0191]: the value of the associated type `Bar` in `Foo<()>` must be specified
   --> $DIR/assoc_type_bounds.rs:10:16
    |
 LL |     type Bar
@@ -7,7 +7,7 @@ LL |     type Bar
 LL | fn foo(_: &dyn Foo<()>) {}
    |                ^^^^^^^ help: specify the associated type: `Foo<(), Bar = Type>`
 
-error[E0191]: the value of the associated type `Bar` in `Foo` must be specified
+error[E0191]: the value of the associated type `Bar` in `Foo<i32>` must be specified
   --> $DIR/assoc_type_bounds.rs:11:16
    |
 LL |     type Bar
diff --git a/tests/ui/dyn-compatibility/assoc_type_bounds2.rs b/tests/ui/dyn-compatibility/assoc_type_bounds2.rs
index f7dc2fb8839..2b35016d774 100644
--- a/tests/ui/dyn-compatibility/assoc_type_bounds2.rs
+++ b/tests/ui/dyn-compatibility/assoc_type_bounds2.rs
@@ -7,7 +7,7 @@ trait Foo<T> {
 trait Cake {}
 impl Cake for () {}
 
-fn foo(_: &dyn Foo<()>) {} //~ ERROR: the value of the associated type `Bar` in `Foo` must be specified
-fn bar(_: &dyn Foo<i32>) {} //~ ERROR: the value of the associated type `Bar` in `Foo` must be specified
+fn foo(_: &dyn Foo<()>) {} //~ ERROR: the value of the associated type `Bar` in `Foo<()>` must be specified
+fn bar(_: &dyn Foo<i32>) {} //~ ERROR: the value of the associated type `Bar` in `Foo<i32>` must be specified
 
 fn main() {}
diff --git a/tests/ui/dyn-compatibility/assoc_type_bounds2.stderr b/tests/ui/dyn-compatibility/assoc_type_bounds2.stderr
index 815747436bf..5c4163b1969 100644
--- a/tests/ui/dyn-compatibility/assoc_type_bounds2.stderr
+++ b/tests/ui/dyn-compatibility/assoc_type_bounds2.stderr
@@ -1,4 +1,4 @@
-error[E0191]: the value of the associated type `Bar` in `Foo` must be specified
+error[E0191]: the value of the associated type `Bar` in `Foo<()>` must be specified
   --> $DIR/assoc_type_bounds2.rs:10:16
    |
 LL |     type Bar
@@ -7,7 +7,7 @@ LL |     type Bar
 LL | fn foo(_: &dyn Foo<()>) {}
    |                ^^^^^^^ help: specify the associated type: `Foo<(), Bar = Type>`
 
-error[E0191]: the value of the associated type `Bar` in `Foo` must be specified
+error[E0191]: the value of the associated type `Bar` in `Foo<i32>` must be specified
   --> $DIR/assoc_type_bounds2.rs:11:16
    |
 LL |     type Bar
diff --git a/tests/ui/dyn-compatibility/require-assoc-for-all-super-substs.rs b/tests/ui/dyn-compatibility/require-assoc-for-all-super-substs.rs
new file mode 100644
index 00000000000..1f4e1bf653a
--- /dev/null
+++ b/tests/ui/dyn-compatibility/require-assoc-for-all-super-substs.rs
@@ -0,0 +1,15 @@
+trait Sup<T> {
+    type Assoc: Default;
+}
+
+impl<T: Default> Sup<T> for () {
+    type Assoc = T;
+}
+impl<T: Default, U: Default> Dyn<T, U> for () {}
+
+trait Dyn<A, B>: Sup<A, Assoc = A> + Sup<B> {}
+
+fn main() {
+    let q: <dyn Dyn<i32, u32> as Sup<u32>>::Assoc = Default::default();
+    //~^ ERROR the value of the associated type `Assoc` in `Sup<u32>` must be specified
+}
diff --git a/tests/ui/dyn-compatibility/require-assoc-for-all-super-substs.stderr b/tests/ui/dyn-compatibility/require-assoc-for-all-super-substs.stderr
new file mode 100644
index 00000000000..3d89b52d522
--- /dev/null
+++ b/tests/ui/dyn-compatibility/require-assoc-for-all-super-substs.stderr
@@ -0,0 +1,12 @@
+error[E0191]: the value of the associated type `Assoc` in `Sup<u32>` must be specified
+  --> $DIR/require-assoc-for-all-super-substs.rs:13:17
+   |
+LL |     type Assoc: Default;
+   |     ------------------- `Assoc` defined here
+...
+LL |     let q: <dyn Dyn<i32, u32> as Sup<u32>>::Assoc = Default::default();
+   |                 ^^^^^^^^^^^^^ help: specify the associated type: `Dyn<i32, u32, Assoc = Type>`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0191`.
diff --git a/tests/ui/issues/issue-28344.stderr b/tests/ui/issues/issue-28344.stderr
index d8febe71652..7bc965536e9 100644
--- a/tests/ui/issues/issue-28344.stderr
+++ b/tests/ui/issues/issue-28344.stderr
@@ -12,7 +12,7 @@ help: if this is a dyn-compatible trait, use `dyn`
 LL |     let x: u8 = <dyn BitXor>::bitor(0 as u8, 0 as u8);
    |                 ++++       +
 
-error[E0191]: the value of the associated type `Output` in `BitXor` must be specified
+error[E0191]: the value of the associated type `Output` in `BitXor<_>` must be specified
   --> $DIR/issue-28344.rs:4:17
    |
 LL |     let x: u8 = BitXor::bitor(0 as u8, 0 as u8);
@@ -31,7 +31,7 @@ help: if this is a dyn-compatible trait, use `dyn`
 LL |     let g = <dyn BitXor>::bitor;
    |             ++++       +
 
-error[E0191]: the value of the associated type `Output` in `BitXor` must be specified
+error[E0191]: the value of the associated type `Output` in `BitXor<_>` must be specified
   --> $DIR/issue-28344.rs:9:13
    |
 LL |     let g = BitXor::bitor;
diff --git a/tests/ui/issues/issue-57741-dereference-boxed-value/issue-57741.stderr b/tests/ui/issues/issue-57741-dereference-boxed-value/issue-57741.stderr
index 38014ecce75..3c19b68cffb 100644
--- a/tests/ui/issues/issue-57741-dereference-boxed-value/issue-57741.stderr
+++ b/tests/ui/issues/issue-57741-dereference-boxed-value/issue-57741.stderr
@@ -2,57 +2,61 @@ error[E0308]: mismatched types
   --> $DIR/issue-57741.rs:20:9
    |
 LL |     let y = match x {
-   |                   -
-   |                   |
-   |                   this expression has type `Box<T>`
-   |                   help: consider dereferencing the boxed value: `*x`
+   |                   - this expression has type `Box<T>`
 LL |         T::A(a) | T::B(a) => a,
    |         ^^^^^^^ expected `Box<T>`, found `T`
    |
    = note: expected struct `Box<T>`
                 found enum `T`
+help: consider dereferencing the boxed value
+   |
+LL |     let y = match *x {
+   |                   ~~
 
 error[E0308]: mismatched types
   --> $DIR/issue-57741.rs:20:19
    |
 LL |     let y = match x {
-   |                   -
-   |                   |
-   |                   this expression has type `Box<T>`
-   |                   help: consider dereferencing the boxed value: `*x`
+   |                   - this expression has type `Box<T>`
 LL |         T::A(a) | T::B(a) => a,
    |                   ^^^^^^^ expected `Box<T>`, found `T`
    |
    = note: expected struct `Box<T>`
                 found enum `T`
+help: consider dereferencing the boxed value
+   |
+LL |     let y = match *x {
+   |                   ~~
 
 error[E0308]: mismatched types
   --> $DIR/issue-57741.rs:27:9
    |
 LL |     let y = match x {
-   |                   -
-   |                   |
-   |                   this expression has type `Box<S>`
-   |                   help: consider dereferencing the boxed value: `*x`
+   |                   - this expression has type `Box<S>`
 LL |         S::A { a } | S::B { b: a } => a,
    |         ^^^^^^^^^^ expected `Box<S>`, found `S`
    |
    = note: expected struct `Box<S>`
                 found enum `S`
+help: consider dereferencing the boxed value
+   |
+LL |     let y = match *x {
+   |                   ~~
 
 error[E0308]: mismatched types
   --> $DIR/issue-57741.rs:27:22
    |
 LL |     let y = match x {
-   |                   -
-   |                   |
-   |                   this expression has type `Box<S>`
-   |                   help: consider dereferencing the boxed value: `*x`
+   |                   - this expression has type `Box<S>`
 LL |         S::A { a } | S::B { b: a } => a,
    |                      ^^^^^^^^^^^^^ expected `Box<S>`, found `S`
    |
    = note: expected struct `Box<S>`
                 found enum `S`
+help: consider dereferencing the boxed value
+   |
+LL |     let y = match *x {
+   |                   ~~
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/let-else/let-else-deref-coercion.stderr b/tests/ui/let-else/let-else-deref-coercion.stderr
index 143b838bac5..da8b1f4c48e 100644
--- a/tests/ui/let-else/let-else-deref-coercion.stderr
+++ b/tests/ui/let-else/let-else-deref-coercion.stderr
@@ -5,6 +5,11 @@ LL |         let Bar::Present(z) = self else {
    |             ^^^^^^^^^^^^^^^   ---- this expression has type `&mut Foo`
    |             |
    |             expected `Foo`, found `Bar`
+   |
+help: consider dereferencing to access the inner value using the Deref trait
+   |
+LL |         let Bar::Present(z) = &**self else {
+   |                               ~~~~~~~
 
 error[E0308]: mismatched types
   --> $DIR/let-else-deref-coercion.rs:68:13
@@ -13,6 +18,11 @@ LL |         let Bar(z) = x;
    |             ^^^^^^   - this expression has type `&mut irrefutable::Foo`
    |             |
    |             expected `Foo`, found `Bar`
+   |
+help: consider dereferencing to access the inner value using the Deref trait
+   |
+LL |         let Bar(z) = &**x;
+   |                      ~~~~
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/self/arbitrary_self_types_nonnull.rs b/tests/ui/self/arbitrary_self_types_nonnull.rs
new file mode 100644
index 00000000000..ab1589b956e
--- /dev/null
+++ b/tests/ui/self/arbitrary_self_types_nonnull.rs
@@ -0,0 +1,13 @@
+#![feature(arbitrary_self_types)]
+
+struct A;
+
+impl A {
+    fn m(self: std::ptr::NonNull<Self>) {}
+    //~^ ERROR: invalid `self` parameter type
+    fn n(self: &std::ptr::NonNull<Self>) {}
+    //~^ ERROR: invalid `self` parameter type
+}
+
+fn main() {
+}
diff --git a/tests/ui/self/arbitrary_self_types_nonnull.stderr b/tests/ui/self/arbitrary_self_types_nonnull.stderr
new file mode 100644
index 00000000000..5ebe58b4e48
--- /dev/null
+++ b/tests/ui/self/arbitrary_self_types_nonnull.stderr
@@ -0,0 +1,23 @@
+error[E0307]: invalid `self` parameter type: `NonNull<A>`
+  --> $DIR/arbitrary_self_types_nonnull.rs:6:16
+   |
+LL |     fn m(self: std::ptr::NonNull<Self>) {}
+   |                ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: type of `self` must be `Self` or some type implementing `Receiver`
+   = help: consider changing to `self`, `&self`, `&mut self`, or a type implementing `Receiver` such as `self: Box<Self>`, `self: Rc<Self>`, or `self: Arc<Self>`
+   = note: `NonNull` does not implement `Receiver` because it has methods that may shadow the referent; consider wrapping your `NonNull` in a newtype wrapper for which you implement `Receiver`
+
+error[E0307]: invalid `self` parameter type: `&NonNull<A>`
+  --> $DIR/arbitrary_self_types_nonnull.rs:8:16
+   |
+LL |     fn n(self: &std::ptr::NonNull<Self>) {}
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: type of `self` must be `Self` or some type implementing `Receiver`
+   = help: consider changing to `self`, `&self`, `&mut self`, or a type implementing `Receiver` such as `self: Box<Self>`, `self: Rc<Self>`, or `self: Arc<Self>`
+   = note: `NonNull` does not implement `Receiver` because it has methods that may shadow the referent; consider wrapping your `NonNull` in a newtype wrapper for which you implement `Receiver`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0307`.
diff --git a/tests/ui/self/arbitrary_self_types_weak.rs b/tests/ui/self/arbitrary_self_types_weak.rs
new file mode 100644
index 00000000000..91f2b9e0a95
--- /dev/null
+++ b/tests/ui/self/arbitrary_self_types_weak.rs
@@ -0,0 +1,13 @@
+#![feature(arbitrary_self_types)]
+
+struct A;
+
+impl A {
+    fn m(self: std::rc::Weak<Self>) {}
+    //~^ ERROR: invalid `self` parameter type
+    fn n(self: std::sync::Weak<Self>) {}
+    //~^ ERROR: invalid `self` parameter type
+}
+
+fn main() {
+}
diff --git a/tests/ui/self/arbitrary_self_types_weak.stderr b/tests/ui/self/arbitrary_self_types_weak.stderr
new file mode 100644
index 00000000000..42d239419ad
--- /dev/null
+++ b/tests/ui/self/arbitrary_self_types_weak.stderr
@@ -0,0 +1,23 @@
+error[E0307]: invalid `self` parameter type: `std::rc::Weak<A>`
+  --> $DIR/arbitrary_self_types_weak.rs:6:16
+   |
+LL |     fn m(self: std::rc::Weak<Self>) {}
+   |                ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: type of `self` must be `Self` or some type implementing `Receiver`
+   = help: consider changing to `self`, `&self`, `&mut self`, or a type implementing `Receiver` such as `self: Box<Self>`, `self: Rc<Self>`, or `self: Arc<Self>`
+   = note: `Weak` does not implement `Receiver` because it has methods that may shadow the referent; consider wrapping your `Weak` in a newtype wrapper for which you implement `Receiver`
+
+error[E0307]: invalid `self` parameter type: `std::sync::Weak<A>`
+  --> $DIR/arbitrary_self_types_weak.rs:8:16
+   |
+LL |     fn n(self: std::sync::Weak<Self>) {}
+   |                ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: type of `self` must be `Self` or some type implementing `Receiver`
+   = help: consider changing to `self`, `&self`, `&mut self`, or a type implementing `Receiver` such as `self: Box<Self>`, `self: Rc<Self>`, or `self: Arc<Self>`
+   = note: `Weak` does not implement `Receiver` because it has methods that may shadow the referent; consider wrapping your `Weak` in a newtype wrapper for which you implement `Receiver`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0307`.
diff --git a/tests/ui/suggestions/suggest-deref-in-match-issue-132784.rs b/tests/ui/suggestions/suggest-deref-in-match-issue-132784.rs
new file mode 100644
index 00000000000..205e57f4a9f
--- /dev/null
+++ b/tests/ui/suggestions/suggest-deref-in-match-issue-132784.rs
@@ -0,0 +1,84 @@
+use std::sync::Arc;
+fn main() {
+    let mut x = Arc::new(Some(1));
+    match x {
+        //~^ HELP consider dereferencing to access the inner value using the Deref trait
+        //~| HELP consider dereferencing to access the inner value using the Deref trait
+        Some(_) => {}
+        //~^ ERROR mismatched types
+        None => {}
+        //~^ ERROR mismatched types
+    }
+
+    match &x {
+        //~^ HELP consider dereferencing to access the inner value using the Deref trait
+        //~| HELP consider dereferencing to access the inner value using the Deref trait
+        Some(_) => {}
+        //~^ ERROR mismatched types
+        None => {}
+        //~^ ERROR mismatched types
+    }
+
+    let mut y = Box::new(Some(1));
+    match y {
+        //~^ HELP consider dereferencing to access the inner value using the Deref trait
+        //~| HELP consider dereferencing to access the inner value using the Deref trait
+        Some(_) => {}
+        //~^ ERROR mismatched types
+        None => {}
+        //~^ ERROR mismatched types
+    }
+
+    let mut z = Arc::new(Some(1));
+    match z as Arc<Option<i32>> {
+        //~^ HELP consider dereferencing to access the inner value using the Deref trait
+        //~| HELP consider dereferencing to access the inner value using the Deref trait
+        Some(_) => {}
+        //~^ ERROR mismatched types
+        None => {}
+        //~^ ERROR mismatched types
+    }
+
+    let z_const: &Arc<Option<i32>> = &z;
+    match z_const {
+        //~^ HELP consider dereferencing to access the inner value using the Deref trait
+        //~| HELP consider dereferencing to access the inner value using the Deref trait
+        Some(_) => {}
+        //~^ ERROR mismatched types
+        None => {}
+        //~^ ERROR mismatched types
+    }
+
+    // Normal reference because Arc doesn't implement DerefMut.
+    let z_mut: &mut Arc<Option<i32>> = &mut z;
+    match z_mut {
+        //~^ HELP consider dereferencing to access the inner value using the Deref trait
+        //~| HELP consider dereferencing to access the inner value using the Deref trait
+        Some(_) => {}
+        //~^ ERROR mismatched types
+        None => {}
+        //~^ ERROR mismatched types
+    }
+
+    // Mutable reference because Box does implement DerefMut.
+    let y_mut: &mut Box<Option<i32>> = &mut y;
+    match y_mut {
+        //~^ HELP consider dereferencing to access the inner value using the Deref trait
+        //~| HELP consider dereferencing to access the inner value using the Deref trait
+        Some(_) => {}
+        //~^ ERROR mismatched types
+        None => {}
+        //~^ ERROR mismatched types
+    }
+
+    // Difficult expression.
+    let difficult = Arc::new(Some(1));
+    match (& (&difficult)  ) {
+        //~^ HELP consider dereferencing to access the inner value using the Deref trait
+        //~| HELP consider dereferencing to access the inner value using the Deref trait
+        Some(_) => {}
+        //~^ ERROR mismatched types
+        None => {}
+        //~^ ERROR mismatched types
+    }
+}
diff --git a/tests/ui/suggestions/suggest-deref-in-match-issue-132784.stderr b/tests/ui/suggestions/suggest-deref-in-match-issue-132784.stderr
new file mode 100644
index 00000000000..9338ef19089
--- /dev/null
+++ b/tests/ui/suggestions/suggest-deref-in-match-issue-132784.stderr
@@ -0,0 +1,259 @@
+error[E0308]: mismatched types
+  --> $DIR/suggest-deref-in-match-issue-132784.rs:7:9
+   |
+LL |     match x {
+   |           - this expression has type `Arc<Option<{integer}>>`
+...
+LL |         Some(_) => {}
+   |         ^^^^^^^ expected `Arc<Option<{integer}>>`, found `Option<_>`
+   |
+   = note: expected struct `Arc<Option<{integer}>>`
+                found enum `Option<_>`
+help: consider dereferencing to access the inner value using the Deref trait
+   |
+LL |     match *x {
+   |           ~~
+
+error[E0308]: mismatched types
+  --> $DIR/suggest-deref-in-match-issue-132784.rs:9:9
+   |
+LL |     match x {
+   |           - this expression has type `Arc<Option<{integer}>>`
+...
+LL |         None => {}
+   |         ^^^^ expected `Arc<Option<{integer}>>`, found `Option<_>`
+   |
+   = note: expected struct `Arc<Option<{integer}>>`
+                found enum `Option<_>`
+help: consider dereferencing to access the inner value using the Deref trait
+   |
+LL |     match *x {
+   |           ~~
+
+error[E0308]: mismatched types
+  --> $DIR/suggest-deref-in-match-issue-132784.rs:16:9
+   |
+LL |     match &x {
+   |           -- this expression has type `&Arc<Option<{integer}>>`
+...
+LL |         Some(_) => {}
+   |         ^^^^^^^ expected `Arc<Option<{integer}>>`, found `Option<_>`
+   |
+   = note: expected struct `Arc<Option<{integer}>>`
+                found enum `Option<_>`
+help: consider dereferencing to access the inner value using the Deref trait
+   |
+LL |     match &*x {
+   |           ~~~
+
+error[E0308]: mismatched types
+  --> $DIR/suggest-deref-in-match-issue-132784.rs:18:9
+   |
+LL |     match &x {
+   |           -- this expression has type `&Arc<Option<{integer}>>`
+...
+LL |         None => {}
+   |         ^^^^ expected `Arc<Option<{integer}>>`, found `Option<_>`
+   |
+   = note: expected struct `Arc<Option<{integer}>>`
+                found enum `Option<_>`
+help: consider dereferencing to access the inner value using the Deref trait
+   |
+LL |     match &*x {
+   |           ~~~
+
+error[E0308]: mismatched types
+  --> $DIR/suggest-deref-in-match-issue-132784.rs:26:9
+   |
+LL |     match y {
+   |           - this expression has type `Box<Option<{integer}>>`
+...
+LL |         Some(_) => {}
+   |         ^^^^^^^ expected `Box<Option<{integer}>>`, found `Option<_>`
+   |
+   = note: expected struct `Box<Option<{integer}>>`
+                found enum `Option<_>`
+help: consider dereferencing to access the inner value using the Deref trait
+   |
+LL |     match *y {
+   |           ~~
+
+error[E0308]: mismatched types
+  --> $DIR/suggest-deref-in-match-issue-132784.rs:28:9
+   |
+LL |     match y {
+   |           - this expression has type `Box<Option<{integer}>>`
+...
+LL |         None => {}
+   |         ^^^^ expected `Box<Option<{integer}>>`, found `Option<_>`
+   |
+   = note: expected struct `Box<Option<{integer}>>`
+                found enum `Option<_>`
+help: consider dereferencing to access the inner value using the Deref trait
+   |
+LL |     match *y {
+   |           ~~
+
+error[E0308]: mismatched types
+  --> $DIR/suggest-deref-in-match-issue-132784.rs:36:9
+   |
+LL |     match z as Arc<Option<i32>> {
+   |           --------------------- this expression has type `Arc<Option<i32>>`
+...
+LL |         Some(_) => {}
+   |         ^^^^^^^ expected `Arc<Option<i32>>`, found `Option<_>`
+   |
+   = note: expected struct `Arc<Option<i32>>`
+                found enum `Option<_>`
+help: consider dereferencing to access the inner value using the Deref trait
+   |
+LL |     match *(z as Arc<Option<i32>>) {
+   |           ~~~~~~~~~~~~~~~~~~~~~~~~
+
+error[E0308]: mismatched types
+  --> $DIR/suggest-deref-in-match-issue-132784.rs:38:9
+   |
+LL |     match z as Arc<Option<i32>> {
+   |           --------------------- this expression has type `Arc<Option<i32>>`
+...
+LL |         None => {}
+   |         ^^^^ expected `Arc<Option<i32>>`, found `Option<_>`
+   |
+   = note: expected struct `Arc<Option<i32>>`
+                found enum `Option<_>`
+help: consider dereferencing to access the inner value using the Deref trait
+   |
+LL |     match *(z as Arc<Option<i32>>) {
+   |           ~~~~~~~~~~~~~~~~~~~~~~~~
+
+error[E0308]: mismatched types
+  --> $DIR/suggest-deref-in-match-issue-132784.rs:46:9
+   |
+LL |     match z_const {
+   |           ------- this expression has type `&Arc<Option<i32>>`
+...
+LL |         Some(_) => {}
+   |         ^^^^^^^ expected `Arc<Option<i32>>`, found `Option<_>`
+   |
+   = note: expected struct `Arc<Option<i32>>`
+                found enum `Option<_>`
+help: consider dereferencing to access the inner value using the Deref trait
+   |
+LL |     match &**z_const {
+   |           ~~~~~~~~~~
+
+error[E0308]: mismatched types
+  --> $DIR/suggest-deref-in-match-issue-132784.rs:48:9
+   |
+LL |     match z_const {
+   |           ------- this expression has type `&Arc<Option<i32>>`
+...
+LL |         None => {}
+   |         ^^^^ expected `Arc<Option<i32>>`, found `Option<_>`
+   |
+   = note: expected struct `Arc<Option<i32>>`
+                found enum `Option<_>`
+help: consider dereferencing to access the inner value using the Deref trait
+   |
+LL |     match &**z_const {
+   |           ~~~~~~~~~~
+
+error[E0308]: mismatched types
+  --> $DIR/suggest-deref-in-match-issue-132784.rs:57:9
+   |
+LL |     match z_mut {
+   |           ----- this expression has type `&mut Arc<Option<i32>>`
+...
+LL |         Some(_) => {}
+   |         ^^^^^^^ expected `Arc<Option<i32>>`, found `Option<_>`
+   |
+   = note: expected struct `Arc<Option<i32>>`
+                found enum `Option<_>`
+help: consider dereferencing to access the inner value using the Deref trait
+   |
+LL |     match &**z_mut {
+   |           ~~~~~~~~
+
+error[E0308]: mismatched types
+  --> $DIR/suggest-deref-in-match-issue-132784.rs:59:9
+   |
+LL |     match z_mut {
+   |           ----- this expression has type `&mut Arc<Option<i32>>`
+...
+LL |         None => {}
+   |         ^^^^ expected `Arc<Option<i32>>`, found `Option<_>`
+   |
+   = note: expected struct `Arc<Option<i32>>`
+                found enum `Option<_>`
+help: consider dereferencing to access the inner value using the Deref trait
+   |
+LL |     match &**z_mut {
+   |           ~~~~~~~~
+
+error[E0308]: mismatched types
+  --> $DIR/suggest-deref-in-match-issue-132784.rs:68:9
+   |
+LL |     match y_mut {
+   |           ----- this expression has type `&mut Box<Option<i32>>`
+...
+LL |         Some(_) => {}
+   |         ^^^^^^^ expected `Box<Option<i32>>`, found `Option<_>`
+   |
+   = note: expected struct `Box<Option<i32>>`
+                found enum `Option<_>`
+help: consider dereferencing to access the inner value using the Deref trait
+   |
+LL |     match &**y_mut {
+   |           ~~~~~~~~
+
+error[E0308]: mismatched types
+  --> $DIR/suggest-deref-in-match-issue-132784.rs:70:9
+   |
+LL |     match y_mut {
+   |           ----- this expression has type `&mut Box<Option<i32>>`
+...
+LL |         None => {}
+   |         ^^^^ expected `Box<Option<i32>>`, found `Option<_>`
+   |
+   = note: expected struct `Box<Option<i32>>`
+                found enum `Option<_>`
+help: consider dereferencing to access the inner value using the Deref trait
+   |
+LL |     match &**y_mut {
+   |           ~~~~~~~~
+
+error[E0308]: mismatched types
+  --> $DIR/suggest-deref-in-match-issue-132784.rs:79:9
+   |
+LL |     match (& (&difficult)  ) {
+   |           ------------------ this expression has type `&&Arc<Option<{integer}>>`
+...
+LL |         Some(_) => {}
+   |         ^^^^^^^ expected `Arc<Option<{integer}>>`, found `Option<_>`
+   |
+   = note: expected struct `Arc<Option<{integer}>>`
+                found enum `Option<_>`
+help: consider dereferencing to access the inner value using the Deref trait
+   |
+LL |     match &*difficult {
+   |           ~~~~~~~~~~~
+
+error[E0308]: mismatched types
+  --> $DIR/suggest-deref-in-match-issue-132784.rs:81:9
+   |
+LL |     match (& (&difficult)  ) {
+   |           ------------------ this expression has type `&&Arc<Option<{integer}>>`
+...
+LL |         None => {}
+   |         ^^^^ expected `Arc<Option<{integer}>>`, found `Option<_>`
+   |
+   = note: expected struct `Arc<Option<{integer}>>`
+                found enum `Option<_>`
+help: consider dereferencing to access the inner value using the Deref trait
+   |
+LL |     match &*difficult {
+   |           ~~~~~~~~~~~
+
+error: aborting due to 16 previous errors
+
+For more information about this error, try `rustc --explain E0308`.