]> git.lizzy.rs Git - rust.git/commitdiff
Do not emit type errors on recovered blocks
authorEsteban Küber <esteban@kuber.com.ar>
Thu, 14 Dec 2017 07:05:49 +0000 (23:05 -0800)
committerEsteban Küber <esteban@kuber.com.ar>
Thu, 21 Dec 2017 22:57:42 +0000 (14:57 -0800)
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.

25 files changed:
src/librustc/diagnostics.rs
src/librustc/hir/lowering.rs
src/librustc/hir/mod.rs
src/librustc/ich/impls_hir.rs
src/librustc_driver/pretty.rs
src/librustc_typeck/check/mod.rs
src/libsyntax/ast.rs
src/libsyntax/ext/build.rs
src/libsyntax/fold.rs
src/libsyntax/parse/mod.rs
src/libsyntax/parse/parser.rs
src/libsyntax_ext/deriving/mod.rs
src/test/compile-fail/issue-34334.rs
src/test/parse-fail/issue-22647.rs
src/test/parse-fail/keywords-followed-by-double-colon.rs
src/test/parse-fail/mut-patterns.rs
src/test/run-pass-fulldeps/pprust-expr-roundtrip.rs
src/test/ui/impossible_range.rs
src/test/ui/impossible_range.stderr
src/test/ui/issue-44406.stderr
src/test/ui/macro-context.stderr
src/test/ui/mismatched_types/recovered-block.rs [new file with mode: 0644]
src/test/ui/mismatched_types/recovered-block.stderr [new file with mode: 0644]
src/test/ui/resolve/token-error-correct.rs
src/test/ui/resolve/token-error-correct.stderr

index 85ae529ae329a62cb152aa068563f1c4a9837d3a..7b48e7801dfb1bf6bd2865328c3f15c97522bf36 100644 (file)
@@ -359,18 +359,21 @@ enum Enum {
 Here are some simple examples of where you'll run into this error:
 
 ```compile_fail,E0106
-struct Foo { x: &bool }        // error
-struct Foo<'a> { x: &'a bool } // correct
+struct Foo1 { x: &bool }
+              // ^ expected lifetime parameter
+struct Foo2<'a> { x: &'a bool } // correct
 
-struct Bar { x: Foo }
-               ^^^ expected lifetime parameter
-struct Bar<'a> { x: Foo<'a> } // correct
+struct Bar1 { x: Foo2 }
+              // ^^^^ expected lifetime parameter
+struct Bar2<'a> { x: Foo2<'a> } // correct
 
-enum Bar { A(u8), B(&bool), }        // error
-enum Bar<'a> { A(u8), B(&'a bool), } // correct
+enum Baz1 { A(u8), B(&bool), }
+                  // ^ expected lifetime parameter
+enum Baz2<'a> { A(u8), B(&'a bool), } // correct
 
-type MyStr = &str;        // error
-type MyStr<'a> = &'a str; // correct
+type MyStr1 = &str;
+           // ^ expected lifetime parameter
+type MyStr2<'a> = &'a str; // correct
 ```
 
 Lifetime elision is a special, limited kind of inference for lifetimes in
index 847cf64ce6a031f75cdae383ca9cec0e3cd37dc5..ece239516cfbcc3209f2e7ac22317084e6f9071f 100644 (file)
@@ -1835,6 +1835,7 @@ fn lower_block(&mut self, b: &Block, targeted_by_break: bool) -> P<hir::Block> {
             rules: self.lower_block_check_mode(&b.rules),
             span: b.span,
             targeted_by_break,
+            recovered: b.recovered,
         })
     }
 
@@ -2691,6 +2692,7 @@ fn lower_expr(&mut self, e: &Expr) -> hir::Expr {
                                 rules: hir::DefaultBlock,
                                 span,
                                 targeted_by_break: false,
+                                recovered: blk.recovered,
                             });
                             P(self.expr_block(blk, ThinVec::new()))
                         }
