about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <476013+matthiaskrgr@users.noreply.github.com>2025-07-11 07:35:20 +0200
committerGitHub <noreply@github.com>2025-07-11 07:35:20 +0200
commit140f2fa5ae32814cd3915adbb86af8b93efce9c4 (patch)
tree61a2a855242cfcabc8069af5d8d49170937e7e29
parent2ffaa1ec0ddef46d60851d51109e359cdf159bfd (diff)
parentd67bf6095a9a3f278a223a20b316c235360c1c90 (diff)
downloadrust-140f2fa5ae32814cd3915adbb86af8b93efce9c4.tar.gz
rust-140f2fa5ae32814cd3915adbb86af8b93efce9c4.zip
Rollup merge of #143661 - Muscraft:other-suggestion-message, r=estebank
chore: Improve how the other suggestions message gets rendered

Note: This change is part of my ongoing work to use `annotate-snippets` as `rustc`'s emitter

This change started as a way to remove some specialty code paths from `annotate-snippets`, by making the "and {} other candidates" message get rendered like a secondary message with no level, but turned into a fix for the message's Unicode output. Before this change, when using the Unicode output, the other suggestions message would get rendered outside of the main suggestion block, making it feel disconnected from what it was referring to. This change makes it so that the message is on the last line of the block, aligning its rendering with other secondary messages, and making it clear what the message is referring to.

Before:
```
error[E0433]: failed to resolve: use of undeclared type `IntoIter`
   ╭▸ $DIR/issue-82956.rs:28:24
   │
LL │         let mut iter = IntoIter::new(self);
   │                        ━━━━━━━━ use of undeclared type `IntoIter`
   ╰╴
help: consider importing one of these structs
   ╭╴
LL + use std::array::IntoIter;
   ├╴
LL + use std::collections::binary_heap::IntoIter;
   ├╴
LL + use std::collections::btree_map::IntoIter;
   ├╴
LL + use std::collections::btree_set::IntoIter;
   ╰╴
     and 9 other candidates
```

After:
```
error[E0433]: failed to resolve: use of undeclared type `IntoIter`
   ╭▸ $DIR/issue-82956.rs:28:24
   │
LL │         let mut iter = IntoIter::new(self);
   │                        ━━━━━━━━ use of undeclared type `IntoIter`
   ╰╴
help: consider importing one of these structs
   ╭╴
LL + use std::array::IntoIter;
   ├╴
LL + use std::collections::binary_heap::IntoIter;
   ├╴
LL + use std::collections::btree_map::IntoIter;
   ├╴
LL + use std::collections::btree_set::IntoIter;
   │
   ╰ and 9 other candidates
```
-rw-r--r--compiler/rustc_errors/src/emitter.rs9
-rw-r--r--tests/ui/associated-types/associated-types-in-ambiguous-context.stderr2
-rw-r--r--tests/ui/const-generics/issues/issue-82956.stderr2
-rw-r--r--tests/ui/did_you_mean/issue-56028-there-is-an-enum-variant.stderr4
-rw-r--r--tests/ui/impl-trait/call_method_without_import.no_import.stderr2
-rw-r--r--tests/ui/imports/issue-56125.stderr2
-rw-r--r--tests/ui/lint/use_suggestion_json.stderr2
-rw-r--r--tests/ui/privacy/suggest-box-new.stderr4
-rw-r--r--tests/ui/rust-2018/issue-52202-use-suggestions.stderr2
-rw-r--r--tests/ui/suggestions/multi-suggestion.ascii.stderr130
-rw-r--r--tests/ui/suggestions/multi-suggestion.rs22
-rw-r--r--tests/ui/suggestions/multi-suggestion.unicode.stderr130
-rw-r--r--tests/ui/suggestions/too-many-field-suggestions.stderr4
13 files changed, 301 insertions, 14 deletions
diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs
index 510f37f37e2..95400ac2ca3 100644
--- a/compiler/rustc_errors/src/emitter.rs
+++ b/compiler/rustc_errors/src/emitter.rs
@@ -2446,17 +2446,22 @@ impl HumanEmitter {
                     | DisplaySuggestion::Underline => row_num - 1,
                     DisplaySuggestion::None => row_num,
                 };
