about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-06-05 22:44:59 +0000
committerbors <bors@rust-lang.org>2023-06-05 22:44:59 +0000
commitadc719d7147d5e2578ce08e0b4504be44650256e (patch)
treee9c83e9ca6e6fdb862d664eddeb5cb3cfd87f42e
parente6d4725c76f3b526c74454bc51afdf6daf133506 (diff)
parentdcdd867a5298b5e5aedb77dc6b38862aa1867a44 (diff)
downloadrust-adc719d7147d5e2578ce08e0b4504be44650256e.tar.gz
rust-adc719d7147d5e2578ce08e0b4504be44650256e.zip
Auto merge of #112324 - matthiaskrgr:rollup-qscmi3c, r=matthiaskrgr
Rollup of 6 pull requests

Successful merges:

 - #112081 (Avoid ICE on `#![doc(test(...)]` with literal parameter)
 - #112196 (Resolve vars in result from `scrape_region_constraints`)
 - #112303 (Normalize in infcx instead of globally for `Option::as_deref` suggestion)
 - #112316 (Ensure space is inserted after keyword in `unused_delims`)
 - #112318 (Merge method, type and const object safety checks)
 - #112322 (Don't mention `IMPLIED_BOUNDS_ENTAILMENT` if signatures reference error)

Failed merges:

 - #112251 (rustdoc: convert `if let Some()` that always matches to variable)

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/mod.rs6
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_impl_item.rs6
-rw-r--r--compiler/rustc_hir_analysis/src/check/mod.rs2
-rw-r--r--compiler/rustc_lint/src/unused.rs59
-rw-r--r--compiler/rustc_passes/messages.ftl2
-rw-r--r--compiler/rustc_passes/src/check_attr.rs19
-rw-r--r--compiler/rustc_passes/src/errors.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs5
-rw-r--r--compiler/rustc_trait_selection/src/traits/object_safety.rs94
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs15
-rw-r--r--tests/ui/attributes/doc-test-literal.rs7
-rw-r--r--tests/ui/attributes/doc-test-literal.stderr17
-rw-r--r--tests/ui/implied-bounds/references-err.rs22
-rw-r--r--tests/ui/implied-bounds/references-err.stderr9
-rw-r--r--tests/ui/issues/issue-13167.rs2
-rw-r--r--tests/ui/issues/issue-15734.rs4
-rw-r--r--tests/ui/lint/lint-unnecessary-parens.fixed8
-rw-r--r--tests/ui/lint/lint-unnecessary-parens.rs8
-rw-r--r--tests/ui/lint/lint-unnecessary-parens.stderr86
-rw-r--r--tests/ui/mismatched_types/suggest-option-asderef-inference-var.rs9
-rw-r--r--tests/ui/mismatched_types/suggest-option-asderef-inference-var.stderr24
-rw-r--r--tests/ui/mismatched_types/suggest-option-asderef-unfixable.rs6
-rw-r--r--tests/ui/mismatched_types/suggest-option-asderef-unfixable.stderr33
-rw-r--r--tests/ui/mismatched_types/suggest-option-asderef.fixed9
-rw-r--r--tests/ui/mismatched_types/suggest-option-asderef.rs9
-rw-r--r--tests/ui/mismatched_types/suggest-option-asderef.stderr33
-rw-r--r--tests/ui/nll/issue-53119.rs2
27 files changed, 364 insertions, 136 deletions
diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs
index 3d78ea9aa9b..95517f01414 100644
--- a/compiler/rustc_hir_analysis/src/astconv/mod.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs
@@ -1601,7 +1601,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                             tcx.associated_items(pred.def_id())
                                 .in_definition_order()
                                 .filter(|item| item.kind == ty::AssocKind::Type)
-                                .filter(|item| tcx.opt_rpitit_info(item.def_id).is_none())
+                                .filter(|item| item.opt_rpitit_info.is_none())
                                 .map(|item| item.def_id),
                         );
                     }
@@ -1643,6 +1643,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             }
         }
 
+        // `dyn Trait<Assoc = Foo>` desugars to (not Rust syntax) `dyn Trait where <Self as Trait>::Assoc = Foo`.
+        // 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 (projection_bound, _) in &projection_bounds {
             for def_ids in associated_types.values_mut() {
                 def_ids.remove(&projection_bound.projection_def_id());
diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
index 31b89525f15..dce31975dbc 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
@@ -302,7 +302,7 @@ fn compare_method_predicate_entailment<'tcx>(
         return Err(emitted);
     }
 
