Rollup merge of #151290 - Unique-Usman:ua/nostruct, r=estebank
Recover from struct literals with placeholder or empty path Based on earlier work by León Orell Valerian Liehr.
This commit is contained in:
commit
6ff5bb3968
8 changed files with 187 additions and 6 deletions
|
|
@ -822,9 +822,19 @@ parse_struct_literal_body_without_path =
|
|||
struct literal body without path
|
||||
.suggestion = you might have forgotten to add the struct literal inside the block
|
||||
|
||||
parse_struct_literal_body_without_path_late =
|
||||
struct literal body without path
|
||||
.label = struct name missing for struct literal
|
||||
.suggestion = add the correct type
|
||||
|
||||
parse_struct_literal_not_allowed_here = struct literals are not allowed here
|
||||
.suggestion = surround the struct literal with parentheses
|
||||
|
||||
parse_struct_literal_placeholder_path =
|
||||
placeholder `_` is not allowed for the path in struct literals
|
||||
.label = not allowed in struct literals
|
||||
.suggestion = replace it with the correct type
|
||||
|
||||
parse_suffixed_literal_in_attribute = suffixed literals are not allowed in attributes
|
||||
.help = instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.)
|
||||
|
||||
|
|
|
|||
|
|
@ -3684,3 +3684,22 @@ pub(crate) struct ImplReuseInherentImpl {
|
|||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(parse_struct_literal_placeholder_path)]
|
||||
pub(crate) struct StructLiteralPlaceholderPath {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
#[suggestion(applicability = "has-placeholders", code = "/* Type */", style = "verbose")]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(parse_struct_literal_body_without_path_late)]
|
||||
pub(crate) struct StructLiteralWithoutPathLate {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
#[suggestion(applicability = "has-placeholders", code = "/* Type */ ", style = "verbose")]
|
||||
pub suggestion_span: Span,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1468,6 +1468,9 @@ impl<'a> Parser<'a> {
|
|||
} else if this.check(exp!(OpenParen)) {
|
||||
this.parse_expr_tuple_parens(restrictions)
|
||||
} else if this.check(exp!(OpenBrace)) {
|
||||
if let Some(expr) = this.maybe_recover_bad_struct_literal_path(false)? {
|
||||
return Ok(expr);
|
||||
}
|
||||
this.parse_expr_block(None, lo, BlockCheckMode::Default)
|
||||
} else if this.check(exp!(Or)) || this.check(exp!(OrOr)) {
|
||||
this.parse_expr_closure().map_err(|mut err| {
|
||||
|
|
@ -1542,6 +1545,9 @@ impl<'a> Parser<'a> {
|
|||
} else if this.check_keyword(exp!(Let)) {
|
||||
this.parse_expr_let(restrictions)
|
||||
} else if this.eat_keyword(exp!(Underscore)) {
|
||||
if let Some(expr) = this.maybe_recover_bad_struct_literal_path(true)? {
|
||||
return Ok(expr);
|
||||
}
|
||||
Ok(this.mk_expr(this.prev_token.span, ExprKind::Underscore))
|
||||
} else if this.token_uninterpolated_span().at_least_rust_2018() {
|
||||
// `Span::at_least_rust_2018()` is somewhat expensive; don't get it repeatedly.
|
||||
|
|
@ -3698,6 +3704,45 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn maybe_recover_bad_struct_literal_path(
|
||||
&mut self,
|
||||
is_underscore_entry_point: bool,
|
||||
) -> PResult<'a, Option<Box<Expr>>> {
|
||||
if self.may_recover()
|
||||
&& self.check_noexpect(&token::OpenBrace)
|
||||
&& (!self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL)
|
||||
&& self.is_likely_struct_lit())
|
||||
{
|
||||
let span = if is_underscore_entry_point {
|
||||
self.prev_token.span
|
||||
} else {
|
||||
self.token.span.shrink_to_lo()
|
||||
};
|
||||
|
||||
self.bump(); // {
|
||||
let expr = self.parse_expr_struct(
|
||||
None,
|
||||
Path::from_ident(Ident::new(kw::Underscore, span)),
|
||||
false,
|
||||
)?;
|
||||
|
||||
let guar = if is_underscore_entry_point {
|
||||
self.dcx().create_err(errors::StructLiteralPlaceholderPath { span }).emit()
|
||||
} else {
|
||||
self.dcx()
|
||||
.create_err(errors::StructLiteralWithoutPathLate {
|
||||
span: expr.span,
|
||||
suggestion_span: expr.span.shrink_to_lo(),
|
||||
})
|
||||
.emit()
|
||||
};
|
||||
|
||||
Ok(Some(self.mk_expr_err(expr.span, guar)))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn parse_struct_fields(
|
||||
&mut self,
|
||||
pth: ast::Path,
|
||||
|
|
|
|||
|
|
@ -21,14 +21,12 @@ LL | let x = {
|
|||
| _____________^
|
||||
LL | | val: (),
|
||||
LL | | };
|
||||
| |_____^
|
||||
| |_____^ struct name missing for struct literal
|
||||
|
|
||||
help: you might have forgotten to add the struct literal inside the block
|
||||
|
|
||||
LL ~ let x = { SomeStruct {
|
||||
LL | val: (),
|
||||
LL ~ } };
|
||||
help: add the correct type
|
||||
|
|
||||
LL | let x = /* Type */ {
|
||||
| ++++++++++
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/bare-struct-body.rs:11:14
|
||||
|
|
|
|||
14
tests/ui/parser/struct-lit-placeholder-or-empty-path.rs
Normal file
14
tests/ui/parser/struct-lit-placeholder-or-empty-path.rs
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
fn main() {
|
||||
let _ = {foo: (), bar: {} }; //~ ERROR struct literal body without path
|
||||
//~| NOTE struct name missing for struct literal
|
||||
//~| HELP add the correct type
|
||||
let _ = _ {foo: (), bar: {} }; //~ ERROR placeholder `_` is not allowed for the path in struct literals
|
||||
//~| NOTE not allowed in struct literals
|
||||
//~| HELP replace it with the correct type
|
||||
let _ = {foo: ()}; //~ ERROR struct literal body without path
|
||||
//~| NOTE struct name missing for struct literal
|
||||
//~| HELP add the correct type
|
||||
let _ = _ {foo: ()}; //~ ERROR placeholder `_` is not allowed for the path in struct literals
|
||||
//~| NOTE not allowed in struct literals
|
||||
//~| HELP replace it with the correct type
|
||||
}
|
||||
48
tests/ui/parser/struct-lit-placeholder-or-empty-path.stderr
Normal file
48
tests/ui/parser/struct-lit-placeholder-or-empty-path.stderr
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
error: struct literal body without path
|
||||
--> $DIR/struct-lit-placeholder-or-empty-path.rs:2:13
|
||||
|
|
||||
LL | let _ = {foo: (), bar: {} };
|
||||
| ^^^^^^^^^^^^^^^^^^^ struct name missing for struct literal
|
||||
|
|
||||
help: add the correct type
|
||||
|
|
||||
LL | let _ = /* Type */ {foo: (), bar: {} };
|
||||
| ++++++++++
|
||||
|
||||
error: placeholder `_` is not allowed for the path in struct literals
|
||||
--> $DIR/struct-lit-placeholder-or-empty-path.rs:5:13
|
||||
|
|
||||
LL | let _ = _ {foo: (), bar: {} };
|
||||
| ^ not allowed in struct literals
|
||||
|
|
||||
help: replace it with the correct type
|
||||
|
|
||||
LL - let _ = _ {foo: (), bar: {} };
|
||||
LL + let _ = /* Type */ {foo: (), bar: {} };
|
||||
|
|
||||
|
||||
error: struct literal body without path
|
||||
--> $DIR/struct-lit-placeholder-or-empty-path.rs:8:13
|
||||
|
|
||||
LL | let _ = {foo: ()};
|
||||
| ^^^^^^^^^ struct name missing for struct literal
|
||||
|
|
||||
help: add the correct type
|
||||
|
|
||||
LL | let _ = /* Type */ {foo: ()};
|
||||
| ++++++++++
|
||||
|
||||
error: placeholder `_` is not allowed for the path in struct literals
|
||||
--> $DIR/struct-lit-placeholder-or-empty-path.rs:11:13
|
||||
|
|
||||
LL | let _ = _ {foo: ()};
|
||||
| ^ not allowed in struct literals
|
||||
|
|
||||
help: replace it with the correct type
|
||||
|
|
||||
LL - let _ = _ {foo: ()};
|
||||
LL + let _ = /* Type */ {foo: ()};
|
||||
|
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
21
tests/ui/suggestions/struct-lit-placeholder-path.rs
Normal file
21
tests/ui/suggestions/struct-lit-placeholder-path.rs
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
// Regression test for issue #98282.
|
||||
|
||||
mod blah {
|
||||
pub struct Stuff { x: i32 }
|
||||
pub fn do_stuff(_: Stuff) {}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
blah::do_stuff(_ { x: 10 });
|
||||
//~^ ERROR placeholder `_` is not allowed for the path in struct literals
|
||||
//~| NOTE not allowed in struct literals
|
||||
//~| HELP replace it with the correct type
|
||||
}
|
||||
|
||||
#[cfg(FALSE)]
|
||||
fn disabled() {
|
||||
blah::do_stuff(_ { x: 10 });
|
||||
//~^ ERROR placeholder `_` is not allowed for the path in struct literals
|
||||
//~| NOTE not allowed in struct literals
|
||||
//~| HELP replace it with the correct type
|
||||
}
|
||||
26
tests/ui/suggestions/struct-lit-placeholder-path.stderr
Normal file
26
tests/ui/suggestions/struct-lit-placeholder-path.stderr
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
error: placeholder `_` is not allowed for the path in struct literals
|
||||
--> $DIR/struct-lit-placeholder-path.rs:9:20
|
||||
|
|
||||
LL | blah::do_stuff(_ { x: 10 });
|
||||
| ^ not allowed in struct literals
|
||||
|
|
||||
help: replace it with the correct type
|
||||
|
|
||||
LL - blah::do_stuff(_ { x: 10 });
|
||||
LL + blah::do_stuff(/* Type */ { x: 10 });
|
||||
|
|
||||
|
||||
error: placeholder `_` is not allowed for the path in struct literals
|
||||
--> $DIR/struct-lit-placeholder-path.rs:17:20
|
||||
|
|
||||
LL | blah::do_stuff(_ { x: 10 });
|
||||
| ^ not allowed in struct literals
|
||||
|
|
||||
help: replace it with the correct type
|
||||
|
|
||||
LL - blah::do_stuff(_ { x: 10 });
|
||||
LL + blah::do_stuff(/* Type */ { x: 10 });
|
||||
|
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue