From 8cfd249198dd0e04558d725452b91f4db3984633 Mon Sep 17 00:00:00 2001
From: Michael Goulet <michael@errs.io>
Date: Fri, 22 Sep 2023 19:47:34 +0000
Subject: [PATCH 1/8] Allow higher-ranked fn sigs in ValuePairs

---
 .../src/check/compare_impl_item.rs            |  5 +++-
 compiler/rustc_hir_analysis/src/check/mod.rs  | 11 ++++-----
 compiler/rustc_infer/src/infer/at.rs          | 23 ++++++++++++++++++-
 .../src/infer/error_reporting/mod.rs          |  9 +++-----
 .../trait_impl_difference.rs                  |  6 ++---
 compiler/rustc_infer/src/infer/mod.rs         |  2 +-
 compiler/rustc_passes/src/check_attr.rs       |  5 +++-
 .../panic-handler-bad-signature-1.stderr      |  4 ++--
 .../panic-handler-bad-signature-2.stderr      |  4 ++--
 .../panic-handler-bad-signature-3.stderr      |  2 +-
 .../panic-handler-bad-signature-5.stderr      |  4 ++--
 11 files changed, 48 insertions(+), 27 deletions(-)

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 7be18a36d63..ba58f0d57ad 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
@@ -1134,7 +1134,10 @@ fn report_trait_method_mismatch<'tcx>(
         &mut diag,
         &cause,
         trait_err_span.map(|sp| (sp, Cow::from("type in trait"))),
-        Some(infer::ValuePairs::Sigs(ExpectedFound { expected: trait_sig, found: impl_sig })),
+        Some(infer::ValuePairs::PolySigs(ExpectedFound {
+            expected: ty::Binder::dummy(trait_sig),
+            found: ty::Binder::dummy(impl_sig),
+        })),
         terr,
         false,
         false,
diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs
index 0cf3cee66b5..88c98fa979e 100644
--- a/compiler/rustc_hir_analysis/src/check/mod.rs
+++ b/compiler/rustc_hir_analysis/src/check/mod.rs
@@ -573,10 +573,7 @@ pub fn check_function_signature<'tcx>(
     let norm_cause = ObligationCause::misc(cause.span, local_id);
     let actual_sig = ocx.normalize(&norm_cause, param_env, actual_sig);
 
-    let expected_ty = Ty::new_fn_ptr(tcx, expected_sig);
-    let actual_ty = Ty::new_fn_ptr(tcx, actual_sig);
-
-    match ocx.eq(&cause, param_env, expected_ty, actual_ty) {
+    match ocx.eq(&cause, param_env, expected_sig, actual_sig) {
         Ok(()) => {
             let errors = ocx.select_all_or_error();
             if !errors.is_empty() {
@@ -595,9 +592,9 @@ pub fn check_function_signature<'tcx>(
                 &mut diag,
                 &cause,
                 None,
-                Some(infer::ValuePairs::Sigs(ExpectedFound {
-                    expected: tcx.liberate_late_bound_regions(fn_id, expected_sig),
-                    found: tcx.liberate_late_bound_regions(fn_id, actual_sig),
+                Some(infer::ValuePairs::PolySigs(ExpectedFound {
+                    expected: expected_sig,
+                    found: actual_sig,
                 })),
                 err,
                 false,
diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs
index 6d5db3336cf..2797d079761 100644
--- a/compiler/rustc_infer/src/infer/at.rs
+++ b/compiler/rustc_infer/src/infer/at.rs
@@ -478,7 +478,28 @@ impl<'tcx> ToTrace<'tcx> for ty::FnSig<'tcx> {
         a: Self,
         b: Self,
     ) -> TypeTrace<'tcx> {
-        TypeTrace { cause: cause.clone(), values: Sigs(ExpectedFound::new(a_is_expected, a, b)) }
+        TypeTrace {
+            cause: cause.clone(),
+            values: PolySigs(ExpectedFound::new(
+                a_is_expected,
+                ty::Binder::dummy(a),
+                ty::Binder::dummy(b),
+            )),
+        }
+    }
+}
+
+impl<'tcx> ToTrace<'tcx> for ty::PolyFnSig<'tcx> {
+    fn to_trace(
+        cause: &ObligationCause<'tcx>,
+        a_is_expected: bool,
+        a: Self,
+        b: Self,
+    ) -> TypeTrace<'tcx> {
+        TypeTrace {
+            cause: cause.clone(),
+            values: PolySigs(ExpectedFound::new(a_is_expected, a, b)),
+        }
     }
 }
 
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index 1beb13cb94c..e418864026f 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -1660,7 +1660,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                             _ => (false, Mismatch::Fixed("type")),
                         }
                     }