@@ -3507,6 +3509,7 @@ fn block_all(&mut self, span: Span, stmts: hir::HirVec<hir::Stmt>, expr: Option<
             rules: hir::DefaultBlock,
             span,
             targeted_by_break: false,
+            recovered: false,
         }
     }
 
@@ -3610,6 +3613,7 @@ fn signal_block_expr(&mut self,
             stmts,
             expr: Some(expr),
             targeted_by_break: false,
+            recovered: false,
         });
         self.expr_block(block, attrs)
     }
index 5e132865ca87d020e76ffc32e056434a75eb865f..144a3fea971143d6b0ef4dc101b5d22adeefeaa4 100644 (file)
@@ -625,6 +625,11 @@ pub struct Block {
     /// currently permitted in Rust itself, but it is generated as
     /// part of `catch` statements.
     pub targeted_by_break: bool,
+    /// If true, don't emit return value type errors as the parser had
+    /// to recover from a parse error so this block will not have an
+    /// appropriate type. A parse error will have been emitted so the
+    /// compilation will never succeed if this is true.
+    pub recovered: bool,
 }
 
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash)]
index 02a394f9634c2da4332fe78341536b311336825e..b0c7ce3cf2321b0be86e1e16855c30ab4dfbb0c1 100644 (file)
@@ -378,12 +378,14 @@ fn hash_stable<W: StableHasherResult>(&self,
             rules,
             span,
             targeted_by_break,
+            recovered,
         } = *self;
 
         stmts.hash_stable(hcx, hasher);
         expr.hash_stable(hcx, hasher);
         rules.hash_stable(hcx, hasher);
         span.hash_stable(hcx, hasher);
+        recovered.hash_stable(hcx, hasher);
         targeted_by_break.hash_stable(hcx, hasher);
     }
 }
