about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2017-04-08 11:47:48 +0000
committerbors <bors@rust-lang.org>2017-04-08 11:47:48 +0000
commitfe39e94d6cd6eba00b3aadf323b3f4d029aad7eb (patch)
treef042bd71f6f987365c4583a254f0a008cd70f4dd /src
parent4cadff61ef395f3937d950e35304969ced2ea0b0 (diff)
parent8c31412c2f84c7d76602b2598c5c1352da61d022 (diff)
downloadrust-fe39e94d6cd6eba00b3aadf323b3f4d029aad7eb.tar.gz
rust-fe39e94d6cd6eba00b3aadf323b3f4d029aad7eb.zip
Auto merge of #40887 - estebank:ty-placeholder, r=petrochenkov
Introduce `TyErr` independent from `TyInfer`

Add a `TyErr` type to represent unknown types in places where
parse errors have happened, while still able to build the AST.

Initially only used to represent incorrectly written fn arguments and
avoid "expected X parameters, found Y" errors when called with the
appropriate amount of parameters. We cannot use `TyInfer` for this as
`_` is not allowed as a valid argument type.

Example output:

```rust
error: expected one of `:` or `@`, found `,`
  --> file.rs:12:9
   |
12 | fn bar(x, y: usize) {}
   |         ^

error[E0061]: this function takes 2 parameters but 3 parameters were supplied
  --> file.rs:19:9
   |
12 | fn bar(x, y) {}
   | --------------- defined here
...
19 |     bar(1, 2, 3);
   |         ^^^^^^^ expected 2 parameters
```

