1
Fork 0

Improve diagnostic for E0178 (bad + in type)

Namely, use a more sensical primary span.
Don't pretty-print AST nodes for the diagnostic message. Why:
* It's lossy (e.g., it doesn't replicate trailing `+`s in trait objects.
* It's prone to leak error nodes (printed as `(/*ERROR*/)`) since
  the LHS can easily represent recovered code (e.g., `fn(i32?) + T`).
This commit is contained in:
León Orell Valerian Liehr 2025-04-15 07:44:24 +02:00
parent 8887af72a0
commit 6242335fdb
No known key found for this signature in database
GPG key ID: D17A07215F68E713
14 changed files with 51 additions and 52 deletions

View file

@ -543,7 +543,7 @@ parse_maybe_recover_from_bad_qpath_stage_2 =
.suggestion = types that don't start with an identifier need to be surrounded with angle brackets in qualified paths .suggestion = types that don't start with an identifier need to be surrounded with angle brackets in qualified paths
parse_maybe_recover_from_bad_type_plus = parse_maybe_recover_from_bad_type_plus =
expected a path on the left-hand side of `+`, not `{$ty}` expected a path on the left-hand side of `+`
parse_maybe_report_ambiguous_plus = parse_maybe_report_ambiguous_plus =
ambiguous `+` in a type ambiguous `+` in a type

View file

@ -30,7 +30,6 @@ pub(crate) struct AmbiguousPlus {
#[derive(Diagnostic)] #[derive(Diagnostic)]
#[diag(parse_maybe_recover_from_bad_type_plus, code = E0178)] #[diag(parse_maybe_recover_from_bad_type_plus, code = E0178)]
pub(crate) struct BadTypePlus { pub(crate) struct BadTypePlus {
pub ty: String,
#[primary_span] #[primary_span]
pub span: Span, pub span: Span,
#[subdiagnostic] #[subdiagnostic]

View file

@ -1636,19 +1636,19 @@ impl<'a> Parser<'a> {
self.bump(); // `+` self.bump(); // `+`
let _bounds = self.parse_generic_bounds()?; let _bounds = self.parse_generic_bounds()?;
let sum_span = ty.span.to(self.prev_token.span);
let sub = match &ty.kind { let sub = match &ty.kind {
TyKind::Ref(_lifetime, mut_ty) => { TyKind::Ref(_lifetime, mut_ty) => {
let lo = mut_ty.ty.span.shrink_to_lo(); let lo = mut_ty.ty.span.shrink_to_lo();
let hi = self.prev_token.span.shrink_to_hi(); let hi = self.prev_token.span.shrink_to_hi();
BadTypePlusSub::AddParen { suggestion: AddParen { lo, hi } } BadTypePlusSub::AddParen { suggestion: AddParen { lo, hi } }
} }
TyKind::Ptr(..) | TyKind::BareFn(..) => BadTypePlusSub::ForgotParen { span: sum_span }, TyKind::Ptr(..) | TyKind::BareFn(..) => {
_ => BadTypePlusSub::ExpectPath { span: sum_span }, BadTypePlusSub::ForgotParen { span: ty.span.to(self.prev_token.span) }
}
_ => BadTypePlusSub::ExpectPath { span: ty.span },
}; };
self.dcx().emit_err(BadTypePlus { ty: pprust::ty_to_string(ty), span: sum_span, sub }); self.dcx().emit_err(BadTypePlus { span: ty.span, sub });
Ok(()) Ok(())
} }

View file

@ -1,41 +1,43 @@
error[E0178]: expected a path on the left-hand side of `+`, not `&'a Foo` error[E0178]: expected a path on the left-hand side of `+`
--> $DIR/E0178.rs:6:8 --> $DIR/E0178.rs:6:8
| |
LL | w: &'a Foo + Copy, LL | w: &'a Foo + Copy,
| ^^^^^^^^^^^^^^ | ^^^^^^^
| |
help: try adding parentheses help: try adding parentheses
| |
LL | w: &'a (Foo + Copy), LL | w: &'a (Foo + Copy),
| + + | + +
error[E0178]: expected a path on the left-hand side of `+`, not `&'a Foo` error[E0178]: expected a path on the left-hand side of `+`
--> $DIR/E0178.rs:7:8 --> $DIR/E0178.rs:7:8
| |
LL | x: &'a Foo + 'a, LL | x: &'a Foo + 'a,
| ^^^^^^^^^^^^ | ^^^^^^^
| |
help: try adding parentheses help: try adding parentheses
| |
LL | x: &'a (Foo + 'a), LL | x: &'a (Foo + 'a),
| + + | + +
error[E0178]: expected a path on the left-hand side of `+`, not `&'a mut Foo` error[E0178]: expected a path on the left-hand side of `+`
--> $DIR/E0178.rs:8:8 --> $DIR/E0178.rs:8:8
| |
LL | y: &'a mut Foo + 'a, LL | y: &'a mut Foo + 'a,
| ^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^
| |
help: try adding parentheses help: try adding parentheses
| |
LL | y: &'a mut (Foo + 'a), LL | y: &'a mut (Foo + 'a),
| + + | + +
error[E0178]: expected a path on the left-hand side of `+`, not `fn() -> Foo` error[E0178]: expected a path on the left-hand side of `+`
--> $DIR/E0178.rs:9:8 --> $DIR/E0178.rs:9:8
| |
LL | z: fn() -> Foo + 'a, LL | z: fn() -> Foo + 'a,
| ^^^^^^^^^^^^^^^^ perhaps you forgot parentheses? | ^^^^^^^^^^^-----
| |
| perhaps you forgot parentheses?
error: aborting due to 4 previous errors error: aborting due to 4 previous errors