-                self.draw_col_separator_end(&mut buffer, row, max_line_num_len + 1);
+                if other_suggestions > 0 {
+                    self.draw_col_separator_no_space(&mut buffer, row, max_line_num_len + 1);
+                } else {
+                    self.draw_col_separator_end(&mut buffer, row, max_line_num_len + 1);
+                }
                 row_num = row + 1;
             }
         }
         if other_suggestions > 0 {
+            self.draw_note_separator(&mut buffer, row_num, max_line_num_len + 1, false);
             let msg = format!(
                 "and {} other candidate{}",
                 other_suggestions,
                 pluralize!(other_suggestions)
             );
-            buffer.puts(row_num, max_line_num_len + 3, &msg, Style::NoStyle);
+            buffer.append(row_num, &msg, Style::NoStyle);
         }
 
         emit_to_destination(&buffer.render(), level, &mut self.dst, self.short_message)?;
diff --git a/tests/ui/associated-types/associated-types-in-ambiguous-context.stderr b/tests/ui/associated-types/associated-types-in-ambiguous-context.stderr
index a7647cf26aa..71a1360cb5a 100644
--- a/tests/ui/associated-types/associated-types-in-ambiguous-context.stderr
+++ b/tests/ui/associated-types/associated-types-in-ambiguous-context.stderr
@@ -42,7 +42,7 @@ LL + type X = <CString as Deref>::Target;
 LL - type X = std::ops::Deref::Target;
 LL + type X = <IoSlice<'_> as Deref>::Target;
    |
-     and N other candidates
+   = and N other candidates
 
 error[E0223]: ambiguous associated type
   --> $DIR/associated-types-in-ambiguous-context.rs:13:23
diff --git a/tests/ui/const-generics/issues/issue-82956.stderr b/tests/ui/const-generics/issues/issue-82956.stderr
index 5e380eea81c..fd93e5122a5 100644
--- a/tests/ui/const-generics/issues/issue-82956.stderr
+++ b/tests/ui/const-generics/issues/issue-82956.stderr
@@ -14,7 +14,7 @@ LL + use std::collections::btree_map::IntoIter;
    |
 LL + use std::collections::btree_set::IntoIter;
    |
-     and 9 other candidates
+   = and 9 other candidates
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/did_you_mean/issue-56028-there-is-an-enum-variant.stderr b/tests/ui/did_you_mean/issue-56028-there-is-an-enum-variant.stderr
index 927f9e842e6..12965800a02 100644
--- a/tests/ui/did_you_mean/issue-56028-there-is-an-enum-variant.stderr
+++ b/tests/ui/did_you_mean/issue-56028-there-is-an-enum-variant.stderr
@@ -18,7 +18,7 @@ LL + fn setup() -> Determine { Set }
 LL - fn setup() -> Set { Set }
 LL + fn setup() -> PutDown { Set }
    |
-     and 3 other candidates
+   = and 3 other candidates
 
 error[E0425]: cannot find value `Set` in this scope
   --> $DIR/issue-56028-there-is-an-enum-variant.rs:9:21
@@ -36,7 +36,7 @@ LL + use Determine::Set;
    |
 LL + use PutDown::Set;
    |
-     and 3 other candidates
+   = and 3 other candidates
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/impl-trait/call_method_without_import.no_import.stderr b/tests/ui/impl-trait/call_method_without_import.no_import.stderr
index 72982b695bb..e59409ea27e 100644
--- a/tests/ui/impl-trait/call_method_without_import.no_import.stderr
+++ b/tests/ui/impl-trait/call_method_without_import.no_import.stderr
@@ -30,7 +30,7 @@ LL + use std::fmt::Display;
    |
 LL + use std::fmt::LowerExp;
    |
-     and 5 other candidates
+   = and 5 other candidates
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/imports/issue-56125.stderr b/tests/ui/imports/issue-56125.stderr
index 81336d51df4..371130facf9 100644
--- a/tests/ui/imports/issue-56125.stderr
+++ b/tests/ui/imports/issue-56125.stderr
@@ -18,7 +18,7 @@ LL +     use ::issue_56125::issue_56125;
 LL -     use empty::issue_56125;
 LL +     use ::issue_56125::last_segment::issue_56125;
    |
-     and 1 other candidate
+   = and 1 other candidate
 
 error[E0659]: `issue_56125` is ambiguous
   --> $DIR/issue-56125.rs:6:9
