about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorEsteban Küber <esteban@kuber.com.ar>2020-05-29 09:24:59 -0700
committerEsteban Küber <esteban@kuber.com.ar>2020-06-10 14:09:51 -0700
commitc29b3fa1484c625bd34cb4d94fc76f36c6233447 (patch)
tree20e2737f33c3ae1a777c4524a34a549ed1117795 /src
parentbb8674837a9cc5225020e07fc3f164762bb4c11c (diff)
downloadrust-c29b3fa1484c625bd34cb4d94fc76f36c6233447.tar.gz
rust-c29b3fa1484c625bd34cb4d94fc76f36c6233447.zip
On recursive ADT, provide indirection structured suggestion
Diffstat (limited to 'src')
-rw-r--r--src/librustc_errors/diagnostic.rs23
-rw-r--r--src/librustc_errors/diagnostic_builder.rs13
-rw-r--r--src/librustc_middle/ty/util.rs10
-rw-r--r--src/librustc_trait_selection/traits/error_reporting/mod.rs66
-rw-r--r--src/librustc_typeck/check/mod.rs6
-rw-r--r--src/test/ui/infinite/infinite-tag-type-recursion.stderr9
-rw-r--r--src/test/ui/issues/issue-17431-1.stderr11
-rw-r--r--src/test/ui/issues/issue-17431-2.stderr22
-rw-r--r--src/test/ui/issues/issue-17431-3.stderr11
-rw-r--r--src/test/ui/issues/issue-17431-4.stderr11
-rw-r--r--src/test/ui/issues/issue-17431-5.stderr11
-rw-r--r--src/test/ui/issues/issue-17431-6.stderr9
-rw-r--r--src/test/ui/issues/issue-17431-7.stderr9
-rw-r--r--src/test/ui/issues/issue-2718-a.stderr9
-rw-r--r--src/test/ui/issues/issue-3008-1.stderr9
-rw-r--r--src/test/ui/issues/issue-3008-2.stderr11
-rw-r--r--src/test/ui/issues/issue-3008-3.stderr9
-rw-r--r--src/test/ui/issues/issue-32326.stderr5
-rw-r--r--src/test/ui/issues/issue-3779.stderr11
-rw-r--r--src/test/ui/issues/issue-57271.stderr18
-rw-r--r--src/test/ui/recursion/recursive-enum.stderr9
-rw-r--r--src/test/ui/sized-cycle-note.stderr22
-rw-r--r--src/test/ui/span/E0072.stderr11
-rw-r--r--src/test/ui/span/multiline-span-E0072.stderr11
-rw-r--r--src/test/ui/span/recursive-type-field.stderr23
-rw-r--r--src/test/ui/type/type-recursive.stderr11
-rw-r--r--src/test/ui/union/union-nonrepresentable.stderr11
27 files changed, 315 insertions, 66 deletions
diff --git a/src/librustc_errors/diagnostic.rs b/src/librustc_errors/diagnostic.rs
index cff83c3d5cd..acaa26c6ad2 100644
--- a/src/librustc_errors/diagnostic.rs
+++ b/src/librustc_errors/diagnostic.rs
@@ -296,6 +296,29 @@ impl Diagnostic {
         self
     }
 
+    pub fn multipart_suggestions(
+        &mut self,
+        msg: &str,
+        suggestions: Vec<Vec<(Span, String)>>,
+        applicability: Applicability,
+    ) -> &mut Self {
+        self.suggestions.push(CodeSuggestion {
+            substitutions: suggestions
+                .into_iter()
+                .map(|suggestion| Substitution {
+                    parts: suggestion
+                        .into_iter()
+                        .map(|(span, snippet)| SubstitutionPart { snippet, span })
+                        .collect(),
+                })
+                .collect(),
+            msg: msg.to_owned(),
+            style: SuggestionStyle::ShowCode,
+            applicability,
+        });
+        self
+    }
+
     /// Prints out a message with for a multipart suggestion without showing the suggested code.
     ///
     /// This is intended to be used for suggestions that are obvious in what the changes need to
