From fa0428c9d0f336cf51748621543679736f04cce6 Mon Sep 17 00:00:00 2001
From: Michael Goulet <michael@errs.io>
Date: Fri, 19 Apr 2024 15:18:00 -0400
Subject: [PATCH 1/2] Flip spans for precise capturing syntax not capturing a
 ty/ct param

---
 .../rustc_hir_analysis/src/check/check.rs     | 29 ++++++++++++-------
 .../src/errors/precise_captures.rs            |  6 ++--
 .../precise-capturing/capture-parent-arg.rs   |  2 +-
 .../capture-parent-arg.stderr                 |  7 ++---
 .../forgot-to-capture-const.stderr            |  6 ++--
 .../forgot-to-capture-type.rs                 |  2 +-
 .../forgot-to-capture-type.stderr             | 13 +++++----
 7 files changed, 37 insertions(+), 28 deletions(-)

diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index 36553591de8..8dfbcbfd76f 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -580,10 +580,11 @@ fn check_opaque_precise_captures<'tcx>(tcx: TyCtxt<'tcx>, opaque_def_id: LocalDe
 
             match param.kind {
                 ty::GenericParamDefKind::Lifetime => {
+                    let use_span = tcx.def_span(param.def_id);
+                    let opaque_span = tcx.def_span(opaque_def_id);
                     // Check if the lifetime param was captured but isn't named in the precise captures list.
                     if variances[param.index as usize] == ty::Invariant {
-                        let param_span = if let DefKind::OpaqueTy =
-                            tcx.def_kind(tcx.parent(param.def_id))
+                        if let DefKind::OpaqueTy = tcx.def_kind(tcx.parent(param.def_id))
                             && let ty::ReEarlyParam(ty::EarlyParamRegion { def_id, .. })
                             | ty::ReLateParam(ty::LateParamRegion {
                                 bound_region: ty::BoundRegionKind::BrNamed(def_id, _),
@@ -591,16 +592,22 @@ fn check_opaque_precise_captures<'tcx>(tcx: TyCtxt<'tcx>, opaque_def_id: LocalDe
                             }) = *tcx
                                 .map_opaque_lifetime_to_parent_lifetime(param.def_id.expect_local())
                         {
-                            Some(tcx.def_span(def_id))
+                            tcx.dcx().emit_err(errors::LifetimeNotCaptured {
+                                opaque_span,
+                                use_span,
+                                param_span: tcx.def_span(def_id),
+                            });
                         } else {
-                            None
-                        };
-                        // FIXME(precise_capturing): Structured suggestion for this would be useful
-                        tcx.dcx().emit_err(errors::LifetimeNotCaptured {
-                            use_span: tcx.def_span(param.def_id),
-                            param_span,
-                            opaque_span: tcx.def_span(opaque_def_id),
-                        });
+                            // If the `use_span` is actually just the param itself, then we must
+                            // have not duplicated the lifetime but captured the original.
+                            // The "effective" `use_span` will be the span of the opaque itself,
+                            // and the param span will be the def span of the param.
+                            tcx.dcx().emit_err(errors::LifetimeNotCaptured {
+                                opaque_span,
+                                use_span: opaque_span,
+                                param_span: use_span,
+                            });
+                        }
                         continue;
                     }
                 }
diff --git a/compiler/rustc_hir_analysis/src/errors/precise_captures.rs b/compiler/rustc_hir_analysis/src/errors/precise_captures.rs
index 520bf1d9f40..d1b2205dd9a 100644
--- a/compiler/rustc_hir_analysis/src/errors/precise_captures.rs
+++ b/compiler/rustc_hir_analysis/src/errors/precise_captures.rs
@@ -6,9 +6,9 @@ use rustc_span::{Span, Symbol};
 #[note]
 pub struct ParamNotCaptured {
     #[primary_span]
-    pub param_span: Span,
-    #[label]
     pub opaque_span: Span,
+    #[label]
+    pub param_span: Span,
     pub kind: &'static str,
 }
 
@@ -18,7 +18,7 @@ pub struct LifetimeNotCaptured {
     #[primary_span]
     pub use_span: Span,
     #[label(hir_analysis_param_label)]
-    pub param_span: Option<Span>,
+    pub param_span: Span,
     #[label]
     pub opaque_span: Span,
 }