diff --git a/tests/ui/lint/use_suggestion_json.stderr b/tests/ui/lint/use_suggestion_json.stderr
index 0d4304e2e2e..558c2260fce 100644
--- a/tests/ui/lint/use_suggestion_json.stderr
+++ b/tests/ui/lint/use_suggestion_json.stderr
@@ -419,7 +419,7 @@ mod foo {
 \u001b[0m   \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m
 \u001b[0m\u001b[1m\u001b[38;5;12mLL\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[38;5;10m+ use std::collections::hash_map::Iter;\u001b[0m
 \u001b[0m   \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m
-\u001b[0m     and 9 other candidates\u001b[0m
+\u001b[0m   \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m= \u001b[0m\u001b[0mand 9 other candidates\u001b[0m
 
 "
 }
diff --git a/tests/ui/privacy/suggest-box-new.stderr b/tests/ui/privacy/suggest-box-new.stderr
index b651348de29..6c47b52c9de 100644
--- a/tests/ui/privacy/suggest-box-new.stderr
+++ b/tests/ui/privacy/suggest-box-new.stderr
@@ -63,7 +63,7 @@ LL -             x: (),
 LL -         })),
 LL +         wtf: Some(Box::new_in(_, _)),
    |
-     and 12 other candidates
+   = and 12 other candidates
 help: consider using the `Default` trait
    |
 LL -         wtf: Some(Box(U {
@@ -118,7 +118,7 @@ LL +     let _ = Box::new_zeroed();
 LL -     let _ = Box {};
 LL +     let _ = Box::new_in(_, _);
    |
-     and 12 other candidates
+   = and 12 other candidates
 help: consider using the `Default` trait
    |
 LL -     let _ = Box {};
diff --git a/tests/ui/rust-2018/issue-52202-use-suggestions.stderr b/tests/ui/rust-2018/issue-52202-use-suggestions.stderr
index ee1a336ea98..0eb1d46637b 100644
--- a/tests/ui/rust-2018/issue-52202-use-suggestions.stderr
+++ b/tests/ui/rust-2018/issue-52202-use-suggestions.stderr
@@ -14,7 +14,7 @@ LL + use std::collections::hash_map::Drain;
    |
 LL + use std::collections::hash_set::Drain;
    |
-     and 3 other candidates
+   = and 3 other candidates
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/suggestions/multi-suggestion.ascii.stderr b/tests/ui/suggestions/multi-suggestion.ascii.stderr
new file mode 100644
index 00000000000..f2a146fbd52
--- /dev/null
+++ b/tests/ui/suggestions/multi-suggestion.ascii.stderr
@@ -0,0 +1,130 @@
+error[E0423]: expected function, tuple struct or tuple variant, found struct `std::collections::HashMap`
+  --> $DIR/multi-suggestion.rs:17:13
+   |
+LL |     let _ = std::collections::HashMap();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+  --> $SRC_DIR/std/src/collections/hash/map.rs:LL:COL
+   |
+   = note: `std::collections::HashMap` defined here
+   |
+help: you might have meant to use an associated function to build this type
+   |
+LL |     let _ = std::collections::HashMap::new();
+   |                                      +++++
+LL -     let _ = std::collections::HashMap();
+LL +     let _ = std::collections::HashMap::with_capacity(_);
+   |
+LL -     let _ = std::collections::HashMap();
+LL +     let _ = std::collections::HashMap::with_hasher(_);
+   |
+LL -     let _ = std::collections::HashMap();
+LL +     let _ = std::collections::HashMap::with_capacity_and_hasher(_, _);
+   |
+help: consider using the `Default` trait
+   |
+LL |     let _ = <std::collections::HashMap as std::default::Default>::default();
+   |             +                          ++++++++++++++++++++++++++++++++++
+
+error[E0423]: cannot initialize a tuple struct which contains private fields
+  --> $DIR/multi-suggestion.rs:11:19
+   |
+LL |         wtf: Some(Box(U {
+   |                   ^^^
+   |
+note: constructor is not visible here due to private fields
+  --> $SRC_DIR/alloc/src/boxed.rs:LL:COL
+   |
+   = note: private field
+   |
+   = note: private field
+help: you might have meant to use an associated function to build this type
+   |
+LL -         wtf: Some(Box(U {
+LL -             wtf: None,
+LL -             x: (),
+LL -         })),
+LL +         wtf: Some(Box::new(_)),
+   |
+LL -         wtf: Some(Box(U {
+LL -             wtf: None,
+LL -             x: (),
+LL -         })),
+LL +         wtf: Some(Box::new_uninit()),
+   |
+LL -         wtf: Some(Box(U {
+LL -             wtf: None,
+LL -             x: (),
+LL -         })),
+LL +         wtf: Some(Box::new_zeroed()),
+   |
+LL -         wtf: Some(Box(U {
+LL -             wtf: None,
+LL -             x: (),
+LL -         })),
+LL +         wtf: Some(Box::new_in(_, _)),
+   |
+   = and 12 other candidates
+help: consider using the `Default` trait
+   |
+LL -         wtf: Some(Box(U {
+LL +         wtf: Some(<Box as std::default::Default>::default()),
+   |
+
+error: cannot construct `HashMap<_, _, _>` with struct literal syntax due to private fields
+  --> $DIR/multi-suggestion.rs:19:13
+   |
+LL |     let _ = std::collections::HashMap {};
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: private field `base` that was not provided
+help: you might have meant to use an associated function to build this type
+   |
+LL -     let _ = std::collections::HashMap {};
+LL +     let _ = std::collections::HashMap::new();
+   |
+LL -     let _ = std::collections::HashMap {};
+LL +     let _ = std::collections::HashMap::with_capacity(_);
+   |
+LL -     let _ = std::collections::HashMap {};
+LL +     let _ = std::collections::HashMap::with_hasher(_);
+   |
+LL -     let _ = std::collections::HashMap {};
+LL +     let _ = std::collections::HashMap::with_capacity_and_hasher(_, _);
+   |
+help: consider using the `Default` trait
+   |
+LL -     let _ = std::collections::HashMap {};
+LL +     let _ = <std::collections::HashMap as std::default::Default>::default();
+   |
+
+error: cannot construct `Box<_, _>` with struct literal syntax due to private fields
+  --> $DIR/multi-suggestion.rs:21:13
+   |
+LL |     let _ = Box {};
+   |             ^^^
+   |
+   = note: private fields `0` and `1` that were not provided
+help: you might have meant to use an associated function to build this type
+   |
+LL -     let _ = Box {};
+LL +     let _ = Box::new(_);
+   |
+LL -     let _ = Box {};
+LL +     let _ = Box::new_uninit();
+   |
+LL -     let _ = Box {};
+LL +     let _ = Box::new_zeroed();
+   |
+LL -     let _ = Box {};
+LL +     let _ = Box::new_in(_, _);
+   |
+   = and 12 other candidates
+help: consider using the `Default` trait
+   |
+LL -     let _ = Box {};
+LL +     let _ = <Box as std::default::Default>::default();
+   |
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0423`.
diff --git a/tests/ui/suggestions/multi-suggestion.rs b/tests/ui/suggestions/multi-suggestion.rs
new file mode 100644
index 00000000000..99d2407aa21
--- /dev/null
+++ b/tests/ui/suggestions/multi-suggestion.rs
@@ -0,0 +1,22 @@
+//@ revisions: ascii unicode
+//@[unicode] compile-flags: -Zunstable-options --error-format=human-unicode
+
+#![allow(dead_code)]
+struct U <T> {
+    wtf: Option<Box<U<T>>>,
+    x: T,
+}
+fn main() {
+    U {
+        wtf: Some(Box(U { //[ascii]~ ERROR cannot initialize a tuple struct which contains private fields
+            wtf: None,
+            x: (),
+        })),
+        x: ()
+    };
+    let _ = std::collections::HashMap();
+    //[ascii]~^ ERROR expected function, tuple struct or tuple variant, found struct `std::collections::HashMap`
+    let _ = std::collections::HashMap {};
+    //[ascii]~^ ERROR cannot construct `HashMap<_, _, _>` with struct literal syntax due to private fields
+    let _ = Box {}; //[ascii]~ ERROR cannot construct `Box<_, _>` with struct literal syntax due to private fields
+}
diff --git a/tests/ui/suggestions/multi-suggestion.unicode.stderr b/tests/ui/suggestions/multi-suggestion.unicode.stderr
new file mode 100644
index 00000000000..69df481579b
--- /dev/null
+++ b/tests/ui/suggestions/multi-suggestion.unicode.stderr
@@ -0,0 +1,130 @@
+error[E0423]: expected function, tuple struct or tuple variant, found struct `std::collections::HashMap`
+   ╭▸ $DIR/multi-suggestion.rs:17:13
+   │
+LL │     let _ = std::collections::HashMap();
+   │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━
+   ╭▸ $SRC_DIR/std/src/collections/hash/map.rs:LL:COL
+   │
+   ╰ note: `std::collections::HashMap` defined here
+   ╰╴
+help: you might have meant to use an associated function to build this type
+   ╭╴
+LL │     let _ = std::collections::HashMap::new();
+   ├╴                                     +++++
+LL -     let _ = std::collections::HashMap();
+LL +     let _ = std::collections::HashMap::with_capacity(_);
+   ├╴
+LL -     let _ = std::collections::HashMap();
+LL +     let _ = std::collections::HashMap::with_hasher(_);
+   ├╴
+LL -     let _ = std::collections::HashMap();
+LL +     let _ = std::collections::HashMap::with_capacity_and_hasher(_, _);
+   ╰╴
+help: consider using the `Default` trait
+   ╭╴
+LL │     let _ = <std::collections::HashMap as std::default::Default>::default();
+   ╰╴            +                          ++++++++++++++++++++++++++++++++++
+
+error[E0423]: cannot initialize a tuple struct which contains private fields
+   ╭▸ $DIR/multi-suggestion.rs:11:19
+   │
+LL │         wtf: Some(Box(U {
+   │                   ━━━
+   ╰╴
+note: constructor is not visible here due to private fields
+   ╭▸ $SRC_DIR/alloc/src/boxed.rs:LL:COL
+   │
+   ╰ note: private field
+   │
+   ╰ note: private field
+help: you might have meant to use an associated function to build this type
+   ╭╴
+LL -         wtf: Some(Box(U {
+LL -             wtf: None,
+LL -             x: (),
+LL -         })),
+LL +         wtf: Some(Box::new(_)),
+   ├╴
+LL -         wtf: Some(Box(U {
+LL -             wtf: None,
+LL -             x: (),
+LL -         })),
+LL +         wtf: Some(Box::new_uninit()),
+   ├╴
+LL -         wtf: Some(Box(U {
+LL -             wtf: None,
+LL -             x: (),
+LL -         })),
+LL +         wtf: Some(Box::new_zeroed()),
+   ├╴
+LL -         wtf: Some(Box(U {
+LL -             wtf: None,
+LL -             x: (),
+LL -         })),
+LL +         wtf: Some(Box::new_in(_, _)),
+   │
+   ╰ and 12 other candidates
+help: consider using the `Default` trait
+   ╭╴
+LL -         wtf: Some(Box(U {
+LL +         wtf: Some(<Box as std::default::Default>::default()),
+   ╰╴
+
+error: cannot construct `HashMap<_, _, _>` with struct literal syntax due to private fields
+   ╭▸ $DIR/multi-suggestion.rs:19:13
+   │
+LL │     let _ = std::collections::HashMap {};
+   │             ━━━━━━━━━━━━━━━━━━━━━━━━━
+   │
+   ╰ note: private field `base` that was not provided
+help: you might have meant to use an associated function to build this type
+   ╭╴
+LL -     let _ = std::collections::HashMap {};
+LL +     let _ = std::collections::HashMap::new();
+   ├╴
+LL -     let _ = std::collections::HashMap {};
+LL +     let _ = std::collections::HashMap::with_capacity(_);
+   ├╴
+LL -     let _ = std::collections::HashMap {};
+LL +     let _ = std::collections::HashMap::with_hasher(_);
+   ├╴
+LL -     let _ = std::collections::HashMap {};
+LL +     let _ = std::collections::HashMap::with_capacity_and_hasher(_, _);
+   ╰╴
+help: consider using the `Default` trait
+   ╭╴
+LL -     let _ = std::collections::HashMap {};
+LL +     let _ = <std::collections::HashMap as std::default::Default>::default();
+   ╰╴
+
+error: cannot construct `Box<_, _>` with struct literal syntax due to private fields
+   ╭▸ $DIR/multi-suggestion.rs:21:13
+   │
+LL │     let _ = Box {};
+   │             ━━━
+   │
+   ╰ note: private fields `0` and `1` that were not provided
+help: you might have meant to use an associated function to build this type
+   ╭╴
+LL -     let _ = Box {};
+LL +     let _ = Box::new(_);
+   ├╴
+LL -     let _ = Box {};
+LL +     let _ = Box::new_uninit();
+   ├╴
+LL -     let _ = Box {};
+LL +     let _ = Box::new_zeroed();
+   ├╴
+LL -     let _ = Box {};
+LL +     let _ = Box::new_in(_, _);
+   │
+   ╰ and 12 other candidates
+help: consider using the `Default` trait
+   ╭╴
+LL -     let _ = Box {};
+LL +     let _ = <Box as std::default::Default>::default();
+   ╰╴
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0423`.
diff --git a/tests/ui/suggestions/too-many-field-suggestions.stderr b/tests/ui/suggestions/too-many-field-suggestions.stderr
index ac5c8cb60cc..0cb0c8bec07 100644
--- a/tests/ui/suggestions/too-many-field-suggestions.stderr
+++ b/tests/ui/suggestions/too-many-field-suggestions.stderr
@@ -17,7 +17,7 @@ LL |     t.a2.bar();
    |       +++
 LL |     t.a3.bar();
    |       +++
-     and 6 other candidates
+   = and 6 other candidates
 
 error[E0609]: no field `field` on type `Thing`
   --> $DIR/too-many-field-suggestions.rs:26:7
@@ -35,7 +35,7 @@ LL |     t.a2.field;
    |       +++
 LL |     t.a3.field;
    |       +++
-     and 6 other candidates
+   = and 6 other candidates
 
 error: aborting due to 2 previous errors