Fix bad suggestion when wrong parentheses around a dyn trait

This commit is contained in:
yukang 2023-08-14 17:51:19 +08:00
parent fd9525adb0
commit ddcd7cac41
8 changed files with 105 additions and 28 deletions

View File

@ -310,8 +310,8 @@ parse_inclusive_range_no_end = inclusive range with no end
.suggestion_open_range = use `..` instead .suggestion_open_range = use `..` instead
.note = inclusive ranges must be bounded at the end (`..=b` or `a..=b`) .note = inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
parse_incorrect_braces_trait_bounds = incorrect braces around trait bounds parse_incorrect_parens_trait_bounds = incorrect parentheses around trait bounds
.suggestion = remove the parentheses parse_incorrect_parens_trait_bounds_sugg = fix the parentheses
parse_incorrect_semicolon = parse_incorrect_semicolon =
expected item, found `;` expected item, found `;`

View File

@ -2636,21 +2636,24 @@ pub(crate) struct MissingPlusBounds {
} }
#[derive(Diagnostic)] #[derive(Diagnostic)]
#[diag(parse_incorrect_braces_trait_bounds)] #[diag(parse_incorrect_parens_trait_bounds)]
pub(crate) struct IncorrectBracesTraitBounds { pub(crate) struct IncorrectParensTraitBounds {
#[primary_span] #[primary_span]
pub span: Vec<Span>, pub span: Vec<Span>,
#[subdiagnostic] #[subdiagnostic]
pub sugg: IncorrectBracesTraitBoundsSugg, pub sugg: IncorrectParensTraitBoundsSugg,
} }
#[derive(Subdiagnostic)] #[derive(Subdiagnostic)]
#[multipart_suggestion(parse_suggestion, applicability = "machine-applicable")] #[multipart_suggestion(
pub(crate) struct IncorrectBracesTraitBoundsSugg { parse_incorrect_parens_trait_bounds_sugg,
applicability = "machine-applicable"
)]
pub(crate) struct IncorrectParensTraitBoundsSugg {
#[suggestion_part(code = " ")] #[suggestion_part(code = " ")]
pub l: Span, pub wrong_span: Span,
#[suggestion_part(code = "")] #[suggestion_part(code = "(")]
pub r: Span, pub new_span: Span,
} }
#[derive(Diagnostic)] #[derive(Diagnostic)]

View File

@ -714,6 +714,7 @@ fn can_begin_bound(&mut self) -> bool {
/// ``` /// ```
fn parse_generic_bound(&mut self) -> PResult<'a, GenericBound> { fn parse_generic_bound(&mut self) -> PResult<'a, GenericBound> {
let lo = self.token.span; let lo = self.token.span;
let leading_token = self.prev_token.clone();
let has_parens = self.eat(&token::OpenDelim(Delimiter::Parenthesis)); let has_parens = self.eat(&token::OpenDelim(Delimiter::Parenthesis));
let inner_lo = self.token.span; let inner_lo = self.token.span;
@ -722,7 +723,7 @@ fn parse_generic_bound(&mut self) -> PResult<'a, GenericBound> {
self.error_lt_bound_with_modifiers(modifiers); self.error_lt_bound_with_modifiers(modifiers);
self.parse_generic_lt_bound(lo, inner_lo, has_parens)? self.parse_generic_lt_bound(lo, inner_lo, has_parens)?
} else { } else {
self.parse_generic_ty_bound(lo, has_parens, modifiers)? self.parse_generic_ty_bound(lo, has_parens, modifiers, &leading_token)?
}; };
Ok(bound) Ok(bound)
@ -827,6 +828,7 @@ fn parse_generic_ty_bound(
lo: Span, lo: Span,
has_parens: bool, has_parens: bool,
modifiers: BoundModifiers, modifiers: BoundModifiers,
leading_token: &Token,
) -> PResult<'a, GenericBound> { ) -> PResult<'a, GenericBound> {
let mut lifetime_defs = self.parse_late_bound_lifetime_defs()?; let mut lifetime_defs = self.parse_late_bound_lifetime_defs()?;
let mut path = if self.token.is_keyword(kw::Fn) let mut path = if self.token.is_keyword(kw::Fn)
@ -873,18 +875,18 @@ fn parse_generic_ty_bound(
} }
if has_parens { if has_parens {
if self.token.is_like_plus() { // Someone has written something like `&dyn (Trait + Other)`. The correct code
// Someone has written something like `&dyn (Trait + Other)`. The correct code // would be `&(dyn Trait + Other)`
// would be `&(dyn Trait + Other)`, but we don't have access to the appropriate if self.token.is_like_plus() && leading_token.is_keyword(kw::Dyn) {
// span to suggest that. When written as `&dyn Trait + Other`, an appropriate
// suggestion is given.
let bounds = vec![]; let bounds = vec![];
self.parse_remaining_bounds(bounds, true)?; self.parse_remaining_bounds(bounds, true)?;
self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; self.expect(&token::CloseDelim(Delimiter::Parenthesis))?;
let sp = vec![lo, self.prev_token.span]; self.sess.emit_err(errors::IncorrectParensTraitBounds {
self.sess.emit_err(errors::IncorrectBracesTraitBounds { span: vec![lo, self.prev_token.span],
span: sp, sugg: errors::IncorrectParensTraitBoundsSugg {
sugg: errors::IncorrectBracesTraitBoundsSugg { l: lo, r: self.prev_token.span }, wrong_span: leading_token.span.shrink_to_hi().to(lo),
new_span: leading_token.span.shrink_to_lo(),
},
}); });
} else { } else {
self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; self.expect(&token::CloseDelim(Delimiter::Parenthesis))?;

View File

@ -3,9 +3,9 @@
fn foo1(_: &dyn Drop + AsRef<str>) {} //~ ERROR ambiguous `+` in a type fn foo1(_: &dyn Drop + AsRef<str>) {} //~ ERROR ambiguous `+` in a type
//~^ ERROR only auto traits can be used as additional traits in a trait object //~^ ERROR only auto traits can be used as additional traits in a trait object
fn foo2(_: &dyn (Drop + AsRef<str>)) {} //~ ERROR incorrect braces around trait bounds fn foo2(_: &dyn (Drop + AsRef<str>)) {} //~ ERROR incorrect parentheses around trait bounds
fn foo2_no_space(_: &dyn(Drop + AsRef<str>)) {} //~ ERROR incorrect braces around trait bounds fn foo2_no_space(_: &dyn(Drop + AsRef<str>)) {} //~ ERROR incorrect parentheses around trait bounds
fn foo3(_: &dyn {Drop + AsRef<str>}) {} //~ ERROR expected parameter name, found `{` fn foo3(_: &dyn {Drop + AsRef<str>}) {} //~ ERROR expected parameter name, found `{`
//~^ ERROR expected one of `!`, `(`, `)`, `*`, `,`, `?`, `for`, `~`, lifetime, or path, found `{` //~^ ERROR expected one of `!`, `(`, `)`, `*`, `,`, `?`, `for`, `~`, lifetime, or path, found `{`

View File

@ -4,28 +4,28 @@ error: ambiguous `+` in a type
LL | fn foo1(_: &dyn Drop + AsRef<str>) {} LL | fn foo1(_: &dyn Drop + AsRef<str>) {}
| ^^^^^^^^^^^^^^^^^^^^^ help: use parentheses to disambiguate: `(dyn Drop + AsRef<str>)` | ^^^^^^^^^^^^^^^^^^^^^ help: use parentheses to disambiguate: `(dyn Drop + AsRef<str>)`
error: incorrect braces around trait bounds error: incorrect parentheses around trait bounds
--> $DIR/trait-object-delimiters.rs:6:17 --> $DIR/trait-object-delimiters.rs:6:17
| |
LL | fn foo2(_: &dyn (Drop + AsRef<str>)) {} LL | fn foo2(_: &dyn (Drop + AsRef<str>)) {}
| ^ ^ | ^ ^
| |
help: remove the parentheses help: fix the parentheses
| |
LL - fn foo2(_: &dyn (Drop + AsRef<str>)) {} LL - fn foo2(_: &dyn (Drop + AsRef<str>)) {}
LL + fn foo2(_: &dyn Drop + AsRef<str>) {} LL + fn foo2(_: &(dyn Drop + AsRef<str>)) {}
| |
error: incorrect braces around trait bounds error: incorrect parentheses around trait bounds
--> $DIR/trait-object-delimiters.rs:8:25 --> $DIR/trait-object-delimiters.rs:8:25
| |
LL | fn foo2_no_space(_: &dyn(Drop + AsRef<str>)) {} LL | fn foo2_no_space(_: &dyn(Drop + AsRef<str>)) {}
| ^ ^ | ^ ^
| |
help: remove the parentheses help: fix the parentheses
| |
LL - fn foo2_no_space(_: &dyn(Drop + AsRef<str>)) {} LL - fn foo2_no_space(_: &dyn(Drop + AsRef<str>)) {}
LL + fn foo2_no_space(_: &dyn Drop + AsRef<str>) {} LL + fn foo2_no_space(_: &(dyn Drop + AsRef<str>)) {}
| |
error: expected parameter name, found `{` error: expected parameter name, found `{`

View File

@ -0,0 +1,17 @@
//run-rustfix
#![allow(dead_code)]
trait Trait {}
fn assert_send(ptr: *mut dyn Trait) -> *mut (dyn Trait + Send) {
//~^ ERROR incorrect parentheses around trait bounds
ptr as _
}
fn foo2(_: &(dyn Trait + Send)) {}
//~^ ERROR incorrect parentheses around trait bounds
fn foo3(_: &(dyn Trait + Send)) {}
//~^ ERROR incorrect parentheses around trait bounds
fn main() {}

View File

@ -0,0 +1,17 @@
//run-rustfix
#![allow(dead_code)]
trait Trait {}
fn assert_send(ptr: *mut dyn Trait) -> *mut dyn (Trait + Send) {
//~^ ERROR incorrect parentheses around trait bounds
ptr as _
}
fn foo2(_: &dyn (Trait + Send)) {}
//~^ ERROR incorrect parentheses around trait bounds
fn foo3(_: &dyn(Trait + Send)) {}
//~^ ERROR incorrect parentheses around trait bounds
fn main() {}

View File

@ -0,0 +1,38 @@
error: incorrect parentheses around trait bounds
--> $DIR/issue-114797-bad-parentheses-dyn-trait.rs:6:49
|
LL | fn assert_send(ptr: *mut dyn Trait) -> *mut dyn (Trait + Send) {
| ^ ^
|
help: fix the parentheses
|
LL - fn assert_send(ptr: *mut dyn Trait) -> *mut dyn (Trait + Send) {
LL + fn assert_send(ptr: *mut dyn Trait) -> *mut (dyn Trait + Send) {
|
error: incorrect parentheses around trait bounds
--> $DIR/issue-114797-bad-parentheses-dyn-trait.rs:11:17
|
LL | fn foo2(_: &dyn (Trait + Send)) {}
| ^ ^
|
help: fix the parentheses
|
LL - fn foo2(_: &dyn (Trait + Send)) {}
LL + fn foo2(_: &(dyn Trait + Send)) {}
|
error: incorrect parentheses around trait bounds
--> $DIR/issue-114797-bad-parentheses-dyn-trait.rs:14:16
|
LL | fn foo3(_: &dyn(Trait + Send)) {}
| ^ ^
|
help: fix the parentheses
|
LL - fn foo3(_: &dyn(Trait + Send)) {}
LL + fn foo3(_: &(dyn Trait + Send)) {}
|
error: aborting due to 3 previous errors