index 769ade5dbcc54f08f76c56d94c1a98f04e248910..4b51a0fbb83a84002e3a7a008918248a91df1ee6 100644 (file)
@@ -729,6 +729,7 @@ fn fold_impl_item(&mut self, i: ast::ImplItem) -> SmallVector<ast::ImplItem> {
 
     fn fold_block(&mut self, b: P<ast::Block>) -> P<ast::Block> {
         fn expr_to_block(rules: ast::BlockCheckMode,
+                         recovered: bool,
                          e: Option<P<ast::Expr>>,
                          sess: &Session) -> P<ast::Block> {
             P(ast::Block {
@@ -744,12 +745,13 @@ fn expr_to_block(rules: ast::BlockCheckMode,
                 rules,
                 id: sess.next_node_id(),
                 span: syntax_pos::DUMMY_SP,
+                recovered,
             })
         }
 
         if !self.within_static_or_const {
 
-            let empty_block = expr_to_block(BlockCheckMode::Default, None, self.sess);
+            let empty_block = expr_to_block(BlockCheckMode::Default, false, None, self.sess);
             let loop_expr = P(ast::Expr {
                 node: ast::ExprKind::Loop(empty_block, None),
                 id: self.sess.next_node_id(),
@@ -757,7 +759,7 @@ fn expr_to_block(rules: ast::BlockCheckMode,
                 attrs: ast::ThinVec::new(),
             });
 
-            expr_to_block(b.rules, Some(loop_expr), self.sess)
+            expr_to_block(b.rules, b.recovered, Some(loop_expr), self.sess)
 
         } else {
             fold::noop_fold_block(b, self)
index 14296e78ddd1c6c2fa55777c4a2072f85beac2a9..ee0da4b8f36143b867a8c988dee70f7e75df3d1d 100644 (file)
@@ -4279,7 +4279,12 @@ fn check_block_with_expected(&self,
                 //
                 // #41425 -- label the implicit `()` as being the
                 // "found type" here, rather than the "expected type".
-                if !self.diverges.get().always() {
+                //
+                // #44579 -- if the block was recovered during parsing,
+                // the type would be nonsensical and it is not worth it
+                // to perform the type check, so we avoid generating the
+                // diagnostic output.
+                if !self.diverges.get().always() && !blk.recovered {
                     coerce.coerce_forced_unit(self, &self.misc(blk.span), &mut |err| {
                         if let Some(expected_ty) = expected.only_has_type(self) {
                             self.consider_hint_about_removing_semicolon(blk,
index 1d399f159c8153a01d18993cac6922fcd52635e9..a8bc8f7e0ce7f409c204fd1355c0cefbc9d4939d 100644 (file)
@@ -468,6 +468,7 @@ pub struct Block {
     /// Distinguishes between `unsafe { ... }` and `{ ... }`
     pub rules: BlockCheckMode,
     pub span: Span,
+    pub recovered: bool,
 }
 
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash)]
index 9a96432f11d4eacdc2ef5464a4d6589e6718693a..8aeebecf66139178c0fef6a2aaa8ae894c7d84d6 100644 (file)
@@ -594,6 +594,7 @@ fn block(&self, span: Span, stmts: Vec<ast::Stmt>) -> P<ast::Block> {
            id: ast::DUMMY_NODE_ID,
            rules: BlockCheckMode::Default,
            span,
+           recovered: false,
         })
     }
 
index 6f973e2bcfaef918da6388e0f6bfc592887e57b3..279add5d2991e50c56380b192a5b5f94273fe458 100644 (file)
@@ -851,11 +851,12 @@ fn noop_fold_bounds<T: Folder>(bounds: TyParamBounds, folder: &mut T)
 }
 
 pub fn noop_fold_block<T: Folder>(b: P<Block>, folder: &mut T) -> P<Block> {
-    b.map(|Block {id, stmts, rules, span}| Block {
+    b.map(|Block {id, stmts, rules, span, recovered}| Block {
         id: folder.new_id(id),
         stmts: stmts.move_flat_map(|s| folder.fold_stmt(s).into_iter()),
         rules,
         span: folder.new_span(span),
+        recovered,
     })
 }
 
index 89a54989f9693af1165c1006a2afd0a7119b3861..f96c7e8598f0bb580b41b8e97b44c932867d713e 100644 (file)
@@ -931,6 +931,7 @@ fn parser_done(p: Parser){
                                         id: ast::DUMMY_NODE_ID,
                                         rules: ast::BlockCheckMode::Default, // no idea
                                         span: sp(15,21),
+                                        recovered: false,
                                     })),
                             vis: ast::Visibility::Inherited,
                             span: sp(0,21)})));
index d943453924689f502788520f5f224c057a7a97cc..bb46cef5ee2a2ab0d27b5deb076f06242ea75443 100644 (file)
@@ -4371,13 +4371,15 @@ fn parse_inner_attrs_and_block(&mut self) -> PResult<'a, (Vec<Attribute>, P<Bloc
     /// Precondition: already parsed the '{'.
     fn parse_block_tail(&mut self, lo: Span, s: BlockCheckMode) -> PResult<'a, P<Block>> {
         let mut stmts = vec![];
+        let mut recovered = false;
 
         while !self.eat(&token::CloseDelim(token::Brace)) {
             let stmt = match self.parse_full_stmt(false) {
                 Err(mut err) => {
                     err.emit();
-                    self.recover_stmt_(SemiColonMode::Ignore, BlockMode::Break);
+                    self.recover_stmt_(SemiColonMode::Ignore, BlockMode::Ignore);
                     self.eat(&token::CloseDelim(token::Brace));
+                    recovered = true;
                     break;
                 }
                 Ok(stmt) => stmt,
@@ -4396,12 +4398,13 @@ fn parse_block_tail(&mut self, lo: Span, s: BlockCheckMode) -> PResult<'a, P<Blo
             id: ast::DUMMY_NODE_ID,
             rules: s,
             span: lo.to(self.prev_span),
+            recovered,
         }))
     }
 
     /// Parse a statement, including the trailing semicolon.
     pub fn parse_full_stmt(&mut self, macro_legacy_warnings: bool) -> PResult<'a, Option<Stmt>> {
-        let mut stmt = match self.parse_stmt_(macro_legacy_warnings) {
+        let mut stmt = match self.parse_stmt_without_recovery(macro_legacy_warnings)? {
             Some(stmt) => stmt,
             None => return Ok(None),
         };
index a6696b533694e9680946442030ac98389f73d741..a3246a21d5ab67935f805b1c249d2ab5e4438559 100644 (file)
@@ -158,5 +158,6 @@ fn call_intrinsic(cx: &ExtCtxt,
         id: ast::DUMMY_NODE_ID,
         rules: ast::BlockCheckMode::Unsafe(ast::CompilerGenerated),
         span,
+        recovered: false,
     }))
 }