Fix #34264.
Diffstat (limited to 'src')
-rw-r--r--src/librustc/hir/intravisit.rs2
-rw-r--r--src/librustc/hir/lowering.rs1
-rw-r--r--src/librustc/hir/mod.rs2
-rw-r--r--src/librustc/hir/print.rs3
-rw-r--r--src/librustc/ich/impls_hir.rs2
-rw-r--r--src/librustc_typeck/astconv.rs3
-rw-r--r--src/librustdoc/clean/mod.rs2
-rw-r--r--src/libsyntax/ast.rs2
-rw-r--r--src/libsyntax/fold.rs2
-rw-r--r--src/libsyntax/parse/parser.rs25
-rw-r--r--src/libsyntax/print/pprust.rs3
-rw-r--r--src/libsyntax/visit.rs2
-rw-r--r--src/test/ui/span/issue-34264.rs20
-rw-r--r--src/test/ui/span/issue-34264.stderr49
14 files changed, 113 insertions, 5 deletions
diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs
index c7ad143c949..2c8b145f126 100644
--- a/src/librustc/hir/intravisit.rs
+++ b/src/librustc/hir/intravisit.rs
@@ -578,7 +578,7 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) {
         TyTypeof(expression) => {
             visitor.visit_nested_body(expression)
         }
-        TyInfer => {}
+        TyInfer | TyErr => {}
     }
 }
 
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index 3f4390536b0..30fec50d4eb 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -555,6 +555,7 @@ impl<'a> LoweringContext<'a> {
     fn lower_ty(&mut self, t: &Ty) -> P<hir::Ty> {
         let kind = match t.node {
             TyKind::Infer => hir::TyInfer,
+            TyKind::Err => hir::TyErr,
             TyKind::Slice(ref ty) => hir::TySlice(self.lower_ty(ty)),
             TyKind::Ptr(ref mt) => hir::TyPtr(self.lower_mt(mt)),
             TyKind::Rptr(ref region, ref mt) => {
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index d5000ac9c18..0da405d1821 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -1351,6 +1351,8 @@ pub enum Ty_ {
     /// TyInfer means the type should be inferred instead of it having been
     /// specified. This can appear anywhere in a type.
     TyInfer,
+    /// Placeholder for a type that has failed to be defined.
+    TyErr,
 }
 
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs
index 04a65fd5e3a..4a5a35aa82c 100644
--- a/src/librustc/hir/print.rs
+++ b/src/librustc/hir/print.rs
@@ -450,6 +450,9 @@ impl<'a> State<'a> {
             hir::TyInfer => {
                 word(&mut self.s, "_")?;
             }
+            hir::TyErr => {
+                word(&mut self.s, "?")?;
+            }
         }
         self.end()
     }
diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs
index fb18f50027e..9cf8a0693d3 100644
--- a/src/librustc/ich/impls_hir.rs
+++ b/src/librustc/ich/impls_hir.rs
@@ -230,6 +230,7 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::Ty {
             hir::TyTraitObject(..) |
             hir::TyImplTrait(..)   |
             hir::TyTypeof(..)      |
+            hir::TyErr             |
             hir::TyInfer           => {
                 NodeIdHashingMode::Ignore
             }
@@ -282,6 +283,7 @@ impl_stable_hash_for!(enum hir::Ty_ {
     TyTraitObject(trait_refs, lifetime),
     TyImplTrait(bounds),
     TyTypeof(body_id),
+    TyErr,
     TyInfer
 });
 
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 923ec05c22b..66c4a81a5c0 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -1229,6 +1229,9 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                 // handled specially and will not descend into this routine.
                 self.ty_infer(ast_ty.span)
             }
+            hir::TyErr => {
+                tcx.types.err
+            }
         };
 
         cache.borrow_mut().insert(ast_ty.id, result_ty);
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index f3ea6c4467c..ac72d7d29a2 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1805,7 +1805,7 @@ impl Clean<Type> for hir::Ty {
             }
             TyBareFn(ref barefn) => BareFunction(box barefn.clean(cx)),
             TyImplTrait(ref bounds) => ImplTrait(bounds.clean(cx)),
-            TyInfer => Infer,
+            TyInfer | TyErr => Infer,
             TyTypeof(..) => panic!("Unimplemented type {:?}", self.node),
         }
     }
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 9eb86aa006d..c6a3e8a2ded 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -1361,6 +1361,8 @@ pub enum TyKind {
     ImplicitSelf,
     // A macro in the type position.
     Mac(Mac),
+    /// Placeholder for a kind that has failed to be defined.
+    Err,
 }
 
 /// Inline assembly dialect.
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index 1a4e196ac55..92e25b00e0a 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -358,7 +358,7 @@ pub fn noop_fold_ty<T: Folder>(t: P<Ty>, fld: &mut T) -> P<Ty> {
     t.map(|Ty {id, node, span}| Ty {
         id: fld.new_id(id),
         node: match node {
-            TyKind::Infer | TyKind::ImplicitSelf => node,
+            TyKind::Infer | TyKind::ImplicitSelf | TyKind::Err => node,
             TyKind::Slice(ty) => TyKind::Slice(fld.fold_ty(ty)),
             TyKind::Ptr(mt) => TyKind::Ptr(fld.fold_mt(mt)),
             TyKind::Rptr(region, mt) => {
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 0dd2c03acb6..43d21015a4f 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -407,6 +407,25 @@ impl From<P<Expr>> for LhsExpr {
     }
 }
 
+/// Create a placeholder argument.
+fn dummy_arg(span: Span) -> Arg {
+    let spanned = Spanned {
+        span: span,
+        node: keywords::Invalid.ident()
+    };
+    let pat = P(Pat {
+        id: ast::DUMMY_NODE_ID,
+        node: PatKind::Ident(BindingMode::ByValue(Mutability::Immutable), spanned, None),
+        span: span
+    });
+    let ty = Ty {
+        node: TyKind::Err,
+        span: span,
+        id: ast::DUMMY_NODE_ID
+    };
+    Arg { ty: P(ty), pat: pat, id: ast::DUMMY_NODE_ID }
+}
+
 impl<'a> Parser<'a> {
     pub fn new(sess: &'a ParseSess,
                tokens: TokenStream,
@@ -4376,8 +4395,12 @@ impl<'a> Parser<'a> {
                             Ok(arg) => Ok(Some(arg)),
                             Err(mut e) => {
                                 e.emit();
+                                let lo = p.prev_span;
+                                // Skip every token until next possible arg or end.
                                 p.eat_to_tokens(&[&token::Comma, &token::CloseDelim(token::Paren)]);
-                                Ok(None)
+                                // Create a placeholder argument for proper arg count (#34264).
+                                let span = lo.to(p.prev_span);
+                                Ok(Some(dummy_arg(span)))
                             }
                         }
                     }
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index f042a18d610..e7feff2b79f 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -1095,6 +1095,9 @@ impl<'a> State<'a> {
             ast::TyKind::Infer => {
                 word(&mut self.s, "_")?;
             }
+            ast::TyKind::Err => {
+                word(&mut self.s, "?")?;
+            }
             ast::TyKind::ImplicitSelf => {
                 word(&mut self.s, "Self")?;
             }
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index a5333f3bb6a..b5e9a1892ac 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -350,7 +350,7 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) {
         TyKind::Typeof(ref expression) => {
             visitor.visit_expr(expression)
         }
-        TyKind::Infer | TyKind::ImplicitSelf => {}
+        TyKind::Infer | TyKind::ImplicitSelf | TyKind::Err => {}
         TyKind::Mac(ref mac) => {
             visitor.visit_mac(mac)
         }
diff --git a/src/test/ui/span/issue-34264.rs b/src/test/ui/span/issue-34264.rs
new file mode 100644
index 00000000000..00482f50618
--- /dev/null
+++ b/src/test/ui/span/issue-34264.rs
@@ -0,0 +1,20 @@
+// 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.
+
+fn foo(Option<i32>, String) {}
+fn bar(x, y: usize) {}
+
+fn main() {
+    foo(Some(42), 2);
+    foo(Some(42), 2, "");
+    bar("", "");
+    bar(1, 2);
+    bar(1, 2, 3);
+}
diff --git a/src/test/ui/span/issue-34264.stderr b/src/test/ui/span/issue-34264.stderr
new file mode 100644
index 00000000000..98183e2f082
--- /dev/null
+++ b/src/test/ui/span/issue-34264.stderr
@@ -0,0 +1,49 @@
+error: expected one of `:` or `@`, found `<`
+  --> $DIR/issue-34264.rs:11:14
+   |
+11 | fn foo(Option<i32>, String) {}
+   |              ^ expected one of `:` or `@` here
+
+error: expected one of `:` or `@`, found `)`
+  --> $DIR/issue-34264.rs:11:27
+   |
+11 | fn foo(Option<i32>, String) {}
+   |                           ^ expected one of `:` or `@` here
+
+error: expected one of `:` or `@`, found `,`
+  --> $DIR/issue-34264.rs:12:9
+   |
+12 | fn bar(x, y: usize) {}
+   |         ^ expected one of `:` or `@` here
+
+error[E0061]: this function takes 2 parameters but 3 parameters were supplied
+  --> $DIR/issue-34264.rs:16:9
+   |
+11 | fn foo(Option<i32>, String) {}
+   | ------------------------------ defined here
+...
+16 |     foo(Some(42), 2, "");
+   |         ^^^^^^^^^^^^^^^ expected 2 parameters
+
+error[E0308]: mismatched types
+  --> $DIR/issue-34264.rs:17:13
+   |
+17 |     bar("", "");
+   |             ^^ expected usize, found reference
+   |
+   = note: expected type `usize`
+              found type `&'static str`
+   = help: here are some functions which might fulfill your needs:
+           - .len()
+
+error[E0061]: this function takes 2 parameters but 3 parameters were supplied
+  --> $DIR/issue-34264.rs:19:9
+   |
+12 | fn bar(x, y: usize) {}
+   | ---------------------- defined here
+...
+19 |     bar(1, 2, 3);
+   |         ^^^^^^^ expected 2 parameters
+
+error: aborting due to 3 previous errors
+