about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-05-18 07:12:11 +0000
committerbors <bors@rust-lang.org>2022-05-18 07:12:11 +0000
commita084b7ad35adb508bd2e053fc2a1b9a53df9536c (patch)
tree540179ca7bc9385501adc59c6ade1586bc03364a
parent77972d2d0134fb597249b3b64dcf9510a790c34e (diff)
parenta2c2720e09202e1f988ff568efa4dcac8a71a504 (diff)
downloadrust-a084b7ad35adb508bd2e053fc2a1b9a53df9536c.tar.gz
rust-a084b7ad35adb508bd2e053fc2a1b9a53df9536c.zip
Auto merge of #97135 - Dylan-DPC:rollup-06u9pqn, r=Dylan-DPC
Rollup of 6 pull requests

Successful merges:

 - #94639 (Suggest dereferencing non-lval mutable reference on assignment)
 - #95979 (update coherence docs, fix generator + opaque type ICE)
 - #96378 (Mention traits and types involved in unstable trait upcasting)
 - #96917 (Make HashMap fall back to RtlGenRandom if BCryptGenRandom fails)
 - #97101 (Add tracking issue for ExitCode::exit_process)
 - #97123 (Clean fix for #96223)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--compiler/rustc_middle/src/traits/mod.rs3
-rw-r--r--compiler/rustc_trait_selection/src/traits/coherence.rs27
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs12
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs246
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs30
-rw-r--r--compiler/rustc_typeck/src/check/coercion.rs42
-rw-r--r--compiler/rustc_typeck/src/check/demand.rs21
-rw-r--r--compiler/rustc_typeck/src/check/expr.rs47
-rw-r--r--compiler/rustc_typeck/src/check/op.rs52
-rw-r--r--library/std/src/process.rs2
-rw-r--r--library/std/src/sys/windows/c.rs4
-rw-r--r--library/std/src/sys/windows/rand.rs74
-rw-r--r--src/test/ui/binop/issue-77910-1.stderr14
-rw-r--r--src/test/ui/coherence/coherence-with-closure.rs15
-rw-r--r--src/test/ui/coherence/coherence-with-closure.stderr24
-rw-r--r--src/test/ui/coherence/coherence-with-generator.rs19
-rw-r--r--src/test/ui/coherence/coherence-with-generator.stderr24
-rw-r--r--src/test/ui/feature-gates/feature-gate-trait_upcasting.stderr3
-rw-r--r--src/test/ui/issues/issue-11515.stderr3
-rw-r--r--src/test/ui/issues/issue-5239-1.stderr5
-rw-r--r--src/test/ui/suggestions/imm-ref-trait-object-literal-bound-regions.stderr1
-rw-r--r--src/test/ui/suggestions/mut-ref-reassignment.stderr4
-rw-r--r--src/test/ui/typeck/assign-non-lval-derefmut.fixed15
-rw-r--r--src/test/ui/typeck/assign-non-lval-derefmut.rs15
-rw-r--r--src/test/ui/typeck/assign-non-lval-derefmut.stderr58
-rw-r--r--src/test/ui/typeck/assign-non-lval-mut-ref.fixed15
-rw-r--r--src/test/ui/typeck/assign-non-lval-mut-ref.rs15
-rw-r--r--src/test/ui/typeck/assign-non-lval-mut-ref.stderr56
-rw-r--r--src/test/ui/typeck/issue-93486.stderr5
29 files changed, 636 insertions, 215 deletions
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index 26374939085..4d30c0e35e4 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -61,6 +61,9 @@ pub enum Reveal {
     ///     let x: <() as Assoc>::Output = true;
     /// }
     /// ```
+    ///
+    /// We also do not reveal the hidden type of opaque types during
+    /// type-checking.
     UserFacing,
 
     /// At codegen time, all monomorphic projections will succeed.
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index d09cc4fb62f..e56173b2dc5 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -645,7 +645,7 @@ fn orphan_check_trait_ref<'tcx>(
                 .substs
                 .types()
                 .flat_map(|ty| uncover_fundamental_ty(tcx, ty, in_crate))
-                .find(|ty| ty_is_local_constructor(*ty, in_crate));
+                .find(|&ty| ty_is_local_constructor(tcx, ty, in_crate));
 
             debug!("orphan_check_trait_ref: uncovered ty local_type: `{:?}`", local_type);
 
@@ -677,7 +677,7 @@ fn contained_non_local_types<'tcx>(
     ty: Ty<'tcx>,
     in_crate: InCrate,
 ) -> Vec<Ty<'tcx>> {
-    if ty_is_local_constructor(ty, in_crate) {
+    if ty_is_local_constructor(tcx, ty, in_crate) {
         Vec::new()
     } else {
         match fundamental_ty_inner_tys(tcx, ty) {
@@ -730,7 +730,7 @@ fn def_id_is_local(def_id: DefId, in_crate: InCrate) -> bool {
     }
 }
 
-fn ty_is_local_constructor(ty: Ty<'_>, in_crate: InCrate) -> bool {
+fn ty_is_local_constructor(tcx: TyCtxt<'_>, ty: Ty<'_>, in_crate: InCrate) -> bool {
     debug!("ty_is_local_constructor({:?})", ty);
 
     match *ty.kind() {
@@ -789,11 +789,6 @@ fn ty_is_local_constructor(ty: Ty<'_>, in_crate: InCrate) -> bool {
             false
         }
 
-        ty::Closure(..) => {
-            // Similar to the `Opaque` case (#83613).
-            false
-        }
-
         ty::Dynamic(ref tt, ..) => {
             if let Some(principal) = tt.principal() {
                 def_id_is_local(principal.def_id(), in_crate)
@@ -804,8 +799,20 @@ fn ty_is_local_constructor(ty: Ty<'_>, in_crate: InCrate) -> bool {
 
         ty::Error(_) => true,
 
-        ty::Generator(..) | ty::GeneratorWitness(..) => {
-            bug!("ty_is_local invoked on unexpected type: {:?}", ty)
+        // These variants should never appear during coherence checking because they
+        // cannot be named directly.
+        //
+        // They could be indirectly used through an opaque type. While using opaque types
+        // in impls causes an error, this path can still be hit afterwards.
+        //
+        // See `test/ui/coherence/coherence-with-closure.rs` for an example where this
+        // could happens.
+        ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(..) => {
+            tcx.sess.delay_span_bug(
+                DUMMY_SP,
+                format!("ty_is_local invoked on closure or generator: {:?}", ty),
+            );
+            true
         }
     }
 }
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index 6082d7529c3..266fcc777ef 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -1384,8 +1384,7 @@ trait InferCtxtPrivExt<'hir, 'tcx> {
     fn mk_trait_obligation_with_new_self_ty(
         &self,
         param_env: ty::ParamEnv<'tcx>,
-        trait_ref: ty::PolyTraitPredicate<'tcx>,
-        new_self_ty: Ty<'tcx>,
+        trait_ref_and_ty: ty::Binder<'tcx, (ty::TraitPredicate<'tcx>, Ty<'tcx>)>,
     ) -> PredicateObligation<'tcx>;
 
     fn maybe_report_ambiguity(
@@ -1923,14 +1922,11 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
     fn mk_trait_obligation_with_new_self_ty(
         &self,
         param_env: ty::ParamEnv<'tcx>,
-        trait_ref: ty::PolyTraitPredicate<'tcx>,
-        new_self_ty: Ty<'tcx>,
+        trait_ref_and_ty: ty::Binder<'tcx, (ty::TraitPredicate<'tcx>, Ty<'tcx>)>,
     ) -> PredicateObligation<'tcx> {
-        assert!(!new_self_ty.has_escaping_bound_vars());
-
-        let trait_pred = trait_ref.map_bound_ref(|tr| ty::TraitPredicate {
+        let trait_pred = trait_ref_and_ty.map_bound_ref(|(tr, new_self_ty)| ty::TraitPredicate {
             trait_ref: ty::TraitRef {
-                substs: self.tcx.mk_substs_trait(new_self_ty, &tr.trait_ref.substs[1..]),
+                substs: self.tcx.mk_substs_trait(*new_self_ty, &tr.trait_ref.substs[1..]),
                 ..tr.trait_ref
             },
             ..*tr
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index 833e232e636..c3ee849d857 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -628,17 +628,21 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
             if let Some(parent_trait_pred) = parent_trait_pred {
                 real_trait_pred = parent_trait_pred;
             }
-            let Some(real_ty) = real_trait_pred.self_ty().no_bound_vars() else {
-                continue;
-            };
+
+            // Skipping binder here, remapping below
+            let real_ty = real_trait_pred.self_ty().skip_binder();
 
             if let ty::Ref(region, base_ty, mutbl) = *real_ty.kind() {
                 let mut autoderef = Autoderef::new(self, param_env, body_id, span, base_ty, span);
                 if let Some(steps) = autoderef.find_map(|(ty, steps)| {
                     // Re-add the `&`
                     let ty = self.tcx.mk_ref(region, TypeAndMut { ty, mutbl });
-                    let obligation =
-                        self.mk_trait_obligation_with_new_self_ty(param_env, real_trait_pred, ty);
+
+                    // Remapping bound vars here
+                    let real_trait_pred_and_ty =
+                        real_trait_pred.map_bound(|inner_trait_pred| (inner_trait_pred, ty));
+                    let obligation = self
+                        .mk_trait_obligation_with_new_self_ty(param_env, real_trait_pred_and_ty);
                     Some(steps).filter(|_| self.predicate_may_hold(&obligation))
                 }) {
                     if steps > 0 {
@@ -659,10 +663,13 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                     }
                 } else if real_trait_pred != trait_pred {
                     // This branch addresses #87437.
+
+                    // Remapping bound vars here
+                    let real_trait_pred_and_base_ty =
+                        real_trait_pred.map_bound(|inner_trait_pred| (inner_trait_pred, base_ty));
                     let obligation = self.mk_trait_obligation_with_new_self_ty(
                         param_env,
-                        real_trait_pred,
-                        base_ty,
+                        real_trait_pred_and_base_ty,
                     );
                     if self.predicate_may_hold(&obligation) {
                         err.span_suggestion_verbose(
@@ -720,9 +727,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
         err: &mut Diagnostic,
         trait_pred: ty::PolyTraitPredicate<'tcx>,
     ) -> bool {
-        let Some(self_ty) = trait_pred.self_ty().no_bound_vars() else {
-            return false;
-        };
+        // Skipping binder here, remapping below
+        let self_ty = trait_pred.self_ty().skip_binder();
 
         let (def_id, output_ty, callable) = match *self_ty.kind() {
             ty::Closure(def_id, substs) => (def_id, substs.as_closure().sig().output(), "closure"),
@@ -731,14 +737,15 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
         };
         let msg = format!("use parentheses to call the {}", callable);
 
-        // `mk_trait_obligation_with_new_self_ty` only works for types with no escaping bound
-        // variables, so bail out if we have any.
-        let Some(output_ty) = output_ty.no_bound_vars() else {
-            return false;
-        };
+        // "We should really create a single list of bound vars from the combined vars
+        // from the predicate and function, but instead we just liberate the function bound vars"
+        let output_ty = self.tcx.liberate_late_bound_regions(def_id, output_ty);
+
+        // Remapping bound vars here
+        let trait_pred_and_self = trait_pred.map_bound(|trait_pred| (trait_pred, output_ty));
 
         let new_obligation =
-            self.mk_trait_obligation_with_new_self_ty(obligation.param_env, trait_pred, output_ty);
+            self.mk_trait_obligation_with_new_self_ty(obligation.param_env, trait_pred_and_self);
 
         match self.evaluate_obligation(&new_obligation) {
             Ok(
@@ -842,96 +849,97 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
         let param_env = obligation.param_env;
 
         // Try to apply the original trait binding obligation by borrowing.
-        let mut try_borrowing = |old_pred: ty::PolyTraitPredicate<'tcx>,
-                                 blacklist: &[DefId]|
-         -> bool {
-            if blacklist.contains(&old_pred.def_id()) {
-                return false;
-            }
-
-            // This is a quick fix to resolve an ICE (#96223).
-            // This change should probably be deeper.
-            // As suggested by @jackh726, `mk_trait_obligation_with_new_self_ty` could take a `Binder<(TraitRef, Ty)>
-            // instead of `Binder<Ty>` leading to some changes to its call places.
-            let Some(orig_ty) = old_pred.self_ty().no_bound_vars() else {
-                return false;
-            };
-            let mk_result = |new_ty| {
-                let obligation =
-                    self.mk_trait_obligation_with_new_self_ty(param_env, old_pred, new_ty);
-                self.predicate_must_hold_modulo_regions(&obligation)
-            };
-            let imm_result = mk_result(self.tcx.mk_imm_ref(self.tcx.lifetimes.re_static, orig_ty));
-            let mut_result = mk_result(self.tcx.mk_mut_ref(self.tcx.lifetimes.re_static, orig_ty));
-
-            if imm_result || mut_result {
-                if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
-                    // We have a very specific type of error, where just borrowing this argument
-                    // might solve the problem. In cases like this, the important part is the
-                    // original type obligation, not the last one that failed, which is arbitrary.
-                    // Because of this, we modify the error to refer to the original obligation and
-                    // return early in the caller.
-
-                    let msg = format!(
-                        "the trait bound `{}: {}` is not satisfied",
-                        orig_ty,
-                        old_pred.print_modifiers_and_trait_path(),
-                    );
-                    if has_custom_message {
-                        err.note(&msg);
-                    } else {
-                        err.message =
-                            vec![(rustc_errors::DiagnosticMessage::Str(msg), Style::NoStyle)];
-                    }
-                    if snippet.starts_with('&') {
-                        // This is already a literal borrow and the obligation is failing
-                        // somewhere else in the obligation chain. Do not suggest non-sense.
-                        return false;
-                    }
-                    err.span_label(
-                        span,
-                        &format!(
-                            "expected an implementor of trait `{}`",
-                            old_pred.print_modifiers_and_trait_path(),
-                        ),
-                    );
+        let mut try_borrowing =
+            |old_pred: ty::PolyTraitPredicate<'tcx>, blacklist: &[DefId]| -> bool {
+                if blacklist.contains(&old_pred.def_id()) {
+                    return false;
+                }
+                // We map bounds to `&T` and `&mut T`
+                let trait_pred_and_imm_ref = old_pred.map_bound(|trait_pred| {
+                    (
+                        trait_pred,
+                        self.tcx.mk_imm_ref(self.tcx.lifetimes.re_static, trait_pred.self_ty()),
+                    )
+                });
+                let trait_pred_and_mut_ref = old_pred.map_bound(|trait_pred| {
+                    (
+                        trait_pred,
+                        self.tcx.mk_mut_ref(self.tcx.lifetimes.re_static, trait_pred.self_ty()),
+                    )
+                });
 
-                    // This if is to prevent a special edge-case
-                    if matches!(
-                        span.ctxt().outer_expn_data().kind,
-                        ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop)
-                    ) {
-                        // We don't want a borrowing suggestion on the fields in structs,
-                        // ```
-                        // struct Foo {
-                        //  the_foos: Vec<Foo>
-                        // }
-                        // ```
-
-                        if imm_result && mut_result {
-                            err.span_suggestions(
-                                span.shrink_to_lo(),
-                                "consider borrowing here",
-                                ["&".to_string(), "&mut ".to_string()].into_iter(),
-                                Applicability::MaybeIncorrect,
-                            );
+                let mk_result = |trait_pred_and_new_ty| {
+                    let obligation =
+                        self.mk_trait_obligation_with_new_self_ty(param_env, trait_pred_and_new_ty);
+                    self.predicate_must_hold_modulo_regions(&obligation)
+                };
+                let imm_result = mk_result(trait_pred_and_imm_ref);
+                let mut_result = mk_result(trait_pred_and_mut_ref);
+
+                if imm_result || mut_result {
+                    if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
+                        // We have a very specific type of error, where just borrowing this argument
+                        // might solve the problem. In cases like this, the important part is the
+                        // original type obligation, not the last one that failed, which is arbitrary.
+                        // Because of this, we modify the error to refer to the original obligation and
+                        // return early in the caller.
+
+                        let msg = format!("the trait bound `{}` is not satisfied", old_pred);
+                        if has_custom_message {
+                            err.note(&msg);
                         } else {
-                            err.span_suggestion_verbose(
-                                span.shrink_to_lo(),
-                                &format!(
-                                    "consider{} borrowing here",
-                                    if mut_result { " mutably" } else { "" }
-                                ),
-                                format!("&{}", if mut_result { "mut " } else { "" }),
-                                Applicability::MaybeIncorrect,
-                            );
+                            err.message =
+                                vec![(rustc_errors::DiagnosticMessage::Str(msg), Style::NoStyle)];
                         }
+                        if snippet.starts_with('&') {
+                            // This is already a literal borrow and the obligation is failing
+                            // somewhere else in the obligation chain. Do not suggest non-sense.
+                            return false;
+                        }
+                        err.span_label(
+                            span,
+                            &format!(
+                                "expected an implementor of trait `{}`",
+                                old_pred.print_modifiers_and_trait_path(),
+                            ),
+                        );
+
+                        // This if is to prevent a special edge-case
+                        if matches!(
+                            span.ctxt().outer_expn_data().kind,
+                            ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop)
+                        ) {
+                            // We don't want a borrowing suggestion on the fields in structs,
+                            // ```
+                            // struct Foo {
+                            //  the_foos: Vec<Foo>
+                            // }
+                            // ```
+
+                            if imm_result && mut_result {
+                                err.span_suggestions(
+                                    span.shrink_to_lo(),
+                                    "consider borrowing here",
+                                    ["&".to_string(), "&mut ".to_string()].into_iter(),
+                                    Applicability::MaybeIncorrect,
+                                );
+                            } else {
+                                err.span_suggestion_verbose(
+                                    span.shrink_to_lo(),
+                                    &format!(
+                                        "consider{} borrowing here",
+                                        if mut_result { " mutably" } else { "" }
+                                    ),
+                                    format!("&{}", if mut_result { "mut " } else { "" }),
+                                    Applicability::MaybeIncorrect,
+                                );
+                            }
+                        }
+                        return true;
                     }
-                    return true;
                 }
-            }
-            return false;
-        };
+                return false;
+            };
 
         if let ObligationCauseCode::ImplDerivedObligation(cause) = &*code {
             try_borrowing(cause.derived.parent_trait_pred, &[])
@@ -992,9 +1000,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                 return false;
             }
 
-            let Some(mut suggested_ty) = trait_pred.self_ty().no_bound_vars() else {
-                return false;
-            };
+            // Skipping binder here, remapping below
+            let mut suggested_ty = trait_pred.self_ty().skip_binder();
 
             for refs_remaining in 0..refs_number {
                 let ty::Ref(_, inner_ty, _) = suggested_ty.kind() else {
@@ -1002,10 +1009,13 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                 };
                 suggested_ty = *inner_ty;
 
+                // Remapping bound vars here
+                let trait_pred_and_suggested_ty =
+                    trait_pred.map_bound(|trait_pred| (trait_pred, suggested_ty));
+
                 let new_obligation = self.mk_trait_obligation_with_new_self_ty(
                     obligation.param_env,
-                    trait_pred,
-                    suggested_ty,
+                    trait_pred_and_suggested_ty,
                 );
 
                 if self.predicate_may_hold(&new_obligation) {
@@ -1125,26 +1135,21 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                 return;
             }
 
+            // Skipping binder here, remapping below
             if let ty::Ref(region, t_type, mutability) = *trait_pred.skip_binder().self_ty().kind()
             {
-                if region.is_late_bound() || t_type.has_escaping_bound_vars() {
-                    // Avoid debug assertion in `mk_obligation_for_def_id`.
-                    //
-                    // If the self type has escaping bound vars then it's not
-                    // going to be the type of an expression, so the suggestion
-                    // probably won't apply anyway.
-                    return;
-                }
-
                 let suggested_ty = match mutability {
                     hir::Mutability::Mut => self.tcx.mk_imm_ref(region, t_type),
                     hir::Mutability::Not => self.tcx.mk_mut_ref(region, t_type),
                 };
 
+                // Remapping bound vars here
+                let trait_pred_and_suggested_ty =
+                    trait_pred.map_bound(|trait_pred| (trait_pred, suggested_ty));
+
                 let new_obligation = self.mk_trait_obligation_with_new_self_ty(
                     obligation.param_env,
-                    trait_pred,
-                    suggested_ty,
+                    trait_pred_and_suggested_ty,
                 );
                 let suggested_ty_would_satisfy_obligation = self
                     .evaluate_obligation_no_overflow(&new_obligation)
@@ -1195,7 +1200,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
             // Only suggest this if the expression behind the semicolon implements the predicate
             && let Some(typeck_results) = self.in_progress_typeck_results
             && let Some(ty) = typeck_results.borrow().expr_ty_opt(expr)
-            && self.predicate_may_hold(&self.mk_trait_obligation_with_new_self_ty(obligation.param_env, trait_pred, ty))
+            && self.predicate_may_hold(&self.mk_trait_obligation_with_new_self_ty(
+                obligation.param_env, trait_pred.map_bound(|trait_pred| (trait_pred, ty))
+            ))
         {
             err.span_label(
                 expr.span,
@@ -2727,8 +2734,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                 );
                 let try_obligation = self.mk_trait_obligation_with_new_self_ty(
                     obligation.param_env,
-                    trait_pred,
-                    normalized_ty.ty().unwrap(),
+                    trait_pred.map_bound(|trait_pred| (trait_pred, normalized_ty.ty().unwrap())),
                 );
                 debug!("suggest_await_before_try: try_trait_obligation {:?}", try_obligation);
                 if self.predicate_may_hold(&try_obligation)
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index a1577a30c91..57ded504b3c 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -103,22 +103,31 @@ pub struct SelectionContext<'cx, 'tcx> {
     /// require themselves.
     freshener: TypeFreshener<'cx, 'tcx>,
 
-    /// If `true`, indicates that the evaluation should be conservative
-    /// and consider the possibility of types outside this crate.
+    /// During coherence we have to assume that other crates may add
+    /// additional impls which we currently don't know about.
+    ///
+    /// To deal with this evaluation should be conservative
+    /// and consider the possibility of impls from outside this crate.
     /// This comes up primarily when resolving ambiguity. Imagine
     /// there is some trait reference `$0: Bar` where `$0` is an
     /// inference variable. If `intercrate` is true, then we can never
     /// say for sure that this reference is not implemented, even if
     /// there are *no impls at all for `Bar`*, because `$0` could be
     /// bound to some type that in a downstream crate that implements
-    /// `Bar`. This is the suitable mode for coherence. Elsewhere,
-    /// though, we set this to false, because we are only interested
-    /// in types that the user could actually have written --- in
-    /// other words, we consider `$0: Bar` to be unimplemented if
+    /// `Bar`.
+    ///
+    /// Outside of coherence we set this to false because we are only
+    /// interested in types that the user could actually have written.
+    /// In other words, we consider `$0: Bar` to be unimplemented if
     /// there is no type that the user could *actually name* that
     /// would satisfy it. This avoids crippling inference, basically.
     intercrate: bool,
-
+    /// If `intercrate` is set, we remember predicates which were
+    /// considered ambiguous because of impls potentially added in other crates.
+    /// This is used in coherence to give improved diagnostics.
+    /// We don't do his until we detect a coherence error because it can
+    /// lead to false overflow results (#47139) and because always
+    /// computing it may negatively impact performance.
     intercrate_ambiguity_causes: Option<Vec<IntercrateAmbiguityCause>>,
 
     /// The mode that trait queries run in, which informs our error handling
@@ -240,11 +249,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         }
     }
 
-    /// Enables tracking of intercrate ambiguity causes. These are
-    /// used in coherence to give improved diagnostics. We don't do
-    /// this until we detect a coherence error because it can lead to
-    /// false overflow results (#47139) and because it costs
-    /// computation time.
+    /// Enables tracking of intercrate ambiguity causes. See
+    /// the documentation of [`Self::intercrate_ambiguity_causes`] for more.
     pub fn enable_tracking_intercrate_ambiguity_causes(&mut self) {
         assert!(self.intercrate);
         assert!(self.intercrate_ambiguity_causes.is_none());
diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs
index 57d30799354..71957a2d1b0 100644
--- a/compiler/rustc_typeck/src/check/coercion.rs
+++ b/compiler/rustc_typeck/src/check/coercion.rs
@@ -58,7 +58,8 @@ use rustc_session::parse::feature_err;
 use rustc_span::symbol::sym;
 use rustc_span::{self, BytePos, DesugaringKind, Span};
 use rustc_target::spec::abi::Abi;
-use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
+use rustc_trait_selection::infer::InferCtxtExt as _;
+use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
 use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode};
 
 use smallvec::{smallvec, SmallVec};
@@ -615,7 +616,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
         )];
 
         let mut has_unsized_tuple_coercion = false;
-        let mut has_trait_upcasting_coercion = false;
+        let mut has_trait_upcasting_coercion = None;
 
         // Keep resolving `CoerceUnsized` and `Unsize` predicates to avoid
         // emitting a coercion in cases like `Foo<$1>` -> `Foo<$2>`, where
@@ -635,7 +636,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
                             && data_a.principal_def_id() != data_b.principal_def_id()
                         {
                             debug!("coerce_unsized: found trait upcasting coercion");
-                            has_trait_upcasting_coercion = true;
+                            has_trait_upcasting_coercion = Some((self_ty, unsize_ty));
                         }
                         if let ty::Tuple(..) = unsize_ty.kind() {
                             debug!("coerce_unsized: found unsized tuple coercion");
@@ -706,14 +707,19 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
             .emit();
         }
 
-        if has_trait_upcasting_coercion && !self.tcx().features().trait_upcasting {
-            feature_err(
+        if let Some((sub, sup)) = has_trait_upcasting_coercion
+            && !self.tcx().features().trait_upcasting
+        {
+            // Renders better when we erase regions, since they're not really the point here.
+            let (sub, sup) = self.tcx.erase_regions((sub, sup));
+            let mut err = feature_err(
                 &self.tcx.sess.parse_sess,
                 sym::trait_upcasting,
                 self.cause.span,
-                "trait upcasting coercion is experimental",
-            )
-            .emit();
+                &format!("cannot cast `{sub}` to `{sup}`, trait upcasting coercion is experimental"),
+            );
+            err.note(&format!("required when coercing `{source}` into `{target}`"));
+            err.emit();
         }
 
         Ok(coercion)
@@ -962,6 +968,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             .find_map(|(ty, steps)| self.probe(|_| coerce.unify(ty, target)).ok().map(|_| steps))
     }
 
+    /// Given a type, this function will calculate and return the type given
+    /// for `<Ty as Deref>::Target` only if `Ty` also implements `DerefMut`.
+    ///
+    /// This function is for diagnostics only, since it does not register
+    /// trait or region sub-obligations. (presumably we could, but it's not
+    /// particularly important for diagnostics...)
+    pub fn deref_once_mutably_for_diagnostic(&self, expr_ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
+        self.autoderef(rustc_span::DUMMY_SP, expr_ty).nth(1).and_then(|(deref_ty, _)| {
+            self.infcx
+                .type_implements_trait(
+                    self.infcx.tcx.lang_items().deref_mut_trait()?,
+                    expr_ty,
+                    ty::List::empty(),
+                    self.param_env,
+                )
+                .may_apply()
+                .then(|| deref_ty)
+        })
+    }
+
     /// Given some expressions, their known unified type and another expression,
     /// tries to unify the types, potentially inserting coercions on any of the
     /// provided expressions and returns their LUB (aka "common supertype").
diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs
index ae4cebe866b..ede2180a8e9 100644
--- a/compiler/rustc_typeck/src/check/demand.rs
+++ b/compiler/rustc_typeck/src/check/demand.rs
@@ -696,28 +696,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         };
 
                         if let Some(hir::Node::Expr(hir::Expr {
-                            kind: hir::ExprKind::Assign(left_expr, ..),
+                            kind: hir::ExprKind::Assign(..),
                             ..
                         })) = self.tcx.hir().find(self.tcx.hir().get_parent_node(expr.hir_id))
                         {
                             if mutability == hir::Mutability::Mut {
-                                // Found the following case:
-                                // fn foo(opt: &mut Option<String>){ opt = None }
-                                //                                   ---   ^^^^
-                                //                                   |     |
-                                //    consider dereferencing here: `*opt`  |
-                                // expected mutable reference, found enum `Option`
-                                if sm.span_to_snippet(left_expr.span).is_ok() {
-                                    return Some((
-                                        left_expr.span.shrink_to_lo(),
-                                        "consider dereferencing here to assign to the mutable \
-                                         borrowed piece of memory"
-                                            .to_string(),
-                                        "*".to_string(),
-                                        Applicability::MachineApplicable,
-                                        true,
-                                    ));
-                                }
+                                // Suppressing this diagnostic, we'll properly print it in `check_expr_assign`
+                                return None;
                             }
                         }
 
diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs
index f3a5b9f13dd..6d56445771a 100644
--- a/compiler/rustc_typeck/src/check/expr.rs
+++ b/compiler/rustc_typeck/src/check/expr.rs
@@ -51,6 +51,7 @@ use rustc_span::lev_distance::find_best_match_for_name;
 use rustc_span::source_map::Span;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{BytePos, Pos};
+use rustc_trait_selection::infer::InferCtxtExt;
 use rustc_trait_selection::traits::{self, ObligationCauseCode};
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
@@ -836,6 +837,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         lhs: &'tcx hir::Expr<'tcx>,
         err_code: &'static str,
         op_span: Span,
+        adjust_err: impl FnOnce(&mut DiagnosticBuilder<'tcx, ErrorGuaranteed>),
     ) {
         if lhs.is_syntactic_place_expr() {
             return;
@@ -858,6 +860,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             );
         });
 
+        adjust_err(&mut err);
+
         err.emit();
     }
 
@@ -1050,10 +1054,47 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             return self.tcx.ty_error();
         }
 
-        self.check_lhs_assignable(lhs, "E0070", span);
-
         let lhs_ty = self.check_expr_with_needs(&lhs, Needs::MutPlace);
-        let rhs_ty = self.check_expr_coercable_to_type(&rhs, lhs_ty, Some(lhs));
+
+        let suggest_deref_binop = |err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>,
+                                   rhs_ty: Ty<'tcx>| {
+            if let Some(lhs_deref_ty) = self.deref_once_mutably_for_diagnostic(lhs_ty) {
+                // Can only assign if the type is sized, so if `DerefMut` yields a type that is
+                // unsized, do not suggest dereferencing it.
+                let lhs_deref_ty_is_sized = self
+                    .infcx
+                    .type_implements_trait(
+                        self.tcx.lang_items().sized_trait().unwrap(),
+                        lhs_deref_ty,
+                        ty::List::empty(),
+                        self.param_env,
+                    )
+                    .may_apply();
+                if lhs_deref_ty_is_sized && self.can_coerce(rhs_ty, lhs_deref_ty) {
+                    err.span_suggestion_verbose(
+                        lhs.span.shrink_to_lo(),
+                        "consider dereferencing here to assign to the mutably borrowed value",
+                        "*".to_string(),
+                        Applicability::MachineApplicable,
+                    );
+                }
+            }
+        };
+
+        self.check_lhs_assignable(lhs, "E0070", span, |err| {
+            let rhs_ty = self.check_expr(&rhs);
+            suggest_deref_binop(err, rhs_ty);
+        });
+
+        // This is (basically) inlined `check_expr_coercable_to_type`, but we want
+        // to suggest an additional fixup here in `suggest_deref_binop`.
+        let rhs_ty = self.check_expr_with_hint(&rhs, lhs_ty);
+        if let (_, Some(mut diag)) =
+            self.demand_coerce_diag(rhs, rhs_ty, lhs_ty, Some(lhs), AllowTwoPhase::No)
+        {
+            suggest_deref_binop(&mut diag, rhs_ty);
+            diag.emit();
+        }
 
         self.require_type_is_sized(lhs_ty, lhs.span, traits::AssignmentLhsSized);
 
diff --git a/compiler/rustc_typeck/src/check/op.rs b/compiler/rustc_typeck/src/check/op.rs
index 1ae53a77adc..c99d9d8f923 100644
--- a/compiler/rustc_typeck/src/check/op.rs
+++ b/compiler/rustc_typeck/src/check/op.rs
@@ -41,7 +41,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 return_ty
             };
 
-        self.check_lhs_assignable(lhs, "E0067", op.span);
+        self.check_lhs_assignable(lhs, "E0067", op.span, |err| {
+            if let Some(lhs_deref_ty) = self.deref_once_mutably_for_diagnostic(lhs_ty) {
+                if self
+                    .lookup_op_method(
+                        lhs_deref_ty,
+                        Some(rhs_ty),
+                        Some(rhs),
+                        Op::Binary(op, IsAssign::Yes),
+                    )
+                    .is_ok()
+                {
+                    // Suppress this error, since we already emitted
+                    // a deref suggestion in check_overloaded_binop
+                    err.delay_as_bug();
+                }
+            }
+        });
 
         ty
     }
@@ -404,16 +420,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         (err, missing_trait, use_output)
                     }
                 };
-                if let Ref(_, rty, _) = lhs_ty.kind() {
-                    if self.infcx.type_is_copy_modulo_regions(self.param_env, *rty, lhs_expr.span)
-                        && self
-                            .lookup_op_method(
-                                *rty,
-                                Some(rhs_ty),
-                                Some(rhs_expr),
-                                Op::Binary(op, is_assign),
-                            )
-                            .is_ok()
+
+                let mut suggest_deref_binop = |lhs_deref_ty: Ty<'tcx>| {
+                    if self
+                        .lookup_op_method(
+                            lhs_deref_ty,
+                            Some(rhs_ty),
+                            Some(rhs_expr),
+                            Op::Binary(op, is_assign),
+                        )
+                        .is_ok()
                     {
                         if let Ok(lstring) = source_map.span_to_snippet(lhs_expr.span) {
                             let msg = &format!(
@@ -423,7 +439,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                     IsAssign::Yes => "=",
                                     IsAssign::No => "",
                                 },
-                                rty.peel_refs(),
+                                lhs_deref_ty.peel_refs(),
                                 lstring,
                             );
                             err.span_suggestion_verbose(
@@ -434,6 +450,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             );
                         }
                     }
+                };
+
+                // We should suggest `a + b` => `*a + b` if `a` is copy, and suggest
+                // `a += b` => `*a += b` if a is a mut ref.
+                if is_assign == IsAssign::Yes
+                    && let Some(lhs_deref_ty) = self.deref_once_mutably_for_diagnostic(lhs_ty) {
+                        suggest_deref_binop(lhs_deref_ty);
+                } else if is_assign == IsAssign::No
+                    && let Ref(_, lhs_deref_ty, _) = lhs_ty.kind() {
+                    if self.infcx.type_is_copy_modulo_regions(self.param_env, *lhs_deref_ty, lhs_expr.span) {
+                        suggest_deref_binop(*lhs_deref_ty);
+                    }
                 }
                 if let Some(missing_trait) = missing_trait {
                     let mut visitor = TypeParamVisitor(vec![]);
diff --git a/library/std/src/process.rs b/library/std/src/process.rs
index 6c5c08d0bea..e253f46406f 100644
--- a/library/std/src/process.rs
+++ b/library/std/src/process.rs
@@ -1764,7 +1764,7 @@ impl ExitCode {
     ///     code.exit_process()
     /// }
     /// ```
-    #[unstable(feature = "exitcode_exit_method", issue = "none")]
+    #[unstable(feature = "exitcode_exit_method", issue = "97100")]
     pub fn exit_process(self) -> ! {
         exit(self.to_i32())
     }
diff --git a/library/std/src/sys/windows/c.rs b/library/std/src/sys/windows/c.rs
index 0692da1d795..0bb6fee60c9 100644
--- a/library/std/src/sys/windows/c.rs
+++ b/library/std/src/sys/windows/c.rs
@@ -788,6 +788,10 @@ if #[cfg(not(target_vendor = "uwp"))] {
 
     #[link(name = "advapi32")]
     extern "system" {
+        // Forbidden when targeting UWP
+        #[link_name = "SystemFunction036"]
+        pub fn RtlGenRandom(RandomBuffer: *mut u8, RandomBufferLength: ULONG) -> BOOLEAN;
+
         // Allowed but unused by UWP
         pub fn OpenProcessToken(
             ProcessHandle: HANDLE,
diff --git a/library/std/src/sys/windows/rand.rs b/library/std/src/sys/windows/rand.rs
index de73e9154b4..22e024d8552 100644
--- a/library/std/src/sys/windows/rand.rs
+++ b/library/std/src/sys/windows/rand.rs
@@ -1,8 +1,60 @@
 use crate::io;
+use crate::lazy;
 use crate::mem;
 use crate::sys::c;
 
+/// The kinds of HashMap RNG that may be available
+#[derive(Clone, Copy, Debug, PartialEq)]
+enum HashMapRng {
+    Preferred,
+    Fallback,
+}
+
 pub fn hashmap_random_keys() -> (u64, u64) {
+    match get_hashmap_rng() {
+        HashMapRng::Preferred => {
+            preferred_rng().expect("couldn't generate random bytes with preferred RNG")
+        }
+        HashMapRng::Fallback => {
+            fallback_rng().expect("couldn't generate random bytes with fallback RNG")
+        }
+    }
+}
+
+/// Returns the HashMap RNG that should be used
+///
+/// Panics if they are both broken
+fn get_hashmap_rng() -> HashMapRng {
+    // Assume that if the preferred RNG is broken the first time we use it, it likely means
+    // that: the DLL has failed to load, there is no point to calling it over-and-over again,
+    // and we should cache the result
+    static VALUE: lazy::SyncOnceCell<HashMapRng> = lazy::SyncOnceCell::new();
+    *VALUE.get_or_init(choose_hashmap_rng)
+}
+
+/// Test whether we should use the preferred or fallback RNG
+///
+/// If the preferred RNG is successful, we choose it. Otherwise, if the fallback RNG is successful,
+/// we choose that
+///
+/// Panics if both the preferred and the fallback RNG are both non-functional
+fn choose_hashmap_rng() -> HashMapRng {
+    let preferred_error = match preferred_rng() {
+        Ok(_) => return HashMapRng::Preferred,
+        Err(e) => e,
+    };
+
+    match fallback_rng() {
+        Ok(_) => return HashMapRng::Fallback,
+        Err(fallback_error) => panic!(
+            "preferred RNG broken: `{}`, fallback RNG broken: `{}`",
+            preferred_error, fallback_error
+        ),
+    }
+}
+
+/// Generate random numbers using the preferred RNG function (BCryptGenRandom)
+fn preferred_rng() -> Result<(u64, u64), io::Error> {
     use crate::ptr;
 
     let mut v = (0, 0);
@@ -14,8 +66,22 @@ pub fn hashmap_random_keys() -> (u64, u64) {
             c::BCRYPT_USE_SYSTEM_PREFERRED_RNG,
         )
     };
-    if ret != 0 {
-        panic!("couldn't generate random bytes: {}", io::Error::last_os_error());
-    }
-    return v;
+
+    if ret == 0 { Ok(v) } else { Err(io::Error::last_os_error()) }
+}
+
+/// Generate random numbers using the fallback RNG function (RtlGenRandom)
+#[cfg(not(target_vendor = "uwp"))]
+fn fallback_rng() -> Result<(u64, u64), io::Error> {
+    let mut v = (0, 0);
+    let ret =
+        unsafe { c::RtlGenRandom(&mut v as *mut _ as *mut u8, mem::size_of_val(&v) as c::ULONG) };
+
+    if ret != 0 { Ok(v) } else { Err(io::Error::last_os_error()) }
+}
+
+/// We can't use RtlGenRandom with UWP, so there is no fallback
+#[cfg(target_vendor = "uwp")]
+fn fallback_rng() -> Result<(u64, u64), io::Error> {
+    Err(io::const_io_error!(io::ErrorKind::Unsupported, "RtlGenRandom() not supported on UWP"))
 }
diff --git a/src/test/ui/binop/issue-77910-1.stderr b/src/test/ui/binop/issue-77910-1.stderr
index 95ee51a8826..68303b84208 100644
--- a/src/test/ui/binop/issue-77910-1.stderr
+++ b/src/test/ui/binop/issue-77910-1.stderr
@@ -12,20 +12,14 @@ LL |     assert_eq!(foo, y);
 error[E0277]: `for<'r> fn(&'r i32) -> &'r i32 {foo}` doesn't implement `Debug`
   --> $DIR/issue-77910-1.rs:8:5
    |
+LL | fn foo(s: &i32) -> &i32 {
+   |    --- consider calling this function
+...
 LL |     assert_eq!(foo, y);
    |     ^^^^^^^^^^^^^^^^^^ `for<'r> fn(&'r i32) -> &'r i32 {foo}` cannot be formatted using `{:?}` because it doesn't implement `Debug`
    |
    = help: the trait `Debug` is not implemented for `for<'r> fn(&'r i32) -> &'r i32 {foo}`
-   = help: the following other types implement trait `Debug`:
-             extern "C" fn() -> Ret
-             extern "C" fn(A) -> Ret
-             extern "C" fn(A, ...) -> Ret
-             extern "C" fn(A, B) -> Ret
-             extern "C" fn(A, B, ...) -> Ret
-             extern "C" fn(A, B, C) -> Ret
-             extern "C" fn(A, B, C, ...) -> Ret
-             extern "C" fn(A, B, C, D) -> Ret
-           and 68 others
+   = help: use parentheses to call the function: `foo(s)`
    = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to 2 previous errors
diff --git a/src/test/ui/coherence/coherence-with-closure.rs b/src/test/ui/coherence/coherence-with-closure.rs
new file mode 100644
index 00000000000..6e3281d8508
--- /dev/null
+++ b/src/test/ui/coherence/coherence-with-closure.rs
@@ -0,0 +1,15 @@
+// Test that encountering closures during coherence does not cause issues.
+#![feature(type_alias_impl_trait)]
+type OpaqueClosure = impl Sized;
+fn defining_use() -> OpaqueClosure {
+    || ()
+}
+
+struct Wrapper<T>(T);
+trait Trait {}
+impl Trait for Wrapper<OpaqueClosure> {}
+//~^ ERROR cannot implement trait on type alias impl trait
+impl<T: Sync> Trait for Wrapper<T> {}
+//~^ ERROR conflicting implementations of trait `Trait` for type `Wrapper<OpaqueClosure>`
+
+fn main() {}
diff --git a/src/test/ui/coherence/coherence-with-closure.stderr b/src/test/ui/coherence/coherence-with-closure.stderr
new file mode 100644
index 00000000000..20b986cee69
--- /dev/null
+++ b/src/test/ui/coherence/coherence-with-closure.stderr
@@ -0,0 +1,24 @@
+error: cannot implement trait on type alias impl trait
+  --> $DIR/coherence-with-closure.rs:10:24
+   |
+LL | impl Trait for Wrapper<OpaqueClosure> {}
+   |                        ^^^^^^^^^^^^^
+   |
+note: type alias impl trait defined here
+  --> $DIR/coherence-with-closure.rs:3:22
+   |
+LL | type OpaqueClosure = impl Sized;
+   |                      ^^^^^^^^^^
+
+error[E0119]: conflicting implementations of trait `Trait` for type `Wrapper<OpaqueClosure>`
+  --> $DIR/coherence-with-closure.rs:12:1
+   |
+LL | impl Trait for Wrapper<OpaqueClosure> {}
+   | ------------------------------------- first implementation here
+LL |
+LL | impl<T: Sync> Trait for Wrapper<T> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Wrapper<OpaqueClosure>`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0119`.
diff --git a/src/test/ui/coherence/coherence-with-generator.rs b/src/test/ui/coherence/coherence-with-generator.rs
new file mode 100644
index 00000000000..d34c391db9f
--- /dev/null
+++ b/src/test/ui/coherence/coherence-with-generator.rs
@@ -0,0 +1,19 @@
+// Test that encountering closures during coherence does not cause issues.
+#![feature(type_alias_impl_trait, generators)]
+type OpaqueGenerator = impl Sized;
+fn defining_use() -> OpaqueGenerator {
+    || {
+        for i in 0..10 {
+            yield i;
+        }
+    }
+}
+
+struct Wrapper<T>(T);
+trait Trait {}
+impl Trait for Wrapper<OpaqueGenerator> {}
+//~^ ERROR cannot implement trait on type alias impl trait
+impl<T: Sync> Trait for Wrapper<T> {}
+//~^ ERROR conflicting implementations of trait `Trait` for type `Wrapper<OpaqueGenerator>`
+
+fn main() {}
diff --git a/src/test/ui/coherence/coherence-with-generator.stderr b/src/test/ui/coherence/coherence-with-generator.stderr
new file mode 100644
index 00000000000..249ad3cb9ec
--- /dev/null
+++ b/src/test/ui/coherence/coherence-with-generator.stderr
@@ -0,0 +1,24 @@
+error: cannot implement trait on type alias impl trait
+  --> $DIR/coherence-with-generator.rs:14:24
+   |
+LL | impl Trait for Wrapper<OpaqueGenerator> {}
+   |                        ^^^^^^^^^^^^^^^
+   |
+note: type alias impl trait defined here
+  --> $DIR/coherence-with-generator.rs:3:24
+   |
+LL | type OpaqueGenerator = impl Sized;
+   |                        ^^^^^^^^^^
+
+error[E0119]: conflicting implementations of trait `Trait` for type `Wrapper<OpaqueGenerator>`
+  --> $DIR/coherence-with-generator.rs:16:1
+   |
+LL | impl Trait for Wrapper<OpaqueGenerator> {}
+   | --------------------------------------- first implementation here
+LL |
+LL | impl<T: Sync> Trait for Wrapper<T> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Wrapper<OpaqueGenerator>`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0119`.
diff --git a/src/test/ui/feature-gates/feature-gate-trait_upcasting.stderr b/src/test/ui/feature-gates/feature-gate-trait_upcasting.stderr
index bc13a5d7d7b..93afa78459d 100644
--- a/src/test/ui/feature-gates/feature-gate-trait_upcasting.stderr
+++ b/src/test/ui/feature-gates/feature-gate-trait_upcasting.stderr
@@ -1,4 +1,4 @@
-error[E0658]: trait upcasting coercion is experimental
+error[E0658]: cannot cast `dyn Bar` to `dyn Foo`, trait upcasting coercion is experimental
   --> $DIR/feature-gate-trait_upcasting.rs:11:25
    |
 LL |     let foo: &dyn Foo = bar;
@@ -6,6 +6,7 @@ LL |     let foo: &dyn Foo = bar;
    |
    = note: see issue #65991 <https://github.com/rust-lang/rust/issues/65991> for more information
    = help: add `#![feature(trait_upcasting)]` to the crate attributes to enable
+   = note: required when coercing `&dyn Bar` into `&dyn Foo`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-11515.stderr b/src/test/ui/issues/issue-11515.stderr
index a70e7c416bc..17bfae2a4e4 100644
--- a/src/test/ui/issues/issue-11515.stderr
+++ b/src/test/ui/issues/issue-11515.stderr
@@ -1,4 +1,4 @@
-error[E0658]: trait upcasting coercion is experimental
+error[E0658]: cannot cast `dyn Fn()` to `dyn FnMut()`, trait upcasting coercion is experimental
   --> $DIR/issue-11515.rs:9:33
    |
 LL |     let test = box Test { func: closure };
@@ -6,6 +6,7 @@ LL |     let test = box Test { func: closure };
    |
    = note: see issue #65991 <https://github.com/rust-lang/rust/issues/65991> for more information
    = help: add `#![feature(trait_upcasting)]` to the crate attributes to enable
+   = note: required when coercing `Box<(dyn Fn() + 'static)>` into `Box<(dyn FnMut() + 'static)>`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-5239-1.stderr b/src/test/ui/issues/issue-5239-1.stderr
index b743f0df4b1..f53ddb95416 100644
--- a/src/test/ui/issues/issue-5239-1.stderr
+++ b/src/test/ui/issues/issue-5239-1.stderr
@@ -5,11 +5,6 @@ LL |     let x = |ref x: isize| { x += 1; };
    |                              -^^^^^
    |                              |
    |                              cannot use `+=` on type `&isize`
-   |
-help: `+=` can be used on `isize`, you can dereference `x`
-   |
-LL |     let x = |ref x: isize| { *x += 1; };
-   |                              +
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/suggestions/imm-ref-trait-object-literal-bound-regions.stderr b/src/test/ui/suggestions/imm-ref-trait-object-literal-bound-regions.stderr
index 0783f04dc9b..ba6af8f15fa 100644
--- a/src/test/ui/suggestions/imm-ref-trait-object-literal-bound-regions.stderr
+++ b/src/test/ui/suggestions/imm-ref-trait-object-literal-bound-regions.stderr
@@ -5,6 +5,7 @@ LL |     foo::<S>(s);
    |     ^^^^^^^^ the trait `for<'b> Trait` is not implemented for `&'b S`
    |
    = help: the trait `Trait` is implemented for `&'a mut S`
+   = note: `for<'b> Trait` is implemented for `&'b mut S`, but not for `&'b S`
 note: required by a bound in `foo`
   --> $DIR/imm-ref-trait-object-literal-bound-regions.rs:11:20
    |
diff --git a/src/test/ui/suggestions/mut-ref-reassignment.stderr b/src/test/ui/suggestions/mut-ref-reassignment.stderr
index 3bd98c76307..b3cb6dd0614 100644
--- a/src/test/ui/suggestions/mut-ref-reassignment.stderr
+++ b/src/test/ui/suggestions/mut-ref-reassignment.stderr
@@ -8,7 +8,7 @@ LL |     opt = None;
    |
    = note: expected mutable reference `&mut Option<String>`
                            found enum `Option<_>`
-help: consider dereferencing here to assign to the mutable borrowed piece of memory
+help: consider dereferencing here to assign to the mutably borrowed value
    |
 LL |     *opt = None;
    |     +
@@ -34,7 +34,7 @@ LL |     opt = Some(String::new())
    |
    = note: expected mutable reference `&mut Option<String>`
                            found enum `Option<String>`
-help: consider dereferencing here to assign to the mutable borrowed piece of memory
+help: consider dereferencing here to assign to the mutably borrowed value
    |
 LL |     *opt = Some(String::new())
    |     +
diff --git a/src/test/ui/typeck/assign-non-lval-derefmut.fixed b/src/test/ui/typeck/assign-non-lval-derefmut.fixed
new file mode 100644
index 00000000000..0c23199af22
--- /dev/null
+++ b/src/test/ui/typeck/assign-non-lval-derefmut.fixed
@@ -0,0 +1,15 @@
+// run-rustfix
+
+fn main() {
+    let x = std::sync::Mutex::new(1usize);
+    *x.lock().unwrap() = 2;
+    //~^ ERROR invalid left-hand side of assignment
+    *x.lock().unwrap() += 1;
+    //~^ ERROR binary assignment operation `+=` cannot be applied to type `MutexGuard<'_, usize>`
+
+    let mut y = x.lock().unwrap();
+    *y = 2;
+    //~^ ERROR mismatched types
+    *y += 1;
+    //~^ ERROR binary assignment operation `+=` cannot be applied to type `MutexGuard<'_, usize>`
+}
diff --git a/src/test/ui/typeck/assign-non-lval-derefmut.rs b/src/test/ui/typeck/assign-non-lval-derefmut.rs
new file mode 100644
index 00000000000..ec1882f5271
--- /dev/null
+++ b/src/test/ui/typeck/assign-non-lval-derefmut.rs
@@ -0,0 +1,15 @@
+// run-rustfix
+
+fn main() {
+    let x = std::sync::Mutex::new(1usize);
+    x.lock().unwrap() = 2;
+    //~^ ERROR invalid left-hand side of assignment
+    x.lock().unwrap() += 1;
+    //~^ ERROR binary assignment operation `+=` cannot be applied to type `MutexGuard<'_, usize>`
+
+    let mut y = x.lock().unwrap();
+    y = 2;
+    //~^ ERROR mismatched types
+    y += 1;
+    //~^ ERROR binary assignment operation `+=` cannot be applied to type `MutexGuard<'_, usize>`
+}
diff --git a/src/test/ui/typeck/assign-non-lval-derefmut.stderr b/src/test/ui/typeck/assign-non-lval-derefmut.stderr
new file mode 100644
index 00000000000..a6fcdfe21f4
--- /dev/null
+++ b/src/test/ui/typeck/assign-non-lval-derefmut.stderr
@@ -0,0 +1,58 @@
+error[E0070]: invalid left-hand side of assignment
+  --> $DIR/assign-non-lval-derefmut.rs:5:23
+   |
+LL |     x.lock().unwrap() = 2;
+   |     ----------------- ^
+   |     |
+   |     cannot assign to this expression
+   |
+help: consider dereferencing here to assign to the mutably borrowed value
+   |
+LL |     *x.lock().unwrap() = 2;
+   |     +
+
+error[E0368]: binary assignment operation `+=` cannot be applied to type `MutexGuard<'_, usize>`
+  --> $DIR/assign-non-lval-derefmut.rs:7:5
+   |
+LL |     x.lock().unwrap() += 1;
+   |     -----------------^^^^^
+   |     |
+   |     cannot use `+=` on type `MutexGuard<'_, usize>`
+   |
+help: `+=` can be used on `usize`, you can dereference `x.lock().unwrap()`
+   |
+LL |     *x.lock().unwrap() += 1;
+   |     +
+
+error[E0308]: mismatched types
+  --> $DIR/assign-non-lval-derefmut.rs:11:9
+   |
+LL |     let mut y = x.lock().unwrap();
+   |                 ----------------- expected due to this value
+LL |     y = 2;
+   |         ^ expected struct `MutexGuard`, found integer
+   |
+   = note: expected struct `MutexGuard<'_, usize>`
+                found type `{integer}`
+help: consider dereferencing here to assign to the mutably borrowed value
+   |
+LL |     *y = 2;
+   |     +
+
+error[E0368]: binary assignment operation `+=` cannot be applied to type `MutexGuard<'_, usize>`
+  --> $DIR/assign-non-lval-derefmut.rs:13:5
+   |
+LL |     y += 1;
+   |     -^^^^^
+   |     |
+   |     cannot use `+=` on type `MutexGuard<'_, usize>`
+   |
+help: `+=` can be used on `usize`, you can dereference `y`
+   |
+LL |     *y += 1;
+   |     +
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0070, E0308, E0368.
+For more information about an error, try `rustc --explain E0070`.
diff --git a/src/test/ui/typeck/assign-non-lval-mut-ref.fixed b/src/test/ui/typeck/assign-non-lval-mut-ref.fixed
new file mode 100644
index 00000000000..10c7b9dbfb3
--- /dev/null
+++ b/src/test/ui/typeck/assign-non-lval-mut-ref.fixed
@@ -0,0 +1,15 @@
+// run-rustfix
+
+fn main() {
+    let mut x = vec![1usize];
+    *x.last_mut().unwrap() = 2;
+    //~^ ERROR invalid left-hand side of assignment
+    *x.last_mut().unwrap() += 1;
+    //~^ ERROR binary assignment operation `+=` cannot be applied to type `&mut usize`
+
+    let y = x.last_mut().unwrap();
+    *y = 2;
+    //~^ ERROR mismatched types
+    *y += 1;
+    //~^ ERROR binary assignment operation `+=` cannot be applied to type `&mut usize`
+}
diff --git a/src/test/ui/typeck/assign-non-lval-mut-ref.rs b/src/test/ui/typeck/assign-non-lval-mut-ref.rs
new file mode 100644
index 00000000000..bceff0ef09d
--- /dev/null
+++ b/src/test/ui/typeck/assign-non-lval-mut-ref.rs
@@ -0,0 +1,15 @@
+// run-rustfix
+
+fn main() {
+    let mut x = vec![1usize];
+    x.last_mut().unwrap() = 2;
+    //~^ ERROR invalid left-hand side of assignment
+    x.last_mut().unwrap() += 1;
+    //~^ ERROR binary assignment operation `+=` cannot be applied to type `&mut usize`
+
+    let y = x.last_mut().unwrap();
+    y = 2;
+    //~^ ERROR mismatched types
+    y += 1;
+    //~^ ERROR binary assignment operation `+=` cannot be applied to type `&mut usize`
+}
diff --git a/src/test/ui/typeck/assign-non-lval-mut-ref.stderr b/src/test/ui/typeck/assign-non-lval-mut-ref.stderr
new file mode 100644
index 00000000000..be2e9fe95e8
--- /dev/null
+++ b/src/test/ui/typeck/assign-non-lval-mut-ref.stderr
@@ -0,0 +1,56 @@
+error[E0070]: invalid left-hand side of assignment
+  --> $DIR/assign-non-lval-mut-ref.rs:5:27
+   |
+LL |     x.last_mut().unwrap() = 2;
+   |     --------------------- ^
+   |     |
+   |     cannot assign to this expression
+   |
+help: consider dereferencing here to assign to the mutably borrowed value
+   |
+LL |     *x.last_mut().unwrap() = 2;
+   |     +
+
+error[E0368]: binary assignment operation `+=` cannot be applied to type `&mut usize`
+  --> $DIR/assign-non-lval-mut-ref.rs:7:5
+   |
+LL |     x.last_mut().unwrap() += 1;
+   |     ---------------------^^^^^
+   |     |
+   |     cannot use `+=` on type `&mut usize`
+   |
+help: `+=` can be used on `usize`, you can dereference `x.last_mut().unwrap()`
+   |
+LL |     *x.last_mut().unwrap() += 1;
+   |     +
+
+error[E0308]: mismatched types
+  --> $DIR/assign-non-lval-mut-ref.rs:11:9
+   |
+LL |     let y = x.last_mut().unwrap();
+   |             --------------------- expected due to this value
+LL |     y = 2;
+   |         ^ expected `&mut usize`, found integer
+   |
+help: consider dereferencing here to assign to the mutably borrowed value
+   |
+LL |     *y = 2;
+   |     +
+
+error[E0368]: binary assignment operation `+=` cannot be applied to type `&mut usize`
+  --> $DIR/assign-non-lval-mut-ref.rs:13:5
+   |
+LL |     y += 1;
+   |     -^^^^^
+   |     |
+   |     cannot use `+=` on type `&mut usize`
+   |
+help: `+=` can be used on `usize`, you can dereference `y`
+   |
+LL |     *y += 1;
+   |     +
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0070, E0308, E0368.
+For more information about an error, try `rustc --explain E0070`.
diff --git a/src/test/ui/typeck/issue-93486.stderr b/src/test/ui/typeck/issue-93486.stderr
index 70b5b63f1cb..167edc8942a 100644
--- a/src/test/ui/typeck/issue-93486.stderr
+++ b/src/test/ui/typeck/issue-93486.stderr
@@ -5,6 +5,11 @@ LL |         vec![].last_mut().unwrap() = 3_u8;
    |         -------------------------- ^
    |         |
    |         cannot assign to this expression
+   |
+help: consider dereferencing here to assign to the mutably borrowed value
+   |
+LL |         *vec![].last_mut().unwrap() = 3_u8;
+   |         +
 
 error: aborting due to previous error