Rollup merge of #57779 - estebank:recover-struct-fields, r=davidtwco
Recover from parse errors in literal struct fields and incorrect float literals Fix #52496.
This commit is contained in:
commit
2dd63a2e10
11 changed files with 225 additions and 44 deletions
|
@ -100,6 +100,7 @@ pub enum PathStyle {
|
||||||
enum SemiColonMode {
|
enum SemiColonMode {
|
||||||
Break,
|
Break,
|
||||||
Ignore,
|
Ignore,
|
||||||
|
Comma,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Debug)]
|
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||||
|
@ -1988,6 +1989,44 @@ impl<'a> Parser<'a> {
|
||||||
|
|
||||||
result.unwrap()
|
result.unwrap()
|
||||||
}
|
}
|
||||||
|
token::Dot if self.look_ahead(1, |t| match t {
|
||||||
|
token::Literal(parse::token::Lit::Integer(_) , _) => true,
|
||||||
|
_ => false,
|
||||||
|
}) => { // recover from `let x = .4;`
|
||||||
|
let lo = self.span;
|
||||||
|
self.bump();
|
||||||
|
if let token::Literal(
|
||||||
|
parse::token::Lit::Integer(val),
|
||||||
|
suffix,
|
||||||
|
) = self.token {
|
||||||
|
let suffix = suffix.and_then(|s| {
|
||||||
|
let s = s.as_str().get();
|
||||||
|
if ["f32", "f64"].contains(&s) {
|
||||||
|
Some(s)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}).unwrap_or("");
|
||||||
|
self.bump();
|
||||||
|
let sp = lo.to(self.prev_span);
|
||||||
|
let mut err = self.diagnostic()
|
||||||
|
.struct_span_err(sp, "float literals must have an integer part");
|
||||||
|
err.span_suggestion_with_applicability(
|
||||||
|
sp,
|
||||||
|
"must have an integer part",
|
||||||
|
format!("0.{}{}", val, suffix),
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
);
|
||||||
|
err.emit();
|
||||||
|
return Ok(match suffix {
|
||||||
|
"f32" => ast::LitKind::Float(val, ast::FloatTy::F32),
|
||||||
|
"f64" => ast::LitKind::Float(val, ast::FloatTy::F64),
|
||||||
|
_ => ast::LitKind::FloatUnsuffixed(val),
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
unreachable!();
|
||||||
|
};
|
||||||
|
}
|
||||||
_ => { return self.unexpected_last(&self.token); }
|
_ => { return self.unexpected_last(&self.token); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2656,8 +2695,24 @@ impl<'a> Parser<'a> {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut recovery_field = None;
|
||||||
|
if let token::Ident(ident, _) = self.token {
|
||||||
|
if !self.token.is_reserved_ident() && self.look_ahead(1, |t| *t == token::Colon) {
|
||||||
|
// Use in case of error after field-looking code: `S { foo: () with a }`
|
||||||
|
let mut ident = ident.clone();
|
||||||
|
ident.span = self.span;
|
||||||
|
recovery_field = Some(ast::Field {
|
||||||
|
ident,
|
||||||
|
span: self.span,
|
||||||
|
expr: self.mk_expr(self.span, ExprKind::Err, ThinVec::new()),
|
||||||
|
is_shorthand: false,
|
||||||
|
attrs: ThinVec::new(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut parsed_field = None;
|
||||||
match self.parse_field() {
|
match self.parse_field() {
|
||||||
Ok(f) => fields.push(f),
|
Ok(f) => parsed_field = Some(f),
|
||||||
Err(mut e) => {
|
Err(mut e) => {
|
||||||
e.span_label(struct_sp, "while parsing this struct");
|
e.span_label(struct_sp, "while parsing this struct");
|
||||||
e.emit();
|
e.emit();
|
||||||
|
@ -2666,19 +2721,28 @@ impl<'a> Parser<'a> {
|
||||||
// what comes next as additional fields, rather than
|
// what comes next as additional fields, rather than
|
||||||
// bailing out until next `}`.
|
// bailing out until next `}`.
|
||||||
if self.token != token::Comma {
|
if self.token != token::Comma {
|
||||||
self.recover_stmt();
|
self.recover_stmt_(SemiColonMode::Comma, BlockMode::Ignore);
|
||||||
break;
|
if self.token != token::Comma {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
match self.expect_one_of(&[token::Comma],
|
match self.expect_one_of(&[token::Comma],
|
||||||
&[token::CloseDelim(token::Brace)]) {
|
&[token::CloseDelim(token::Brace)]) {
|
||||||
Ok(()) => {}
|
Ok(()) => if let Some(f) = parsed_field.or(recovery_field) {
|
||||||
|
// only include the field if there's no parse error for the field name
|
||||||
|
fields.push(f);
|
||||||
|
}
|
||||||
Err(mut e) => {
|
Err(mut e) => {
|
||||||
|
if let Some(f) = recovery_field {
|
||||||
|
fields.push(f);
|
||||||
|
}
|
||||||
|
e.span_label(struct_sp, "while parsing this struct");
|
||||||
e.emit();
|
e.emit();
|
||||||
self.recover_stmt();
|
self.recover_stmt_(SemiColonMode::Comma, BlockMode::Ignore);
|
||||||
break;
|
self.eat(&token::Comma);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4542,13 +4606,13 @@ impl<'a> Parser<'a> {
|
||||||
token::CloseDelim(token::DelimToken::Brace) => {
|
token::CloseDelim(token::DelimToken::Brace) => {
|
||||||
if brace_depth == 0 {
|
if brace_depth == 0 {
|
||||||
debug!("recover_stmt_ return - close delim {:?}", self.token);
|
debug!("recover_stmt_ return - close delim {:?}", self.token);
|
||||||
return;
|
break;
|
||||||
}
|
}
|
||||||
brace_depth -= 1;
|
brace_depth -= 1;
|
||||||
self.bump();
|
self.bump();
|
||||||
if in_block && bracket_depth == 0 && brace_depth == 0 {
|
if in_block && bracket_depth == 0 && brace_depth == 0 {
|
||||||
debug!("recover_stmt_ return - block end {:?}", self.token);
|
debug!("recover_stmt_ return - block end {:?}", self.token);
|
||||||
return;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
token::CloseDelim(token::DelimToken::Bracket) => {
|
token::CloseDelim(token::DelimToken::Bracket) => {
|
||||||
|
@ -4560,7 +4624,7 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
token::Eof => {
|
token::Eof => {
|
||||||
debug!("recover_stmt_ return - Eof");
|
debug!("recover_stmt_ return - Eof");
|
||||||
return;
|
break;
|
||||||
}
|
}
|
||||||
token::Semi => {
|
token::Semi => {
|
||||||
self.bump();
|
self.bump();
|
||||||
|
@ -4568,7 +4632,17 @@ impl<'a> Parser<'a> {
|
||||||
brace_depth == 0 &&
|
brace_depth == 0 &&
|
||||||
bracket_depth == 0 {
|
bracket_depth == 0 {
|
||||||
debug!("recover_stmt_ return - Semi");
|
debug!("recover_stmt_ return - Semi");
|
||||||
return;
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
token::Comma => {
|
||||||
|
if break_on_semi == SemiColonMode::Comma &&
|
||||||
|
brace_depth == 0 &&
|
||||||
|
bracket_depth == 0 {
|
||||||
|
debug!("recover_stmt_ return - Semi");
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
self.bump();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
|
12
src/test/ui/issues/issue-52496.rs
Normal file
12
src/test/ui/issues/issue-52496.rs
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
struct Foo { bar: f64, baz: i64, bat: i64 }
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let _ = Foo { bar: .5, baz: 42 };
|
||||||
|
//~^ ERROR float literals must have an integer part
|
||||||
|
//~| ERROR missing field `bat` in initializer of `Foo`
|
||||||
|
let bar = 1.5f32;
|
||||||
|
let _ = Foo { bar.into(), bat: -1, . };
|
||||||
|
//~^ ERROR expected one of
|
||||||
|
//~| ERROR missing fields `bar`, `baz` in initializer of `Foo`
|
||||||
|
//~| ERROR expected identifier, found `.`
|
||||||
|
}
|
37
src/test/ui/issues/issue-52496.stderr
Normal file
37
src/test/ui/issues/issue-52496.stderr
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
error: float literals must have an integer part
|
||||||
|
--> $DIR/issue-52496.rs:4:24
|
||||||
|
|
|
||||||
|
LL | let _ = Foo { bar: .5, baz: 42 };
|
||||||
|
| ^^ help: must have an integer part: `0.5`
|
||||||
|
|
||||||
|
error: expected one of `,` or `}`, found `.`
|
||||||
|
--> $DIR/issue-52496.rs:8:22
|
||||||
|
|
|
||||||
|
LL | let _ = Foo { bar.into(), bat: -1, . };
|
||||||
|
| --- ^ expected one of `,` or `}` here
|
||||||
|
| |
|
||||||
|
| while parsing this struct
|
||||||
|
|
||||||
|
error: expected identifier, found `.`
|
||||||
|
--> $DIR/issue-52496.rs:8:40
|
||||||
|
|
|
||||||
|
LL | let _ = Foo { bar.into(), bat: -1, . };
|
||||||
|
| --- ^ expected identifier
|
||||||
|
| |
|
||||||
|
| while parsing this struct
|
||||||
|
|
||||||
|
error[E0063]: missing field `bat` in initializer of `Foo`
|
||||||
|
--> $DIR/issue-52496.rs:4:13
|
||||||
|
|
|
||||||
|
LL | let _ = Foo { bar: .5, baz: 42 };
|
||||||
|
| ^^^ missing `bat`
|
||||||
|
|
||||||
|
error[E0063]: missing fields `bar`, `baz` in initializer of `Foo`
|
||||||
|
--> $DIR/issue-52496.rs:8:13
|
||||||
|
|
|
||||||
|
LL | let _ = Foo { bar.into(), bat: -1, . };
|
||||||
|
| ^^^ missing `bar`, `baz`
|
||||||
|
|
||||||
|
error: aborting due to 5 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0063`.
|
|
@ -5,7 +5,6 @@ fn main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
let a = S { foo: (), bar: () };
|
let a = S { foo: (), bar: () };
|
||||||
let b = S { foo: () with a };
|
let b = S { foo: () with a, bar: () };
|
||||||
//~^ ERROR expected one of `,`, `.`, `?`, `}`, or an operator, found `with`
|
//~^ ERROR expected one of `,`, `.`, `?`, `}`, or an operator, found `with`
|
||||||
//~| ERROR missing field `bar` in initializer of `main::S`
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,10 @@
|
||||||
error: expected one of `,`, `.`, `?`, `}`, or an operator, found `with`
|
error: expected one of `,`, `.`, `?`, `}`, or an operator, found `with`
|
||||||
--> $DIR/removed-syntax-with-1.rs:8:25
|
--> $DIR/removed-syntax-with-1.rs:8:25
|
||||||
|
|
|
|
||||||
LL | let b = S { foo: () with a };
|
LL | let b = S { foo: () with a, bar: () };
|
||||||
| ^^^^ expected one of `,`, `.`, `?`, `}`, or an operator here
|
| - ^^^^ expected one of `,`, `.`, `?`, `}`, or an operator here
|
||||||
|
| |
|
||||||
|
| while parsing this struct
|
||||||
|
|
||||||
error[E0063]: missing field `bar` in initializer of `main::S`
|
error: aborting due to previous error
|
||||||
--> $DIR/removed-syntax-with-1.rs:8:13
|
|
||||||
|
|
|
||||||
LL | let b = S { foo: () with a };
|
|
||||||
| ^ missing `bar`
|
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0063`.
|
|
||||||
|
|
|
@ -7,6 +7,5 @@ fn main() {
|
||||||
let a = S { foo: (), bar: () };
|
let a = S { foo: (), bar: () };
|
||||||
let b = S { foo: (), with a };
|
let b = S { foo: (), with a };
|
||||||
//~^ ERROR expected one of `,` or `}`, found `a`
|
//~^ ERROR expected one of `,` or `}`, found `a`
|
||||||
//~| ERROR cannot find value `with` in this scope
|
//~| ERROR missing field `bar` in initializer of `main::S`
|
||||||
//~| ERROR struct `main::S` has no field named `with`
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,23 +2,16 @@ error: expected one of `,` or `}`, found `a`
|
||||||
--> $DIR/removed-syntax-with-2.rs:8:31
|
--> $DIR/removed-syntax-with-2.rs:8:31
|
||||||
|
|
|
|
||||||
LL | let b = S { foo: (), with a };
|
LL | let b = S { foo: (), with a };
|
||||||
| ^ expected one of `,` or `}` here
|
| - ^ expected one of `,` or `}` here
|
||||||
|
| |
|
||||||
|
| while parsing this struct
|
||||||
|
|
||||||
error[E0425]: cannot find value `with` in this scope
|
error[E0063]: missing field `bar` in initializer of `main::S`
|
||||||
--> $DIR/removed-syntax-with-2.rs:8:26
|
--> $DIR/removed-syntax-with-2.rs:8:13
|
||||||
|
|
|
|
||||||
LL | let b = S { foo: (), with a };
|
LL | let b = S { foo: (), with a };
|
||||||
| ^^^^ not found in this scope
|
| ^ missing `bar`
|
||||||
|
|
||||||
error[E0560]: struct `main::S` has no field named `with`
|
error: aborting due to 2 previous errors
|
||||||
--> $DIR/removed-syntax-with-2.rs:8:26
|
|
||||||
|
|
|
||||||
LL | let b = S { foo: (), with a };
|
|
||||||
| ^^^^ `main::S` does not have this field
|
|
||||||
|
|
|
||||||
= note: available fields are: `foo`, `bar`
|
|
||||||
|
|
||||||
error: aborting due to 3 previous errors
|
For more information about this error, try `rustc --explain E0063`.
|
||||||
|
|
||||||
Some errors occurred: E0425, E0560.
|
|
||||||
For more information about an error, try `rustc --explain E0425`.
|
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
struct Rgb(u8, u8, u8);
|
struct Rgb(u8, u8, u8);
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let _ = Rgb { 0, 1, 2 }; //~ ERROR expected identifier, found `0`
|
let _ = Rgb { 0, 1, 2 };
|
||||||
//~| ERROR missing fields `0`, `1`, `2` in initializer of `Rgb`
|
//~^ ERROR expected identifier, found `0`
|
||||||
|
//~| ERROR expected identifier, found `1`
|
||||||
|
//~| ERROR expected identifier, found `2`
|
||||||
|
//~| ERROR missing fields `0`, `1`, `2` in initializer of `Rgb`
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +1,33 @@
|
||||||
error: expected identifier, found `0`
|
error: expected identifier, found `0`
|
||||||
--> $DIR/struct-field-numeric-shorthand.rs:4:19
|
--> $DIR/struct-field-numeric-shorthand.rs:4:19
|
||||||
|
|
|
|
||||||
LL | let _ = Rgb { 0, 1, 2 }; //~ ERROR expected identifier, found `0`
|
LL | let _ = Rgb { 0, 1, 2 };
|
||||||
| --- ^ expected identifier
|
| --- ^ expected identifier
|
||||||
| |
|
| |
|
||||||
| while parsing this struct
|
| while parsing this struct
|
||||||
|
|
||||||
|
error: expected identifier, found `1`
|
||||||
|
--> $DIR/struct-field-numeric-shorthand.rs:4:22
|
||||||
|
|
|
||||||
|
LL | let _ = Rgb { 0, 1, 2 };
|
||||||
|
| --- ^ expected identifier
|
||||||
|
| |
|
||||||
|
| while parsing this struct
|
||||||
|
|
||||||
|
error: expected identifier, found `2`
|
||||||
|
--> $DIR/struct-field-numeric-shorthand.rs:4:25
|
||||||
|
|
|
||||||
|
LL | let _ = Rgb { 0, 1, 2 };
|
||||||
|
| --- ^ expected identifier
|
||||||
|
| |
|
||||||
|
| while parsing this struct
|
||||||
|
|
||||||
error[E0063]: missing fields `0`, `1`, `2` in initializer of `Rgb`
|
error[E0063]: missing fields `0`, `1`, `2` in initializer of `Rgb`
|
||||||
--> $DIR/struct-field-numeric-shorthand.rs:4:13
|
--> $DIR/struct-field-numeric-shorthand.rs:4:13
|
||||||
|
|
|
|
||||||
LL | let _ = Rgb { 0, 1, 2 }; //~ ERROR expected identifier, found `0`
|
LL | let _ = Rgb { 0, 1, 2 };
|
||||||
| ^^^ missing `0`, `1`, `2`
|
| ^^^ missing `0`, `1`, `2`
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error: aborting due to 4 previous errors
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0063`.
|
For more information about this error, try `rustc --explain E0063`.
|
||||||
|
|
11
src/test/ui/suggestions/recover-invalid-float.rs
Normal file
11
src/test/ui/suggestions/recover-invalid-float.rs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
fn main() {
|
||||||
|
let _: usize = .3;
|
||||||
|
//~^ ERROR float literals must have an integer part
|
||||||
|
//~| ERROR mismatched types
|
||||||
|
let _: usize = .42f32;
|
||||||
|
//~^ ERROR float literals must have an integer part
|
||||||
|
//~| ERROR mismatched types
|
||||||
|
let _: usize = .5f64;
|
||||||
|
//~^ ERROR float literals must have an integer part
|
||||||
|
//~| ERROR mismatched types
|
||||||
|
}
|
42
src/test/ui/suggestions/recover-invalid-float.stderr
Normal file
42
src/test/ui/suggestions/recover-invalid-float.stderr
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
error: float literals must have an integer part
|
||||||
|
--> $DIR/recover-invalid-float.rs:2:20
|
||||||
|
|
|
||||||
|
LL | let _: usize = .3;
|
||||||
|
| ^^ help: must have an integer part: `0.3`
|
||||||
|
|
||||||
|
error: float literals must have an integer part
|
||||||
|
--> $DIR/recover-invalid-float.rs:5:20
|
||||||
|
|
|
||||||
|
LL | let _: usize = .42f32;
|
||||||
|
| ^^^^^^ help: must have an integer part: `0.42f32`
|
||||||
|
|
||||||
|
error: float literals must have an integer part
|
||||||
|
--> $DIR/recover-invalid-float.rs:8:20
|
||||||
|
|
|
||||||
|
LL | let _: usize = .5f64;
|
||||||
|
| ^^^^^ help: must have an integer part: `0.5f64`
|
||||||
|
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/recover-invalid-float.rs:2:20
|
||||||
|
|
|
||||||
|
LL | let _: usize = .3;
|
||||||
|
| ^^ expected usize, found floating-point number
|
||||||
|
|
|
||||||
|
= note: expected type `usize`
|
||||||
|
found type `{float}`
|
||||||
|
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/recover-invalid-float.rs:5:20
|
||||||
|
|
|
||||||
|
LL | let _: usize = .42f32;
|
||||||
|
| ^^^^^^ expected usize, found f32
|
||||||
|
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/recover-invalid-float.rs:8:20
|
||||||
|
|
|
||||||
|
LL | let _: usize = .5f64;
|
||||||
|
| ^^^^^ expected usize, found f64
|
||||||
|
|
||||||
|
error: aborting due to 6 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0308`.
|
Loading…
Add table
Add a link
Reference in a new issue