index 95b5fabc81e4f0e2930023e38f4b2f237d098122..a752a36ade28d8d22cd4671db0453a8b18dffb19 100644 (file)
@@ -11,5 +11,4 @@
 fn main () {
     let sr: Vec<(u32, _, _) = vec![]; //~ ERROR expected one of `,` or `>`, found `=`
     let sr2: Vec<(u32, _, _)> = sr.iter().map(|(faction, th_sender, th_receiver)| {}).collect();
-    //~^ ERROR cannot find value `sr` in this scope
 }
index 3da9d1a8712ad0512aa4a41abd85dbe714d8a138..1ace57edba3d8152d5d7732f9ccace943e529747 100644 (file)
@@ -16,7 +16,6 @@ fn main() {
         println!("Y {}",x);
         return x;
     };
-    //~^ ERROR expected item, found `;`
 
     caller(bar_handler);
 }
index bb8a1dfdb19063485201351b6b11250080446486..7a5b48c5f004db2fd49e0c53b4dca6aa78be457d 100644 (file)
 // compile-flags: -Z parse-only
 
 fn main() {
-    struct::foo();  //~ ERROR expected identifier
-    mut::baz(); //~ ERROR expected expression, found keyword `mut`
+    struct::foo();
+    //~^ ERROR expected identifier
+}
+fn bar() {
+    mut::baz();
+    //~^ ERROR expected expression, found keyword `mut`
 }
index ffb455975521a6fd888a2eff1a82a015a81283e3..71d826c67f8bd6320130eb8047c3c9a7572f08ed 100644 (file)
@@ -15,5 +15,4 @@
 pub fn main() {
     struct Foo { x: isize }
     let mut Foo { x: x } = Foo { x: 3 }; //~ ERROR: expected one of `:`, `;`, `=`, or `@`, found `{`
-    //~^ ERROR expected item, found `=`
 }
index e84a982f7b3267a73e62aaf67201e6008192106f..5afa9a217e05c9d642ff032aa427896a62d634d6 100644 (file)
@@ -131,6 +131,7 @@ fn iter_exprs(depth: usize, f: &mut FnMut(P<Expr>)) {
                     id: DUMMY_NODE_ID,
                     rules: BlockCheckMode::Default,
                     span: DUMMY_SP,
+                    recovered: false,
                 });
                 iter_exprs(depth - 1, &mut |e| g(ExprKind::If(e, block.clone(), None)));
             },
index 330a9213bc71dbf2a5a296110777fa749a141129..5c72c506e6bf009fef18bf29071f984bb452d4a6 100644 (file)
@@ -17,11 +17,13 @@ pub fn main() {
     0..;
     ..1;
     0..1;
-
     ..=; //~ERROR inclusive range with no end
-    0..=; //~ERROR inclusive range with no end
+         //~^HELP bounded at the end
+}
+
+fn _foo1() {
     ..=1;
     0..=1;
+    0..=; //~ERROR inclusive range with no end
+          //~^HELP bounded at the end
 }