View file

@ -1,19 +1,19 @@
error[E0178]: expected a path on the left-hand side of `+`, not `&Copy` error[E0178]: expected a path on the left-hand side of `+`
--> $DIR/trait-object-reference-without-parens-suggestion.rs:4:12 --> $DIR/trait-object-reference-without-parens-suggestion.rs:4:12
| |
LL | let _: &Copy + 'static; LL | let _: &Copy + 'static;
| ^^^^^^^^^^^^^^^ | ^^^^^
| |
help: try adding parentheses help: try adding parentheses
| |
LL | let _: &(Copy + 'static); LL | let _: &(Copy + 'static);
| + + | + +
error[E0178]: expected a path on the left-hand side of `+`, not `&'static Copy` error[E0178]: expected a path on the left-hand side of `+`
--> $DIR/trait-object-reference-without-parens-suggestion.rs:6:12 --> $DIR/trait-object-reference-without-parens-suggestion.rs:6:12
| |
LL | let _: &'static Copy + 'static; LL | let _: &'static Copy + 'static;
| ^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^
| |
help: try adding parentheses help: try adding parentheses
| |

View file

@ -27,7 +27,7 @@ type A = fn() -> impl A + B;
type A = fn() -> dyn A + B; type A = fn() -> dyn A + B;
//~^ ERROR ambiguous `+` in a type //~^ ERROR ambiguous `+` in a type
type A = fn() -> A + B; type A = fn() -> A + B;
//~^ ERROR expected a path on the left-hand side of `+`, not `fn() -> A` //~^ ERROR expected a path on the left-hand side of `+`
type A = Fn() -> impl A +; type A = Fn() -> impl A +;
//~^ ERROR ambiguous `+` in a type //~^ ERROR ambiguous `+` in a type
@ -44,6 +44,6 @@ type A = &impl A + B;
type A = &dyn A + B; type A = &dyn A + B;
//~^ ERROR ambiguous `+` in a type //~^ ERROR ambiguous `+` in a type
type A = &A + B; type A = &A + B;
//~^ ERROR expected a path on the left-hand side of `+`, not `&A` //~^ ERROR expected a path on the left-hand side of `+`
fn main() {} fn main() {}

View file

@ -31,11 +31,13 @@ help: try adding parentheses
LL | type A = fn() -> (dyn A + B); LL | type A = fn() -> (dyn A + B);
| + + | + +
error[E0178]: expected a path on the left-hand side of `+`, not `fn() -> A` error[E0178]: expected a path on the left-hand side of `+`
--> $DIR/impl-trait-plus-priority.rs:29:10 --> $DIR/impl-trait-plus-priority.rs:29:10
| |
LL | type A = fn() -> A + B; LL | type A = fn() -> A + B;
| ^^^^^^^^^^^^^ perhaps you forgot parentheses? | ^^^^^^^^^----
| |
| perhaps you forgot parentheses?
error: ambiguous `+` in a type error: ambiguous `+` in a type
--> $DIR/impl-trait-plus-priority.rs:32:18 --> $DIR/impl-trait-plus-priority.rs:32:18
@ -103,11 +105,11 @@ help: try adding parentheses
LL | type A = &(dyn A + B); LL | type A = &(dyn A + B);
| + + | + +
error[E0178]: expected a path on the left-hand side of `+`, not `&A` error[E0178]: expected a path on the left-hand side of `+`
--> $DIR/impl-trait-plus-priority.rs:46:10 --> $DIR/impl-trait-plus-priority.rs:46:10
| |
LL | type A = &A + B; LL | type A = &A + B;
| ^^^^^^ | ^^
| |
help: try adding parentheses help: try adding parentheses
| |

View file