diff --git a/tests/ui/impl-trait/precise-capturing/capture-parent-arg.rs b/tests/ui/impl-trait/precise-capturing/capture-parent-arg.rs
index f880bb038d5..35b28d0e6fb 100644
--- a/tests/ui/impl-trait/precise-capturing/capture-parent-arg.rs
+++ b/tests/ui/impl-trait/precise-capturing/capture-parent-arg.rs
@@ -31,8 +31,8 @@ impl<'a> W<'a> {
 
 // But also make sure that we error here...
 impl<'a> W<'a> {
-//~^ ERROR `impl Trait` captures lifetime parameter, but it is not mentioned in `use<...>` precise captures list
     fn bad2() -> impl use<> Into<<Self as Tr>::Assoc> {}
+    //~^ ERROR `impl Trait` captures lifetime parameter, but it is not mentioned in `use<...>` precise captures list
 }
 
 fn main() {}
diff --git a/tests/ui/impl-trait/precise-capturing/capture-parent-arg.stderr b/tests/ui/impl-trait/precise-capturing/capture-parent-arg.stderr
index 85790d57163..13aaa999707 100644
--- a/tests/ui/impl-trait/precise-capturing/capture-parent-arg.stderr
+++ b/tests/ui/impl-trait/precise-capturing/capture-parent-arg.stderr
@@ -16,13 +16,12 @@ LL |     fn bad1() -> impl use<> Into<<W<'a> as Tr>::Assoc> {}
    |                  -------------------^^---------------- lifetime captured due to being mentioned in the bounds of the `impl Trait`
 
 error: `impl Trait` captures lifetime parameter, but it is not mentioned in `use<...>` precise captures list
-  --> $DIR/capture-parent-arg.rs:33:6
+  --> $DIR/capture-parent-arg.rs:34:18
    |
 LL | impl<'a> W<'a> {
-   |      ^^
-LL |
+   |      -- this lifetime parameter is captured
 LL |     fn bad2() -> impl use<> Into<<Self as Tr>::Assoc> {}
-   |                  ------------------------------------ lifetime captured due to being mentioned in the bounds of the `impl Trait`
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime captured due to being mentioned in the bounds of the `impl Trait`
 
 error: aborting due to 2 previous errors; 1 warning emitted
 
diff --git a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-const.stderr b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-const.stderr
index 9c99f2b711e..8eeedc4db44 100644
--- a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-const.stderr
+++ b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-const.stderr
@@ -8,10 +8,12 @@ LL | #![feature(precise_capturing)]
    = note: `#[warn(incomplete_features)]` on by default
 
 error: `impl Trait` must mention all const parameters in scope
-  --> $DIR/forgot-to-capture-const.rs:4:13
+  --> $DIR/forgot-to-capture-const.rs:4:34
    |
 LL | fn constant<const C: usize>() -> impl use<> Sized {}
-   |             ^^^^^^^^^^^^^^       ---------------- const parameter is implicitly captured by this `impl Trait`
+   |             --------------       ^^^^^^^^^^^^^^^^
+   |             |
+   |             const parameter is implicitly captured by this `impl Trait`
    |
    = note: currently, all const parameters are required to be mentioned in the precise captures list
 
diff --git a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.rs b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.rs
index 6eaff01183d..4c04d177b06 100644
--- a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.rs
+++ b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.rs
@@ -5,8 +5,8 @@ fn type_param<T>() -> impl use<> Sized {}
 //~^ ERROR `impl Trait` must mention all type parameters in scope
 
 trait Foo {
-//~^ ERROR `impl Trait` must mention all type parameters in scope
     fn bar() -> impl use<> Sized;
+    //~^ ERROR `impl Trait` must mention all type parameters in scope
 }
 
 fn main() {}
diff --git a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.stderr b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.stderr
index a8eb4547dcd..8cd873ea46d 100644
--- a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.stderr
+++ b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.stderr
@@ -8,21 +8,22 @@ LL | #![feature(precise_capturing)]
    = note: `#[warn(incomplete_features)]` on by default
 
 error: `impl Trait` must mention all type parameters in scope
-  --> $DIR/forgot-to-capture-type.rs:4:15
+  --> $DIR/forgot-to-capture-type.rs:4:23
    |
 LL | fn type_param<T>() -> impl use<> Sized {}
-   |               ^       ---------------- type parameter is implicitly captured by this `impl Trait`
+   |               -       ^^^^^^^^^^^^^^^^
+   |               |
+   |               type parameter is implicitly captured by this `impl Trait`
    |
    = note: currently, all type parameters are required to be mentioned in the precise captures list
 
 error: `impl Trait` must mention all type parameters in scope
-  --> $DIR/forgot-to-capture-type.rs:7:1
+  --> $DIR/forgot-to-capture-type.rs:8:17
    |
 LL | trait Foo {
-   | ^^^^^^^^^
-LL |
+   | --------- type parameter is implicitly captured by this `impl Trait`
 LL |     fn bar() -> impl use<> Sized;
-   |                 ---------------- type parameter is implicitly captured by this `impl Trait`
+   |                 ^^^^^^^^^^^^^^^^
    |
    = note: currently, all type parameters are required to be mentioned in the precise captures list
 

From 57085a06d9279173aac3d45a1a56c728047f45a3 Mon Sep 17 00:00:00 2001
From: Michael Goulet <michael@errs.io>
Date: Sat, 20 Apr 2024 11:39:43 -0400
Subject: [PATCH 2/2] Explicitly mention `Self`

---
 compiler/rustc_hir_analysis/messages.ftl      |  6 +++++-
 .../rustc_hir_analysis/src/check/check.rs     | 20 +++++++++++++------
 .../src/errors/precise_captures.rs            | 10 ++++++++++
 .../forgot-to-capture-const.stderr            |  2 +-
 .../forgot-to-capture-type.rs                 |  2 +-
 .../forgot-to-capture-type.stderr             |  6 +++---
 6 files changed, 34 insertions(+), 12 deletions(-)

diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl
index 0ff78ebff99..06b5ee299b8 100644
--- a/compiler/rustc_hir_analysis/messages.ftl
+++ b/compiler/rustc_hir_analysis/messages.ftl
@@ -351,7 +351,7 @@ hir_analysis_param_in_ty_of_assoc_const_binding =
         *[normal] the {$param_def_kind} `{$param_name}` is defined here
     }
 
-hir_analysis_param_not_captured = `impl Trait` must mention all {$kind} parameters in scope
+hir_analysis_param_not_captured = `impl Trait` must mention all {$kind} parameters in scope in `use<...>`
     .label = {$kind} parameter is implicitly captured by this `impl Trait`
     .note = currently, all {$kind} parameters are required to be mentioned in the precise captures list
 
@@ -405,6 +405,10 @@ hir_analysis_self_in_impl_self =
     `Self` is not valid in the self type of an impl block
     .note = replace `Self` with a different type
 
+hir_analysis_self_ty_not_captured = `impl Trait` must mention the `Self` type of the trait in `use<...>`
+    .label = `Self` type parameter is implicitly captured by this `impl Trait`
+    .note = currently, all type parameters are required to be mentioned in the precise captures list
+
 hir_analysis_simd_ffi_highly_experimental = use of SIMD type{$snip} in FFI is highly experimental and may result in invalid code
     .help = add `#![feature(simd_ffi)]` to the crate attributes to enable
 
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index 8dfbcbfd76f..a43a67d50d8 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -612,12 +612,20 @@ fn check_opaque_precise_captures<'tcx>(tcx: TyCtxt<'tcx>, opaque_def_id: LocalDe
                     }
                 }
                 ty::GenericParamDefKind::Type { .. } => {
-                    // FIXME(precise_capturing): Structured suggestion for this would be useful
-                    tcx.dcx().emit_err(errors::ParamNotCaptured {
-                        param_span: tcx.def_span(param.def_id),
-                        opaque_span: tcx.def_span(opaque_def_id),
-                        kind: "type",
-                    });
+                    if matches!(tcx.def_kind(param.def_id), DefKind::Trait | DefKind::TraitAlias) {
+                        // FIXME(precise_capturing): Structured suggestion for this would be useful
+                        tcx.dcx().emit_err(errors::SelfTyNotCaptured {
+                            trait_span: tcx.def_span(param.def_id),
+                            opaque_span: tcx.def_span(opaque_def_id),
+                        });
+                    } else {
+                        // FIXME(precise_capturing): Structured suggestion for this would be useful
+                        tcx.dcx().emit_err(errors::ParamNotCaptured {
+                            param_span: tcx.def_span(param.def_id),
+                            opaque_span: tcx.def_span(opaque_def_id),
+                            kind: "type",
+                        });
+                    }
                 }
                 ty::GenericParamDefKind::Const { .. } => {
                     // FIXME(precise_capturing): Structured suggestion for this would be useful
diff --git a/compiler/rustc_hir_analysis/src/errors/precise_captures.rs b/compiler/rustc_hir_analysis/src/errors/precise_captures.rs
index d1b2205dd9a..8a9b5fe6369 100644
--- a/compiler/rustc_hir_analysis/src/errors/precise_captures.rs
+++ b/compiler/rustc_hir_analysis/src/errors/precise_captures.rs
@@ -12,6 +12,16 @@ pub struct ParamNotCaptured {
     pub kind: &'static str,
 }
 
+#[derive(Diagnostic)]
+#[diag(hir_analysis_self_ty_not_captured)]
+#[note]
+pub struct SelfTyNotCaptured {
+    #[primary_span]
+    pub opaque_span: Span,
+    #[label]
+    pub trait_span: Span,
+}
+
 #[derive(Diagnostic)]
 #[diag(hir_analysis_lifetime_not_captured)]
 pub struct LifetimeNotCaptured {
diff --git a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-const.stderr b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-const.stderr
index 8eeedc4db44..3f78e7c56b6 100644
--- a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-const.stderr
+++ b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-const.stderr
@@ -7,7 +7,7 @@ LL | #![feature(precise_capturing)]
    = note: see issue #123432 <https://github.com/rust-lang/rust/issues/123432> for more information
    = note: `#[warn(incomplete_features)]` on by default
 
-error: `impl Trait` must mention all const parameters in scope
+error: `impl Trait` must mention all const parameters in scope in `use<...>`
   --> $DIR/forgot-to-capture-const.rs:4:34
    |
 LL | fn constant<const C: usize>() -> impl use<> Sized {}
diff --git a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.rs b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.rs
index 4c04d177b06..d359ea5e26d 100644
--- a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.rs
+++ b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.rs
@@ -6,7 +6,7 @@ fn type_param<T>() -> impl use<> Sized {}
 
 trait Foo {
     fn bar() -> impl use<> Sized;
-    //~^ ERROR `impl Trait` must mention all type parameters in scope
+    //~^ ERROR `impl Trait` must mention the `Self` type of the trait
 }
 
 fn main() {}
diff --git a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.stderr b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.stderr
index 8cd873ea46d..26994d0bdbf 100644
--- a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.stderr
+++ b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.stderr
@@ -7,7 +7,7 @@ LL | #![feature(precise_capturing)]
    = note: see issue #123432 <https://github.com/rust-lang/rust/issues/123432> for more information
    = note: `#[warn(incomplete_features)]` on by default
 
-error: `impl Trait` must mention all type parameters in scope
+error: `impl Trait` must mention all type parameters in scope in `use<...>`
   --> $DIR/forgot-to-capture-type.rs:4:23
    |
 LL | fn type_param<T>() -> impl use<> Sized {}
@@ -17,11 +17,11 @@ LL | fn type_param<T>() -> impl use<> Sized {}
    |
    = note: currently, all type parameters are required to be mentioned in the precise captures list
 
-error: `impl Trait` must mention all type parameters in scope
+error: `impl Trait` must mention the `Self` type of the trait in `use<...>`
   --> $DIR/forgot-to-capture-type.rs:8:17
    |
 LL | trait Foo {
-   | --------- type parameter is implicitly captured by this `impl Trait`
+   | --------- `Self` type parameter is implicitly captured by this `impl Trait`
 LL |     fn bar() -> impl use<> Sized;
    |                 ^^^^^^^^^^^^^^^^
    |