-    if check_implied_wf == CheckImpliedWfMode::Check {
+    if check_implied_wf == CheckImpliedWfMode::Check && !(impl_sig, trait_sig).references_error() {
         // We need to check that the impl's args are well-formed given
         // the hybrid param-env (impl + trait method where-clauses).
         ocx.register_obligation(traits::Obligation::new(
@@ -1216,7 +1216,7 @@ fn compare_number_of_generics<'tcx>(
     // has mismatched type or const generic arguments, then the method that it's
     // inheriting the generics from will also have mismatched arguments, and
     // we'll report an error for that instead. Delay a bug for safety, though.
-    if tcx.opt_rpitit_info(trait_.def_id).is_some() {
+    if trait_.opt_rpitit_info.is_some() {
         return Err(tcx.sess.delay_span_bug(
             rustc_span::DUMMY_SP,
             "errors comparing numbers of generics of trait/impl functions were not emitted",
@@ -2006,7 +2006,7 @@ pub(super) fn check_type_bounds<'tcx>(
     // A synthetic impl Trait for RPITIT desugaring has no HIR, which we currently use to get the
     // span for an impl's associated type. Instead, for these, use the def_span for the synthesized
     // associated type.
-    let impl_ty_span = if tcx.opt_rpitit_info(impl_ty.def_id).is_some() {
+    let impl_ty_span = if impl_ty.opt_rpitit_info.is_some() {
         tcx.def_span(impl_ty_def_id)
     } else {
         match tcx.hir().get_by_def_id(impl_ty_def_id) {
diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs
index 3971a4c01d6..c9e74896ac0 100644
--- a/compiler/rustc_hir_analysis/src/check/mod.rs
+++ b/compiler/rustc_hir_analysis/src/check/mod.rs
@@ -188,7 +188,7 @@ fn missing_items_err(
     full_impl_span: Span,
 ) {
     let missing_items =
-        missing_items.iter().filter(|trait_item| tcx.opt_rpitit_info(trait_item.def_id).is_none());
+        missing_items.iter().filter(|trait_item| trait_item.opt_rpitit_info.is_none());
 
     let missing_items_msg = missing_items
         .clone()
diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs
index 8f75fa11dd9..04df23c736b 100644
--- a/compiler/rustc_lint/src/unused.rs
+++ b/compiler/rustc_lint/src/unused.rs
@@ -556,6 +556,7 @@ trait UnusedDelimLint {
         followed_by_block: bool,
         left_pos: Option<BytePos>,
         right_pos: Option<BytePos>,
+        is_kw: bool,
     );
 
     fn is_expr_delims_necessary(
@@ -624,6 +625,7 @@ trait UnusedDelimLint {
         ctx: UnusedDelimsCtx,
         left_pos: Option<BytePos>,
         right_pos: Option<BytePos>,
+        is_kw: bool,
     ) {
         // If `value` has `ExprKind::Err`, unused delim lint can be broken.
         // For example, the following code caused ICE.
@@ -667,7 +669,7 @@ trait UnusedDelimLint {
             left_pos.is_some_and(|s| s >= value.span.lo()),
             right_pos.is_some_and(|s| s <= value.span.hi()),
         );
-        self.emit_unused_delims(cx, value.span, spans, ctx.into(), keep_space);
+        self.emit_unused_delims(cx, value.span, spans, ctx.into(), keep_space, is_kw);
     }
 
     fn emit_unused_delims(
@@ -677,6 +679,7 @@ trait UnusedDelimLint {
         spans: Option<(Span, Span)>,
         msg: &str,
         keep_space: (bool, bool),
+        is_kw: bool,
     ) {
         let primary_span = if let Some((lo, hi)) = spans {
             if hi.is_empty() {
@@ -690,7 +693,7 @@ trait UnusedDelimLint {
         let suggestion = spans.map(|(lo, hi)| {
             let sm = cx.sess().source_map();
             let lo_replace =
-                    if keep_space.0 &&
+                    if (keep_space.0 || is_kw) &&
                         let Ok(snip) = sm.span_to_prev_source(lo) && !snip.ends_with(' ') {
                         " "
                         } else {
@@ -720,7 +723,7 @@ trait UnusedDelimLint {
 
     fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
         use rustc_ast::ExprKind::*;
-        let (value, ctx, followed_by_block, left_pos, right_pos) = match e.kind {
+        let (value, ctx, followed_by_block, left_pos, right_pos, is_kw) = match e.kind {
             // Do not lint `unused_braces` in `if let` expressions.
             If(ref cond, ref block, _)
                 if !matches!(cond.kind, Let(_, _, _))
@@ -728,7 +731,7 @@ trait UnusedDelimLint {
             {
                 let left = e.span.lo() + rustc_span::BytePos(2);
                 let right = block.span.lo();
-                (cond, UnusedDelimsCtx::IfCond, true, Some(left), Some(right))
+                (cond, UnusedDelimsCtx::IfCond, true, Some(left), Some(right), true)
             }
 
             // Do not lint `unused_braces` in `while let` expressions.
@@ -738,27 +741,27 @@ trait UnusedDelimLint {
             {
                 let left = e.span.lo() + rustc_span::BytePos(5);
                 let right = block.span.lo();
-                (cond, UnusedDelimsCtx::WhileCond, true, Some(left), Some(right))
+                (cond, UnusedDelimsCtx::WhileCond, true, Some(left), Some(right), true)
             }
 
             ForLoop(_, ref cond, ref block, ..) => {
-                (cond, UnusedDelimsCtx::ForIterExpr, true, None, Some(block.span.lo()))
+                (cond, UnusedDelimsCtx::ForIterExpr, true, None, Some(block.span.lo()), true)
             }
 
             Match(ref head, _) if Self::LINT_EXPR_IN_PATTERN_MATCHING_CTX => {
                 let left = e.span.lo() + rustc_span::BytePos(5);
-                (head, UnusedDelimsCtx::MatchScrutineeExpr, true, Some(left), None)
+                (head, UnusedDelimsCtx::MatchScrutineeExpr, true, Some(left), None, true)
             }
 
             Ret(Some(ref value)) => {
                 let left = e.span.lo() + rustc_span::BytePos(3);
-                (value, UnusedDelimsCtx::ReturnValue, false, Some(left), None)
+                (value, UnusedDelimsCtx::ReturnValue, false, Some(left), None, true)
             }
 
-            Index(_, ref value) => (value, UnusedDelimsCtx::IndexExpr, false, None, None),
+            Index(_, ref value) => (value, UnusedDelimsCtx::IndexExpr, false, None, None, false),
 
             Assign(_, ref value, _) | AssignOp(.., ref value) => {
-                (value, UnusedDelimsCtx::AssignedValue, false, None, None)
+                (value, UnusedDelimsCtx::AssignedValue, false, None, None, false)
             }
             // either function/method call, or something this lint doesn't care about
             ref call_or_other => {
@@ -778,12 +781,20 @@ trait UnusedDelimLint {
                     return;
                 }
                 for arg in args_to_check {
-                    self.check_unused_delims_expr(cx, arg, ctx, false, None, None);
+                    self.check_unused_delims_expr(cx, arg, ctx, false, None, None, false);
                 }
                 return;
             }
         };
-        self.check_unused_delims_expr(cx, &value, ctx, followed_by_block, left_pos, right_pos);
+        self.check_unused_delims_expr(
+            cx,
+            &value,
+            ctx,
+            followed_by_block,
+            left_pos,
+            right_pos,
+            is_kw,
+        );
     }
 
     fn check_stmt(&mut self, cx: &EarlyContext<'_>, s: &ast::Stmt) {
@@ -794,7 +805,7 @@ trait UnusedDelimLint {
                         None => UnusedDelimsCtx::AssignedValue,
                         Some(_) => UnusedDelimsCtx::AssignedValueLetElse,
                     };
-                    self.check_unused_delims_expr(cx, init, ctx, false, None, None);
+                    self.check_unused_delims_expr(cx, init, ctx, false, None, None, false);
                 }
             }
             StmtKind::Expr(ref expr) => {
@@ -805,6 +816,7 @@ trait UnusedDelimLint {
                     false,
                     None,
                     None,
+                    false,
                 );
             }
             _ => {}
@@ -824,6 +836,7 @@ trait UnusedDelimLint {
                 false,
                 None,
                 None,
+                false,
             );
         }
     }
@@ -879,6 +892,7 @@ impl UnusedDelimLint for UnusedParens {
         followed_by_block: bool,
         left_pos: Option<BytePos>,
         right_pos: Option<BytePos>,
+        is_kw: bool,
     ) {
         match value.kind {
             ast::ExprKind::Paren(ref inner) => {
@@ -893,7 +907,7 @@ impl UnusedDelimLint for UnusedParens {
                                 _,
                             ) if node.lazy()))
                 {
-                    self.emit_unused_delims_expr(cx, value, ctx, left_pos, right_pos)
+                    self.emit_unused_delims_expr(cx, value, ctx, left_pos, right_pos, is_kw)
                 }
             }
             ast::ExprKind::Let(_, ref expr, _) => {
@@ -904,6 +918,7 @@ impl UnusedDelimLint for UnusedParens {
                     followed_by_block,
                     None,
                     None,
+                    false,
                 );
             }
             _ => {}
@@ -942,7 +957,7 @@ impl UnusedParens {
                 .span
                 .find_ancestor_inside(value.span)
                 .map(|inner| (value.span.with_hi(inner.lo()), value.span.with_lo(inner.hi())));
-            self.emit_unused_delims(cx, value.span, spans, "pattern", keep_space);
+            self.emit_unused_delims(cx, value.span, spans, "pattern", keep_space, false);
         }
     }
 }
@@ -967,6 +982,7 @@ impl EarlyLintPass for UnusedParens {
                     true,
                     None,
                     None,
+                    true,
                 );
                 for stmt in &block.stmts {
                     <Self as UnusedDelimLint>::check_stmt(self, cx, stmt);
@@ -985,6 +1001,7 @@ impl EarlyLintPass for UnusedParens {
                         false,
                         None,
                         None,
+                        true,
                     );
                 }
             }
@@ -1043,6 +1060,7 @@ impl EarlyLintPass for UnusedParens {
                     false,
                     None,
                     None,
+                    false,
                 );
             }
             ast::TyKind::Paren(r) => {
@@ -1057,7 +1075,7 @@ impl EarlyLintPass for UnusedParens {
                             .find_ancestor_inside(ty.span)
                             .map(|r| (ty.span.with_hi(r.lo()), ty.span.with_lo(r.hi())));
 
-                        self.emit_unused_delims(cx, ty.span, spans, "type", (false, false));
+                        self.emit_unused_delims(cx, ty.span, spans, "type", (false, false), false);
                     }
                 }
                 self.with_self_ty_parens = false;
@@ -1130,6 +1148,7 @@ impl UnusedDelimLint for UnusedBraces {
         followed_by_block: bool,
         left_pos: Option<BytePos>,
         right_pos: Option<BytePos>,
+        is_kw: bool,
     ) {
         match value.kind {
             ast::ExprKind::Block(ref inner, None)
@@ -1170,7 +1189,7 @@ impl UnusedDelimLint for UnusedBraces {
                             && !value.span.from_expansion()
                             && !inner.span.from_expansion()
                         {
-                            self.emit_unused_delims_expr(cx, value, ctx, left_pos, right_pos)
+                            self.emit_unused_delims_expr(cx, value, ctx, left_pos, right_pos, is_kw)
                         }
                     }
                 }
@@ -1183,6 +1202,7 @@ impl UnusedDelimLint for UnusedBraces {
                     followed_by_block,
                     None,
                     None,
+                    false,
                 );
             }
             _ => {}
@@ -1207,6 +1227,7 @@ impl EarlyLintPass for UnusedBraces {
                 false,
                 None,
                 None,
+                false,
             );
         }
     }
@@ -1220,6 +1241,7 @@ impl EarlyLintPass for UnusedBraces {
                 false,
                 None,
                 None,
+                false,
             );
         }
     }
@@ -1233,6 +1255,7 @@ impl EarlyLintPass for UnusedBraces {
                 false,
                 None,
                 None,
+                false,
             );
         }
     }
@@ -1247,6 +1270,7 @@ impl EarlyLintPass for UnusedBraces {
                     false,
                     None,
                     None,
+                    false,
                 );
             }
 
@@ -1258,6 +1282,7 @@ impl EarlyLintPass for UnusedBraces {
                     false,
                     None,
                     None,
+                    false,
                 );
             }
 
diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl
index 7f9222dac6c..e76f1614b93 100644
--- a/compiler/rustc_passes/messages.ftl
+++ b/compiler/rustc_passes/messages.ftl
@@ -211,6 +211,8 @@ passes_doc_keyword_not_mod =
 passes_doc_keyword_only_impl =
     `#[doc(keyword = "...")]` should be used on impl blocks
 
+passes_doc_test_literal = `#![doc(test(...)]` does not take a literal
+
 passes_doc_test_takes_list =
     `#[doc(test(...)]` takes a list of attributes
 
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index c3189d1fefe..c35c7da2664 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -944,21 +944,28 @@ impl CheckAttrVisitor<'_> {
         let mut is_valid = true;
         if let Some(metas) = meta.meta_item_list() {
             for i_meta in metas {
-                match i_meta.name_or_empty() {
-                    sym::attr | sym::no_crate_inject => {}
-                    _ => {
+                match (i_meta.name_or_empty(), i_meta.meta_item()) {
+                    (sym::attr | sym::no_crate_inject, _) => {}
+                    (_, Some(m)) => {
                         self.tcx.emit_spanned_lint(
                             INVALID_DOC_ATTRIBUTES,
                             hir_id,
                             i_meta.span(),
                             errors::DocTestUnknown {
-                                path: rustc_ast_pretty::pprust::path_to_string(
-                                    &i_meta.meta_item().unwrap().path,
-                                ),
+                                path: rustc_ast_pretty::pprust::path_to_string(&m.path),
                             },
                         );
                         is_valid = false;
                     }
+                    (_, None) => {
+                        self.tcx.emit_spanned_lint(
+                            INVALID_DOC_ATTRIBUTES,
+                            hir_id,
+                            i_meta.span(),
+                            errors::DocTestLiteral,
+                        );
+                        is_valid = false;
+                    }
                 }
             }
         } else {
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index 99fc69d1bec..ae624dbc9c9 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -282,6 +282,10 @@ pub struct DocTestUnknown {
 }
 
 #[derive(LintDiagnostic)]
+#[diag(passes_doc_test_literal)]
+pub struct DocTestLiteral;
+
+#[derive(LintDiagnostic)]
 #[diag(passes_doc_test_takes_list)]
 pub struct DocTestTakesList;
 
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 42038dbc3d8..80d0faca670 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -3592,8 +3592,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
             // Extract `<U as Deref>::Target` assoc type and check that it is `T`
             && let Some(deref_target_did) = tcx.lang_items().deref_target()
             && let projection = tcx.mk_projection(deref_target_did, tcx.mk_substs(&[ty::GenericArg::from(found_ty)]))
-            && let Ok(deref_target) = tcx.try_normalize_erasing_regions(param_env, projection)
-            && deref_target == target_ty
+            && let InferOk { value: deref_target, obligations } = infcx.at(&ObligationCause::dummy(), param_env).normalize(projection)
+            && obligations.iter().all(|obligation| infcx.predicate_must_hold_modulo_regions(obligation))
+            && infcx.can_eq(param_env, deref_target, target_ty)
         {
             let help = if let hir::Mutability::Mut = needs_mut
                 && let Some(deref_mut_did) = tcx.lang_items().deref_mut_trait()
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index 048302187cf..b2771915eef 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -115,15 +115,11 @@ fn object_safety_violations_for_trait(
     tcx: TyCtxt<'_>,
     trait_def_id: DefId,
 ) -> Vec<ObjectSafetyViolation> {
-    // Check methods for violations.
+    // Check assoc items for violations.
     let mut violations: Vec<_> = tcx
         .associated_items(trait_def_id)
         .in_definition_order()
-        .filter(|item| item.kind == ty::AssocKind::Fn)
-        .filter_map(|&item| {
-            object_safety_violation_for_method(tcx, trait_def_id, item)
-                .map(|(code, span)| ObjectSafetyViolation::Method(item.name, code, span))
-        })
+        .filter_map(|&item| object_safety_violation_for_assoc_item(tcx, trait_def_id, item))
         .collect();
 
     // Check the trait itself.
@@ -145,30 +141,6 @@ fn object_safety_violations_for_trait(
         violations.push(ObjectSafetyViolation::SupertraitNonLifetimeBinder(spans));
     }
 
-    violations.extend(
-        tcx.associated_items(trait_def_id)
-            .in_definition_order()
-            .filter(|item| item.kind == ty::AssocKind::Const)
-            .map(|item| {
-                let ident = item.ident(tcx);
-                ObjectSafetyViolation::AssocConst(ident.name, ident.span)
-            }),
-    );
-
-    if !tcx.features().generic_associated_types_extended {
-        violations.extend(
-            tcx.associated_items(trait_def_id)
-                .in_definition_order()
-                .filter(|item| item.kind == ty::AssocKind::Type)
-                .filter(|item| !tcx.generics_of(item.def_id).params.is_empty())
-                .filter(|item| tcx.opt_rpitit_info(item.def_id).is_none())
-                .map(|item| {
-                    let ident = item.ident(tcx);
-                    ObjectSafetyViolation::GAT(ident.name, ident.span)
-                }),
-        );
-    }
-
     debug!(
         "object_safety_violations_for_trait(trait_def_id={:?}) = {:?}",
         trait_def_id, violations
@@ -401,34 +373,54 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
     })
 }
 
-/// Returns `Some(_)` if this method makes the containing trait not object safe.
-fn object_safety_violation_for_method(
+/// Returns `Some(_)` if this item makes the containing trait not object safe.
+#[instrument(level = "debug", skip(tcx), ret)]
+fn object_safety_violation_for_assoc_item(
     tcx: TyCtxt<'_>,
     trait_def_id: DefId,
-    method: ty::AssocItem,
-) -> Option<(MethodViolationCode, Span)> {
-    debug!("object_safety_violation_for_method({:?}, {:?})", trait_def_id, method);
-    // Any method that has a `Self : Sized` requisite is otherwise
+    item: ty::AssocItem,
+) -> Option<ObjectSafetyViolation> {
+    // Any item that has a `Self : Sized` requisite is otherwise
     // exempt from the regulations.
-    if generics_require_sized_self(tcx, method.def_id) {
+    if generics_require_sized_self(tcx, item.def_id) {
         return None;
     }
 
-    let violation = virtual_call_violation_for_method(tcx, trait_def_id, method);
-    // Get an accurate span depending on the violation.
-    violation.map(|v| {
-        let node = tcx.hir().get_if_local(method.def_id);
-        let span = match (&v, node) {
-            (MethodViolationCode::ReferencesSelfInput(Some(span)), _) => *span,
-            (MethodViolationCode::UndispatchableReceiver(Some(span)), _) => *span,
-            (MethodViolationCode::ReferencesImplTraitInTrait(span), _) => *span,
-            (MethodViolationCode::ReferencesSelfOutput, Some(node)) => {
-                node.fn_decl().map_or(method.ident(tcx).span, |decl| decl.output.span())
+    match item.kind {
+        // Associated consts are never object safe, as they can't have `where` bounds yet at all,
+        // and associated const bounds in trait objects aren't a thing yet either.
+        ty::AssocKind::Const => {
+            Some(ObjectSafetyViolation::AssocConst(item.name, item.ident(tcx).span))
+        }
+        ty::AssocKind::Fn => virtual_call_violation_for_method(tcx, trait_def_id, item).map(|v| {
+            let node = tcx.hir().get_if_local(item.def_id);
+            // Get an accurate span depending on the violation.
+            let span = match (&v, node) {
+                (MethodViolationCode::ReferencesSelfInput(Some(span)), _) => *span,
+                (MethodViolationCode::UndispatchableReceiver(Some(span)), _) => *span,
+                (MethodViolationCode::ReferencesImplTraitInTrait(span), _) => *span,
+                (MethodViolationCode::ReferencesSelfOutput, Some(node)) => {
+                    node.fn_decl().map_or(item.ident(tcx).span, |decl| decl.output.span())
+                }
+                _ => item.ident(tcx).span,
+            };
+
+            ObjectSafetyViolation::Method(item.name, v, span)
+        }),
+        // Associated types can only be object safe if they have `Self: Sized` bounds.
+        ty::AssocKind::Type => {
+            if !tcx.features().generic_associated_types_extended
+                && !tcx.generics_of(item.def_id).params.is_empty()
+                && item.opt_rpitit_info.is_none()
+            {
+                Some(ObjectSafetyViolation::GAT(item.name, item.ident(tcx).span))
+            } else {
+                // We will permit associated types if they are explicitly mentioned in the trait object.
+                // We can't check this here, as here we only check if it is guaranteed to not be possible.
+                None
             }
-            _ => method.ident(tcx).span,
-        };
-        (v, span)
-    })
+        }
+    }
 }
 
 /// Returns `Some(_)` if this method cannot be called on a trait
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs
index 6d8d2103f39..8b0973021bc 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs
@@ -5,6 +5,7 @@ use crate::traits::ObligationCtxt;
 use rustc_errors::ErrorGuaranteed;
 use rustc_infer::infer::region_constraints::RegionConstraintData;
 use rustc_middle::traits::query::NoSolution;
+use rustc_middle::ty::{TyCtxt, TypeFoldable};
 use rustc_span::source_map::DUMMY_SP;
 use rustc_span::Span;
 
@@ -24,9 +25,10 @@ impl<F> CustomTypeOp<F> {
     }
 }
 
-impl<'tcx, F, R: fmt::Debug> super::TypeOp<'tcx> for CustomTypeOp<F>
+impl<'tcx, F, R> super::TypeOp<'tcx> for CustomTypeOp<F>
 where
     F: FnOnce(&ObligationCtxt<'_, 'tcx>) -> Result<R, NoSolution>,
+    R: fmt::Debug + TypeFoldable<TyCtxt<'tcx>>,
 {
     type Output = R;
     /// We can't do any custom error reporting for `CustomTypeOp`, so
@@ -57,12 +59,16 @@ impl<F> fmt::Debug for CustomTypeOp<F> {
 
 /// Executes `op` and then scrapes out all the "old style" region
 /// constraints that result, creating query-region-constraints.
-pub fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>(
+pub fn scrape_region_constraints<'tcx, Op, R>(
     infcx: &InferCtxt<'tcx>,
     op: impl FnOnce(&ObligationCtxt<'_, 'tcx>) -> Result<R, NoSolution>,
     name: &'static str,
     span: Span,
-) -> Result<(TypeOpOutput<'tcx, Op>, RegionConstraintData<'tcx>), ErrorGuaranteed> {
+) -> Result<(TypeOpOutput<'tcx, Op>, RegionConstraintData<'tcx>), ErrorGuaranteed>
+where
+    R: TypeFoldable<TyCtxt<'tcx>>,
+    Op: super::TypeOp<'tcx, Output = R>,
+{
     // During NLL, we expect that nobody will register region
     // obligations **except** as part of a custom type op (and, at the
     // end of each custom type op, we scrape out the region
@@ -91,6 +97,9 @@ pub fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>(
         }
     })?;
 
+    // Next trait solver performs operations locally, and normalize goals should resolve vars.
+    let value = infcx.resolve_vars_if_possible(value);
+
     let region_obligations = infcx.take_registered_region_obligations();
     let region_constraint_data = infcx.take_and_reset_region_constraints();
     let region_constraints = query_response::make_query_region_constraints(
diff --git a/tests/ui/attributes/doc-test-literal.rs b/tests/ui/attributes/doc-test-literal.rs
new file mode 100644
index 00000000000..a06a1afcb3f
--- /dev/null
+++ b/tests/ui/attributes/doc-test-literal.rs
@@ -0,0 +1,7 @@
+#![deny(warnings)]
+
+#![doc(test(""))]
+//~^ ERROR `#![doc(test(...)]` does not take a literal
+//~^^ WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+
+fn main() {}
diff --git a/tests/ui/attributes/doc-test-literal.stderr b/tests/ui/attributes/doc-test-literal.stderr
new file mode 100644
index 00000000000..ebee09994ba
--- /dev/null
+++ b/tests/ui/attributes/doc-test-literal.stderr
@@ -0,0 +1,17 @@
+error: `#![doc(test(...)]` does not take a literal
+  --> $DIR/doc-test-literal.rs:3:13
+   |
+LL | #![doc(test(""))]
+   |             ^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
+note: the lint level is defined here
+  --> $DIR/doc-test-literal.rs:1:9
+   |
+LL | #![deny(warnings)]
+   |         ^^^^^^^^
+   = note: `#[deny(invalid_doc_attributes)]` implied by `#[deny(warnings)]`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/implied-bounds/references-err.rs b/tests/ui/implied-bounds/references-err.rs
new file mode 100644
index 00000000000..203d512e398
--- /dev/null
+++ b/tests/ui/implied-bounds/references-err.rs
@@ -0,0 +1,22 @@
+trait Identity {
+    type Identity;
+}
+impl<T> Identity for T {
+    type Identity = T;
+}
+
+trait Trait {
+    type Assoc: Identity;
+    fn tokenize(&self) -> <Self::Assoc as Identity>::Identity;
+}
+
+impl Trait for () {
+    type Assoc = DoesNotExist;
+    //~^ ERROR cannot find type `DoesNotExist` in this scope
+
+    fn tokenize(&self) -> <Self::Assoc as Identity>::Identity {
+        unimplemented!()
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/implied-bounds/references-err.stderr b/tests/ui/implied-bounds/references-err.stderr
new file mode 100644
index 00000000000..6076eea3c75
--- /dev/null
+++ b/tests/ui/implied-bounds/references-err.stderr
@@ -0,0 +1,9 @@
+error[E0412]: cannot find type `DoesNotExist` in this scope
+  --> $DIR/references-err.rs:14:18
+   |
+LL |     type Assoc = DoesNotExist;
+   |                  ^^^^^^^^^^^^ not found in this scope
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0412`.
diff --git a/tests/ui/issues/issue-13167.rs b/tests/ui/issues/issue-13167.rs
index 8584c98decf..9a9f129ec3a 100644
--- a/tests/ui/issues/issue-13167.rs
+++ b/tests/ui/issues/issue-13167.rs
@@ -1,5 +1,7 @@
 // check-pass
 // pretty-expanded FIXME #23616
+// revisions: current next
+//[next] compile-flags: -Ztrait-solver=next
 
 use std::slice;
 
diff --git a/tests/ui/issues/issue-15734.rs b/tests/ui/issues/issue-15734.rs
index be582060601..27410d4c3b0 100644
--- a/tests/ui/issues/issue-15734.rs
+++ b/tests/ui/issues/issue-15734.rs
@@ -1,6 +1,6 @@
 // run-pass
-// If `Index` used an associated type for its output, this test would
-// work more smoothly.
+// revisions: current next
+//[next] compile-flags: -Ztrait-solver=next
 
 use std::ops::Index;
 
diff --git a/tests/ui/lint/lint-unnecessary-parens.fixed b/tests/ui/lint/lint-unnecessary-parens.fixed
index 9c144324f2f..bafac05d8da 100644
--- a/tests/ui/lint/lint-unnecessary-parens.fixed
+++ b/tests/ui/lint/lint-unnecessary-parens.fixed
@@ -35,6 +35,14 @@ pub fn passes_unused_parens_lint() -> &'static (dyn Trait) {
     panic!()
 }
 
+pub fn parens_with_keyword(e: &[()]) -> i32 {
+    if true {} //~ ERROR unnecessary parentheses around `if`
+    while true {} //~ ERROR unnecessary parentheses around `while`
+    for _ in e {} //~ ERROR unnecessary parentheses around `for`
+    match 1 { _ => ()} //~ ERROR unnecessary parentheses around `match`
+    return 1; //~ ERROR unnecessary parentheses around `return` value
+}
+
 macro_rules! baz {
     ($($foo:expr),+) => {
         ($($foo),*)
diff --git a/tests/ui/lint/lint-unnecessary-parens.rs b/tests/ui/lint/lint-unnecessary-parens.rs
index 4fd9cabb3b0..ce537a4dc1d 100644
--- a/tests/ui/lint/lint-unnecessary-parens.rs
+++ b/tests/ui/lint/lint-unnecessary-parens.rs
@@ -35,6 +35,14 @@ pub fn passes_unused_parens_lint() -> &'static (dyn Trait) {
     panic!()
 }
 
+pub fn parens_with_keyword(e: &[()]) -> i32 {
+    if(true) {} //~ ERROR unnecessary parentheses around `if`
+    while(true) {} //~ ERROR unnecessary parentheses around `while`
+    for _ in(e) {} //~ ERROR unnecessary parentheses around `for`
+    match(1) { _ => ()} //~ ERROR unnecessary parentheses around `match`
+    return(1); //~ ERROR unnecessary parentheses around `return` value
+}
+
 macro_rules! baz {
     ($($foo:expr),+) => {
         ($($foo),*)
diff --git a/tests/ui/lint/lint-unnecessary-parens.stderr b/tests/ui/lint/lint-unnecessary-parens.stderr
index e13620f06ce..2ad07530f8c 100644
--- a/tests/ui/lint/lint-unnecessary-parens.stderr
+++ b/tests/ui/lint/lint-unnecessary-parens.stderr
@@ -63,8 +63,68 @@ LL -     (5)
 LL +     5
    |
 
+error: unnecessary parentheses around `if` condition
+  --> $DIR/lint-unnecessary-parens.rs:39:7
+   |
+LL |     if(true) {}
+   |       ^    ^
+   |
+help: remove these parentheses
+   |
+LL -     if(true) {}
+LL +     if true {}
+   |
+
+error: unnecessary parentheses around `while` condition
+  --> $DIR/lint-unnecessary-parens.rs:40:10
+   |
+LL |     while(true) {}
+   |          ^    ^
+   |
+help: remove these parentheses
+   |
+LL -     while(true) {}
+LL +     while true {}
+   |
+
+error: unnecessary parentheses around `for` iterator expression
+  --> $DIR/lint-unnecessary-parens.rs:41:13
+   |
+LL |     for _ in(e) {}
+   |             ^ ^
+   |
+help: remove these parentheses
+   |
+LL -     for _ in(e) {}
+LL +     for _ in e {}
+   |
+
+error: unnecessary parentheses around `match` scrutinee expression
+  --> $DIR/lint-unnecessary-parens.rs:42:10
+   |
+LL |     match(1) { _ => ()}
+   |          ^ ^
+   |
+help: remove these parentheses
+   |
+LL -     match(1) { _ => ()}
+LL +     match 1 { _ => ()}
+   |
+
+error: unnecessary parentheses around `return` value
+  --> $DIR/lint-unnecessary-parens.rs:43:11
+   |
+LL |     return(1);
+   |           ^ ^
+   |
+help: remove these parentheses
+   |
+LL -     return(1);
+LL +     return 1;
+   |
+
 error: unnecessary parentheses around assigned value
-  --> $DIR/lint-unnecessary-parens.rs:44:31
+  --> $DIR/lint-unnecessary-parens.rs:52:31
    |
 LL | pub const CONST_ITEM: usize = (10);
    |                               ^  ^
@@ -76,7 +136,7 @@ LL + pub const CONST_ITEM: usize = 10;
    |
 
 error: unnecessary parentheses around assigned value
-  --> $DIR/lint-unnecessary-parens.rs:45:33
+  --> $DIR/lint-unnecessary-parens.rs:53:33
    |
 LL | pub static STATIC_ITEM: usize = (10);
    |                                 ^  ^
@@ -88,7 +148,7 @@ LL + pub static STATIC_ITEM: usize = 10;
    |
 
 error: unnecessary parentheses around function argument
-  --> $DIR/lint-unnecessary-parens.rs:49:9
+  --> $DIR/lint-unnecessary-parens.rs:57:9
    |
 LL |     bar((true));
    |         ^    ^
@@ -100,7 +160,7 @@ LL +     bar(true);
    |
 
 error: unnecessary parentheses around `if` condition
-  --> $DIR/lint-unnecessary-parens.rs:51:8
+  --> $DIR/lint-unnecessary-parens.rs:59:8
    |
 LL |     if (true) {}
    |        ^    ^
@@ -112,7 +172,7 @@ LL +     if true {}
    |
 
 error: unnecessary parentheses around `while` condition
-  --> $DIR/lint-unnecessary-parens.rs:52:11
+  --> $DIR/lint-unnecessary-parens.rs:60:11
    |
 LL |     while (true) {}
    |           ^    ^
@@ -124,7 +184,7 @@ LL +     while true {}
    |
 
 error: unnecessary parentheses around `match` scrutinee expression
-  --> $DIR/lint-unnecessary-parens.rs:53:11
+  --> $DIR/lint-unnecessary-parens.rs:61:11
    |
 LL |     match (true) {
    |           ^    ^
@@ -136,7 +196,7 @@ LL +     match true {
    |
 
 error: unnecessary parentheses around `let` scrutinee expression
-  --> $DIR/lint-unnecessary-parens.rs:56:16
+  --> $DIR/lint-unnecessary-parens.rs:64:16
    |
 LL |     if let 1 = (1) {}
    |                ^ ^
@@ -148,7 +208,7 @@ LL +     if let 1 = 1 {}
    |
 
 error: unnecessary parentheses around `let` scrutinee expression
-  --> $DIR/lint-unnecessary-parens.rs:57:19
+  --> $DIR/lint-unnecessary-parens.rs:65:19
    |
 LL |     while let 1 = (2) {}
    |                   ^ ^
@@ -160,7 +220,7 @@ LL +     while let 1 = 2 {}
    |
 
 error: unnecessary parentheses around method argument
-  --> $DIR/lint-unnecessary-parens.rs:73:24
+  --> $DIR/lint-unnecessary-parens.rs:81:24
    |
 LL |     X { y: false }.foo((true));
    |                        ^    ^
@@ -172,7 +232,7 @@ LL +     X { y: false }.foo(true);
    |
 
 error: unnecessary parentheses around assigned value
-  --> $DIR/lint-unnecessary-parens.rs:75:18
+  --> $DIR/lint-unnecessary-parens.rs:83:18
    |
 LL |     let mut _a = (0);
    |                  ^ ^
@@ -184,7 +244,7 @@ LL +     let mut _a = 0;
    |
 
 error: unnecessary parentheses around assigned value
-  --> $DIR/lint-unnecessary-parens.rs:76:10
+  --> $DIR/lint-unnecessary-parens.rs:84:10
    |
 LL |     _a = (0);
    |          ^ ^
@@ -196,7 +256,7 @@ LL +     _a = 0;
    |
 
 error: unnecessary parentheses around assigned value
-  --> $DIR/lint-unnecessary-parens.rs:77:11
+  --> $DIR/lint-unnecessary-parens.rs:85:11
    |
 LL |     _a += (1);
    |           ^ ^
@@ -207,5 +267,5 @@ LL -     _a += (1);
 LL +     _a += 1;
    |
 
-error: aborting due to 17 previous errors
+error: aborting due to 22 previous errors
 
diff --git a/tests/ui/mismatched_types/suggest-option-asderef-inference-var.rs b/tests/ui/mismatched_types/suggest-option-asderef-inference-var.rs
new file mode 100644
index 00000000000..5febbbe392b
--- /dev/null
+++ b/tests/ui/mismatched_types/suggest-option-asderef-inference-var.rs
@@ -0,0 +1,9 @@
+fn deref_int(a: &i32) -> i32 {
+    *a
+}
+
+fn main() {
+    // https://github.com/rust-lang/rust/issues/112293
+    let _has_inference_vars: Option<i32> = Some(0).map(deref_int);
+    //~^ ERROR type mismatch in function arguments
+}
diff --git a/tests/ui/mismatched_types/suggest-option-asderef-inference-var.stderr b/tests/ui/mismatched_types/suggest-option-asderef-inference-var.stderr
new file mode 100644
index 00000000000..71c4729e310
--- /dev/null
+++ b/tests/ui/mismatched_types/suggest-option-asderef-inference-var.stderr
@@ -0,0 +1,24 @@
+error[E0631]: type mismatch in function arguments
+  --> $DIR/suggest-option-asderef-inference-var.rs:7:56
+   |
+LL | fn deref_int(a: &i32) -> i32 {
+   | ---------------------------- found signature defined here
+...
+LL |     let _has_inference_vars: Option<i32> = Some(0).map(deref_int);
+   |                                                    --- ^^^^^^^^^ expected due to this
+   |                                                    |
+   |                                                    required by a bound introduced by this call
+   |
+   = note: expected function signature `fn({integer}) -> _`
+              found function signature `for<'a> fn(&'a i32) -> _`
+note: required by a bound in `Option::<T>::map`
+  --> $SRC_DIR/core/src/option.rs:LL:COL
+help: do not borrow the argument
+   |
+LL - fn deref_int(a: &i32) -> i32 {
+LL + fn deref_int(a: i32) -> i32 {
+   |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0631`.
diff --git a/tests/ui/mismatched_types/suggest-option-asderef-unfixable.rs b/tests/ui/mismatched_types/suggest-option-asderef-unfixable.rs
index cc9ba5514fe..ac0831ce655 100644
--- a/tests/ui/mismatched_types/suggest-option-asderef-unfixable.rs
+++ b/tests/ui/mismatched_types/suggest-option-asderef-unfixable.rs
@@ -10,10 +10,6 @@ fn no_args() -> Option<()> {
     Some(())
 }
 
-fn generic_ref<T>(_: &T) -> Option<()> {
-    Some(())
-}
-
 extern "C" fn takes_str_but_wrong_abi(_: &str) -> Option<()> {
     Some(())
 }
@@ -33,8 +29,6 @@ fn main() {
     //~^ ERROR expected a `FnOnce<(String,)>` closure, found `for<'a> unsafe fn(&'a str) -> Option<()> {takes_str_but_unsafe}`
     let _ = produces_string().and_then(no_args);
     //~^ ERROR function is expected to take 1 argument, but it takes 0 arguments
-    let _ = produces_string().and_then(generic_ref);
-    //~^ ERROR type mismatch in function arguments
     let _ = Some(TypeWithoutDeref).and_then(takes_str_but_too_many_refs);
     //~^ ERROR type mismatch in function arguments
 }
diff --git a/tests/ui/mismatched_types/suggest-option-asderef-unfixable.stderr b/tests/ui/mismatched_types/suggest-option-asderef-unfixable.stderr
index 079909eb48d..ecfbd27b180 100644
--- a/tests/ui/mismatched_types/suggest-option-asderef-unfixable.stderr
+++ b/tests/ui/mismatched_types/suggest-option-asderef-unfixable.stderr
@@ -1,5 +1,5 @@
 error[E0631]: type mismatch in function arguments
-  --> $DIR/suggest-option-asderef-unfixable.rs:28:40
+  --> $DIR/suggest-option-asderef-unfixable.rs:24:40
    |
 LL | fn takes_str_but_too_many_refs(_: &&str) -> Option<()> {
    | ------------------------------------------------------ found signature defined here
@@ -15,7 +15,7 @@ note: required by a bound in `Option::<T>::and_then`
   --> $SRC_DIR/core/src/option.rs:LL:COL
 
 error[E0277]: expected a `FnOnce<(String,)>` closure, found `for<'a> extern "C" fn(&'a str) -> Option<()> {takes_str_but_wrong_abi}`
-  --> $DIR/suggest-option-asderef-unfixable.rs:30:40
+  --> $DIR/suggest-option-asderef-unfixable.rs:26:40
    |
 LL |     let _ = produces_string().and_then(takes_str_but_wrong_abi);
    |                               -------- ^^^^^^^^^^^^^^^^^^^^^^^ expected an `FnOnce<(String,)>` closure, found `for<'a> extern "C" fn(&'a str) -> Option<()> {takes_str_but_wrong_abi}`
@@ -27,7 +27,7 @@ note: required by a bound in `Option::<T>::and_then`
   --> $SRC_DIR/core/src/option.rs:LL:COL
 
 error[E0277]: expected a `FnOnce<(String,)>` closure, found `for<'a> unsafe fn(&'a str) -> Option<()> {takes_str_but_unsafe}`
-  --> $DIR/suggest-option-asderef-unfixable.rs:32:40
+  --> $DIR/suggest-option-asderef-unfixable.rs:28:40
    |
 LL |     let _ = produces_string().and_then(takes_str_but_unsafe);
    |                               -------- ^^^^^^^^^^^^^^^^^^^^ call the function in a closure: `|| unsafe { /* code */ }`
@@ -40,7 +40,7 @@ note: required by a bound in `Option::<T>::and_then`
   --> $SRC_DIR/core/src/option.rs:LL:COL
 
 error[E0593]: function is expected to take 1 argument, but it takes 0 arguments
-  --> $DIR/suggest-option-asderef-unfixable.rs:34:40
+  --> $DIR/suggest-option-asderef-unfixable.rs:30:40
    |
 LL | fn no_args() -> Option<()> {
    | -------------------------- takes 0 arguments
@@ -54,28 +54,7 @@ note: required by a bound in `Option::<T>::and_then`
   --> $SRC_DIR/core/src/option.rs:LL:COL
 
 error[E0631]: type mismatch in function arguments
-  --> $DIR/suggest-option-asderef-unfixable.rs:36:40
-   |
-LL | fn generic_ref<T>(_: &T) -> Option<()> {
-   | -------------------------------------- found signature defined here
-...
-LL |     let _ = produces_string().and_then(generic_ref);
-   |                               -------- ^^^^^^^^^^^ expected due to this
-   |                               |
-   |                               required by a bound introduced by this call
-   |
-   = note: expected function signature `fn(String) -> _`
-              found function signature `for<'a> fn(&'a _) -> _`
-note: required by a bound in `Option::<T>::and_then`
-  --> $SRC_DIR/core/src/option.rs:LL:COL
-help: do not borrow the argument
-   |
-LL - fn generic_ref<T>(_: &T) -> Option<()> {
-LL + fn generic_ref<T>(_: T) -> Option<()> {
-   |
-
-error[E0631]: type mismatch in function arguments
-  --> $DIR/suggest-option-asderef-unfixable.rs:38:45
+  --> $DIR/suggest-option-asderef-unfixable.rs:32:45
    |
 LL | fn takes_str_but_too_many_refs(_: &&str) -> Option<()> {
    | ------------------------------------------------------ found signature defined here
@@ -90,7 +69,7 @@ LL |     let _ = Some(TypeWithoutDeref).and_then(takes_str_but_too_many_refs);
 note: required by a bound in `Option::<T>::and_then`
   --> $SRC_DIR/core/src/option.rs:LL:COL
 
-error: aborting due to 6 previous errors
+error: aborting due to 5 previous errors
 
 Some errors have detailed explanations: E0277, E0593, E0631.
 For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/mismatched_types/suggest-option-asderef.fixed b/tests/ui/mismatched_types/suggest-option-asderef.fixed
index 08805999341..5c42ece3c5d 100644
--- a/tests/ui/mismatched_types/suggest-option-asderef.fixed
+++ b/tests/ui/mismatched_types/suggest-option-asderef.fixed
@@ -16,6 +16,11 @@ fn generic<T>(_: T) -> Option<()> {
     Some(())
 }
 
+fn generic_ref<T>(_: T) -> Option<()> {
+    //~^ HELP do not borrow the argument
+    Some(())
+}
+
 fn main() {
     let _: Option<()> = produces_string().as_deref().and_then(takes_str);
     //~^ ERROR type mismatch in function arguments
@@ -27,4 +32,8 @@ fn main() {
     //~^ ERROR type mismatch in function arguments
     //~| HELP call `Option::as_deref_mut()` first
     let _ = produces_string().and_then(generic);
+
+    let _ = produces_string().as_deref().and_then(generic_ref);
+    //~^ ERROR type mismatch in function arguments
+    //~| HELP call `Option::as_deref()` first
 }
diff --git a/tests/ui/mismatched_types/suggest-option-asderef.rs b/tests/ui/mismatched_types/suggest-option-asderef.rs
index 3cfb2ffa828..a5278b8fb16 100644
--- a/tests/ui/mismatched_types/suggest-option-asderef.rs
+++ b/tests/ui/mismatched_types/suggest-option-asderef.rs
@@ -16,6 +16,11 @@ fn generic<T>(_: T) -> Option<()> {
     Some(())
 }
 
+fn generic_ref<T>(_: &T) -> Option<()> {
+    //~^ HELP do not borrow the argument
+    Some(())
+}
+
 fn main() {
     let _: Option<()> = produces_string().and_then(takes_str);
     //~^ ERROR type mismatch in function arguments
@@ -27,4 +32,8 @@ fn main() {
     //~^ ERROR type mismatch in function arguments
     //~| HELP call `Option::as_deref_mut()` first
     let _ = produces_string().and_then(generic);
+
+    let _ = produces_string().and_then(generic_ref);
+    //~^ ERROR type mismatch in function arguments
+    //~| HELP call `Option::as_deref()` first
 }
diff --git a/tests/ui/mismatched_types/suggest-option-asderef.stderr b/tests/ui/mismatched_types/suggest-option-asderef.stderr
index 46da19d2bf4..01341603dde 100644
--- a/tests/ui/mismatched_types/suggest-option-asderef.stderr
+++ b/tests/ui/mismatched_types/suggest-option-asderef.stderr
@@ -1,5 +1,5 @@
 error[E0631]: type mismatch in function arguments
-  --> $DIR/suggest-option-asderef.rs:20:52
+  --> $DIR/suggest-option-asderef.rs:25:52
    |
 LL | fn takes_str(_: &str) -> Option<()> {
    | ----------------------------------- found signature defined here
@@ -19,7 +19,7 @@ LL |     let _: Option<()> = produces_string().as_deref().and_then(takes_str);
    |                                          +++++++++++
 
 error[E0631]: type mismatch in function arguments
-  --> $DIR/suggest-option-asderef.rs:23:55
+  --> $DIR/suggest-option-asderef.rs:28:55
    |
 LL | fn takes_str(_: &str) -> Option<()> {
    | ----------------------------------- found signature defined here
@@ -39,7 +39,7 @@ LL |     let _: Option<Option<()>> = produces_string().as_deref().map(takes_str)
    |                                                  +++++++++++
 
 error[E0631]: type mismatch in function arguments
-  --> $DIR/suggest-option-asderef.rs:26:55
+  --> $DIR/suggest-option-asderef.rs:31:55
    |
 LL | fn takes_str_mut(_: &mut str) -> Option<()> {
    | ------------------------------------------- found signature defined here
@@ -58,6 +58,31 @@ help: call `Option::as_deref_mut()` first
 LL |     let _: Option<Option<()>> = produces_string().as_deref_mut().map(takes_str_mut);
    |                                                  +++++++++++++++
 
-error: aborting due to 3 previous errors
+error[E0631]: type mismatch in function arguments
+  --> $DIR/suggest-option-asderef.rs:36:40
+   |
+LL | fn generic_ref<T>(_: &T) -> Option<()> {
+   | -------------------------------------- found signature defined here
+...
+LL |     let _ = produces_string().and_then(generic_ref);
+   |                               -------- ^^^^^^^^^^^ expected due to this
+   |                               |
+   |                               required by a bound introduced by this call
+   |
+   = note: expected function signature `fn(String) -> _`
+              found function signature `for<'a> fn(&'a _) -> _`
+note: required by a bound in `Option::<T>::and_then`
+  --> $SRC_DIR/core/src/option.rs:LL:COL
+help: do not borrow the argument
+   |
+LL - fn generic_ref<T>(_: &T) -> Option<()> {
+LL + fn generic_ref<T>(_: T) -> Option<()> {
+   |
+help: call `Option::as_deref()` first
+   |
+LL |     let _ = produces_string().as_deref().and_then(generic_ref);
+   |                              +++++++++++
+
+error: aborting due to 4 previous errors
 
 For more information about this error, try `rustc --explain E0631`.
diff --git a/tests/ui/nll/issue-53119.rs b/tests/ui/nll/issue-53119.rs
index 03c9c071c9b..015b72367f1 100644
--- a/tests/ui/nll/issue-53119.rs
+++ b/tests/ui/nll/issue-53119.rs
@@ -1,4 +1,6 @@
 // check-pass
+// revisions: current next
+//[next] compile-flags: -Ztrait-solver=next
 
 use std::ops::Deref;