-                    ValuePairs::Sigs(infer::ExpectedFound { expected, found }) => {
+                    ValuePairs::PolySigs(infer::ExpectedFound { expected, found }) => {
                         OpaqueTypesVisitor::visit_expected_found(self.tcx, expected, found, span)
                             .report(diag);
                         (false, Mismatch::Fixed("signature"))
@@ -2232,15 +2232,12 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     ret => ret,
                 }
             }
-            infer::Sigs(exp_found) => {
+            infer::PolySigs(exp_found) => {
                 let exp_found = self.resolve_vars_if_possible(exp_found);
                 if exp_found.references_error() {
                     return None;
                 }
-                let (exp, fnd) = self.cmp_fn_sig(
-                    &ty::Binder::dummy(exp_found.expected),
-                    &ty::Binder::dummy(exp_found.found),
-                );
+                let (exp, fnd) = self.cmp_fn_sig(&exp_found.expected, &exp_found.found);
                 Some((exp, fnd, None, None))
             }
         }
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
index d2ba9966f03..cb51254a14b 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
@@ -35,14 +35,14 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
             && let (Subtype(sup_trace), Subtype(sub_trace)) = (&sup_origin, &sub_origin)
             && let CompareImplItemObligation { trait_item_def_id, .. } = sub_trace.cause.code()
             && sub_trace.values == sup_trace.values
-            && let ValuePairs::Sigs(ExpectedFound { expected, found }) = sub_trace.values
+            && let ValuePairs::PolySigs(ExpectedFound { expected, found }) = sub_trace.values
         {
             // FIXME(compiler-errors): Don't like that this needs `Ty`s, but
             // all of the region highlighting machinery only deals with those.
             let guar = self.emit_err(
                 var_origin.span(),
-                Ty::new_fn_ptr(self.cx.tcx,ty::Binder::dummy(expected)),
-                Ty::new_fn_ptr(self.cx.tcx,ty::Binder::dummy(found)),
+                Ty::new_fn_ptr(self.cx.tcx, expected),
+                Ty::new_fn_ptr(self.cx.tcx, found),
                 *trait_item_def_id,
             );
             return Some(guar);
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index 4cf9d44ed65..aeb3177af02 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -383,7 +383,7 @@ pub enum ValuePairs<'tcx> {
     Aliases(ExpectedFound<ty::AliasTy<'tcx>>),
     TraitRefs(ExpectedFound<ty::TraitRef<'tcx>>),
     PolyTraitRefs(ExpectedFound<ty::PolyTraitRef<'tcx>>),
-    Sigs(ExpectedFound<ty::FnSig<'tcx>>),
+    PolySigs(ExpectedFound<ty::PolyFnSig<'tcx>>),
     ExistentialTraitRef(ExpectedFound<ty::PolyExistentialTraitRef<'tcx>>),
     ExistentialProjection(ExpectedFound<ty::PolyExistentialProjection<'tcx>>),
 }
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 12118a0268b..afba366a365 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -2333,7 +2333,10 @@ impl CheckAttrVisitor<'_> {
                 &mut diag,
                 &cause,
                 None,
-                Some(ValuePairs::Sigs(ExpectedFound { expected: expected_sig, found: sig })),
+                Some(ValuePairs::PolySigs(ExpectedFound {
+                    expected: ty::Binder::dummy(expected_sig),
+                    found: ty::Binder::dummy(sig),
+                })),
                 terr,
                 false,
                 false,
diff --git a/tests/ui/panic-handler/panic-handler-bad-signature-1.stderr b/tests/ui/panic-handler/panic-handler-bad-signature-1.stderr
index d12bfbf269e..85555c43906 100644
--- a/tests/ui/panic-handler/panic-handler-bad-signature-1.stderr
+++ b/tests/ui/panic-handler/panic-handler-bad-signature-1.stderr
@@ -4,8 +4,8 @@ error[E0308]: `#[panic_handler]` function has wrong type
 LL | fn panic(info: PanicInfo) -> () {}
    |                ^^^^^^^^^ expected `&PanicInfo<'_>`, found `PanicInfo<'_>`
    |
-   = note: expected signature `fn(&PanicInfo<'_>) -> !`
-              found signature `fn(PanicInfo<'_>)`
+   = note: expected signature `for<'a, 'b> fn(&'a PanicInfo<'b>) -> !`
+              found signature `for<'a> fn(PanicInfo<'a>)`
 
 error: aborting due to previous error
 
diff --git a/tests/ui/panic-handler/panic-handler-bad-signature-2.stderr b/tests/ui/panic-handler/panic-handler-bad-signature-2.stderr
index 06e32d5fb84..84eba2a5a63 100644
--- a/tests/ui/panic-handler/panic-handler-bad-signature-2.stderr
+++ b/tests/ui/panic-handler/panic-handler-bad-signature-2.stderr
@@ -4,8 +4,8 @@ error[E0308]: `#[panic_handler]` function has wrong type
 LL | fn panic(info: &'static PanicInfo) -> !
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
    |
-   = note: expected fn pointer `for<'a, 'b> fn(&'a PanicInfo<'b>) -> _`
-              found fn pointer `for<'a> fn(&'static PanicInfo<'a>) -> _`
+   = note: expected signature `for<'a, 'b> fn(&'a PanicInfo<'b>) -> _`
+              found signature `for<'a> fn(&'static PanicInfo<'a>) -> _`
 
 error: aborting due to previous error
 
diff --git a/tests/ui/panic-handler/panic-handler-bad-signature-3.stderr b/tests/ui/panic-handler/panic-handler-bad-signature-3.stderr
index 8365f5769eb..cdf55ab6534 100644
--- a/tests/ui/panic-handler/panic-handler-bad-signature-3.stderr
+++ b/tests/ui/panic-handler/panic-handler-bad-signature-3.stderr
@@ -4,7 +4,7 @@ error[E0308]: `#[panic_handler]` function has wrong type
 LL | fn panic() -> ! {
    | ^^^^^^^^^^^^^^^ incorrect number of function parameters
    |
-   = note: expected signature `fn(&PanicInfo<'_>) -> _`
+   = note: expected signature `for<'a, 'b> fn(&'a PanicInfo<'b>) -> _`
               found signature `fn() -> _`
 
 error: aborting due to previous error
diff --git a/tests/ui/panic-handler/panic-handler-bad-signature-5.stderr b/tests/ui/panic-handler/panic-handler-bad-signature-5.stderr
index 22b8d5ca811..20c17587590 100644
--- a/tests/ui/panic-handler/panic-handler-bad-signature-5.stderr
+++ b/tests/ui/panic-handler/panic-handler-bad-signature-5.stderr
@@ -4,8 +4,8 @@ error[E0308]: `#[panic_handler]` function has wrong type
 LL | fn panic(info: &PanicInfo<'static>) -> !
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
    |
-   = note: expected fn pointer `for<'a, 'b> fn(&'a PanicInfo<'b>) -> _`
-              found fn pointer `for<'a> fn(&'a PanicInfo<'static>) -> _`
+   = note: expected signature `for<'a, 'b> fn(&'a PanicInfo<'b>) -> _`
+              found signature `for<'a> fn(&'a PanicInfo<'static>) -> _`
 
 error: aborting due to previous error
 

From 82e7cec16d7143907f145c895f7208c0a3906e03 Mon Sep 17 00:00:00 2001
From: Michael Goulet <michael@errs.io>
Date: Sat, 23 Sep 2023 00:56:43 +0000
Subject: [PATCH 2/8] Tweak expected message to explain what it's actually
 signifying

---
 .../src/infer/error_reporting/note_and_explain.rs      | 10 +++++++---
 .../ui/associated-types/defaults-specialization.stderr |  4 ++--
 .../specialization/specialization-default-types.stderr |  2 +-
 3 files changed, 10 insertions(+), 6 deletions(-)

diff --git a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs
index 445f68160d2..b34900da83b 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs
@@ -616,9 +616,13 @@ fn foo(&self) -> Self::T { String::new() }
                 for item in &items[..] {
                     if let hir::AssocItemKind::Type = item.kind {
                         let assoc_ty = tcx.type_of(item.id.owner_id).instantiate_identity();
-
-                        if self.infcx.can_eq(param_env, assoc_ty, found) {
-                            diag.span_label(item.span, "expected this associated type");
+                        if let hir::Defaultness::Default { has_value: true } = tcx.defaultness(item.id.owner_id)
+                            && self.infcx.can_eq(param_env, assoc_ty, found)
+                        {
+                            diag.span_label(
+                                item.span,
+                                format!("associated type is `default` and may be overridden"),
+                            );
                             return true;
                         }
                     }
diff --git a/tests/ui/associated-types/defaults-specialization.stderr b/tests/ui/associated-types/defaults-specialization.stderr
index 7e21f7fc306..7ef433d859f 100644
--- a/tests/ui/associated-types/defaults-specialization.stderr
+++ b/tests/ui/associated-types/defaults-specialization.stderr
@@ -29,7 +29,7 @@ error[E0053]: method `make` has an incompatible type for trait
   --> $DIR/defaults-specialization.rs:35:18
    |
 LL |     default type Ty = bool;
-   |     ----------------------- expected this associated type
+   |     ----------------------- associated type is `default` and may be overridden
 LL |
 LL |     fn make() -> bool { true }
    |                  ^^^^
@@ -76,7 +76,7 @@ error[E0308]: mismatched types
   --> $DIR/defaults-specialization.rs:44:29
    |
 LL |     default type Ty = bool;
-   |     ----------------------- expected this associated type
+   |     ----------------------- associated type is `default` and may be overridden
 LL |
 LL |     fn make() -> Self::Ty { true }
    |                  --------   ^^^^ expected associated type, found `bool`
diff --git a/tests/ui/specialization/specialization-default-types.stderr b/tests/ui/specialization/specialization-default-types.stderr
index ecccf29a107..774ac953617 100644
--- a/tests/ui/specialization/specialization-default-types.stderr
+++ b/tests/ui/specialization/specialization-default-types.stderr
@@ -12,7 +12,7 @@ error[E0308]: mismatched types
   --> $DIR/specialization-default-types.rs:15:9
    |
 LL |     default type Output = Box<T>;
-   |     ----------------------------- expected this associated type
+   |     ----------------------------- associated type is `default` and may be overridden
 LL |     default fn generate(self) -> Self::Output {
    |                                  ------------ expected `<T as Example>::Output` because of return type
 LL |         Box::new(self)

From c4a4926083e9f0b9aeef549f93cb66cd9d4076d7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Sat, 23 Sep 2023 01:34:50 +0000
Subject: [PATCH 3/8] More accurate suggestion for `self.` and `Self::`

Fix #115992.
---
 .../rustc_resolve/src/late/diagnostics.rs     | 17 +++++--
 tests/ui/suggestions/assoc_fn_without_self.rs |  8 ++++
 .../suggestions/assoc_fn_without_self.stderr  | 46 ++++++++++++++++---
 3 files changed, 60 insertions(+), 11 deletions(-)

diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index c34b7df9b46..44dba9b7be7 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -224,14 +224,21 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                     && let FnKind::Fn(_, _, sig, ..) = fn_kind
                     && let Some(items) = self.diagnostic_metadata.current_impl_items
                     && let Some(item) = items.iter().find(|i| {
-                        if let AssocItemKind::Fn(..) | AssocItemKind::Const(..) = &i.kind
-                            && i.ident.name == item_str.name
-                            // don't suggest if the item is in Fn signature arguments
-                            // issue #112590
+                        if i.ident.name == item_str.name
+                            // Don't suggest if the item is in Fn signature arguments (#112590).
                             && !sig.span.contains(item_span)
                         {
                             debug!(?item_str.name);
-                            return true
+                            return match &i.kind {
+                                AssocItemKind::Fn(fn_)
+                                if !sig.decl.has_self() && fn_.sig.decl.has_self() => {
+                                    // Ensure that we only suggest `self.` if `self` is available,
+                                    // you can't call `fn foo(&self)` from `fn bar()` (#115992).
+                                    false
+                                }
+                                AssocItemKind::Fn(_) | AssocItemKind::Const(..) => true,
+                                _ => false
+                            }
                         }
                         false
                     })
diff --git a/tests/ui/suggestions/assoc_fn_without_self.rs b/tests/ui/suggestions/assoc_fn_without_self.rs
index 778d9847773..35c16ef3e9f 100644
--- a/tests/ui/suggestions/assoc_fn_without_self.rs
+++ b/tests/ui/suggestions/assoc_fn_without_self.rs
@@ -17,4 +17,12 @@ impl S {
         bar(); //~ ERROR cannot find function `bar` in this scope
         baz(2, 3); //~ ERROR cannot find function `baz` in this scope
     }
+    fn d(&self) {
+        fn c() {
+            foo(); //~ ERROR cannot find function `foo` in this scope
+        }
+        foo(); //~ ERROR cannot find function `foo` in this scope
+        bar(); //~ ERROR cannot find function `bar` in this scope
+        baz(2, 3); //~ ERROR cannot find function `baz` in this scope
+    }
 }
diff --git a/tests/ui/suggestions/assoc_fn_without_self.stderr b/tests/ui/suggestions/assoc_fn_without_self.stderr
index febdd67338c..a7fab36bf8d 100644
--- a/tests/ui/suggestions/assoc_fn_without_self.stderr
+++ b/tests/ui/suggestions/assoc_fn_without_self.stderr
@@ -14,11 +14,6 @@ error[E0425]: cannot find function `bar` in this scope
    |
 LL |         bar();
    |         ^^^ not found in this scope
-   |
-help: consider using the associated function
-   |
-LL |         self.bar();
-   |         +++++
 
 error[E0425]: cannot find function `baz` in this scope
   --> $DIR/assoc_fn_without_self.rs:18:9
@@ -37,6 +32,45 @@ error[E0425]: cannot find function `foo` in this scope
 LL |             foo();
    |             ^^^ not found in this scope
 
-error: aborting due to 4 previous errors
+error[E0425]: cannot find function `foo` in this scope
+  --> $DIR/assoc_fn_without_self.rs:24:9
+   |
+LL |         foo();
+   |         ^^^ not found in this scope
+   |
+help: consider using the associated function
+   |
+LL |         Self::foo();
+   |         ++++++
+
+error[E0425]: cannot find function `bar` in this scope
+  --> $DIR/assoc_fn_without_self.rs:25:9
+   |
+LL |         bar();
+   |         ^^^ not found in this scope
+   |
+help: consider using the associated function
+   |
+LL |         self.bar();
+   |         +++++
+
+error[E0425]: cannot find function `baz` in this scope
+  --> $DIR/assoc_fn_without_self.rs:26:9
+   |
+LL |         baz(2, 3);
+   |         ^^^ not found in this scope
+   |
+help: consider using the associated function
+   |
+LL |         Self::baz(2, 3);
+   |         ++++++
+
+error[E0425]: cannot find function `foo` in this scope
+  --> $DIR/assoc_fn_without_self.rs:22:13
+   |
+LL |             foo();
+   |             ^^^ not found in this scope
+
+error: aborting due to 8 previous errors
 
 For more information about this error, try `rustc --explain E0425`.

From 0e986825762edd031bc6bf4a78d9162ac2ed6268 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Sat, 23 Sep 2023 01:47:06 +0000
Subject: [PATCH 4/8] When encountering method on `Self` that we can't suggest,
 mention it

---
 .../rustc_resolve/src/late/diagnostics.rs     | 58 +++++++++----------
 .../suggestions/assoc_fn_without_self.stderr  |  3 +
 2 files changed, 31 insertions(+), 30 deletions(-)

diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 44dba9b7be7..c690ac6c043 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -214,6 +214,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                 module: None,
             }
         } else {
+            let mut span_label = None;
             let item_span = path.last().unwrap().ident.span;
             let (mod_prefix, mod_str, module, suggestion) = if path.len() == 1 {
                 debug!(?self.diagnostic_metadata.current_impl_items);
@@ -224,39 +225,36 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                     && let FnKind::Fn(_, _, sig, ..) = fn_kind
                     && let Some(items) = self.diagnostic_metadata.current_impl_items
                     && let Some(item) = items.iter().find(|i| {
-                        if i.ident.name == item_str.name
+                        i.ident.name == item_str.name
                             // Don't suggest if the item is in Fn signature arguments (#112590).
                             && !sig.span.contains(item_span)
-                        {
-                            debug!(?item_str.name);
-                            return match &i.kind {
-                                AssocItemKind::Fn(fn_)
-                                if !sig.decl.has_self() && fn_.sig.decl.has_self() => {
-                                    // Ensure that we only suggest `self.` if `self` is available,
-                                    // you can't call `fn foo(&self)` from `fn bar()` (#115992).
-                                    false
-                                }
-                                AssocItemKind::Fn(_) | AssocItemKind::Const(..) => true,
-                                _ => false
-                            }
-                        }
-                        false
                     })
                 {
-                    let self_sugg = match &item.kind {
-                        AssocItemKind::Fn(fn_) if fn_.sig.decl.has_self() => "self.",
-                        _ => "Self::",
-                    };
-
-                    Some((
-                        item_span.shrink_to_lo(),
-                        match &item.kind {
-                            AssocItemKind::Fn(..) => "consider using the associated function",
-                            AssocItemKind::Const(..) => "consider using the associated constant",
-                            _ => unreachable!("item kind was filtered above"),
-                        },
-                        self_sugg.to_string()
-                    ))
+                    let sp = item_span.shrink_to_lo();
+                    match &item.kind {
+                        AssocItemKind::Fn(fn_)
+                        if !sig.decl.has_self() && fn_.sig.decl.has_self() => {
+                            // Ensure that we only suggest `self.` if `self` is available,
+                            // you can't call `fn foo(&self)` from `fn bar()` (#115992).
+                            // We also want to mention that the method exists.
+                            span_label = Some((
+                                item.ident.span,
+                                "a method by that name is available on `Self` here",
+                            ));
+                            None
+                        }
+                        AssocItemKind::Fn(fn_) => Some((
+                            sp,
+                            "consider using the associated function",
+                            if fn_.sig.decl.has_self() { "self." } else { "Self::" },
+                        )),
+                        AssocItemKind::Const(..) => Some((
+                            sp,
+                            "consider using the associated constant",
+                            "Self::",
+                        )),
+                        _ => None
+                    }
                 } else {
                     None
                 };
@@ -321,7 +319,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                 msg: format!("cannot find {expected} `{item_str}` in {mod_prefix}{mod_str}"),
                 fallback_label,
                 span: item_span,
-                span_label: None,
+                span_label,
                 could_be_expr: false,
                 suggestion,
                 module,
diff --git a/tests/ui/suggestions/assoc_fn_without_self.stderr b/tests/ui/suggestions/assoc_fn_without_self.stderr
index a7fab36bf8d..26fcc2a0181 100644
--- a/tests/ui/suggestions/assoc_fn_without_self.stderr
+++ b/tests/ui/suggestions/assoc_fn_without_self.stderr
@@ -12,6 +12,9 @@ LL |         Self::foo();
 error[E0425]: cannot find function `bar` in this scope
   --> $DIR/assoc_fn_without_self.rs:17:9
    |
+LL |     fn bar(&self) {}
+   |        --- a method by that name is available on `Self` here
+...
 LL |         bar();
    |         ^^^ not found in this scope
 

From ac5e18756a4f0987c5861e45b82ac6f410fd4734 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Sat, 23 Sep 2023 01:54:05 +0000
Subject: [PATCH 5/8] Tweak wording and logic

---
 compiler/rustc_resolve/src/late/diagnostics.rs    | 15 ++++++++++-----
 tests/ui/resolve/issue-103474.stderr              |  2 +-
 tests/ui/resolve/issue-2356.stderr                |  4 ++--
 tests/ui/self/class-missing-self.stderr           |  2 +-
 .../suggestions/assoc-const-without-self.stderr   |  2 +-
 tests/ui/suggestions/assoc_fn_without_self.stderr | 10 +++++-----
 6 files changed, 20 insertions(+), 15 deletions(-)

diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index c690ac6c043..06a08f29a1e 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -243,15 +243,20 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                             ));
                             None
                         }
-                        AssocItemKind::Fn(fn_) => Some((
+                        AssocItemKind::Fn(fn_) if fn_.sig.decl.has_self() => Some((
                             sp,
-                            "consider using the associated function",
-                            if fn_.sig.decl.has_self() { "self." } else { "Self::" },
+                            "consider using the method on `Self`",
+                            "self.".to_string(),
+                        )),
+                        AssocItemKind::Fn(_) => Some((
+                            sp,
+                            "consider using the associated function on `Self`",
+                            "Self::".to_string(),
                         )),
                         AssocItemKind::Const(..) => Some((
                             sp,
-                            "consider using the associated constant",
-                            "Self::",
+                            "consider using the associated constant on `Self`",
+                            "Self::".to_string(),
                         )),
                         _ => None
                     }
diff --git a/tests/ui/resolve/issue-103474.stderr b/tests/ui/resolve/issue-103474.stderr
index 415d231552a..e48fb31eccc 100644
--- a/tests/ui/resolve/issue-103474.stderr
+++ b/tests/ui/resolve/issue-103474.stderr
@@ -19,7 +19,7 @@ error[E0425]: cannot find function `first` in this scope
 LL |         first()
    |         ^^^^^ not found in this scope
    |
-help: consider using the associated function
+help: consider using the method on `Self`
    |
 LL |         self.first()
    |         +++++
diff --git a/tests/ui/resolve/issue-2356.stderr b/tests/ui/resolve/issue-2356.stderr
index 30f5f059526..273e8b2a661 100644
--- a/tests/ui/resolve/issue-2356.stderr
+++ b/tests/ui/resolve/issue-2356.stderr
@@ -73,7 +73,7 @@ error[E0425]: cannot find function `static_method` in this scope
 LL |         static_method();
    |         ^^^^^^^^^^^^^ not found in this scope
    |
-help: consider using the associated function
+help: consider using the associated function on `Self`
    |
 LL |         Self::static_method();
    |         ++++++
@@ -102,7 +102,7 @@ error[E0425]: cannot find function `grow_older` in this scope
 LL |     grow_older();
    |     ^^^^^^^^^^ not found in this scope
    |
-help: consider using the associated function
+help: consider using the associated function on `Self`
    |
 LL |     Self::grow_older();
    |     ++++++
diff --git a/tests/ui/self/class-missing-self.stderr b/tests/ui/self/class-missing-self.stderr
index 3c37d819743..08493b4f9a2 100644
--- a/tests/ui/self/class-missing-self.stderr
+++ b/tests/ui/self/class-missing-self.stderr
@@ -10,7 +10,7 @@ error[E0425]: cannot find function `sleep` in this scope
 LL |       sleep();
    |       ^^^^^ not found in this scope
    |
-help: consider using the associated function
+help: consider using the method on `Self`
    |
 LL |       self.sleep();
    |       +++++
diff --git a/tests/ui/suggestions/assoc-const-without-self.stderr b/tests/ui/suggestions/assoc-const-without-self.stderr
index 88d72da70cb..05528d277be 100644
--- a/tests/ui/suggestions/assoc-const-without-self.stderr
+++ b/tests/ui/suggestions/assoc-const-without-self.stderr
@@ -4,7 +4,7 @@ error[E0425]: cannot find value `A_CONST` in this scope
 LL |         A_CONST
    |         ^^^^^^^ not found in this scope
    |
-help: consider using the associated constant
+help: consider using the associated constant on `Self`
    |
 LL |         Self::A_CONST
    |         ++++++
diff --git a/tests/ui/suggestions/assoc_fn_without_self.stderr b/tests/ui/suggestions/assoc_fn_without_self.stderr
index 26fcc2a0181..9cee7c7ee5e 100644
--- a/tests/ui/suggestions/assoc_fn_without_self.stderr
+++ b/tests/ui/suggestions/assoc_fn_without_self.stderr
@@ -4,7 +4,7 @@ error[E0425]: cannot find function `foo` in this scope
 LL |         foo();
    |         ^^^ not found in this scope
    |
-help: consider using the associated function
+help: consider using the associated function on `Self`
    |
 LL |         Self::foo();
    |         ++++++
@@ -24,7 +24,7 @@ error[E0425]: cannot find function `baz` in this scope
 LL |         baz(2, 3);
    |         ^^^ not found in this scope
    |
-help: consider using the associated function
+help: consider using the associated function on `Self`
    |
 LL |         Self::baz(2, 3);
    |         ++++++
@@ -41,7 +41,7 @@ error[E0425]: cannot find function `foo` in this scope
 LL |         foo();
    |         ^^^ not found in this scope
    |
-help: consider using the associated function
+help: consider using the associated function on `Self`
    |
 LL |         Self::foo();
    |         ++++++
@@ -52,7 +52,7 @@ error[E0425]: cannot find function `bar` in this scope
 LL |         bar();
    |         ^^^ not found in this scope
    |
-help: consider using the associated function
+help: consider using the method on `Self`
    |
 LL |         self.bar();
    |         +++++
@@ -63,7 +63,7 @@ error[E0425]: cannot find function `baz` in this scope
 LL |         baz(2, 3);
    |         ^^^ not found in this scope
    |
-help: consider using the associated function
+help: consider using the associated function on `Self`
    |
 LL |         Self::baz(2, 3);
    |         ++++++

From 7d8559ac9077e35a687d5b16f17f2f493421f3ab Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Sat, 23 Sep 2023 01:59:22 +0000
Subject: [PATCH 6/8] Add test

---
 ...ethod-in-self-not-available-in-assoc-fn.rs | 15 +++++++++++++
 ...d-in-self-not-available-in-assoc-fn.stderr | 21 +++++++++++++++++++
 2 files changed, 36 insertions(+)
 create mode 100644 tests/ui/resolve/field-and-method-in-self-not-available-in-assoc-fn.rs
 create mode 100644 tests/ui/resolve/field-and-method-in-self-not-available-in-assoc-fn.stderr

diff --git a/tests/ui/resolve/field-and-method-in-self-not-available-in-assoc-fn.rs b/tests/ui/resolve/field-and-method-in-self-not-available-in-assoc-fn.rs
new file mode 100644
index 00000000000..9e72c36151e
--- /dev/null
+++ b/tests/ui/resolve/field-and-method-in-self-not-available-in-assoc-fn.rs
@@ -0,0 +1,15 @@
+struct Foo {
+    field: u32,
+}
+
+impl Foo {
+    fn field(&self) -> u32 {
+        self.field
+    }
+
+    fn new() -> Foo {
+        field; //~ ERROR cannot find value `field` in this scope
+        Foo { field } //~ ERROR cannot find value `field` in this scope
+    }
+}
+fn main() {}
diff --git a/tests/ui/resolve/field-and-method-in-self-not-available-in-assoc-fn.stderr b/tests/ui/resolve/field-and-method-in-self-not-available-in-assoc-fn.stderr
new file mode 100644
index 00000000000..2eb3861e5f1
--- /dev/null
+++ b/tests/ui/resolve/field-and-method-in-self-not-available-in-assoc-fn.stderr
@@ -0,0 +1,21 @@
+error[E0425]: cannot find value `field` in this scope
+  --> $DIR/field-and-method-in-self-not-available-in-assoc-fn.rs:11:9
+   |
+LL |     fn field(&self) -> u32 {
+   |        ----- a method by that name is available on `Self` here
+...
+LL |         field;
+   |         ^^^^^ a field by this name exists in `Self`
+
+error[E0425]: cannot find value `field` in this scope
+  --> $DIR/field-and-method-in-self-not-available-in-assoc-fn.rs:12:15
+   |
+LL |     fn field(&self) -> u32 {
+   |        ----- a method by that name is available on `Self` here
+...
+LL |         Foo { field }
+   |               ^^^^^ a field by this name exists in `Self`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0425`.

From 8ec5639bc204217cf0a37ba92d35358f787b6d69 Mon Sep 17 00:00:00 2001
From: Camille GILLOT <gillot.camille@gmail.com>
Date: Tue, 5 Sep 2023 17:14:37 +0000
Subject: [PATCH 7/8] Reuse calculate_debuginfo_offset for fragments.

---
 .../rustc_codegen_ssa/src/mir/debuginfo.rs    | 43 +++++--------------
 1 file changed, 10 insertions(+), 33 deletions(-)

diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
index d1560114763..0dc30d21c5b 100644
--- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
@@ -158,8 +158,7 @@ fn calculate_debuginfo_offset<
     L: DebugInfoOffsetLocation<'tcx, Bx>,
 >(
     bx: &mut Bx,
-    local: mir::Local,
-    var: &PerLocalVarDebugInfo<'tcx, Bx::DIVariable>,
+    projection: &[mir::PlaceElem<'tcx>],
     base: L,
 ) -> DebugInfoOffset<L> {
     let mut direct_offset = Size::ZERO;
@@ -167,7 +166,7 @@ fn calculate_debuginfo_offset<
     let mut indirect_offsets = vec![];
     let mut place = base;
 
-    for elem in &var.projection[..] {
+    for elem in projection {
         match *elem {
             mir::ProjectionElem::Deref => {
                 indirect_offsets.push(Size::ZERO);
@@ -188,11 +187,7 @@ fn calculate_debuginfo_offset<
             } => {
                 let offset = indirect_offsets.last_mut().unwrap_or(&mut direct_offset);
                 let FieldsShape::Array { stride, count: _ } = place.layout().fields else {
-                    span_bug!(
-                        var.source_info.span,
-                        "ConstantIndex on non-array type {:?}",
-                        place.layout()
-                    )
+                    bug!("ConstantIndex on non-array type {:?}", place.layout())
                 };
                 *offset += stride * index;
                 place = place.project_constant_index(bx, index);
@@ -200,11 +195,7 @@ fn calculate_debuginfo_offset<
             _ => {
                 // Sanity check for `can_use_in_debuginfo`.
                 debug_assert!(!elem.can_use_in_debuginfo());
-                span_bug!(
-                    var.source_info.span,
-                    "unsupported var debuginfo place `{:?}`",
-                    mir::Place { local, projection: var.projection },
-                )
+                bug!("unsupported var debuginfo projection `{:?}`", projection)
             }
         }
     }
@@ -407,7 +398,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         let Some(dbg_loc) = self.dbg_loc(var.source_info) else { return };
 
         let DebugInfoOffset { direct_offset, indirect_offsets, result: _ } =
-            calculate_debuginfo_offset(bx, local, &var, base.layout);
+            calculate_debuginfo_offset(bx, &var.projection, base.layout);
 
         // When targeting MSVC, create extra allocas for arguments instead of pointing multiple
         // dbg_var_addr() calls into the same alloca with offsets. MSVC uses CodeView records
@@ -425,7 +416,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
 
         if should_create_individual_allocas {
             let DebugInfoOffset { direct_offset: _, indirect_offsets: _, result: place } =
-                calculate_debuginfo_offset(bx, local, &var, base);
+                calculate_debuginfo_offset(bx, &var.projection, base);
 
             // Create a variable which will be a pointer to the actual value
             let ptr_ty = Ty::new_ptr(
@@ -532,23 +523,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             let fragment = if let Some(ref fragment) = var.composite {
                 let var_layout = self.cx.layout_of(var_ty);
 
-                let mut fragment_start = Size::ZERO;
-                let mut fragment_layout = var_layout;
-
-                for elem in &fragment.projection {
-                    match *elem {
-                        mir::ProjectionElem::Field(field, _) => {
-                            let i = field.index();
-                            fragment_start += fragment_layout.fields.offset(i);
-                            fragment_layout = fragment_layout.field(self.cx, i);
-                        }
-                        _ => span_bug!(
-                            var.source_info.span,
-                            "unsupported fragment projection `{:?}`",
-                            elem,
-                        ),
-                    }
-                }
+                let DebugInfoOffset { direct_offset, indirect_offsets, result: fragment_layout } =
+                    calculate_debuginfo_offset(bx, &fragment.projection, var_layout);
+                debug_assert!(indirect_offsets.is_empty());
 
                 if fragment_layout.size == Size::ZERO {
                     // Fragment is a ZST, so does not represent anything. Avoid generating anything
@@ -559,7 +536,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     // DWARF is concerned, it's not really a fragment.
                     None
                 } else {
-                    Some(fragment_start..fragment_start + fragment_layout.size)
+                    Some(direct_offset..direct_offset + fragment_layout.size)
                 }
             } else {
                 None

From 2d25a25e5dc5636778d1e4e86bf6fa2d9a1be0af Mon Sep 17 00:00:00 2001
From: Guillaume Gomez <guillaume.gomez@huawei.com>
Date: Sat, 23 Sep 2023 20:03:03 +0200
Subject: [PATCH 8/8] Migrate GUI colors test to original CSS color format

---
 tests/rustdoc-gui/default-settings.goml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tests/rustdoc-gui/default-settings.goml b/tests/rustdoc-gui/default-settings.goml
index 3466f3693f9..ff4abb65c02 100644
--- a/tests/rustdoc-gui/default-settings.goml
+++ b/tests/rustdoc-gui/default-settings.goml
@@ -5,4 +5,4 @@
 go-to: "file://" + |DOC_PATH| + "/settings/index.html"
 // Wait a bit to be sure the default theme is applied.
 // If the theme isn't applied, the command will time out.
-wait-for-css: ("body", {"background-color": "rgb(15, 20, 25)"})
+wait-for-css: ("body", {"background-color": "#0f1419"})