@ -12,7 +12,7 @@ mac!('a);
// avoid false positives // avoid false positives
fn y<'a>(y: &mut 'a + Send) { fn y<'a>(y: &mut 'a + Send) {
//~^ ERROR expected a path on the left-hand side of `+`, not `&mut 'a` //~^ ERROR expected a path on the left-hand side of `+`
//~| ERROR at least one trait is required for an object type //~| ERROR at least one trait is required for an object type
let z = y as &mut 'a + Send; let z = y as &mut 'a + Send;
//~^ ERROR expected value, found trait `Send` //~^ ERROR expected value, found trait `Send`

View file

@ -10,11 +10,11 @@ LL - fn x<'a>(x: &mut 'a i32){}
LL + fn x<'a>(x: &'a mut i32){} LL + fn x<'a>(x: &'a mut i32){}
| |
error[E0178]: expected a path on the left-hand side of `+`, not `&mut 'a` error[E0178]: expected a path on the left-hand side of `+`
--> $DIR/issue-73568-lifetime-after-mut.rs:14:13 --> $DIR/issue-73568-lifetime-after-mut.rs:14:13
| |
LL | fn y<'a>(y: &mut 'a + Send) { LL | fn y<'a>(y: &mut 'a + Send) {
| ^^^^^^^^^^^^^^ | ^^^^^^^
| |
help: try adding parentheses help: try adding parentheses
| |

View file

@ -5,12 +5,8 @@
auto trait Auto {} auto trait Auto {}
fn main() { fn main() {
let _: Box<((Auto)) + Auto>; let _: Box<((Auto)) + Auto>; //~ ERROR expected a path on the left-hand side of `+`
//~^ ERROR expected a path on the left-hand side of `+`, not `((Auto))` let _: Box<(Auto + Auto) + Auto>; //~ ERROR expected a path on the left-hand side of `+`
let _: Box<(Auto + Auto) + Auto>; let _: Box<(Auto +) + Auto>; //~ ERROR expected a path on the left-hand side of `+`
//~^ ERROR expected a path on the left-hand side of `+`, not `(Auto + Auto)` let _: Box<(dyn Auto) + Auto>; //~ ERROR expected a path on the left-hand side of `+`
let _: Box<(Auto +) + Auto>;
//~^ ERROR expected a path on the left-hand side of `+`, not `(Auto)`
let _: Box<(dyn Auto) + Auto>;
//~^ ERROR expected a path on the left-hand side of `+`, not `(dyn Auto)`
} }

View file

@ -1,26 +1,26 @@
error[E0178]: expected a path on the left-hand side of `+`, not `((Auto))` error[E0178]: expected a path on the left-hand side of `+`
--> $DIR/trait-object-bad-parens.rs:8:16 --> $DIR/trait-object-bad-parens.rs:8:16
| |
LL | let _: Box<((Auto)) + Auto>; LL | let _: Box<((Auto)) + Auto>;
| ^^^^^^^^^^^^^^^ expected a path | ^^^^^^^^ expected a path
error[E0178]: expected a path on the left-hand side of `+`, not `(Auto + Auto)` error[E0178]: expected a path on the left-hand side of `+`
--> $DIR/trait-object-bad-parens.rs:10:16 --> $DIR/trait-object-bad-parens.rs:9:16
| |
LL | let _: Box<(Auto + Auto) + Auto>; LL | let _: Box<(Auto + Auto) + Auto>;
| ^^^^^^^^^^^^^^^^^^^^ expected a path | ^^^^^^^^^^^^^ expected a path
error[E0178]: expected a path on the left-hand side of `+`, not `(Auto)` error[E0178]: expected a path on the left-hand side of `+`
--> $DIR/trait-object-bad-parens.rs:12:16 --> $DIR/trait-object-bad-parens.rs:10:16
| |
LL | let _: Box<(Auto +) + Auto>; LL | let _: Box<(Auto +) + Auto>;
| ^^^^^^^^^^^^^^^ expected a path | ^^^^^^^^ expected a path
error[E0178]: expected a path on the left-hand side of `+`, not `(dyn Auto)` error[E0178]: expected a path on the left-hand side of `+`
--> $DIR/trait-object-bad-parens.rs:14:16 --> $DIR/trait-object-bad-parens.rs:11:16
| |
LL | let _: Box<(dyn Auto) + Auto>; LL | let _: Box<(dyn Auto) + Auto>;
| ^^^^^^^^^^^^^^^^^ expected a path | ^^^^^^^^^^ expected a path
error: aborting due to 4 previous errors error: aborting due to 4 previous errors

View file

@ -28,11 +28,11 @@ error: expected type, found lifetime
LL | let _: Box<('a) + Trait>; LL | let _: Box<('a) + Trait>;
| ^^ expected type | ^^ expected type
error[E0178]: expected a path on the left-hand side of `+`, not `((/*ERROR*/))` error[E0178]: expected a path on the left-hand side of `+`
--> $DIR/trait-object-lifetime-parens.rs:16:16 --> $DIR/trait-object-lifetime-parens.rs:16:16
| |
LL | let _: Box<('a) + Trait>; LL | let _: Box<('a) + Trait>;
| ^^^^^^^^^^^^ expected a path | ^^^^ expected a path
error[E0782]: expected a type, found a trait error[E0782]: expected a type, found a trait
--> $DIR/trait-object-lifetime-parens.rs:12:16 --> $DIR/trait-object-lifetime-parens.rs:12:16

View file

@ -4,6 +4,6 @@ trait Trait<'a> {}
fn main() { fn main() {
let _: &for<'a> Trait<'a> + 'static; let _: &for<'a> Trait<'a> + 'static;
//~^ ERROR expected a path on the left-hand side of `+`, not `&for<'a> Trait<'a>` //~^ ERROR expected a path on the left-hand side of `+`
//~| HELP try adding parentheses //~| HELP try adding parentheses
} }

View file

@ -1,8 +1,8 @@
error[E0178]: expected a path on the left-hand side of `+`, not `&for<'a> Trait<'a>` error[E0178]: expected a path on the left-hand side of `+`
--> $DIR/trait-object-polytrait-priority.rs:6:12 --> $DIR/trait-object-polytrait-priority.rs:6:12
| |
LL | let _: &for<'a> Trait<'a> + 'static; LL | let _: &for<'a> Trait<'a> + 'static;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^
| |
help: try adding parentheses help: try adding parentheses
| |