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
```
This commit is contained in:
Matthias Krüger 2025-07-11 07:35:20 +02:00 committed by GitHub
commit 140f2fa5ae
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 301 additions and 14 deletions

View file

@ -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)?;

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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
"
}

View file

@ -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 {};

View file

@ -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

View file

@ -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`.

View file

@ -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
}

View file

@ -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`.

View file

@ -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