diff options
| author | Esteban Küber <esteban@kuber.com.ar> | 2019-05-29 15:25:46 -0700 |
|---|---|---|
| committer | Esteban Küber <esteban@kuber.com.ar> | 2019-05-30 17:59:05 -0700 |
| commit | b3ac88ad922a618e6bf0eb269084d60233a311e4 (patch) | |
| tree | c2343ffa058f014297095185fcb09e163c20bb85 /src/libsyntax | |
| parent | aee7012fab26d5e307a2fe767e4e7c847c5a45ee (diff) | |
| download | rust-b3ac88ad922a618e6bf0eb269084d60233a311e4.tar.gz rust-b3ac88ad922a618e6bf0eb269084d60233a311e4.zip | |
Recover gracefully from argument with missing type or param name
Diffstat (limited to 'src/libsyntax')
| -rw-r--r-- | src/libsyntax/ast.rs | 2 | ||||
| -rw-r--r-- | src/libsyntax/mut_visit.rs | 2 | ||||
| -rw-r--r-- | src/libsyntax/parse/diagnostics.rs | 28 | ||||
| -rw-r--r-- | src/libsyntax/parse/parser.rs | 45 |
4 files changed, 59 insertions, 18 deletions
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 75e83bd9f9c..3e25f22f0a4 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1780,6 +1780,8 @@ pub enum ArgSource { Normal, /// Argument from `async fn` lowering, contains the original binding pattern. AsyncFn(P<Pat>), + /// Placeholder argument caused by incorrect syntax. Used to silence unecessary errors. + Recovery, } /// Alternative representation for `Arg`s describing `self` parameter of methods. diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs index 0016c0d4d7e..e31bded0dec 100644 --- a/src/libsyntax/mut_visit.rs +++ b/src/libsyntax/mut_visit.rs @@ -580,7 +580,7 @@ pub fn noop_visit_arg<T: MutVisitor>(Arg { id, pat, ty, source }: &mut Arg, vis: pub fn noop_visit_arg_source<T: MutVisitor>(source: &mut ArgSource, vis: &mut T) { match source { - ArgSource::Normal => {}, + ArgSource::Normal | ArgSource::Recovery => {}, ArgSource::AsyncFn(pat) => vis.visit_pat(pat), } } diff --git a/src/libsyntax/parse/diagnostics.rs b/src/libsyntax/parse/diagnostics.rs index b3d49524d76..b6f26c73a70 100644 --- a/src/libsyntax/parse/diagnostics.rs +++ b/src/libsyntax/parse/diagnostics.rs @@ -1,7 +1,7 @@ use crate::ast; use crate::ast::{ BlockCheckMode, BinOpKind, Expr, ExprKind, Item, ItemKind, Pat, PatKind, PathSegment, QSelf, - Ty, TyKind, VariantData, + Ty, TyKind, VariantData, Ident, }; use crate::parse::{SeqSep, token, PResult, Parser}; use crate::parse::parser::{BlockMode, PathStyle, SemiColonMode, TokenType, TokenExpectType}; @@ -1092,12 +1092,12 @@ impl<'a> Parser<'a> { pat: P<ast::Pat>, require_name: bool, is_trait_item: bool, - ) { + ) -> Option<Ident> { // If we find a pattern followed by an identifier, it could be an (incorrect) // C-style parameter declaration. if self.check_ident() && self.look_ahead(1, |t| { *t == token::Comma || *t == token::CloseDelim(token::Paren) - }) { + }) { // `fn foo(String s) {}` let ident = self.parse_ident().unwrap(); let span = pat.span.with_hi(ident.span.hi()); @@ -1107,18 +1107,30 @@ impl<'a> Parser<'a> { String::from("<identifier>: <type>"), Applicability::HasPlaceholders, ); - } else if require_name && is_trait_item { - if let PatKind::Ident(_, ident, _) = pat.node { + return Some(ident); + } else if let PatKind::Ident(_, ident, _) = pat.node { + if require_name && ( + is_trait_item || + self.token == token::Comma || + self.token == token::CloseDelim(token::Paren) + ) { // `fn foo(a, b) {}` or `fn foo(usize, usize) {}` + err.span_suggestion( + pat.span, + "if this was a parameter name, give it a type", + format!("{}: TypeName", ident), + Applicability::HasPlaceholders, + ); err.span_suggestion( pat.span, - "explicitly ignore parameter", + "if this is a type, explicitly ignore the parameter name", format!("_: {}", ident), Applicability::MachineApplicable, ); + err.note("anonymous parameters are removed in the 2018 edition (see RFC 1685)"); + return Some(ident); } - - err.note("anonymous parameters are removed in the 2018 edition (see RFC 1685)"); } + None } crate fn recover_arg_parse(&mut self) -> PResult<'a, (P<ast::Pat>, P<ast::Ty>)> { diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 746e9cad496..2c35b9ea7fd 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -51,6 +51,7 @@ use crate::parse::diagnostics::Error; use errors::{Applicability, DiagnosticBuilder, DiagnosticId, FatalError}; use rustc_target::spec::abi::{self, Abi}; +use rustc_data_structures::fx::FxHashSet; use syntax_pos::{Span, BytePos, DUMMY_SP, FileName, hygiene::CompilerDesugaringKind}; use log::debug; @@ -452,19 +453,18 @@ impl From<P<Expr>> for LhsExpr { } /// Creates a placeholder argument. -fn dummy_arg(span: Span) -> Arg { - let ident = Ident::new(kw::Invalid, span); +fn dummy_arg(ident: Ident) -> Arg { let pat = P(Pat { id: ast::DUMMY_NODE_ID, node: PatKind::Ident(BindingMode::ByValue(Mutability::Immutable), ident, None), - span, + span: ident.span, }); let ty = Ty { node: TyKind::Err, - span, + span: ident.span, id: ast::DUMMY_NODE_ID }; - Arg { ty: P(ty), pat: pat, id: ast::DUMMY_NODE_ID, source: ast::ArgSource::Normal } + Arg { ty: P(ty), pat: pat, id: ast::DUMMY_NODE_ID, source: ast::ArgSource::Recovery } } #[derive(Copy, Clone, Debug)] @@ -1528,8 +1528,17 @@ impl<'a> Parser<'a> { let pat = self.parse_pat(Some("argument name"))?; if let Err(mut err) = self.expect(&token::Colon) { - self.argument_without_type(&mut err, pat, require_name, is_trait_item); - return Err(err); + if let Some(ident) = self.argument_without_type( + &mut err, + pat, + require_name, + is_trait_item, + ) { + err.emit(); + return Ok(dummy_arg(ident)); + } else { + return Err(err); + } } self.eat_incorrect_doc_comment("a method argument's type"); @@ -5431,7 +5440,7 @@ impl<'a> Parser<'a> { p.eat_to_tokens(&[&token::Comma, &token::CloseDelim(token::Paren)]); // Create a placeholder argument for proper arg count (issue #34264). let span = lo.to(p.prev_span); - Ok(Some(dummy_arg(span))) + Ok(Some(dummy_arg(Ident::new(kw::Invalid, span)))) } } } @@ -5584,7 +5593,7 @@ impl<'a> Parser<'a> { // Parse the rest of the function parameter list. let sep = SeqSep::trailing_allowed(token::Comma); - let (fn_inputs, recovered) = if let Some(self_arg) = self_arg { + let (mut fn_inputs, recovered) = if let Some(self_arg) = self_arg { if self.check(&token::CloseDelim(token::Paren)) { (vec![self_arg], false) } else if self.eat(&token::Comma) { @@ -5607,6 +5616,24 @@ impl<'a> Parser<'a> { // Parse closing paren and return type. self.expect(&token::CloseDelim(token::Paren))?; } + // Replace duplicated recovered arguments with `_` pattern to avoid unecessary errors. + let mut seen_inputs = FxHashSet::default(); + for input in fn_inputs.iter_mut() { + let opt_ident = if let (PatKind::Ident(_, ident, _), ast::ArgSource::Recovery) = ( + &input.pat.node, &input.source, + ) { + Some(*ident) + } else { + None + }; + if let Some(ident) = opt_ident { + if seen_inputs.contains(&ident) { + input.pat.node = PatKind::Wild; + } + seen_inputs.insert(ident); + } + } + Ok(P(FnDecl { inputs: fn_inputs, output: self.parse_ret_ty(true)?, |