diff --git a/src/librustc_errors/diagnostic_builder.rs b/src/librustc_errors/diagnostic_builder.rs
index 2dbd9f4e52f..22bf8fe34aa 100644
--- a/src/librustc_errors/diagnostic_builder.rs
+++ b/src/librustc_errors/diagnostic_builder.rs
@@ -260,6 +260,19 @@ impl<'a> DiagnosticBuilder<'a> {
         self
     }
 
+    pub fn multipart_suggestions(
+        &mut self,
+        msg: &str,
+        suggestions: Vec<Vec<(Span, String)>>,
+        applicability: Applicability,
+    ) -> &mut Self {
+        if !self.0.allow_suggestions {
+            return self;
+        }
+        self.0.diagnostic.multipart_suggestions(msg, suggestions, applicability);
+        self
+    }
+
     pub fn tool_only_multipart_suggestion(
         &mut self,
         msg: &str,
diff --git a/src/librustc_middle/ty/util.rs b/src/librustc_middle/ty/util.rs
index c2b794ca4bd..5cdfa6f9012 100644
--- a/src/librustc_middle/ty/util.rs
+++ b/src/librustc_middle/ty/util.rs
@@ -827,7 +827,15 @@ impl<'tcx> ty::TyS<'tcx> {
                     // Find non representable fields with their spans
                     fold_repr(def.all_fields().map(|field| {
                         let ty = field.ty(tcx, substs);
-                        let span = tcx.hir().span_if_local(field.did).unwrap_or(sp);
+                        let span = match field
+                            .did
+                            .as_local()
+                            .map(|id| tcx.hir().as_local_hir_id(id))
+                            .and_then(|id| tcx.hir().find(id))
+                        {
+                            Some(hir::Node::Field(field)) => field.ty.span,
+                            _ => sp,
+                        };
                         match is_type_structurally_recursive(
                             tcx,
                             span,
diff --git a/src/librustc_trait_selection/traits/error_reporting/mod.rs b/src/librustc_trait_selection/traits/error_reporting/mod.rs
index 1b72a4bf84f..3457f7b4580 100644
--- a/src/librustc_trait_selection/traits/error_reporting/mod.rs
+++ b/src/librustc_trait_selection/traits/error_reporting/mod.rs
@@ -1747,24 +1747,62 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
 pub fn recursive_type_with_infinite_size_error(
     tcx: TyCtxt<'tcx>,
     type_def_id: DefId,
-) -> DiagnosticBuilder<'tcx> {
+    spans: Vec<Span>,
+) {
     assert!(type_def_id.is_local());
     let span = tcx.hir().span_if_local(type_def_id).unwrap();
     let span = tcx.sess.source_map().guess_head_span(span);
-    let mut err = struct_span_err!(
-        tcx.sess,
-        span,
-        E0072,
-        "recursive type `{}` has infinite size",
-        tcx.def_path_str(type_def_id)
-    );
+    let path = tcx.def_path_str(type_def_id);
+    let mut err =
+        struct_span_err!(tcx.sess, span, E0072, "recursive type `{}` has infinite size", path);
     err.span_label(span, "recursive type has infinite size");
-    err.help(&format!(
-        "insert indirection (e.g., a `Box`, `Rc`, or `&`) \
-                           at some point to make `{}` representable",
-        tcx.def_path_str(type_def_id)
-    ));
-    err
+    for &span in &spans {
+        err.span_label(span, "recursive without indirection");
+    }
+    let short_msg = format!("insert some indirection to make `{}` representable", path);
+    let msg = format!(
+        "insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `{}` representable",
+        path,
+    );
+    match &spans[..] {
+        [span] => {
+            err.multipart_suggestions(
+                &short_msg,
+                vec![
+                    vec![
+                        (span.shrink_to_lo(), "Box<".to_string()),
+                        (span.shrink_to_hi(), ">".to_string()),
+                    ],
+                    vec![
+                        (span.shrink_to_lo(), "Rc<".to_string()),
+                        (span.shrink_to_hi(), ">".to_string()),
+                    ],
+                    vec![(span.shrink_to_lo(), "&".to_string())],
+                ],
+                Applicability::HasPlaceholders,
+            );
+        }
+        _ if spans.len() <= 4 => {
+            err.multipart_suggestion(
+                &msg,
+                spans
+                    .iter()
+                    .flat_map(|&span| {
+                        vec![
+                            (span.shrink_to_lo(), "Box<".to_string()),
+                            (span.shrink_to_hi(), ">".to_string()),
+                        ]
+                        .into_iter()
+                    })
+                    .collect(),
+                Applicability::HasPlaceholders,
+            );
+        }
+        _ => {
+            err.help(&msg);
+        }
+    }
+    err.emit();
 }
 
 /// Summarizes information
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index f2aeed4f1e4..1e8a149d7d9 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -2390,11 +2390,7 @@ fn check_representable(tcx: TyCtxt<'_>, sp: Span, item_def_id: LocalDefId) -> bo
     // caught by case 1.
     match rty.is_representable(tcx, sp) {
         Representability::SelfRecursive(spans) => {
-            let mut err = recursive_type_with_infinite_size_error(tcx, item_def_id.to_def_id());
-            for span in spans {
-                err.span_label(span, "recursive without indirection");
-            }
-            err.emit();
+            recursive_type_with_infinite_size_error(tcx, item_def_id.to_def_id(), spans);
             return false;
         }
         Representability::Representable | Representability::ContainsRecursive => (),
diff --git a/src/test/ui/infinite/infinite-tag-type-recursion.stderr b/src/test/ui/infinite/infinite-tag-type-recursion.stderr
index 11f82b842ba..b6a4d8f4cf5 100644
--- a/src/test/ui/infinite/infinite-tag-type-recursion.stderr
+++ b/src/test/ui/infinite/infinite-tag-type-recursion.stderr
@@ -6,7 +6,14 @@ LL | enum MList { Cons(isize, MList), Nil }
    | |
    | recursive type has infinite size
    |
-   = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `MList` representable
+help: insert some indirection to make `MList` representable
+   |
+LL | enum MList { Cons(isize, Box<MList>), Nil }
+   |                          ^^^^     ^
+LL | enum MList { Cons(isize, Rc<MList>), Nil }
+   |                          ^^^     ^
+LL | enum MList { Cons(isize, &MList), Nil }
+   |                          ^
 
 error[E0391]: cycle detected when computing drop-check constraints for `MList`
   --> $DIR/infinite-tag-type-recursion.rs:1:1
diff --git a/src/test/ui/issues/issue-17431-1.stderr b/src/test/ui/issues/issue-17431-1.stderr
index eb5a1366e89..8d44154650e 100644
--- a/src/test/ui/issues/issue-17431-1.stderr
+++ b/src/test/ui/issues/issue-17431-1.stderr
@@ -2,11 +2,18 @@ error[E0072]: recursive type `Foo` has infinite size
   --> $DIR/issue-17431-1.rs:1:1
    |
 LL | struct Foo { foo: Option<Option<Foo>> }
-   | ^^^^^^^^^^   ------------------------ recursive without indirection
+   | ^^^^^^^^^^        ------------------- recursive without indirection
    | |
    | recursive type has infinite size
    |
-   = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `Foo` representable
+help: insert some indirection to make `Foo` representable
+   |
+LL | struct Foo { foo: Box<Option<Option<Foo>>> }
+   |                   ^^^^                   ^
+LL | struct Foo { foo: Rc<Option<Option<Foo>>> }
+   |                   ^^^                   ^
+LL | struct Foo { foo: &Option<Option<Foo>> }
+   |                   ^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-17431-2.stderr b/src/test/ui/issues/issue-17431-2.stderr
index 3a7b0e9ce79..b06184e84da 100644
--- a/src/test/ui/issues/issue-17431-2.stderr
+++ b/src/test/ui/issues/issue-17431-2.stderr
@@ -2,21 +2,35 @@ error[E0072]: recursive type `Baz` has infinite size
   --> $DIR/issue-17431-2.rs:1:1
    |
 LL | struct Baz { q: Option<Foo> }
-   | ^^^^^^^^^^   -------------- recursive without indirection
+   | ^^^^^^^^^^      ----------- recursive without indirection
    | |
    | recursive type has infinite size
    |
-   = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `Baz` representable
+help: insert some indirection to make `Baz` representable
+   |
+LL | struct Baz { q: Box<Option<Foo>> }
+   |                 ^^^^           ^
+LL | struct Baz { q: Rc<Option<Foo>> }
+   |                 ^^^           ^
+LL | struct Baz { q: &Option<Foo> }
+   |                 ^
 
 error[E0072]: recursive type `Foo` has infinite size
   --> $DIR/issue-17431-2.rs:4:1
    |
 LL | struct Foo { q: Option<Baz> }
-   | ^^^^^^^^^^   -------------- recursive without indirection
+   | ^^^^^^^^^^      ----------- recursive without indirection
    | |
    | recursive type has infinite size
    |
-   = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `Foo` representable
+help: insert some indirection to make `Foo` representable
+   |
+LL | struct Foo { q: Box<Option<Baz>> }
+   |                 ^^^^           ^
+LL | struct Foo { q: Rc<Option<Baz>> }
+   |                 ^^^           ^
+LL | struct Foo { q: &Option<Baz> }
+   |                 ^
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/issues/issue-17431-3.stderr b/src/test/ui/issues/issue-17431-3.stderr
index 675a2e27142..f32bd70fd6d 100644
--- a/src/test/ui/issues/issue-17431-3.stderr
+++ b/src/test/ui/issues/issue-17431-3.stderr
@@ -2,11 +2,18 @@ error[E0072]: recursive type `Foo` has infinite size
   --> $DIR/issue-17431-3.rs:3:1
    |
 LL | struct Foo { foo: Mutex<Option<Foo>> }
-   | ^^^^^^^^^^   ----------------------- recursive without indirection
+   | ^^^^^^^^^^        ------------------ recursive without indirection
    | |
    | recursive type has infinite size
    |
-   = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `Foo` representable
+help: insert some indirection to make `Foo` representable
+   |
+LL | struct Foo { foo: Box<Mutex<Option<Foo>>> }
+   |                   ^^^^                  ^
+LL | struct Foo { foo: Rc<Mutex<Option<Foo>>> }
+   |                   ^^^                  ^
+LL | struct Foo { foo: &Mutex<Option<Foo>> }
+   |                   ^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-17431-4.stderr b/src/test/ui/issues/issue-17431-4.stderr
index aff9071095c..372c5e975c8 100644
--- a/src/test/ui/issues/issue-17431-4.stderr
+++ b/src/test/ui/issues/issue-17431-4.stderr
@@ -2,11 +2,18 @@ error[E0072]: recursive type `Foo` has infinite size
   --> $DIR/issue-17431-4.rs:3:1
    |
 LL | struct Foo<T> { foo: Option<Option<Foo<T>>>, marker: marker::PhantomData<T> }
-   | ^^^^^^^^^^^^^   --------------------------- recursive without indirection
+   | ^^^^^^^^^^^^^        ---------------------- recursive without indirection
    | |
    | recursive type has infinite size
    |
-   = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `Foo` representable
+help: insert some indirection to make `Foo` representable
+   |
+LL | struct Foo<T> { foo: Box<Option<Option<Foo<T>>>>, marker: marker::PhantomData<T> }
+   |                      ^^^^                      ^
+LL | struct Foo<T> { foo: Rc<Option<Option<Foo<T>>>>, marker: marker::PhantomData<T> }
+   |                      ^^^                      ^
+LL | struct Foo<T> { foo: &Option<Option<Foo<T>>>, marker: marker::PhantomData<T> }
+   |                      ^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-17431-5.stderr b/src/test/ui/issues/issue-17431-5.stderr
index 537f9f34f55..01b850ac336 100644
--- a/src/test/ui/issues/issue-17431-5.stderr
+++ b/src/test/ui/issues/issue-17431-5.stderr
@@ -2,11 +2,18 @@ error[E0072]: recursive type `Bar` has infinite size
   --> $DIR/issue-17431-5.rs:5:1
    |
 LL | struct Bar<T> { x: Bar<Foo> , marker: marker::PhantomData<T> }
-   | ^^^^^^^^^^^^^   ----------- recursive without indirection
+   | ^^^^^^^^^^^^^      -------- recursive without indirection
    | |
    | recursive type has infinite size
    |
-   = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `Bar` representable
+help: insert some indirection to make `Bar` representable
+   |
+LL | struct Bar<T> { x: Box<Bar<Foo>> , marker: marker::PhantomData<T> }
+   |                    ^^^^        ^
+LL | struct Bar<T> { x: Rc<Bar<Foo>> , marker: marker::PhantomData<T> }
+   |                    ^^^        ^
+LL | struct Bar<T> { x: &Bar<Foo> , marker: marker::PhantomData<T> }
+   |                    ^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-17431-6.stderr b/src/test/ui/issues/issue-17431-6.stderr
index cb2dab95014..ce6c2db07fb 100644
--- a/src/test/ui/issues/issue-17431-6.stderr
+++ b/src/test/ui/issues/issue-17431-6.stderr
@@ -6,7 +6,14 @@ LL | enum Foo { X(Mutex<Option<Foo>>) }
    | |
    | recursive type has infinite size
    |
-   = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `Foo` representable
+help: insert some indirection to make `Foo` representable
+   |
+LL | enum Foo { X(Box<Mutex<Option<Foo>>>) }
+   |              ^^^^                  ^
+LL | enum Foo { X(Rc<Mutex<Option<Foo>>>) }
+   |              ^^^                  ^
+LL | enum Foo { X(&Mutex<Option<Foo>>) }
+   |              ^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-17431-7.stderr b/src/test/ui/issues/issue-17431-7.stderr
index de70851da4b..4fb563ba502 100644
--- a/src/test/ui/issues/issue-17431-7.stderr
+++ b/src/test/ui/issues/issue-17431-7.stderr
@@ -6,7 +6,14 @@ LL | enum Foo { Voo(Option<Option<Foo>>) }
    | |
    | recursive type has infinite size
    |
-   = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `Foo` representable
+help: insert some indirection to make `Foo` representable
+   |
+LL | enum Foo { Voo(Box<Option<Option<Foo>>>) }
+   |                ^^^^                   ^
+LL | enum Foo { Voo(Rc<Option<Option<Foo>>>) }
+   |                ^^^                   ^
+LL | enum Foo { Voo(&Option<Option<Foo>>) }
+   |                ^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-2718-a.stderr b/src/test/ui/issues/issue-2718-a.stderr
index 0f52c791928..48b7a61e059 100644
--- a/src/test/ui/issues/issue-2718-a.stderr
+++ b/src/test/ui/issues/issue-2718-a.stderr
@@ -7,7 +7,14 @@ LL |     pub struct Pong(SendPacket<Ping>);
    |     |               recursive without indirection
    |     recursive type has infinite size
    |
-   = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `pingpong::Pong` representable
+help: insert some indirection to make `pingpong::Pong` representable
+   |
+LL |     pub struct Pong(Box<SendPacket<Ping>>);
+   |                     ^^^^                ^
+LL |     pub struct Pong(Rc<SendPacket<Ping>>);
+   |                     ^^^                ^
+LL |     pub struct Pong(&SendPacket<Ping>);
+   |                     ^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-3008-1.stderr b/src/test/ui/issues/issue-3008-1.stderr
index f12274134ee..d1173a4b333 100644
--- a/src/test/ui/issues/issue-3008-1.stderr
+++ b/src/test/ui/issues/issue-3008-1.stderr
@@ -7,7 +7,14 @@ LL | enum Bar {
 LL |     BarSome(Bar)
    |             --- recursive without indirection
    |
-   = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `Bar` representable
+help: insert some indirection to make `Bar` representable
+   |
+LL |     BarSome(Box<Bar>)
+   |             ^^^^   ^
+LL |     BarSome(Rc<Bar>)
+   |             ^^^   ^
+LL |     BarSome(&Bar)
+   |             ^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-3008-2.stderr b/src/test/ui/issues/issue-3008-2.stderr
index acc15f4b57c..4fd60639b21 100644
--- a/src/test/ui/issues/issue-3008-2.stderr
+++ b/src/test/ui/issues/issue-3008-2.stderr
@@ -2,11 +2,18 @@ error[E0072]: recursive type `Bar` has infinite size
   --> $DIR/issue-3008-2.rs:2:1
    |
 LL | struct Bar { x: Bar }
-   | ^^^^^^^^^^   ------ recursive without indirection
+   | ^^^^^^^^^^      --- recursive without indirection
    | |
    | recursive type has infinite size
    |
-   = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `Bar` representable
+help: insert some indirection to make `Bar` representable
+   |
+LL | struct Bar { x: Box<Bar> }
+   |                 ^^^^   ^
+LL | struct Bar { x: Rc<Bar> }
+   |                 ^^^   ^
+LL | struct Bar { x: &Bar }
+   |                 ^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-3008-3.stderr b/src/test/ui/issues/issue-3008-3.stderr
index d08a3d9708d..e6efad91883 100644
--- a/src/test/ui/issues/issue-3008-3.stderr
+++ b/src/test/ui/issues/issue-3008-3.stderr
@@ -6,7 +6,14 @@ LL | enum E2<T> { V2(E2<E1>, marker::PhantomData<T>), }
    | |
    | recursive type has infinite size
    |
-   = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `E2` representable
+help: insert some indirection to make `E2` representable
+   |
+LL | enum E2<T> { V2(Box<E2<E1>>, marker::PhantomData<T>), }
+   |                 ^^^^      ^
+LL | enum E2<T> { V2(Rc<E2<E1>>, marker::PhantomData<T>), }
+   |                 ^^^      ^
+LL | enum E2<T> { V2(&E2<E1>, marker::PhantomData<T>), }
+   |                 ^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-32326.stderr b/src/test/ui/issues/issue-32326.stderr
index 5967627e51a..0f3d3690b73 100644
--- a/src/test/ui/issues/issue-32326.stderr
+++ b/src/test/ui/issues/issue-32326.stderr
@@ -8,7 +8,10 @@ LL |     Plus(Expr, Expr),
    |          |
    |          recursive without indirection
    |
-   = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `Expr` representable
+help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Expr` representable
+   |
+LL |     Plus(Box<Expr>, Box<Expr>),
+   |          ^^^^    ^  ^^^^    ^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-3779.stderr b/src/test/ui/issues/issue-3779.stderr
index ba1e842c610..9b50ddec12a 100644
--- a/src/test/ui/issues/issue-3779.stderr
+++ b/src/test/ui/issues/issue-3779.stderr
@@ -5,9 +5,16 @@ LL | struct S {
    | ^^^^^^^^ recursive type has infinite size
 LL |
 LL |     element: Option<S>
-   |     ------------------ recursive without indirection
+   |              --------- recursive without indirection
    |
-   = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `S` representable
+help: insert some indirection to make `S` representable
+   |
+LL |     element: Box<Option<S>>
+   |              ^^^^         ^
+LL |     element: Rc<Option<S>>
+   |              ^^^         ^
+LL |     element: &Option<S>
+   |              ^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-57271.stderr b/src/test/ui/issues/issue-57271.stderr
index 4f164624f7a..a6fe83a9b56 100644
--- a/src/test/ui/issues/issue-57271.stderr
+++ b/src/test/ui/issues/issue-57271.stderr
@@ -7,7 +7,14 @@ LL |     Class(ClassTypeSignature),
 LL |     Array(TypeSignature),
    |           ------------- recursive without indirection
    |
-   = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `ObjectType` representable
+help: insert some indirection to make `ObjectType` representable
+   |
+LL |     Array(Box<TypeSignature>),
+   |           ^^^^             ^
+LL |     Array(Rc<TypeSignature>),
+   |           ^^^             ^
+LL |     Array(&TypeSignature),
+   |           ^
 
 error[E0072]: recursive type `TypeSignature` has infinite size
   --> $DIR/issue-57271.rs:19:1
@@ -18,7 +25,14 @@ LL |     Base(BaseType),
 LL |     Object(ObjectType),
    |            ---------- recursive without indirection
    |
-   = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `TypeSignature` representable
+help: insert some indirection to make `TypeSignature` representable
+   |
+LL |     Object(Box<ObjectType>),
+   |            ^^^^          ^
+LL |     Object(Rc<ObjectType>),
+   |            ^^^          ^
+LL |     Object(&ObjectType),
+   |            ^
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/recursion/recursive-enum.stderr b/src/test/ui/recursion/recursive-enum.stderr
index e4674b57a6d..c68badd458b 100644
--- a/src/test/ui/recursion/recursive-enum.stderr
+++ b/src/test/ui/recursion/recursive-enum.stderr
@@ -6,7 +6,14 @@ LL | enum List<T> { Cons(T, List<T>), Nil }
    | |
    | recursive type has infinite size
    |
-   = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `List` representable
+help: insert some indirection to make `List` representable
+   |
+LL | enum List<T> { Cons(T, Box<List<T>>), Nil }
+   |                        ^^^^       ^
+LL | enum List<T> { Cons(T, Rc<List<T>>), Nil }
+   |                        ^^^       ^
+LL | enum List<T> { Cons(T, &List<T>), Nil }
+   |                        ^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/sized-cycle-note.stderr b/src/test/ui/sized-cycle-note.stderr
index 95bdc349426..99d8cfd0a05 100644
--- a/src/test/ui/sized-cycle-note.stderr
+++ b/src/test/ui/sized-cycle-note.stderr
@@ -2,21 +2,35 @@ error[E0072]: recursive type `Baz` has infinite size
   --> $DIR/sized-cycle-note.rs:9:1
    |
 LL | struct Baz { q: Option<Foo> }
-   | ^^^^^^^^^^   -------------- recursive without indirection
+   | ^^^^^^^^^^      ----------- recursive without indirection
    | |
    | recursive type has infinite size
    |
-   = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `Baz` representable
+help: insert some indirection to make `Baz` representable
+   |
+LL | struct Baz { q: Box<Option<Foo>> }
+   |                 ^^^^           ^
+LL | struct Baz { q: Rc<Option<Foo>> }
+   |                 ^^^           ^
+LL | struct Baz { q: &Option<Foo> }
+   |                 ^
 
 error[E0072]: recursive type `Foo` has infinite size
   --> $DIR/sized-cycle-note.rs:11:1
    |
 LL | struct Foo { q: Option<Baz> }
-   | ^^^^^^^^^^   -------------- recursive without indirection
+   | ^^^^^^^^^^      ----------- recursive without indirection
    | |
    | recursive type has infinite size
    |
-   = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `Foo` representable
+help: insert some indirection to make `Foo` representable
+   |
+LL | struct Foo { q: Box<Option<Baz>> }
+   |                 ^^^^           ^
+LL | struct Foo { q: Rc<Option<Baz>> }
+   |                 ^^^           ^
+LL | struct Foo { q: &Option<Baz> }
+   |                 ^
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/span/E0072.stderr b/src/test/ui/span/E0072.stderr
index d4a5e7400d2..855e4facb7b 100644
--- a/src/test/ui/span/E0072.stderr
+++ b/src/test/ui/span/E0072.stderr
@@ -5,9 +5,16 @@ LL | struct ListNode {
    | ^^^^^^^^^^^^^^^ recursive type has infinite size
 LL |     head: u8,
 LL |     tail: Option<ListNode>,
-   |     ---------------------- recursive without indirection
+   |           ---------------- recursive without indirection
    |
-   = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `ListNode` representable
+help: insert some indirection to make `ListNode` representable
+   |
+LL |     tail: Box<Option<ListNode>>,
+   |           ^^^^                ^
+LL |     tail: Rc<Option<ListNode>>,
+   |           ^^^                ^
+LL |     tail: &Option<ListNode>,
+   |           ^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/span/multiline-span-E0072.stderr b/src/test/ui/span/multiline-span-E0072.stderr
index dd322fe833b..260c2157e96 100644
--- a/src/test/ui/span/multiline-span-E0072.stderr
+++ b/src/test/ui/span/multiline-span-E0072.stderr
@@ -6,11 +6,18 @@ LL | | ListNode
 LL | | {
 LL | |     head: u8,
 LL | |     tail: Option<ListNode>,
-   | |     ---------------------- recursive without indirection
+   | |           ---------------- recursive without indirection
 LL | | }
    | |_^ recursive type has infinite size
    |
-   = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `ListNode` representable
+help: insert some indirection to make `ListNode` representable
+   |
+LL |     tail: Box<Option<ListNode>>,
+   |           ^^^^                ^
+LL |     tail: Rc<Option<ListNode>>,
+   |           ^^^                ^
+LL |     tail: &Option<ListNode>,
+   |           ^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/span/recursive-type-field.stderr b/src/test/ui/span/recursive-type-field.stderr
index d240872647e..c1a3270d0a5 100644
--- a/src/test/ui/span/recursive-type-field.stderr
+++ b/src/test/ui/span/recursive-type-field.stderr
@@ -4,9 +4,16 @@ error[E0072]: recursive type `Foo` has infinite size
 LL | struct Foo<'a> {
    | ^^^^^^^^^^^^^^ recursive type has infinite size
 LL |     bar: Bar<'a>,
-   |     ------------ recursive without indirection
+   |          ------- recursive without indirection
    |
-   = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `Foo` representable
+help: insert some indirection to make `Foo` representable
+   |
+LL |     bar: Box<Bar<'a>>,
+   |          ^^^^       ^
+LL |     bar: Rc<Bar<'a>>,
+   |          ^^^       ^
+LL |     bar: &Bar<'a>,
+   |          ^
 
 error[E0072]: recursive type `Bar` has infinite size
   --> $DIR/recursive-type-field.rs:8:1
@@ -14,18 +21,18 @@ error[E0072]: recursive type `Bar` has infinite size
 LL | struct Bar<'a> {
    | ^^^^^^^^^^^^^^ recursive type has infinite size
 LL |     y: (Foo<'a>, Foo<'a>),
-   |     --------------------- recursive without indirection
+   |        ------------------ recursive without indirection
 LL |     z: Option<Bar<'a>>,
-   |     ------------------ recursive without indirection
+   |        --------------- recursive without indirection
 ...
 LL |     d: [Bar<'a>; 1],
-   |     --------------- recursive without indirection
+   |        ------------ recursive without indirection
 LL |     e: Foo<'a>,
-   |     ---------- recursive without indirection
+   |        ------- recursive without indirection
 LL |     x: Bar<'a>,
-   |     ---------- recursive without indirection
+   |        ------- recursive without indirection
    |
-   = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `Bar` representable
+   = help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Bar` representable
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/type/type-recursive.stderr b/src/test/ui/type/type-recursive.stderr
index 72bf372e561..b98a6eac49e 100644
--- a/src/test/ui/type/type-recursive.stderr
+++ b/src/test/ui/type/type-recursive.stderr
@@ -5,9 +5,16 @@ LL | struct T1 {
    | ^^^^^^^^^ recursive type has infinite size
 LL |     foo: isize,
 LL |     foolish: T1
-   |     ----------- recursive without indirection
+   |              -- recursive without indirection
    |
-   = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `T1` representable
+help: insert some indirection to make `T1` representable
+   |
+LL |     foolish: Box<T1>
+   |              ^^^^  ^
+LL |     foolish: Rc<T1>
+   |              ^^^  ^
+LL |     foolish: &T1
+   |              ^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/union/union-nonrepresentable.stderr b/src/test/ui/union/union-nonrepresentable.stderr
index 746c1033ea3..70863a549ad 100644
--- a/src/test/ui/union/union-nonrepresentable.stderr
+++ b/src/test/ui/union/union-nonrepresentable.stderr
@@ -5,9 +5,16 @@ LL | union U {
    | ^^^^^^^ recursive type has infinite size
 LL |     a: u8,
 LL |     b: U,
-   |     ---- recursive without indirection
+   |        - recursive without indirection
    |
-   = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `U` representable
+help: insert some indirection to make `U` representable
+   |
+LL |     b: Box<U>,
+   |        ^^^^ ^
+LL |     b: Rc<U>,
+   |        ^^^ ^
+LL |     b: &U,
+   |        ^
 
 error: aborting due to previous error