-
-
index 75c6d859621ab7d12a145c7c4f1fb9193e838512..e0e26bc4db040118edafaf3dacf50fba451f89e3 100644 (file)
@@ -1,15 +1,15 @@
 error[E0586]: inclusive range with no end
-  --> $DIR/impossible_range.rs:21:8
+  --> $DIR/impossible_range.rs:20:8
    |
-21 |     ..=; //~ERROR inclusive range with no end
+20 |     ..=; //~ERROR inclusive range with no end
    |        ^
    |
    = help: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
 
 error[E0586]: inclusive range with no end
-  --> $DIR/impossible_range.rs:22:9
+  --> $DIR/impossible_range.rs:27:9
    |
-22 |     0..=; //~ERROR inclusive range with no end
+27 |     0..=; //~ERROR inclusive range with no end
    |         ^
    |
    = help: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
index 2e71b001d7ac0402109da26aefb258a2ac89de20..dd6435a954eee7c9c1366b27099216f3afb1179e 100644 (file)
@@ -13,5 +13,3 @@ error: expected type, found keyword `true`
 18 |     foo!(true); //~ ERROR expected type, found keyword
    |          ^^^^ expecting a type here because of type ascription
 
-error: aborting due to 2 previous errors
-
index 37d99913d9795d98a97ee028c724b80aa7e698e7..2be89b67d11ba7a81bdd5e225319073c5a70dace 100644 (file)
@@ -43,5 +43,3 @@ error: expected expression, found reserved keyword `typeof`
 26 |     m!();
    |     ----- in this macro invocation
 
-error: aborting due to 4 previous errors
-
diff --git a/src/test/ui/mismatched_types/recovered-block.rs b/src/test/ui/mismatched_types/recovered-block.rs
new file mode 100644 (file)
index 0000000..f3e3579
--- /dev/null
@@ -0,0 +1,31 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::env;
+
+pub struct Foo {
+    text: String
+}
+
+pub fn foo() -> Foo {
+    let args: Vec<String> = env::args().collect();
+    let text = args[1].clone();
+
+    pub Foo { text }
+}
+//~^^ ERROR missing `struct` for struct definition
+
+pub fn bar() -> Foo {
+    fn
+    Foo { text: "".to_string() }
+}
+//~^^ ERROR expected one of `(` or `<`, found `{`
+
+fn main() {}
diff --git a/src/test/ui/mismatched_types/recovered-block.stderr b/src/test/ui/mismatched_types/recovered-block.stderr
new file mode 100644 (file)
index 0000000..dcaf281
--- /dev/null
@@ -0,0 +1,18 @@
+error: missing `struct` for struct definition
+  --> $DIR/recovered-block.rs:21:8
+   |
+21 |     pub Foo { text }
+   |        ^
+help: add `struct` here to parse `Foo` as a public struct
+   |
+21 |     pub struct Foo { text }
+   |         ^^^^^^
+
+error: expected one of `(` or `<`, found `{`
+  --> $DIR/recovered-block.rs:27:9
+   |
+27 |     Foo { text: "".to_string() }
+   |         ^ expected one of `(` or `<` here
+
+error: aborting due to 2 previous errors
+
index f8b5e670b8426c26ddf9a21a80ae418f34a3dd99..c88f823839dad4db40b3290d35645ad8f0b4def0 100644 (file)
@@ -16,4 +16,3 @@ fn main() {
 }
 //~^ ERROR: incorrect close delimiter: `}`
 //~| ERROR: incorrect close delimiter: `}`
-//~| ERROR: expected expression, found `)`
index 0e396f6254a3b3da2b8aa1f1af8283ae68124c6a..e26f0e85aa676f10ee258136b5a8006ad0cb1c71 100644 (file)
@@ -28,11 +28,5 @@ error: expected expression, found `;`
 14 |     foo(bar(;
    |             ^
 
-error: expected expression, found `)`
-  --> $DIR/token-error-correct.rs:16:1
-   |
-16 | }
-   | ^
-
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors