Skip to content

Commit aaf3e31

Browse files
committed
Do not emit type errors on recovered blocks
When a parse error occurs on a block, the parser will recover and create a block with the statements collected until that point. Now a flag stating that a recovery has been performed in this block is propagated so that the type checker knows that the type of the block (which will be identified as `()`) shouldn't be checked against the expectation to reduce the amount of irrelevant diagnostic errors shown to the user.
1 parent b7b52cc commit aaf3e31

25 files changed

+111
-40
lines changed

src/librustc/diagnostics.rs

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -359,18 +359,21 @@ lifetime elision rules (see below).
359359
Here are some simple examples of where you'll run into this error:
360360
361361
```compile_fail,E0106
362-
struct Foo { x: &bool } // error
363-
struct Foo<'a> { x: &'a bool } // correct
362+
struct Foo1 { x: &bool }
363+
// ^ expected lifetime parameter
364+
struct Foo2<'a> { x: &'a bool } // correct
364365
365-
struct Bar { x: Foo }
366-
^^^ expected lifetime parameter
367-
struct Bar<'a> { x: Foo<'a> } // correct
366+
struct Bar1 { x: Foo2 }
367+
// ^^^^ expected lifetime parameter
368+
struct Bar2<'a> { x: Foo2<'a> } // correct
368369
369-
enum Bar { A(u8), B(&bool), } // error
370-
enum Bar<'a> { A(u8), B(&'a bool), } // correct
370+
enum Baz1 { A(u8), B(&bool), }
371+
// ^ expected lifetime parameter
372+
enum Baz2<'a> { A(u8), B(&'a bool), } // correct
371373
372-
type MyStr = &str; // error
373-
type MyStr<'a> = &'a str; // correct
374+
type MyStr1 = &str;
375+
// ^ expected lifetime parameter
376+
type MyStr2<'a> = &'a str; // correct
374377
```
375378
376379
Lifetime elision is a special, limited kind of inference for lifetimes in

src/librustc/hir/lowering.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1835,6 +1835,7 @@ impl<'a> LoweringContext<'a> {
18351835
rules: self.lower_block_check_mode(&b.rules),
18361836
span: b.span,
18371837
targeted_by_break,
1838+
recovered: b.recovered,
18381839
})
18391840
}
18401841

@@ -2691,6 +2692,7 @@ impl<'a> LoweringContext<'a> {
26912692
rules: hir::DefaultBlock,
26922693
span,
26932694
targeted_by_break: false,
2695+
recovered: blk.recovered,
26942696
});
26952697
P(self.expr_block(blk, ThinVec::new()))
26962698
}
@@ -3507,6 +3509,7 @@ impl<'a> LoweringContext<'a> {
35073509
rules: hir::DefaultBlock,
35083510
span,
35093511
targeted_by_break: false,
3512+
recovered: false,
35103513
}
35113514
}
35123515

@@ -3610,6 +3613,7 @@ impl<'a> LoweringContext<'a> {
36103613
stmts,
36113614
expr: Some(expr),
36123615
targeted_by_break: false,
3616+
recovered: false,
36133617
});
36143618
self.expr_block(block, attrs)
36153619
}

src/librustc/hir/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -625,6 +625,11 @@ pub struct Block {
625625
/// currently permitted in Rust itself, but it is generated as
626626
/// part of `catch` statements.
627627
pub targeted_by_break: bool,
628+
/// If true, don't emit return value type errors as the parser had
629+
/// to recover from a parse error so this block will not have an
630+
/// appropriate type. A parse error will have been emitted so the
631+
/// compilation will never succeed if this is true.
632+
pub recovered: bool,
628633
}
629634

630635
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash)]

src/librustc/ich/impls_hir.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -378,12 +378,14 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::Block {
378378
rules,
379379
span,
380380
targeted_by_break,
381+
recovered,
381382
} = *self;
382383

383384
stmts.hash_stable(hcx, hasher);
384385
expr.hash_stable(hcx, hasher);
385386
rules.hash_stable(hcx, hasher);
386387
span.hash_stable(hcx, hasher);
388+
recovered.hash_stable(hcx, hasher);
387389
targeted_by_break.hash_stable(hcx, hasher);
388390
}
389391
}

src/librustc_driver/pretty.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -729,6 +729,7 @@ impl<'a> fold::Folder for ReplaceBodyWithLoop<'a> {
729729

730730
fn fold_block(&mut self, b: P<ast::Block>) -> P<ast::Block> {
731731
fn expr_to_block(rules: ast::BlockCheckMode,
732+
recovered: bool,
732733
e: Option<P<ast::Expr>>,
733734
sess: &Session) -> P<ast::Block> {
734735
P(ast::Block {
@@ -744,20 +745,21 @@ impl<'a> fold::Folder for ReplaceBodyWithLoop<'a> {
744745
rules,
745746
id: sess.next_node_id(),
746747
span: syntax_pos::DUMMY_SP,
748+
recovered,
747749
})
748750
}
749751

750752
if !self.within_static_or_const {
751753

752-
let empty_block = expr_to_block(BlockCheckMode::Default, None, self.sess);
754+
let empty_block = expr_to_block(BlockCheckMode::Default, false, None, self.sess);
753755
let loop_expr = P(ast::Expr {
754756
node: ast::ExprKind::Loop(empty_block, None),
755757
id: self.sess.next_node_id(),
756758
span: syntax_pos::DUMMY_SP,
757759
attrs: ast::ThinVec::new(),
758760
});
759761

760-
expr_to_block(b.rules, Some(loop_expr), self.sess)
762+
expr_to_block(b.rules, b.recovered, Some(loop_expr), self.sess)
761763

762764
} else {
763765
fold::noop_fold_block(b, self)

src/librustc_typeck/check/mod.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4279,7 +4279,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
42794279
//
42804280
// #41425 -- label the implicit `()` as being the
42814281
// "found type" here, rather than the "expected type".
4282-
if !self.diverges.get().always() {
4282+
//
4283+
// #44579 -- if the block was recovered during parsing,
4284+
// the type would be nonsensical and it is not worth it
4285+
// to perform the type check, so we avoid generating the
4286+
// diagnostic output.
4287+
if !self.diverges.get().always() && !blk.recovered {
42834288
coerce.coerce_forced_unit(self, &self.misc(blk.span), &mut |err| {
42844289
if let Some(expected_ty) = expected.only_has_type(self) {
42854290
self.consider_hint_about_removing_semicolon(blk,

src/libsyntax/ast.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,7 @@ pub struct Block {
468468
/// Distinguishes between `unsafe { ... }` and `{ ... }`
469469
pub rules: BlockCheckMode,
470470
pub span: Span,
471+
pub recovered: bool,
471472
}
472473

473474
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash)]

src/libsyntax/ext/build.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -594,6 +594,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
594594
id: ast::DUMMY_NODE_ID,
595595
rules: BlockCheckMode::Default,
596596
span,
597+
recovered: false,
597598
})
598599
}
599600

src/libsyntax/fold.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -851,11 +851,12 @@ fn noop_fold_bounds<T: Folder>(bounds: TyParamBounds, folder: &mut T)
851851
}
852852

853853
pub fn noop_fold_block<T: Folder>(b: P<Block>, folder: &mut T) -> P<Block> {
854-
b.map(|Block {id, stmts, rules, span}| Block {
854+
b.map(|Block {id, stmts, rules, span, recovered}| Block {
855855
id: folder.new_id(id),
856856
stmts: stmts.move_flat_map(|s| folder.fold_stmt(s).into_iter()),
857857
rules,
858858
span: folder.new_span(span),
859+
recovered,
859860
})
860861
}
861862

src/libsyntax/parse/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -931,6 +931,7 @@ mod tests {
931931
id: ast::DUMMY_NODE_ID,
932932
rules: ast::BlockCheckMode::Default, // no idea
933933
span: sp(15,21),
934+
recovered: false,
934935
})),
935936
vis: ast::Visibility::Inherited,
936937
span: sp(0,21)})));

src/libsyntax/parse/parser.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4371,13 +4371,15 @@ impl<'a> Parser<'a> {
43714371
/// Precondition: already parsed the '{'.
43724372
fn parse_block_tail(&mut self, lo: Span, s: BlockCheckMode) -> PResult<'a, P<Block>> {
43734373
let mut stmts = vec![];
4374+
let mut recovered = false;
43744375

43754376
while !self.eat(&token::CloseDelim(token::Brace)) {
43764377
let stmt = match self.parse_full_stmt(false) {
43774378
Err(mut err) => {
43784379
err.emit();
4379-
self.recover_stmt_(SemiColonMode::Ignore, BlockMode::Break);
4380+
self.recover_stmt_(SemiColonMode::Ignore, BlockMode::Ignore);
43804381
self.eat(&token::CloseDelim(token::Brace));
4382+
recovered = true;
43814383
break;
43824384
}
43834385
Ok(stmt) => stmt,
@@ -4396,12 +4398,13 @@ impl<'a> Parser<'a> {
43964398
id: ast::DUMMY_NODE_ID,
43974399
rules: s,
43984400
span: lo.to(self.prev_span),
4401+
recovered,
43994402
}))
44004403
}
44014404

44024405
/// Parse a statement, including the trailing semicolon.
44034406
pub fn parse_full_stmt(&mut self, macro_legacy_warnings: bool) -> PResult<'a, Option<Stmt>> {
4404-
let mut stmt = match self.parse_stmt_(macro_legacy_warnings) {
4407+
let mut stmt = match self.parse_stmt_without_recovery(macro_legacy_warnings)? {
44054408
Some(stmt) => stmt,
44064409
None => return Ok(None),
44074410
};

src/libsyntax_ext/deriving/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,5 +158,6 @@ fn call_intrinsic(cx: &ExtCtxt,
158158
id: ast::DUMMY_NODE_ID,
159159
rules: ast::BlockCheckMode::Unsafe(ast::CompilerGenerated),
160160
span,
161+
recovered: false,
161162
}))
162163
}

src/test/compile-fail/issue-34334.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,4 @@
1111
fn main () {
1212
let sr: Vec<(u32, _, _) = vec![]; //~ ERROR expected one of `,` or `>`, found `=`
1313
let sr2: Vec<(u32, _, _)> = sr.iter().map(|(faction, th_sender, th_receiver)| {}).collect();
14-
//~^ ERROR cannot find value `sr` in this scope
1514
}

src/test/parse-fail/issue-22647.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ fn main() {
1616
println!("Y {}",x);
1717
return x;
1818
};
19-
//~^ ERROR expected item, found `;`
2019

2120
caller(bar_handler);
2221
}

src/test/parse-fail/keywords-followed-by-double-colon.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@
1111
// compile-flags: -Z parse-only
1212

1313
fn main() {
14-
struct::foo(); //~ ERROR expected identifier
15-
mut::baz(); //~ ERROR expected expression, found keyword `mut`
14+
struct::foo();
15+
//~^ ERROR expected identifier
16+
}
17+
fn bar() {
18+
mut::baz();
19+
//~^ ERROR expected expression, found keyword `mut`
1620
}

src/test/parse-fail/mut-patterns.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,4 @@
1515
pub fn main() {
1616
struct Foo { x: isize }
1717
let mut Foo { x: x } = Foo { x: 3 }; //~ ERROR: expected one of `:`, `;`, `=`, or `@`, found `{`
18-
//~^ ERROR expected item, found `=`
1918
}

src/test/run-pass-fulldeps/pprust-expr-roundtrip.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ fn iter_exprs(depth: usize, f: &mut FnMut(P<Expr>)) {
131131
id: DUMMY_NODE_ID,
132132
rules: BlockCheckMode::Default,
133133
span: DUMMY_SP,
134+
recovered: false,
134135
});
135136
iter_exprs(depth - 1, &mut |e| g(ExprKind::If(e, block.clone(), None)));
136137
},

src/test/ui/impossible_range.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,13 @@ pub fn main() {
1717
0..;
1818
..1;
1919
0..1;
20-
2120
..=; //~ERROR inclusive range with no end
22-
0..=; //~ERROR inclusive range with no end
21+
//~^HELP bounded at the end
22+
}
23+
24+
fn _foo1() {
2325
..=1;
2426
0..=1;
27+
0..=; //~ERROR inclusive range with no end
28+
//~^HELP bounded at the end
2529
}
26-
27-

src/test/ui/impossible_range.stderr

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
error[E0586]: inclusive range with no end
2-
--> $DIR/impossible_range.rs:21:8
2+
--> $DIR/impossible_range.rs:20:8
33
|
4-
21 | ..=; //~ERROR inclusive range with no end
4+
20 | ..=; //~ERROR inclusive range with no end
55
| ^
66
|
77
= help: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
88

99
error[E0586]: inclusive range with no end
10-
--> $DIR/impossible_range.rs:22:9
10+
--> $DIR/impossible_range.rs:27:9
1111
|
12-
22 | 0..=; //~ERROR inclusive range with no end
12+
27 | 0..=; //~ERROR inclusive range with no end
1313
| ^
1414
|
1515
= help: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)

src/test/ui/issue-44406.stderr

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,3 @@ error: expected type, found keyword `true`
1313
18 | foo!(true); //~ ERROR expected type, found keyword
1414
| ^^^^ expecting a type here because of type ascription
1515

16-
error: aborting due to 2 previous errors
17-

src/test/ui/macro-context.stderr

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,5 +43,3 @@ error: expected expression, found reserved keyword `typeof`
4343
26 | m!();
4444
| ----- in this macro invocation
4545

46-
error: aborting due to 4 previous errors
47-
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use std::env;
12+
13+
pub struct Foo {
14+
text: String
15+
}
16+
17+
pub fn foo() -> Foo {
18+
let args: Vec<String> = env::args().collect();
19+
let text = args[1].clone();
20+
21+
pub Foo { text }
22+
}
23+
//~^^ ERROR missing `struct` for struct definition
24+
25+
pub fn bar() -> Foo {
26+
fn
27+
Foo { text: "".to_string() }
28+
}
29+
//~^^ ERROR expected one of `(` or `<`, found `{`
30+
31+
fn main() {}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
error: missing `struct` for struct definition
2+
--> $DIR/recovered-block.rs:21:8
3+
|
4+
21 | pub Foo { text }
5+
| ^
6+
help: add `struct` here to parse `Foo` as a public struct
7+
|
8+
21 | pub struct Foo { text }
9+
| ^^^^^^
10+
11+
error: expected one of `(` or `<`, found `{`
12+
--> $DIR/recovered-block.rs:27:9
13+
|
14+
27 | Foo { text: "".to_string() }
15+
| ^ expected one of `(` or `<` here
16+
17+
error: aborting due to 2 previous errors
18+

src/test/ui/resolve/token-error-correct.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,3 @@ fn main() {
1616
}
1717
//~^ ERROR: incorrect close delimiter: `}`
1818
//~| ERROR: incorrect close delimiter: `}`
19-
//~| ERROR: expected expression, found `)`

src/test/ui/resolve/token-error-correct.stderr

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,5 @@ error: expected expression, found `;`
2828
14 | foo(bar(;
2929
| ^
3030

31-
error: expected expression, found `)`
32-
--> $DIR/token-error-correct.rs:16:1
33-
|
34-
16 | }
35-
| ^
36-
37-
error: aborting due to 4 previous errors
31+
error: aborting due to 3 previous errors
3832

0 commit comments

Comments
 (0)