From 73b50d211b254bf72ce10b5ea4c3e0033e3189f4 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 29 Sep 2019 19:22:18 -0400 Subject: Add support for 'extern const fn' This works just as you might expect - an 'extern const fn' is a 'const fn' that is callable from foreign code. Currently, panicking is not allowed in consts. When RFC 2345 is stabilized, then panicking in an 'extern const fn' will produce a compile-time error when invoked at compile time, and an abort when invoked at runtime. Since this is extending the language (we're allowing the `const` keyword in a new context), I believe that this will need an FCP. However, it's a very minor change, so I didn't think that filing an RFC was necessary. This will allow libc (and other FFI crates) to make many functions `const`, without having to give up on making them `extern` as well. --- src/libsyntax/parse/mod.rs | 2 ++ src/libsyntax/parse/parser.rs | 9 +++++++ src/libsyntax/parse/parser/item.rs | 52 ++++++++++++++++++++++++-------------- 3 files changed, 44 insertions(+), 19 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index fa4c1043122..1518da23b09 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -57,6 +57,8 @@ pub struct GatedSpans { pub yields: Lock>, /// Spans collected for gating `or_patterns`, e.g. `Some(Foo | Bar)`. pub or_patterns: Lock>, + /// Spans collected for gating `const_extern_fn`, e.g. `const extern fn foo`. + pub const_extern_fn: Lock>, } /// Info about a parsing session. diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 95f84d5cb33..6b0b60bfe47 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1486,6 +1486,15 @@ impl<'a> Parser<'a> { Ok(()) } + /// Parses `extern` followed by an optional ABI string, or nothing. + fn parse_extern_abi(&mut self) -> PResult<'a, Abi> { + if self.eat_keyword(kw::Extern) { + Ok(self.parse_opt_abi()?.unwrap_or(Abi::C)) + } else { + Ok(Abi::Rust) + } + } + /// Parses a string as an ABI spec on an extern type or module. Consumes /// the `extern` keyword, if one is found. fn parse_opt_abi(&mut self) -> PResult<'a, Option> { diff --git a/src/libsyntax/parse/parser/item.rs b/src/libsyntax/parse/parser/item.rs index c00a5807d52..d9fec72566c 100644 --- a/src/libsyntax/parse/parser/item.rs +++ b/src/libsyntax/parse/parser/item.rs @@ -149,17 +149,23 @@ impl<'a> Parser<'a> { } if self.eat_keyword(kw::Const) { let const_span = self.prev_span; - if self.check_keyword(kw::Fn) - || (self.check_keyword(kw::Unsafe) - && self.is_keyword_ahead(1, &[kw::Fn])) { + if [kw::Fn, kw::Unsafe, kw::Extern].iter().any(|k| self.check_keyword(*k)) { // CONST FUNCTION ITEM + let unsafety = self.parse_unsafety(); - self.bump(); + + if self.check_keyword(kw::Extern) { + self.sess.gated_spans.const_extern_fn.borrow_mut().push( + lo.to(self.token.span) + ); + } + let abi = self.parse_extern_abi()?; + let header = FnHeader { unsafety, asyncness: respan(const_span, IsAsync::NotAsync), constness: respan(const_span, Constness::Const), - abi: Abi::Rust, + abi, }; return self.parse_item_fn(lo, visibility, attrs, header); } @@ -257,11 +263,7 @@ impl<'a> Parser<'a> { self.bump(); // `unsafe` // `{` is also expected after `unsafe`; in case of error, include it in the diagnostic. self.check(&token::OpenDelim(token::Brace)); - let abi = if self.eat_keyword(kw::Extern) { - self.parse_opt_abi()?.unwrap_or(Abi::C) - } else { - Abi::Rust - }; + let abi = self.parse_extern_abi()?; self.expect_keyword(kw::Fn)?; let fn_span = self.prev_span; let header = FnHeader { @@ -834,11 +836,7 @@ impl<'a> Parser<'a> { let (constness, unsafety, abi) = if is_const_fn { (respan(const_span, Constness::Const), unsafety, Abi::Rust) } else { - let abi = if self.eat_keyword(kw::Extern) { - self.parse_opt_abi()?.unwrap_or(Abi::C) - } else { - Abi::Rust - }; + let abi = self.parse_extern_abi()?; (respan(self.prev_span, Constness::NotConst), unsafety, abi) }; if !self.eat_keyword(kw::Fn) { @@ -1278,14 +1276,30 @@ impl<'a> Parser<'a> { // Treat `const` as `static` for error recovery, but don't add it to expected tokens. if self.check_keyword(kw::Static) || self.token.is_keyword(kw::Const) { if self.token.is_keyword(kw::Const) { - self.diagnostic() - .struct_span_err(self.token.span, "extern items cannot be `const`") - .span_suggestion( + let mut err = self + .struct_span_err(self.token.span, "extern items cannot be `const`"); + + + // The user wrote 'const fn' + if self.is_keyword_ahead(1, &[kw::Fn, kw::Unsafe]) { + err.emit(); + // Consume `const` + self.bump(); + // Consume `unsafe` if present, since `extern` blocks + // don't allow it. This will leave behind a plain 'fn' + self.eat_keyword(kw::Unsafe); + // Treat 'const fn` as a plain `fn` for error recovery purposes. + // We've already emitted an error, so compilation is guaranteed + // to fail + return Ok(self.parse_item_foreign_fn(visibility, lo, attrs, extern_sp)?); + } + err.span_suggestion( self.token.span, "try using a static value", "static".to_owned(), Applicability::MachineApplicable - ).emit(); + ); + err.emit(); } self.bump(); // `static` or `const` return Ok(self.parse_item_foreign_static(visibility, lo, attrs)?); -- cgit 1.4.1-3-g733a5 From 84b680f56fa15e8a9f0bbb16b33d9b94bf89e4d7 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Wed, 2 Oct 2019 01:04:22 -0400 Subject: Add missing 'bump' --- src/libsyntax/parse/parser/item.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/parser/item.rs b/src/libsyntax/parse/parser/item.rs index d9fec72566c..2ac0352764f 100644 --- a/src/libsyntax/parse/parser/item.rs +++ b/src/libsyntax/parse/parser/item.rs @@ -160,6 +160,7 @@ impl<'a> Parser<'a> { ); } let abi = self.parse_extern_abi()?; + self.bump(); // 'fn' let header = FnHeader { unsafety, -- cgit 1.4.1-3-g733a5 From ed60cf2475cabd3d9ad1afdc03bd6952d99b744c Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Sun, 29 Sep 2019 19:07:26 -0700 Subject: When encountering chained operators use heuristics to recover from bad turbofish --- src/libsyntax/parse/diagnostics.rs | 100 ++++++++++++++++++--- src/libsyntax/parse/parser/expr.rs | 4 +- src/test/ui/did_you_mean/issue-40396.stderr | 16 ++-- .../require-parens-for-chained-comparison.rs | 5 +- .../require-parens-for-chained-comparison.stderr | 23 +++-- 5 files changed, 121 insertions(+), 27 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/diagnostics.rs b/src/libsyntax/parse/diagnostics.rs index e8d7b7663ed..0e3d873b252 100644 --- a/src/libsyntax/parse/diagnostics.rs +++ b/src/libsyntax/parse/diagnostics.rs @@ -543,16 +543,25 @@ impl<'a> Parser<'a> { } /// Produces an error if comparison operators are chained (RFC #558). - /// We only need to check the LHS, not the RHS, because all comparison ops - /// have same precedence and are left-associative. - crate fn check_no_chained_comparison(&self, lhs: &Expr, outer_op: &AssocOp) -> PResult<'a, ()> { - debug_assert!(outer_op.is_comparison(), - "check_no_chained_comparison: {:?} is not comparison", - outer_op); + /// We only need to check the LHS, not the RHS, because all comparison ops have same + /// precedence and are left-associative. + /// + /// This can also be hit if someone incorrectly writes `foo()` when they should have used + /// the turbofish syntax. We attempt some heuristic recovery if that is the case. + crate fn check_no_chained_comparison( + &mut self, + lhs: &Expr, + outer_op: &AssocOp, + ) -> PResult<'a, Option>> { + debug_assert!( + outer_op.is_comparison(), + "check_no_chained_comparison: {:?} is not comparison", + outer_op, + ); match lhs.kind { ExprKind::Binary(op, _, _) if op.node.is_comparison() => { // Respan to include both operators. - let op_span = op.span.to(self.token.span); + let op_span = op.span.to(self.prev_span); let mut err = self.struct_span_err( op_span, "chained comparison operators require parentheses", @@ -561,17 +570,84 @@ impl<'a> Parser<'a> { *outer_op == AssocOp::Less || // Include `<` to provide this recommendation *outer_op == AssocOp::Greater // even in a case like the following: { // Foo>> - err.help( - "use `::<...>` instead of `<...>` if you meant to specify type arguments"); - err.help("or use `(...)` if you meant to specify fn arguments"); - // These cases cause too many knock-down errors, bail out (#61329). + let msg = "use `::<...>` instead of `<...>` if you meant to specify type \ + arguments"; + if *outer_op == AssocOp::Less { + // if self.look_ahead(1, |t| t.kind == token::Lt || t.kind == token::ModSep) { + let snapshot = self.clone(); + self.bump(); + // So far we have parsed `foo 0 { + match &self.token.kind { + token::Lt => { + acc += 1; + } + token::Gt => { + acc -= 1; + } + token::BinOp(token::Shr) => { + acc -= 2; + } + token::Eof => { + break; + } + _ => {} + } + self.bump(); + } + if self.token.kind != token::OpenDelim(token::Paren) { + mem::replace(self, snapshot.clone()); + } + } + if self.token.kind == token::OpenDelim(token::Paren) { + err.span_suggestion( + op_span.shrink_to_lo(), + msg, + "::".to_string(), + Applicability::MaybeIncorrect, + ); + let snapshot = self.clone(); + self.bump(); + let mut acc = 1; + while acc > 0 { + match &self.token.kind { + token::OpenDelim(token::Paren) => { + acc += 1; + } + token::CloseDelim(token::Paren) => { + acc -= 1; + } + token::Eof => { + break; + } + _ => {} + } + self.bump(); + } + if self.token.kind == token::Eof { + mem::replace(self, snapshot); + return Err(err); + } else { + err.emit(); + return Ok(Some(self.mk_expr( + lhs.span.to(self.prev_span), + ExprKind::Err, + ThinVec::new(), + ))); + } + } else { + err.help(msg); + err.help("or use `(...)` if you meant to specify fn arguments"); + // These cases cause too many knock-down errors, bail out (#61329). + } return Err(err); } err.emit(); } _ => {} } - Ok(()) + Ok(None) } crate fn maybe_report_ambiguous_plus( diff --git a/src/libsyntax/parse/parser/expr.rs b/src/libsyntax/parse/parser/expr.rs index 23674ad589d..b459782d237 100644 --- a/src/libsyntax/parse/parser/expr.rs +++ b/src/libsyntax/parse/parser/expr.rs @@ -238,7 +238,9 @@ impl<'a> Parser<'a> { self.bump(); if op.is_comparison() { - self.check_no_chained_comparison(&lhs, &op)?; + if let Some(expr) = self.check_no_chained_comparison(&lhs, &op)? { + return Ok(expr); + } } // Special cases: if op == AssocOp::As { diff --git a/src/test/ui/did_you_mean/issue-40396.stderr b/src/test/ui/did_you_mean/issue-40396.stderr index 7a08fda27e3..d0448cc265c 100644 --- a/src/test/ui/did_you_mean/issue-40396.stderr +++ b/src/test/ui/did_you_mean/issue-40396.stderr @@ -2,16 +2,17 @@ error: chained comparison operators require parentheses --> $DIR/issue-40396.rs:2:20 | LL | (0..13).collect>(); - | ^^^^^^^^ + | ^^^^^ +help: use `::<...>` instead of `<...>` if you meant to specify type arguments | - = help: use `::<...>` instead of `<...>` if you meant to specify type arguments - = help: or use `(...)` if you meant to specify fn arguments +LL | (0..13).collect::>(); + | ^^ error: chained comparison operators require parentheses --> $DIR/issue-40396.rs:7:8 | LL | Vec::new(); - | ^^^^^^^ + | ^^^^^ | = help: use `::<...>` instead of `<...>` if you meant to specify type arguments = help: or use `(...)` if you meant to specify fn arguments @@ -20,10 +21,11 @@ error: chained comparison operators require parentheses --> $DIR/issue-40396.rs:12:20 | LL | (0..13).collect(); - | ^^^^^^^^ + | ^^^^^ +help: use `::<...>` instead of `<...>` if you meant to specify type arguments | - = help: use `::<...>` instead of `<...>` if you meant to specify type arguments - = help: or use `(...)` if you meant to specify fn arguments +LL | (0..13).collect::(); + | ^^ error: aborting due to 3 previous errors diff --git a/src/test/ui/parser/require-parens-for-chained-comparison.rs b/src/test/ui/parser/require-parens-for-chained-comparison.rs index 3dcc0c8f3d4..11839938cb0 100644 --- a/src/test/ui/parser/require-parens-for-chained-comparison.rs +++ b/src/test/ui/parser/require-parens-for-chained-comparison.rs @@ -13,5 +13,8 @@ fn main() { f(); //~^ ERROR chained comparison operators require parentheses //~| HELP: use `::<...>` instead of `<...>` - //~| HELP: or use `(...)` + + f, Option>>(1, 2); + //~^ ERROR chained comparison operators require parentheses + //~| HELP: use `::<...>` instead of `<...>` } diff --git a/src/test/ui/parser/require-parens-for-chained-comparison.stderr b/src/test/ui/parser/require-parens-for-chained-comparison.stderr index e927f4c3248..02fb56a7f9b 100644 --- a/src/test/ui/parser/require-parens-for-chained-comparison.stderr +++ b/src/test/ui/parser/require-parens-for-chained-comparison.stderr @@ -2,22 +2,33 @@ error: chained comparison operators require parentheses --> $DIR/require-parens-for-chained-comparison.rs:5:11 | LL | false == false == false; - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^ error: chained comparison operators require parentheses --> $DIR/require-parens-for-chained-comparison.rs:8:11 | LL | false == 0 < 2; - | ^^^^^^^^ + | ^^^^^^ error: chained comparison operators require parentheses --> $DIR/require-parens-for-chained-comparison.rs:13:6 | LL | f(); - | ^^^^ + | ^^^ +help: use `::<...>` instead of `<...>` if you meant to specify type arguments | - = help: use `::<...>` instead of `<...>` if you meant to specify type arguments - = help: or use `(...)` if you meant to specify fn arguments +LL | f::(); + | ^^ + +error: chained comparison operators require parentheses + --> $DIR/require-parens-for-chained-comparison.rs:17:6 + | +LL | f, Option>>(1, 2); + | ^^^^^^^^ +help: use `::<...>` instead of `<...>` if you meant to specify type arguments + | +LL | f::, Option>>(1, 2); + | ^^ error[E0308]: mismatched types --> $DIR/require-parens-for-chained-comparison.rs:8:14 @@ -37,6 +48,6 @@ LL | false == 0 < 2; = note: expected type `bool` found type `{integer}` -error: aborting due to 5 previous errors +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0308`. -- cgit 1.4.1-3-g733a5 From 6c9f298a8bee9b1716b2e6fcdb8305c3f4874fc6 Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Mon, 30 Sep 2019 12:19:22 -0700 Subject: review comments --- src/libsyntax/parse/diagnostics.rs | 87 +++++++++++++++++++++----------------- 1 file changed, 49 insertions(+), 38 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/diagnostics.rs b/src/libsyntax/parse/diagnostics.rs index 0e3d873b252..584c7c2ded5 100644 --- a/src/libsyntax/parse/diagnostics.rs +++ b/src/libsyntax/parse/diagnostics.rs @@ -560,6 +560,7 @@ impl<'a> Parser<'a> { ); match lhs.kind { ExprKind::Binary(op, _, _) if op.node.is_comparison() => { + // Respan to include both operators. let op_span = op.span.to(self.prev_span); let mut err = self.struct_span_err( @@ -573,63 +574,54 @@ impl<'a> Parser<'a> { let msg = "use `::<...>` instead of `<...>` if you meant to specify type \ arguments"; if *outer_op == AssocOp::Less { - // if self.look_ahead(1, |t| t.kind == token::Lt || t.kind == token::ModSep) { let snapshot = self.clone(); self.bump(); - // So far we have parsed `foo 0 { - match &self.token.kind { - token::Lt => { - acc += 1; - } - token::Gt => { - acc -= 1; - } - token::BinOp(token::Shr) => { - acc -= 2; - } - token::Eof => { - break; - } - _ => {} - } - self.bump(); - } + // So far we have parsed `foo(`, so we rewind the parser and bail out. mem::replace(self, snapshot.clone()); } } if self.token.kind == token::OpenDelim(token::Paren) { + // We have high certainty that this was a bad turbofish at this point. + // `foo< bar >(` err.span_suggestion( op_span.shrink_to_lo(), msg, "::".to_string(), Applicability::MaybeIncorrect, ); + let snapshot = self.clone(); - self.bump(); - let mut acc = 1; - while acc > 0 { - match &self.token.kind { - token::OpenDelim(token::Paren) => { - acc += 1; - } - token::CloseDelim(token::Paren) => { - acc -= 1; - } - token::Eof => { - break; - } - _ => {} - } - self.bump(); - } + + // Consume the fn call arguments. + let modifiers = vec![ + (token::OpenDelim(token::Paren), 1), + (token::CloseDelim(token::Paren), -1), + ]; + let early_return = vec![token::Eof]; + self.bump(); // `(` + self.consume_tts(1, &modifiers[..], &early_return[..]); + if self.token.kind == token::Eof { + // Not entirely sure now, but we bubble the error up with the + // suggestion. mem::replace(self, snapshot); return Err(err); } else { + // 99% certain that the suggestion is correct, continue parsing. err.emit(); + // FIXME: actually check that the two expressions in the binop are + // paths and resynthesize new fn call expression instead of using + // `ExprKind::Err` placeholder. return Ok(Some(self.mk_expr( lhs.span.to(self.prev_span), ExprKind::Err, @@ -637,6 +629,8 @@ impl<'a> Parser<'a> { ))); } } else { + // All we know is that this is `foo < bar >` and *nothing* else. Try to + // be helpful, but don't attempt to recover. err.help(msg); err.help("or use `(...)` if you meant to specify fn arguments"); // These cases cause too many knock-down errors, bail out (#61329). @@ -1424,6 +1418,23 @@ impl<'a> Parser<'a> { err } + fn consume_tts( + &mut self, + mut acc: i64, + modifier: &[(token::TokenKind, i64)], // Not using FxHasMap and FxHashSet due to + early_return: &[token::TokenKind], // `token::TokenKind: !Eq + !Hash`. + ) { + while acc > 0 { + if let Some((_, val)) = modifier.iter().filter(|(t, _)| *t == self.token.kind).next() { + acc += *val; + } + if early_return.contains(&self.token.kind) { + break; + } + self.bump(); + } + } + /// Replace duplicated recovered parameters with `_` pattern to avoid unecessary errors. /// /// This is necessary because at this point we don't know whether we parsed a function with -- cgit 1.4.1-3-g733a5 From d7dceaa0c57759d37a48b5a0aa1064b7c89f957b Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Mon, 30 Sep 2019 12:36:44 -0700 Subject: Account for missing turbofish in paths too --- src/libsyntax/parse/diagnostics.rs | 47 ++++++++++++++++++++++++++--- src/test/ui/did_you_mean/issue-40396.stderr | 5 +-- 2 files changed, 46 insertions(+), 6 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/diagnostics.rs b/src/libsyntax/parse/diagnostics.rs index 584c7c2ded5..4fbd36cfefc 100644 --- a/src/libsyntax/parse/diagnostics.rs +++ b/src/libsyntax/parse/diagnostics.rs @@ -585,12 +585,51 @@ impl<'a> Parser<'a> { let early_return = vec![token::Eof]; self.consume_tts(1, &modifiers[..], &early_return[..]); - if self.token.kind != token::OpenDelim(token::Paren) { - // We don't have `foo< bar >(`, so we rewind the parser and bail out. + if !&[ + token::OpenDelim(token::Paren), + token::ModSep, + ].contains(&self.token.kind) { + // We don't have `foo< bar >(` or `foo< bar >::`, so we rewind the + // parser and bail out. mem::replace(self, snapshot.clone()); } } - if self.token.kind == token::OpenDelim(token::Paren) { + if token::ModSep == self.token.kind { + // We have some certainty that this was a bad turbofish at this point. + // `foo< bar >::` + err.span_suggestion( + op_span.shrink_to_lo(), + msg, + "::".to_string(), + Applicability::MaybeIncorrect, + ); + + let snapshot = self.clone(); + + self.bump(); // `::` + // Consume the rest of the likely `foo::new()` or return at `foo`. + match self.parse_expr() { + Ok(_) => { + // 99% certain that the suggestion is correct, continue parsing. + err.emit(); + // FIXME: actually check that the two expressions in the binop are + // paths and resynthesize new fn call expression instead of using + // `ExprKind::Err` placeholder. + return Ok(Some(self.mk_expr( + lhs.span.to(self.prev_span), + ExprKind::Err, + ThinVec::new(), + ))); + } + Err(mut err) => { + err.cancel(); + // Not entirely sure now, but we bubble the error up with the + // suggestion. + mem::replace(self, snapshot); + return Err(err); + } + } + } else if token::OpenDelim(token::Paren) == self.token.kind { // We have high certainty that this was a bad turbofish at this point. // `foo< bar >(` err.span_suggestion( @@ -601,6 +640,7 @@ impl<'a> Parser<'a> { ); let snapshot = self.clone(); + self.bump(); // `(` // Consume the fn call arguments. let modifiers = vec![ @@ -608,7 +648,6 @@ impl<'a> Parser<'a> { (token::CloseDelim(token::Paren), -1), ]; let early_return = vec![token::Eof]; - self.bump(); // `(` self.consume_tts(1, &modifiers[..], &early_return[..]); if self.token.kind == token::Eof { diff --git a/src/test/ui/did_you_mean/issue-40396.stderr b/src/test/ui/did_you_mean/issue-40396.stderr index d0448cc265c..5e3771002b6 100644 --- a/src/test/ui/did_you_mean/issue-40396.stderr +++ b/src/test/ui/did_you_mean/issue-40396.stderr @@ -13,9 +13,10 @@ error: chained comparison operators require parentheses | LL | Vec::new(); | ^^^^^ +help: use `::<...>` instead of `<...>` if you meant to specify type arguments | - = help: use `::<...>` instead of `<...>` if you meant to specify type arguments - = help: or use `(...)` if you meant to specify fn arguments +LL | Vec::::new(); + | ^^ error: chained comparison operators require parentheses --> $DIR/issue-40396.rs:12:20 -- cgit 1.4.1-3-g733a5 From dfdc369b40da72eb9ff466fab89584c7815d7a80 Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Tue, 1 Oct 2019 11:24:05 -0700 Subject: review comments --- src/libsyntax/parse/diagnostics.rs | 79 ++++++++++++---------- src/test/ui/did_you_mean/issue-40396.stderr | 6 +- .../require-parens-for-chained-comparison.rs | 18 +++-- .../require-parens-for-chained-comparison.stderr | 15 +++- 4 files changed, 70 insertions(+), 48 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/diagnostics.rs b/src/libsyntax/parse/diagnostics.rs index 4fbd36cfefc..14c5dc6132c 100644 --- a/src/libsyntax/parse/diagnostics.rs +++ b/src/libsyntax/parse/diagnostics.rs @@ -17,6 +17,8 @@ use syntax_pos::{Span, DUMMY_SP, MultiSpan, SpanSnippetError}; use log::{debug, trace}; use std::mem; +const TURBOFISH: &'static str = "use the \"turbofish\" `::<...>` instead of `<...>` to specify \ + type arguments"; /// Creates a placeholder argument. crate fn dummy_arg(ident: Ident) -> Param { let pat = P(Pat { @@ -544,10 +546,20 @@ impl<'a> Parser<'a> { /// Produces an error if comparison operators are chained (RFC #558). /// We only need to check the LHS, not the RHS, because all comparison ops have same - /// precedence and are left-associative. + /// precedence (see `fn precedence`) and are left-associative (see `fn fixity`). /// /// This can also be hit if someone incorrectly writes `foo()` when they should have used - /// the turbofish syntax. We attempt some heuristic recovery if that is the case. + /// the turbofish (`foo::()`) syntax. We attempt some heuristic recovery if that is the + /// case. + /// + /// Keep in mind that given that `outer_op.is_comparison()` holds and comparison ops are left + /// associative we can infer that we have: + /// + /// outer_op + /// / \ + /// inner_op r2 + /// / \ + /// l1 r1 crate fn check_no_chained_comparison( &mut self, lhs: &Expr, @@ -560,30 +572,36 @@ impl<'a> Parser<'a> { ); match lhs.kind { ExprKind::Binary(op, _, _) if op.node.is_comparison() => { - // Respan to include both operators. let op_span = op.span.to(self.prev_span); let mut err = self.struct_span_err( op_span, "chained comparison operators require parentheses", ); + + let suggest = |err: &mut DiagnosticBuilder<'_>| { + err.span_suggestion( + op_span.shrink_to_lo(), + TURBOFISH, + "::".to_string(), + Applicability::MaybeIncorrect, + ); + }; + if op.node == BinOpKind::Lt && *outer_op == AssocOp::Less || // Include `<` to provide this recommendation *outer_op == AssocOp::Greater // even in a case like the following: { // Foo>> - let msg = "use `::<...>` instead of `<...>` if you meant to specify type \ - arguments"; if *outer_op == AssocOp::Less { let snapshot = self.clone(); self.bump(); - // So far we have parsed `foo Parser<'a> { if token::ModSep == self.token.kind { // We have some certainty that this was a bad turbofish at this point. // `foo< bar >::` - err.span_suggestion( - op_span.shrink_to_lo(), - msg, - "::".to_string(), - Applicability::MaybeIncorrect, - ); + suggest(&mut err); let snapshot = self.clone(); - self.bump(); // `::` + // Consume the rest of the likely `foo::new()` or return at `foo`. match self.parse_expr() { Ok(_) => { @@ -621,8 +634,8 @@ impl<'a> Parser<'a> { ThinVec::new(), ))); } - Err(mut err) => { - err.cancel(); + Err(mut expr_err) => { + expr_err.cancel(); // Not entirely sure now, but we bubble the error up with the // suggestion. mem::replace(self, snapshot); @@ -632,45 +645,39 @@ impl<'a> Parser<'a> { } else if token::OpenDelim(token::Paren) == self.token.kind { // We have high certainty that this was a bad turbofish at this point. // `foo< bar >(` - err.span_suggestion( - op_span.shrink_to_lo(), - msg, - "::".to_string(), - Applicability::MaybeIncorrect, - ); + suggest(&mut err); let snapshot = self.clone(); self.bump(); // `(` // Consume the fn call arguments. - let modifiers = vec![ + let modifiers = [ (token::OpenDelim(token::Paren), 1), (token::CloseDelim(token::Paren), -1), ]; - let early_return = vec![token::Eof]; - self.consume_tts(1, &modifiers[..], &early_return[..]); + self.consume_tts(1, &modifiers[..], &[]); - if self.token.kind == token::Eof { + return if self.token.kind == token::Eof { // Not entirely sure now, but we bubble the error up with the // suggestion. mem::replace(self, snapshot); - return Err(err); + Err(err) } else { // 99% certain that the suggestion is correct, continue parsing. err.emit(); // FIXME: actually check that the two expressions in the binop are // paths and resynthesize new fn call expression instead of using // `ExprKind::Err` placeholder. - return Ok(Some(self.mk_expr( + Ok(Some(self.mk_expr( lhs.span.to(self.prev_span), ExprKind::Err, ThinVec::new(), - ))); + ))) } } else { // All we know is that this is `foo < bar >` and *nothing* else. Try to // be helpful, but don't attempt to recover. - err.help(msg); + err.help(TURBOFISH); err.help("or use `(...)` if you meant to specify fn arguments"); // These cases cause too many knock-down errors, bail out (#61329). } @@ -1459,15 +1466,15 @@ impl<'a> Parser<'a> { fn consume_tts( &mut self, - mut acc: i64, - modifier: &[(token::TokenKind, i64)], // Not using FxHasMap and FxHashSet due to + mut acc: i64, // `i64` because malformed code can have more closing delims than opening. + modifier: &[(token::TokenKind, i64)], // Not using `FxHashMap` and `FxHashSet` due to early_return: &[token::TokenKind], // `token::TokenKind: !Eq + !Hash`. ) { while acc > 0 { - if let Some((_, val)) = modifier.iter().filter(|(t, _)| *t == self.token.kind).next() { + if let Some((_, val)) = modifier.iter().find(|(t, _)| *t == self.token.kind) { acc += *val; } - if early_return.contains(&self.token.kind) { + if self.token.kind == token::Eof || early_return.contains(&self.token.kind) { break; } self.bump(); diff --git a/src/test/ui/did_you_mean/issue-40396.stderr b/src/test/ui/did_you_mean/issue-40396.stderr index dd19bc137e3..9757f8258c1 100644 --- a/src/test/ui/did_you_mean/issue-40396.stderr +++ b/src/test/ui/did_you_mean/issue-40396.stderr @@ -3,7 +3,7 @@ error: chained comparison operators require parentheses | LL | (0..13).collect>(); | ^^^^^ -help: use `::<...>` instead of `<...>` if you meant to specify type arguments +help: use the "turbofish" `::<...>` instead of `<...>` to specify type arguments | LL | (0..13).collect::>(); | ^^ @@ -13,7 +13,7 @@ error: chained comparison operators require parentheses | LL | Vec::new(); | ^^^^^ -help: use `::<...>` instead of `<...>` if you meant to specify type arguments +help: use the "turbofish" `::<...>` instead of `<...>` to specify type arguments | LL | Vec::::new(); | ^^ @@ -23,7 +23,7 @@ error: chained comparison operators require parentheses | LL | (0..13).collect(); | ^^^^^ -help: use `::<...>` instead of `<...>` if you meant to specify type arguments +help: use the "turbofish" `::<...>` instead of `<...>` to specify type arguments | LL | (0..13).collect::(); | ^^ diff --git a/src/test/ui/parser/require-parens-for-chained-comparison.rs b/src/test/ui/parser/require-parens-for-chained-comparison.rs index 11839938cb0..f3bfe2d482f 100644 --- a/src/test/ui/parser/require-parens-for-chained-comparison.rs +++ b/src/test/ui/parser/require-parens-for-chained-comparison.rs @@ -3,18 +3,24 @@ struct X; fn main() { false == false == false; - //~^ ERROR: chained comparison operators require parentheses + //~^ ERROR chained comparison operators require parentheses false == 0 < 2; - //~^ ERROR: chained comparison operators require parentheses - //~| ERROR: mismatched types - //~| ERROR: mismatched types + //~^ ERROR chained comparison operators require parentheses + //~| ERROR mismatched types + //~| ERROR mismatched types f(); //~^ ERROR chained comparison operators require parentheses - //~| HELP: use `::<...>` instead of `<...>` + //~| HELP use the "turbofish" `::<...>` instead of `<...>` to specify type arguments f, Option>>(1, 2); //~^ ERROR chained comparison operators require parentheses - //~| HELP: use `::<...>` instead of `<...>` + //~| HELP use the "turbofish" `::<...>` instead of `<...>` to specify type arguments + + use std::convert::identity; + let _ = identity; + //~^ ERROR chained comparison operators require parentheses + //~| HELP use the "turbofish" `::<...>` instead of `<...>` to specify type arguments + //~| HELP or use `(...)` if you meant to specify fn arguments } diff --git a/src/test/ui/parser/require-parens-for-chained-comparison.stderr b/src/test/ui/parser/require-parens-for-chained-comparison.stderr index 02fb56a7f9b..4b108e1db87 100644 --- a/src/test/ui/parser/require-parens-for-chained-comparison.stderr +++ b/src/test/ui/parser/require-parens-for-chained-comparison.stderr @@ -15,7 +15,7 @@ error: chained comparison operators require parentheses | LL | f(); | ^^^ -help: use `::<...>` instead of `<...>` if you meant to specify type arguments +help: use the "turbofish" `::<...>` instead of `<...>` to specify type arguments | LL | f::(); | ^^ @@ -25,11 +25,20 @@ error: chained comparison operators require parentheses | LL | f, Option>>(1, 2); | ^^^^^^^^ -help: use `::<...>` instead of `<...>` if you meant to specify type arguments +help: use the "turbofish" `::<...>` instead of `<...>` to specify type arguments | LL | f::, Option>>(1, 2); | ^^ +error: chained comparison operators require parentheses + --> $DIR/require-parens-for-chained-comparison.rs:22:21 + | +LL | let _ = identity; + | ^^^^ + | + = help: use the "turbofish" `::<...>` instead of `<...>` to specify type arguments + = help: or use `(...)` if you meant to specify fn arguments + error[E0308]: mismatched types --> $DIR/require-parens-for-chained-comparison.rs:8:14 | @@ -48,6 +57,6 @@ LL | false == 0 < 2; = note: expected type `bool` found type `{integer}` -error: aborting due to 6 previous errors +error: aborting due to 7 previous errors For more information about this error, try `rustc --explain E0308`. -- cgit 1.4.1-3-g733a5 From f1499a864688a484c04c4e53962dc8ec44f79a03 Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Tue, 1 Oct 2019 15:51:50 -0700 Subject: review comments --- src/libsyntax/parse/diagnostics.rs | 37 +++++++++++++++++-------------------- 1 file changed, 17 insertions(+), 20 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/diagnostics.rs b/src/libsyntax/parse/diagnostics.rs index 14c5dc6132c..72206ffb28d 100644 --- a/src/libsyntax/parse/diagnostics.rs +++ b/src/libsyntax/parse/diagnostics.rs @@ -570,6 +570,11 @@ impl<'a> Parser<'a> { "check_no_chained_comparison: {:?} is not comparison", outer_op, ); + + let mk_err_expr = |this: &Self, span| { + Ok(Some(this.mk_expr(span, ExprKind::Err, ThinVec::new()))) + }; + match lhs.kind { ExprKind::Binary(op, _, _) if op.node.is_comparison() => { // Respan to include both operators. @@ -601,7 +606,7 @@ impl<'a> Parser<'a> { (token::Gt, -1), (token::BinOp(token::Shr), -2), ]; - self.consume_tts(1, &modifiers[..], &[]); + self.consume_tts(1, &modifiers[..]); if !&[ token::OpenDelim(token::Paren), @@ -612,7 +617,7 @@ impl<'a> Parser<'a> { mem::replace(self, snapshot.clone()); } } - if token::ModSep == self.token.kind { + return if token::ModSep == self.token.kind { // We have some certainty that this was a bad turbofish at this point. // `foo< bar >::` suggest(&mut err); @@ -628,18 +633,14 @@ impl<'a> Parser<'a> { // FIXME: actually check that the two expressions in the binop are // paths and resynthesize new fn call expression instead of using // `ExprKind::Err` placeholder. - return Ok(Some(self.mk_expr( - lhs.span.to(self.prev_span), - ExprKind::Err, - ThinVec::new(), - ))); + mk_err_expr(self, lhs.span.to(self.prev_span)) } Err(mut expr_err) => { expr_err.cancel(); // Not entirely sure now, but we bubble the error up with the // suggestion. mem::replace(self, snapshot); - return Err(err); + Err(err) } } } else if token::OpenDelim(token::Paren) == self.token.kind { @@ -655,9 +656,9 @@ impl<'a> Parser<'a> { (token::OpenDelim(token::Paren), 1), (token::CloseDelim(token::Paren), -1), ]; - self.consume_tts(1, &modifiers[..], &[]); + self.consume_tts(1, &modifiers[..]); - return if self.token.kind == token::Eof { + if self.token.kind == token::Eof { // Not entirely sure now, but we bubble the error up with the // suggestion. mem::replace(self, snapshot); @@ -668,11 +669,7 @@ impl<'a> Parser<'a> { // FIXME: actually check that the two expressions in the binop are // paths and resynthesize new fn call expression instead of using // `ExprKind::Err` placeholder. - Ok(Some(self.mk_expr( - lhs.span.to(self.prev_span), - ExprKind::Err, - ThinVec::new(), - ))) + mk_err_expr(self, lhs.span.to(self.prev_span)) } } else { // All we know is that this is `foo < bar >` and *nothing* else. Try to @@ -680,8 +677,8 @@ impl<'a> Parser<'a> { err.help(TURBOFISH); err.help("or use `(...)` if you meant to specify fn arguments"); // These cases cause too many knock-down errors, bail out (#61329). - } - return Err(err); + Err(err) + }; } err.emit(); } @@ -1467,14 +1464,14 @@ impl<'a> Parser<'a> { fn consume_tts( &mut self, mut acc: i64, // `i64` because malformed code can have more closing delims than opening. - modifier: &[(token::TokenKind, i64)], // Not using `FxHashMap` and `FxHashSet` due to - early_return: &[token::TokenKind], // `token::TokenKind: !Eq + !Hash`. + // Not using `FxHashMap` due to `token::TokenKind: !Eq + !Hash`. + modifier: &[(token::TokenKind, i64)], ) { while acc > 0 { if let Some((_, val)) = modifier.iter().find(|(t, _)| *t == self.token.kind) { acc += *val; } - if self.token.kind == token::Eof || early_return.contains(&self.token.kind) { + if self.token.kind == token::Eof { break; } self.bump(); -- cgit 1.4.1-3-g733a5 From 02f57f83a9ea5903cb02bdc304800661c8f4296f Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Thu, 3 Oct 2019 13:22:18 -0700 Subject: review comments --- src/librustc_errors/diagnostic.rs | 41 +++++++++++++--- src/librustc_errors/emitter.rs | 4 +- src/librustc_errors/lib.rs | 2 + src/libsyntax/parse/diagnostics.rs | 57 ++++++++++++---------- src/test/ui/did_you_mean/issue-40396.stderr | 6 +-- .../require-parens-for-chained-comparison.rs | 6 +-- .../require-parens-for-chained-comparison.stderr | 6 +-- 7 files changed, 81 insertions(+), 41 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/librustc_errors/diagnostic.rs b/src/librustc_errors/diagnostic.rs index 3f1b91256c4..811a48a39f0 100644 --- a/src/librustc_errors/diagnostic.rs +++ b/src/librustc_errors/diagnostic.rs @@ -298,9 +298,13 @@ impl Diagnostic { /// * may contain a name of a function, variable, or type, but not whole expressions /// /// See `CodeSuggestion` for more information. - pub fn span_suggestion(&mut self, sp: Span, msg: &str, - suggestion: String, - applicability: Applicability) -> &mut Self { + pub fn span_suggestion( + &mut self, + sp: Span, + msg: &str, + suggestion: String, + applicability: Applicability, + ) -> &mut Self { self.suggestions.push(CodeSuggestion { substitutions: vec![Substitution { parts: vec![SubstitutionPart { @@ -315,10 +319,35 @@ impl Diagnostic { self } + pub fn span_suggestion_verbose( + &mut self, + sp: Span, + msg: &str, + suggestion: String, + applicability: Applicability, + ) -> &mut Self { + self.suggestions.push(CodeSuggestion { + substitutions: vec![Substitution { + parts: vec![SubstitutionPart { + snippet: suggestion, + span: sp, + }], + }], + msg: msg.to_owned(), + style: SuggestionStyle::ShowAlways, + applicability, + }); + self + } + /// Prints out a message with multiple suggested edits of the code. - pub fn span_suggestions(&mut self, sp: Span, msg: &str, - suggestions: impl Iterator, applicability: Applicability) -> &mut Self - { + pub fn span_suggestions( + &mut self, + sp: Span, + msg: &str, + suggestions: impl Iterator, + applicability: Applicability, + ) -> &mut Self { self.suggestions.push(CodeSuggestion { substitutions: suggestions.map(|snippet| Substitution { parts: vec![SubstitutionPart { diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index 0c7aa3582ac..bd8191065ee 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -221,7 +221,9 @@ pub trait Emitter { // when this style is set we want the suggestion to be a message, not inline sugg.style != SuggestionStyle::HideCodeAlways && // trivial suggestion for tooling's sake, never shown - sugg.style != SuggestionStyle::CompletelyHidden + sugg.style != SuggestionStyle::CompletelyHidden && + // subtle suggestion, never shown inline + sugg.style != SuggestionStyle::ShowAlways { let substitution = &sugg.substitutions[0].parts[0].snippet.trim(); let msg = if substitution.len() == 0 || sugg.style.hide_inline() { diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index f9dc13ce97e..2fae584c153 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -81,6 +81,8 @@ pub enum SuggestionStyle { /// This will *not* show the code if the suggestion is inline *and* the suggested code is /// empty. ShowCode, + /// Always show the suggested code independently. + ShowAlways, } impl SuggestionStyle { diff --git a/src/libsyntax/parse/diagnostics.rs b/src/libsyntax/parse/diagnostics.rs index 72206ffb28d..e3abf8ffc6c 100644 --- a/src/libsyntax/parse/diagnostics.rs +++ b/src/libsyntax/parse/diagnostics.rs @@ -17,8 +17,7 @@ use syntax_pos::{Span, DUMMY_SP, MultiSpan, SpanSnippetError}; use log::{debug, trace}; use std::mem; -const TURBOFISH: &'static str = "use the \"turbofish\" `::<...>` instead of `<...>` to specify \ - type arguments"; +const TURBOFISH: &'static str = "use `::<...>` instead of `<...>` to specify type arguments"; /// Creates a placeholder argument. crate fn dummy_arg(ident: Ident) -> Param { let pat = P(Pat { @@ -585,7 +584,7 @@ impl<'a> Parser<'a> { ); let suggest = |err: &mut DiagnosticBuilder<'_>| { - err.span_suggestion( + err.span_suggestion_verbose( op_span.shrink_to_lo(), TURBOFISH, "::".to_string(), @@ -647,29 +646,16 @@ impl<'a> Parser<'a> { // We have high certainty that this was a bad turbofish at this point. // `foo< bar >(` suggest(&mut err); - - let snapshot = self.clone(); - self.bump(); // `(` - // Consume the fn call arguments. - let modifiers = [ - (token::OpenDelim(token::Paren), 1), - (token::CloseDelim(token::Paren), -1), - ]; - self.consume_tts(1, &modifiers[..]); - - if self.token.kind == token::Eof { - // Not entirely sure now, but we bubble the error up with the - // suggestion. - mem::replace(self, snapshot); - Err(err) - } else { - // 99% certain that the suggestion is correct, continue parsing. - err.emit(); - // FIXME: actually check that the two expressions in the binop are - // paths and resynthesize new fn call expression instead of using - // `ExprKind::Err` placeholder. - mk_err_expr(self, lhs.span.to(self.prev_span)) + match self.consume_fn_args() { + Err(()) => Err(err), + Ok(()) => { + err.emit(); + // FIXME: actually check that the two expressions in the binop are + // paths and resynthesize new fn call expression instead of using + // `ExprKind::Err` placeholder. + mk_err_expr(self, lhs.span.to(self.prev_span)) + } } } else { // All we know is that this is `foo < bar >` and *nothing* else. Try to @@ -687,6 +673,27 @@ impl<'a> Parser<'a> { Ok(None) } + fn consume_fn_args(&mut self) -> Result<(), ()> { + let snapshot = self.clone(); + self.bump(); // `(` + + // Consume the fn call arguments. + let modifiers = [ + (token::OpenDelim(token::Paren), 1), + (token::CloseDelim(token::Paren), -1), + ]; + self.consume_tts(1, &modifiers[..]); + + if self.token.kind == token::Eof { + // Not entirely sure that what we consumed were fn arguments, rollback. + mem::replace(self, snapshot); + Err(()) + } else { + // 99% certain that the suggestion is correct, continue parsing. + Ok(()) + } + } + crate fn maybe_report_ambiguous_plus( &mut self, allow_plus: bool, diff --git a/src/test/ui/did_you_mean/issue-40396.stderr b/src/test/ui/did_you_mean/issue-40396.stderr index 9757f8258c1..7fc7c2628c4 100644 --- a/src/test/ui/did_you_mean/issue-40396.stderr +++ b/src/test/ui/did_you_mean/issue-40396.stderr @@ -3,7 +3,7 @@ error: chained comparison operators require parentheses | LL | (0..13).collect>(); | ^^^^^ -help: use the "turbofish" `::<...>` instead of `<...>` to specify type arguments +help: use `::<...>` instead of `<...>` to specify type arguments | LL | (0..13).collect::>(); | ^^ @@ -13,7 +13,7 @@ error: chained comparison operators require parentheses | LL | Vec::new(); | ^^^^^ -help: use the "turbofish" `::<...>` instead of `<...>` to specify type arguments +help: use `::<...>` instead of `<...>` to specify type arguments | LL | Vec::::new(); | ^^ @@ -23,7 +23,7 @@ error: chained comparison operators require parentheses | LL | (0..13).collect(); | ^^^^^ -help: use the "turbofish" `::<...>` instead of `<...>` to specify type arguments +help: use `::<...>` instead of `<...>` to specify type arguments | LL | (0..13).collect::(); | ^^ diff --git a/src/test/ui/parser/require-parens-for-chained-comparison.rs b/src/test/ui/parser/require-parens-for-chained-comparison.rs index f3bfe2d482f..9c7a25d589a 100644 --- a/src/test/ui/parser/require-parens-for-chained-comparison.rs +++ b/src/test/ui/parser/require-parens-for-chained-comparison.rs @@ -12,15 +12,15 @@ fn main() { f(); //~^ ERROR chained comparison operators require parentheses - //~| HELP use the "turbofish" `::<...>` instead of `<...>` to specify type arguments + //~| HELP use `::<...>` instead of `<...>` to specify type arguments f, Option>>(1, 2); //~^ ERROR chained comparison operators require parentheses - //~| HELP use the "turbofish" `::<...>` instead of `<...>` to specify type arguments + //~| HELP use `::<...>` instead of `<...>` to specify type arguments use std::convert::identity; let _ = identity; //~^ ERROR chained comparison operators require parentheses - //~| HELP use the "turbofish" `::<...>` instead of `<...>` to specify type arguments + //~| HELP use `::<...>` instead of `<...>` to specify type arguments //~| HELP or use `(...)` if you meant to specify fn arguments } diff --git a/src/test/ui/parser/require-parens-for-chained-comparison.stderr b/src/test/ui/parser/require-parens-for-chained-comparison.stderr index 4b108e1db87..5aa37a40cbd 100644 --- a/src/test/ui/parser/require-parens-for-chained-comparison.stderr +++ b/src/test/ui/parser/require-parens-for-chained-comparison.stderr @@ -15,7 +15,7 @@ error: chained comparison operators require parentheses | LL | f(); | ^^^ -help: use the "turbofish" `::<...>` instead of `<...>` to specify type arguments +help: use `::<...>` instead of `<...>` to specify type arguments | LL | f::(); | ^^ @@ -25,7 +25,7 @@ error: chained comparison operators require parentheses | LL | f, Option>>(1, 2); | ^^^^^^^^ -help: use the "turbofish" `::<...>` instead of `<...>` to specify type arguments +help: use `::<...>` instead of `<...>` to specify type arguments | LL | f::, Option>>(1, 2); | ^^ @@ -36,7 +36,7 @@ error: chained comparison operators require parentheses LL | let _ = identity; | ^^^^ | - = help: use the "turbofish" `::<...>` instead of `<...>` to specify type arguments + = help: use `::<...>` instead of `<...>` to specify type arguments = help: or use `(...)` if you meant to specify fn arguments error[E0308]: mismatched types -- cgit 1.4.1-3-g733a5 From 5f94a53d1a4e03787886b8bca750566d80255f85 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sat, 5 Oct 2019 04:34:26 +0200 Subject: Account for macro invocation in `let mut $pat` diagnostic. --- src/libsyntax/parse/parser/pat.rs | 6 ++- .../issue-65122-mac-invoc-in-mut-patterns.rs | 26 +++++++++++++ .../issue-65122-mac-invoc-in-mut-patterns.stderr | 45 ++++++++++++++++++++++ 3 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/parser/issue-65122-mac-invoc-in-mut-patterns.rs create mode 100644 src/test/ui/parser/issue-65122-mac-invoc-in-mut-patterns.stderr (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index 7eb2a73a11a..48f9e301610 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -4,7 +4,7 @@ use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole}; use crate::ptr::P; use crate::ast::{self, Attribute, Pat, PatKind, FieldPat, RangeEnd, RangeSyntax, Mac}; use crate::ast::{BindingMode, Ident, Mutability, Path, QSelf, Expr, ExprKind}; -use crate::mut_visit::{noop_visit_pat, MutVisitor}; +use crate::mut_visit::{noop_visit_pat, noop_visit_mac, MutVisitor}; use crate::parse::token::{self}; use crate::print::pprust; use crate::source_map::{respan, Span, Spanned}; @@ -481,6 +481,10 @@ impl<'a> Parser<'a> { fn make_all_value_bindings_mutable(pat: &mut P) -> bool { struct AddMut(bool); impl MutVisitor for AddMut { + fn visit_mac(&mut self, mac: &mut Mac) { + noop_visit_mac(mac, self); + } + fn visit_pat(&mut self, pat: &mut P) { if let PatKind::Ident(BindingMode::ByValue(ref mut m @ Mutability::Immutable), ..) = pat.kind diff --git a/src/test/ui/parser/issue-65122-mac-invoc-in-mut-patterns.rs b/src/test/ui/parser/issue-65122-mac-invoc-in-mut-patterns.rs new file mode 100644 index 00000000000..97a405b6999 --- /dev/null +++ b/src/test/ui/parser/issue-65122-mac-invoc-in-mut-patterns.rs @@ -0,0 +1,26 @@ +// Regression test; used to ICE with 'visit_mac disabled by default' due to a +// `MutVisitor` in `fn make_all_value_bindings_mutable` (`parse/parser/pat.rs`). + +macro_rules! mac1 { + ($eval:expr) => { + let mut $eval = (); + //~^ ERROR `mut` must be followed by a named binding + }; +} + +macro_rules! mac2 { + ($eval:pat) => { + let mut $eval = (); + //~^ ERROR `mut` must be followed by a named binding + //~| ERROR expected identifier, found `does_not_exist!()` + }; +} + +fn foo() { + mac1! { does_not_exist!() } + //~^ ERROR cannot find macro `does_not_exist` in this scope + mac2! { does_not_exist!() } + //~^ ERROR cannot find macro `does_not_exist` in this scope +} + +fn main() {} diff --git a/src/test/ui/parser/issue-65122-mac-invoc-in-mut-patterns.stderr b/src/test/ui/parser/issue-65122-mac-invoc-in-mut-patterns.stderr new file mode 100644 index 00000000000..dd193d6a86e --- /dev/null +++ b/src/test/ui/parser/issue-65122-mac-invoc-in-mut-patterns.stderr @@ -0,0 +1,45 @@ +error: `mut` must be followed by a named binding + --> $DIR/issue-65122-mac-invoc-in-mut-patterns.rs:6:13 + | +LL | let mut $eval = (); + | ^^^^^^^^^ help: remove the `mut` prefix: `does_not_exist!()` +... +LL | mac1! { does_not_exist!() } + | --------------------------- in this macro invocation + | + = note: `mut` may be followed by `variable` and `variable @ pattern` + +error: expected identifier, found `does_not_exist!()` + --> $DIR/issue-65122-mac-invoc-in-mut-patterns.rs:13:17 + | +LL | let mut $eval = (); + | ^^^^^ expected identifier +... +LL | mac2! { does_not_exist!() } + | --------------------------- in this macro invocation + +error: `mut` must be followed by a named binding + --> $DIR/issue-65122-mac-invoc-in-mut-patterns.rs:13:13 + | +LL | let mut $eval = (); + | ^^^ help: remove the `mut` prefix: `does_not_exist!()` +... +LL | mac2! { does_not_exist!() } + | --------------------------- in this macro invocation + | + = note: `mut` may be followed by `variable` and `variable @ pattern` + +error: cannot find macro `does_not_exist` in this scope + --> $DIR/issue-65122-mac-invoc-in-mut-patterns.rs:20:13 + | +LL | mac1! { does_not_exist!() } + | ^^^^^^^^^^^^^^ + +error: cannot find macro `does_not_exist` in this scope + --> $DIR/issue-65122-mac-invoc-in-mut-patterns.rs:22:13 + | +LL | mac2! { does_not_exist!() } + | ^^^^^^^^^^^^^^ + +error: aborting due to 5 previous errors + -- cgit 1.4.1-3-g733a5 From e0fe4be4657493fb1cd292911df0d9470d8c38e3 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 1 Oct 2019 12:11:38 +0200 Subject: syntax: cleanup associated const parsing. --- src/libsyntax/parse/parser/item.rs | 71 +++++++++++++++++++++----------------- 1 file changed, 39 insertions(+), 32 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/parser/item.rs b/src/libsyntax/parse/parser/item.rs index 2ac0352764f..6a832d5f301 100644 --- a/src/libsyntax/parse/parser/item.rs +++ b/src/libsyntax/parse/parser/item.rs @@ -4,7 +4,7 @@ use crate::maybe_whole; use crate::ptr::P; use crate::ast::{ self, DUMMY_NODE_ID, Ident, Attribute, AttrStyle, - Item, ItemKind, ImplItem, TraitItem, TraitItemKind, + Item, ItemKind, ImplItem, ImplItemKind, TraitItem, TraitItemKind, UseTree, UseTreeKind, PathSegment, IsAuto, Constness, IsAsync, Unsafety, Defaultness, Visibility, VisibilityKind, Mutability, FnDecl, FnHeader, MethodSig, Block, @@ -727,16 +727,7 @@ impl<'a> Parser<'a> { }; (name, kind, generics) } else if self.is_const_item() { - // This parses the grammar: - // ImplItemConst = "const" Ident ":" Ty "=" Expr ";" - self.expect_keyword(kw::Const)?; - let name = self.parse_ident()?; - self.expect(&token::Colon)?; - let typ = self.parse_ty()?; - self.expect(&token::Eq)?; - let expr = self.parse_expr()?; - self.expect(&token::Semi)?; - (name, ast::ImplItemKind::Const(typ, expr), Generics::default()) + self.parse_impl_const()? } else { let (name, inner_attrs, generics, kind) = self.parse_impl_method(&vis, at_end)?; attrs.extend(inner_attrs); @@ -785,12 +776,25 @@ impl<'a> Parser<'a> { !self.is_keyword_ahead(1, &[kw::Fn, kw::Unsafe]) } + /// This parses the grammar: + /// ImplItemConst = "const" Ident ":" Ty "=" Expr ";" + fn parse_impl_const(&mut self) -> PResult<'a, (Ident, ImplItemKind, Generics)> { + self.expect_keyword(kw::Const)?; + let name = self.parse_ident()?; + self.expect(&token::Colon)?; + let typ = self.parse_ty()?; + self.expect(&token::Eq)?; + let expr = self.parse_expr()?; + self.expect(&token::Semi)?; + Ok((name, ImplItemKind::Const(typ, expr), Generics::default())) + } + /// Parses a method or a macro invocation in a trait impl. fn parse_impl_method( &mut self, vis: &Visibility, at_end: &mut bool - ) -> PResult<'a, (Ident, Vec, Generics, ast::ImplItemKind)> { + ) -> PResult<'a, (Ident, Vec, Generics, ImplItemKind)> { // FIXME: code copied from `parse_macro_use_or_failure` -- use abstraction! if let Some(mac) = self.parse_assoc_macro_invoc("impl", Some(vis), at_end)? { // method macro @@ -935,30 +939,20 @@ impl<'a> Parser<'a> { Ok(item) } - fn parse_trait_item_(&mut self, - at_end: &mut bool, - mut attrs: Vec) -> PResult<'a, TraitItem> { + fn parse_trait_item_( + &mut self, + at_end: &mut bool, + mut attrs: Vec, + ) -> PResult<'a, TraitItem> { let lo = self.token.span; self.eat_bad_pub(); let (name, kind, generics) = if self.eat_keyword(kw::Type) { self.parse_trait_item_assoc_ty()? } else if self.is_const_item() { - self.expect_keyword(kw::Const)?; - let ident = self.parse_ident()?; - self.expect(&token::Colon)?; - let ty = self.parse_ty()?; - let default = if self.eat(&token::Eq) { - let expr = self.parse_expr()?; - self.expect(&token::Semi)?; - Some(expr) - } else { - self.expect(&token::Semi)?; - None - }; - (ident, TraitItemKind::Const(ty, default), Generics::default()) + self.parse_trait_item_const()? } else if let Some(mac) = self.parse_assoc_macro_invoc("trait", None, &mut false)? { // trait item macro. - (Ident::invalid(), ast::TraitItemKind::Macro(mac), Generics::default()) + (Ident::invalid(), TraitItemKind::Macro(mac), Generics::default()) } else { // This is somewhat dubious; We don't want to allow // argument names to be left off if there is a definition... @@ -966,7 +960,7 @@ impl<'a> Parser<'a> { // We don't allow argument names to be left off in edition 2018. let (ident, sig, generics) = self.parse_method_sig(|t| t.span.rust_2018())?; let body = self.parse_trait_method_body(at_end, &mut attrs)?; - (ident, ast::TraitItemKind::Method(sig, body), generics) + (ident, TraitItemKind::Method(sig, body), generics) }; Ok(TraitItem { @@ -980,6 +974,20 @@ impl<'a> Parser<'a> { }) } + fn parse_trait_item_const(&mut self) -> PResult<'a, (Ident, TraitItemKind, Generics)> { + self.expect_keyword(kw::Const)?; + let ident = self.parse_ident()?; + self.expect(&token::Colon)?; + let ty = self.parse_ty()?; + let default = if self.eat(&token::Eq) { + Some(self.parse_expr()?) + } else { + None + }; + self.expect(&token::Semi)?; + Ok((ident, TraitItemKind::Const(ty, default), Generics::default())) + } + /// Parse the "body" of a method in a trait item definition. /// This can either be `;` when there's no body, /// or e.g. a block when the method is a provided one. @@ -1020,8 +1028,7 @@ impl<'a> Parser<'a> { /// Parses the following grammar: /// /// TraitItemAssocTy = Ident ["<"...">"] [":" [GenericBounds]] ["where" ...] ["=" Ty] - fn parse_trait_item_assoc_ty(&mut self) - -> PResult<'a, (Ident, TraitItemKind, Generics)> { + fn parse_trait_item_assoc_ty(&mut self) -> PResult<'a, (Ident, TraitItemKind, Generics)> { let ident = self.parse_ident()?; let mut generics = self.parse_generics()?; -- cgit 1.4.1-3-g733a5 From 3bdbfbe8b9c78bcec9019e7452a2a9396ecc861e Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 1 Oct 2019 12:40:56 +0200 Subject: syntax: de-dups in item parsing. --- src/libsyntax/parse/parser/item.rs | 94 ++++++++++++++++++-------------------- 1 file changed, 44 insertions(+), 50 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/parser/item.rs b/src/libsyntax/parse/parser/item.rs index 6a832d5f301..95137f93b88 100644 --- a/src/libsyntax/parse/parser/item.rs +++ b/src/libsyntax/parse/parser/item.rs @@ -98,7 +98,7 @@ impl<'a> Parser<'a> { let lo = self.token.span; - let visibility = self.parse_visibility(false)?; + let vis = self.parse_visibility(false)?; if self.eat_keyword(kw::Use) { // USE ITEM @@ -106,15 +106,14 @@ impl<'a> Parser<'a> { self.expect(&token::Semi)?; let span = lo.to(self.prev_span); - let item = - self.mk_item(span, Ident::invalid(), item_, visibility, attrs); + let item = self.mk_item(span, Ident::invalid(), item_, vis, attrs); return Ok(Some(item)); } if self.eat_keyword(kw::Extern) { let extern_sp = self.prev_span; if self.eat_keyword(kw::Crate) { - return Ok(Some(self.parse_item_extern_crate(lo, visibility, attrs)?)); + return Ok(Some(self.parse_item_extern_crate(lo, vis, attrs)?)); } let opt_abi = self.parse_opt_abi()?; @@ -128,10 +127,10 @@ impl<'a> Parser<'a> { constness: respan(fn_span, Constness::NotConst), abi: opt_abi.unwrap_or(Abi::C), }; - return self.parse_item_fn(lo, visibility, attrs, header); + return self.parse_item_fn(lo, vis, attrs, header); } else if self.check(&token::OpenDelim(token::Brace)) { return Ok(Some( - self.parse_item_foreign_mod(lo, opt_abi, visibility, attrs, extern_sp)?, + self.parse_item_foreign_mod(lo, opt_abi, vis, attrs, extern_sp)?, )); } @@ -142,10 +141,8 @@ impl<'a> Parser<'a> { self.bump(); // STATIC ITEM let m = self.parse_mutability(); - let (ident, item_, extra_attrs) = self.parse_item_const(Some(m))?; - let span = lo.to(self.prev_span); - let attrs = maybe_append(attrs, extra_attrs); - return Ok(Some(self.mk_item(span, ident, item_, visibility, attrs))); + let info = self.parse_item_const(Some(m)); + return self.mk_item_with_info(attrs, lo, vis, info); } if self.eat_keyword(kw::Const) { let const_span = self.prev_span; @@ -168,7 +165,7 @@ impl<'a> Parser<'a> { constness: respan(const_span, Constness::Const), abi, }; - return self.parse_item_fn(lo, visibility, attrs, header); + return self.parse_item_fn(lo, vis, attrs, header); } // CONST ITEM @@ -184,10 +181,8 @@ impl<'a> Parser<'a> { ) .emit(); } - let (ident, item_, extra_attrs) = self.parse_item_const(None)?; - let span = lo.to(self.prev_span); - let attrs = maybe_append(attrs, extra_attrs); - return Ok(Some(self.mk_item(span, ident, item_, visibility, attrs))); + let info = self.parse_item_const(None); + return self.mk_item_with_info(attrs, lo, vis, info); } // Parses `async unsafe? fn`. @@ -212,7 +207,7 @@ impl<'a> Parser<'a> { constness: respan(fn_span, Constness::NotConst), abi: Abi::Rust, }; - return self.parse_item_fn(lo, visibility, attrs, header); + return self.parse_item_fn(lo, vis, attrs, header); } } if self.check_keyword(kw::Unsafe) && @@ -227,10 +222,8 @@ impl<'a> Parser<'a> { self.expect_keyword(kw::Trait)?; IsAuto::Yes }; - let (ident, item_, extra_attrs) = self.parse_item_trait(is_auto, Unsafety::Unsafe)?; - let span = lo.to(self.prev_span); - let attrs = maybe_append(attrs, extra_attrs); - return Ok(Some(self.mk_item(span, ident, item_, visibility, attrs))); + let info = self.parse_item_trait(is_auto, Unsafety::Unsafe); + return self.mk_item_with_info(attrs, lo, vis, info); } if self.check_keyword(kw::Impl) || self.check_keyword(kw::Unsafe) && @@ -241,10 +234,8 @@ impl<'a> Parser<'a> { let defaultness = self.parse_defaultness(); let unsafety = self.parse_unsafety(); self.expect_keyword(kw::Impl)?; - let (ident, item_, extra_attrs) = self.parse_item_impl(unsafety, defaultness)?; - let span = lo.to(self.prev_span); - let attrs = maybe_append(attrs, extra_attrs); - return Ok(Some(self.mk_item(span, ident, item_, visibility, attrs))); + let info = self.parse_item_impl(unsafety, defaultness); + return self.mk_item_with_info(attrs, lo, vis, info); } if self.check_keyword(kw::Fn) { // FUNCTION ITEM @@ -256,7 +247,7 @@ impl<'a> Parser<'a> { constness: respan(fn_span, Constness::NotConst), abi: Abi::Rust, }; - return self.parse_item_fn(lo, visibility, attrs, header); + return self.parse_item_fn(lo, vis, attrs, header); } if self.check_keyword(kw::Unsafe) && self.look_ahead(1, |t| *t != token::OpenDelim(token::Brace)) { @@ -273,14 +264,12 @@ impl<'a> Parser<'a> { constness: respan(fn_span, Constness::NotConst), abi, }; - return self.parse_item_fn(lo, visibility, attrs, header); + return self.parse_item_fn(lo, vis, attrs, header); } if self.eat_keyword(kw::Mod) { // MODULE ITEM - let (ident, item_, extra_attrs) = self.parse_item_mod(&attrs[..])?; - let span = lo.to(self.prev_span); - let attrs = maybe_append(attrs, extra_attrs); - return Ok(Some(self.mk_item(span, ident, item_, visibility, attrs))); + let info = self.parse_item_mod(&attrs[..]); + return self.mk_item_with_info(attrs, lo, vis, info); } if let Some(type_) = self.eat_type() { let (ident, alias, generics) = type_?; @@ -290,14 +279,12 @@ impl<'a> Parser<'a> { AliasKind::OpaqueTy(bounds) => ItemKind::OpaqueTy(bounds, generics), }; let span = lo.to(self.prev_span); - return Ok(Some(self.mk_item(span, ident, item_, visibility, attrs))); + return Ok(Some(self.mk_item(span, ident, item_, vis, attrs))); } if self.eat_keyword(kw::Enum) { // ENUM ITEM - let (ident, item_, extra_attrs) = self.parse_item_enum()?; - let span = lo.to(self.prev_span); - let attrs = maybe_append(attrs, extra_attrs); - return Ok(Some(self.mk_item(span, ident, item_, visibility, attrs))); + let info = self.parse_item_enum(); + return self.mk_item_with_info(attrs, lo, vis, info); } if self.check_keyword(kw::Trait) || (self.check_keyword(kw::Auto) @@ -311,33 +298,27 @@ impl<'a> Parser<'a> { IsAuto::Yes }; // TRAIT ITEM - let (ident, item_, extra_attrs) = self.parse_item_trait(is_auto, Unsafety::Normal)?; - let span = lo.to(self.prev_span); - let attrs = maybe_append(attrs, extra_attrs); - return Ok(Some(self.mk_item(span, ident, item_, visibility, attrs))); + let info = self.parse_item_trait(is_auto, Unsafety::Normal); + return self.mk_item_with_info(attrs, lo, vis, info); } if self.eat_keyword(kw::Struct) { // STRUCT ITEM - let (ident, item_, extra_attrs) = self.parse_item_struct()?; - let span = lo.to(self.prev_span); - let attrs = maybe_append(attrs, extra_attrs); - return Ok(Some(self.mk_item(span, ident, item_, visibility, attrs))); + let info = self.parse_item_struct(); + return self.mk_item_with_info(attrs, lo, vis, info); } if self.is_union_item() { // UNION ITEM self.bump(); - let (ident, item_, extra_attrs) = self.parse_item_union()?; - let span = lo.to(self.prev_span); - let attrs = maybe_append(attrs, extra_attrs); - return Ok(Some(self.mk_item(span, ident, item_, visibility, attrs))); + let info = self.parse_item_union(); + return self.mk_item_with_info(attrs, lo, vis, info); } - if let Some(macro_def) = self.eat_macro_def(&attrs, &visibility, lo)? { + if let Some(macro_def) = self.eat_macro_def(&attrs, &vis, lo)? { return Ok(Some(macro_def)); } // Verify whether we have encountered a struct or method definition where the user forgot to // add the `struct` or `fn` keyword after writing `pub`: `pub S {}` - if visibility.node.is_pub() && + if vis.node.is_pub() && self.check_ident() && self.look_ahead(1, |t| *t != token::Not) { @@ -428,7 +409,20 @@ impl<'a> Parser<'a> { return Err(err); } } - self.parse_macro_use_or_failure(attrs, macros_allowed, attributes_allowed, lo, visibility) + self.parse_macro_use_or_failure(attrs, macros_allowed, attributes_allowed, lo, vis) + } + + fn mk_item_with_info( + &self, + attrs: Vec, + lo: Span, + vis: Visibility, + info: PResult<'a, ItemInfo>, + ) -> PResult<'a, Option>> { + let (ident, item, extra_attrs) = info?; + let span = lo.to(self.prev_span); + let attrs = maybe_append(attrs, extra_attrs); + Ok(Some(self.mk_item(span, ident, item, vis, attrs))) } fn recover_first_param(&mut self) -> &'static str { -- cgit 1.4.1-3-g733a5 From 090f3fd0c958e4ea8e7a6dfe33ae647d339c0544 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 1 Oct 2019 13:48:54 +0200 Subject: syntax: further item parsing cleanup --- src/libsyntax/parse/parser/item.rs | 59 ++++++++++++++++++++++---------------- 1 file changed, 35 insertions(+), 24 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/parser/item.rs b/src/libsyntax/parse/parser/item.rs index 95137f93b88..004c179b7c7 100644 --- a/src/libsyntax/parse/parser/item.rs +++ b/src/libsyntax/parse/parser/item.rs @@ -141,14 +141,14 @@ impl<'a> Parser<'a> { self.bump(); // STATIC ITEM let m = self.parse_mutability(); - let info = self.parse_item_const(Some(m)); + let info = self.parse_item_const(Some(m))?; return self.mk_item_with_info(attrs, lo, vis, info); } + if self.eat_keyword(kw::Const) { let const_span = self.prev_span; if [kw::Fn, kw::Unsafe, kw::Extern].iter().any(|k| self.check_keyword(*k)) { // CONST FUNCTION ITEM - let unsafety = self.parse_unsafety(); if self.check_keyword(kw::Extern) { @@ -157,7 +157,7 @@ impl<'a> Parser<'a> { ); } let abi = self.parse_extern_abi()?; - self.bump(); // 'fn' + self.bump(); // `fn` let header = FnHeader { unsafety, @@ -181,7 +181,8 @@ impl<'a> Parser<'a> { ) .emit(); } - let info = self.parse_item_const(None); + + let info = self.parse_item_const(None)?; return self.mk_item_with_info(attrs, lo, vis, info); } @@ -210,6 +211,7 @@ impl<'a> Parser<'a> { return self.parse_item_fn(lo, vis, attrs, header); } } + if self.check_keyword(kw::Unsafe) && self.is_keyword_ahead(1, &[kw::Trait, kw::Auto]) { @@ -222,21 +224,24 @@ impl<'a> Parser<'a> { self.expect_keyword(kw::Trait)?; IsAuto::Yes }; - let info = self.parse_item_trait(is_auto, Unsafety::Unsafe); + let info = self.parse_item_trait(is_auto, Unsafety::Unsafe)?; return self.mk_item_with_info(attrs, lo, vis, info); } + if self.check_keyword(kw::Impl) || self.check_keyword(kw::Unsafe) && self.is_keyword_ahead(1, &[kw::Impl]) || self.check_keyword(kw::Default) && - self.is_keyword_ahead(1, &[kw::Impl, kw::Unsafe]) { + self.is_keyword_ahead(1, &[kw::Impl, kw::Unsafe]) + { // IMPL ITEM let defaultness = self.parse_defaultness(); let unsafety = self.parse_unsafety(); self.expect_keyword(kw::Impl)?; - let info = self.parse_item_impl(unsafety, defaultness); + let info = self.parse_item_impl(unsafety, defaultness)?; return self.mk_item_with_info(attrs, lo, vis, info); } + if self.check_keyword(kw::Fn) { // FUNCTION ITEM self.bump(); @@ -249,8 +254,10 @@ impl<'a> Parser<'a> { }; return self.parse_item_fn(lo, vis, attrs, header); } + if self.check_keyword(kw::Unsafe) - && self.look_ahead(1, |t| *t != token::OpenDelim(token::Brace)) { + && self.look_ahead(1, |t| *t != token::OpenDelim(token::Brace)) + { // UNSAFE FUNCTION ITEM self.bump(); // `unsafe` // `{` is also expected after `unsafe`; in case of error, include it in the diagnostic. @@ -266,11 +273,13 @@ impl<'a> Parser<'a> { }; return self.parse_item_fn(lo, vis, attrs, header); } + if self.eat_keyword(kw::Mod) { // MODULE ITEM - let info = self.parse_item_mod(&attrs[..]); + let info = self.parse_item_mod(&attrs[..])?; return self.mk_item_with_info(attrs, lo, vis, info); } + if let Some(type_) = self.eat_type() { let (ident, alias, generics) = type_?; // TYPE ITEM @@ -281,37 +290,41 @@ impl<'a> Parser<'a> { let span = lo.to(self.prev_span); return Ok(Some(self.mk_item(span, ident, item_, vis, attrs))); } + if self.eat_keyword(kw::Enum) { // ENUM ITEM - let info = self.parse_item_enum(); + let info = self.parse_item_enum()?; return self.mk_item_with_info(attrs, lo, vis, info); } + if self.check_keyword(kw::Trait) || (self.check_keyword(kw::Auto) && self.is_keyword_ahead(1, &[kw::Trait])) { - let is_auto = if self.eat_keyword(kw::Trait) { - IsAuto::No - } else { - self.expect_keyword(kw::Auto)?; - self.expect_keyword(kw::Trait)?; + // TRAIT ITEM + let is_auto = if self.eat_keyword(kw::Auto) { IsAuto::Yes + } else { + IsAuto::No }; - // TRAIT ITEM - let info = self.parse_item_trait(is_auto, Unsafety::Normal); + self.expect_keyword(kw::Trait)?; + let info = self.parse_item_trait(is_auto, Unsafety::Normal)?; return self.mk_item_with_info(attrs, lo, vis, info); } + if self.eat_keyword(kw::Struct) { // STRUCT ITEM - let info = self.parse_item_struct(); + let info = self.parse_item_struct()?; return self.mk_item_with_info(attrs, lo, vis, info); } + if self.is_union_item() { // UNION ITEM self.bump(); - let info = self.parse_item_union(); + let info = self.parse_item_union()?; return self.mk_item_with_info(attrs, lo, vis, info); } + if let Some(macro_def) = self.eat_macro_def(&attrs, &vis, lo)? { return Ok(Some(macro_def)); } @@ -417,9 +430,9 @@ impl<'a> Parser<'a> { attrs: Vec, lo: Span, vis: Visibility, - info: PResult<'a, ItemInfo>, + info: ItemInfo, ) -> PResult<'a, Option>> { - let (ident, item, extra_attrs) = info?; + let (ident, item, extra_attrs) = info; let span = lo.to(self.prev_span); let attrs = maybe_append(attrs, extra_attrs); Ok(Some(self.mk_item(span, ident, item, vis, attrs))) @@ -1195,10 +1208,8 @@ impl<'a> Parser<'a> { let allow_c_variadic = header.abi == Abi::C && header.unsafety == Unsafety::Unsafe; let (ident, decl, generics) = self.parse_fn_sig(allow_c_variadic)?; let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; - let span = lo.to(self.prev_span); let kind = ItemKind::Fn(decl, header, generics, body); - let attrs = maybe_append(attrs, Some(inner_attrs)); - Ok(Some(self.mk_item(span, ident, kind, vis, attrs))) + self.mk_item_with_info(attrs, lo, vis, (ident, kind, Some(inner_attrs))) } /// Parse the "signature", including the identifier, parameters, and generics of a function. -- cgit 1.4.1-3-g733a5 From 7f9638d5d4b0b0f4ad592c135e155cdef1ddfb72 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 1 Oct 2019 14:19:08 +0200 Subject: syntax: unify trait parsing a bit. --- src/libsyntax/parse/parser/item.rs | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/parser/item.rs b/src/libsyntax/parse/parser/item.rs index 004c179b7c7..17b23651e80 100644 --- a/src/libsyntax/parse/parser/item.rs +++ b/src/libsyntax/parse/parser/item.rs @@ -217,14 +217,7 @@ impl<'a> Parser<'a> { { // UNSAFE TRAIT ITEM self.bump(); // `unsafe` - let is_auto = if self.eat_keyword(kw::Trait) { - IsAuto::No - } else { - self.expect_keyword(kw::Auto)?; - self.expect_keyword(kw::Trait)?; - IsAuto::Yes - }; - let info = self.parse_item_trait(is_auto, Unsafety::Unsafe)?; + let info = self.parse_item_trait(Unsafety::Unsafe)?; return self.mk_item_with_info(attrs, lo, vis, info); } @@ -302,13 +295,7 @@ impl<'a> Parser<'a> { && self.is_keyword_ahead(1, &[kw::Trait])) { // TRAIT ITEM - let is_auto = if self.eat_keyword(kw::Auto) { - IsAuto::Yes - } else { - IsAuto::No - }; - self.expect_keyword(kw::Trait)?; - let info = self.parse_item_trait(is_auto, Unsafety::Normal)?; + let info = self.parse_item_trait(Unsafety::Normal)?; return self.mk_item_with_info(attrs, lo, vis, info); } @@ -860,8 +847,16 @@ impl<'a> Parser<'a> { Ok(FnHeader { constness, unsafety, asyncness, abi }) } - /// Parses `trait Foo { ... }` or `trait Foo = Bar;`. - fn parse_item_trait(&mut self, is_auto: IsAuto, unsafety: Unsafety) -> PResult<'a, ItemInfo> { + /// Parses `auto? trait Foo { ... }` or `trait Foo = Bar;`. + fn parse_item_trait(&mut self, unsafety: Unsafety) -> PResult<'a, ItemInfo> { + // Parse optional `auto` prefix. + let is_auto = if self.eat_keyword(kw::Auto) { + IsAuto::Yes + } else { + IsAuto::No + }; + + self.expect_keyword(kw::Trait)?; let ident = self.parse_ident()?; let mut tps = self.parse_generics()?; -- cgit 1.4.1-3-g733a5 From a7ba754b6c021bc6244cde8c52d3d0b352082560 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Thu, 3 Oct 2019 03:39:46 +0200 Subject: syntax: unify and simplify fn signature parsing. --- src/libsyntax/parse/parser.rs | 96 ++++++++++++++--------------------- src/libsyntax/parse/parser/item.rs | 55 ++++++++++---------- src/libsyntax/parse/parser/ty.rs | 14 ++--- src/test/ui/parser/issue-33413.rs | 1 + src/test/ui/parser/issue-33413.stderr | 14 ++++- 5 files changed, 88 insertions(+), 92 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 93165b09649..4a457f5a43c 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -11,7 +11,7 @@ mod stmt; mod generics; use crate::ast::{ - self, DUMMY_NODE_ID, AttrStyle, Attribute, BindingMode, CrateSugar, FnDecl, Ident, + self, DUMMY_NODE_ID, AttrStyle, Attribute, BindingMode, CrateSugar, Ident, IsAsync, MacDelimiter, Mutability, Param, StrStyle, SelfKind, TyKind, Visibility, VisibilityKind, Unsafety, }; @@ -56,6 +56,17 @@ crate enum BlockMode { Ignore, } +/// The parsing configuration used to parse a parameter list (see `parse_fn_params`). +struct ParamCfg { + /// Is `self` is allowed as the first parameter? + is_self_allowed: bool, + /// Is `...` allowed as the tail of the parameter list? + allow_c_variadic: bool, + /// `is_name_required` decides if, per-parameter, + /// the parameter must have a pattern or just a type. + is_name_required: fn(&token::Token) -> bool, +} + /// Like `maybe_whole_expr`, but for things other than expressions. #[macro_export] macro_rules! maybe_whole { @@ -1094,26 +1105,18 @@ impl<'a> Parser<'a> { res } - fn parse_fn_params( - &mut self, - named_params: bool, - allow_c_variadic: bool, - ) -> PResult<'a, Vec> { + /// Parses the parameter list of a function, including the `(` and `)` delimiters. + fn parse_fn_params(&mut self, mut cfg: ParamCfg) -> PResult<'a, Vec> { let sp = self.token.span; - let do_not_enforce_named_params_for_c_variadic = |token: &token::Token| { - match token.kind { - token::DotDotDot => false, - _ => named_params, - } - }; + let is_trait_item = cfg.is_self_allowed; let mut c_variadic = false; + // Parse the arguments, starting out with `self` being possibly allowed... let (params, _) = self.parse_paren_comma_seq(|p| { - match p.parse_param_general( - false, - false, - allow_c_variadic, - do_not_enforce_named_params_for_c_variadic, - ) { + let param = p.parse_param_general(&cfg, is_trait_item); + // ...now that we've parsed the first argument, `self` is no longer allowed. + cfg.is_self_allowed = false; + + match param { Ok(param) => Ok( if let TyKind::CVarArgs = param.ty.kind { c_variadic = true; @@ -1144,7 +1147,10 @@ impl<'a> Parser<'a> { } })?; - let params: Vec<_> = params.into_iter().filter_map(|x| x).collect(); + let mut params: Vec<_> = params.into_iter().filter_map(|x| x).collect(); + + // Replace duplicated recovered params with `_` pattern to avoid unecessary errors. + self.deduplicate_recovered_params_names(&mut params); if c_variadic && params.len() <= 1 { self.span_err( @@ -1156,79 +1162,53 @@ impl<'a> Parser<'a> { Ok(params) } - /// Parses the parameter list and result type of a function that may have a `self` parameter. - fn parse_fn_decl_with_self( - &mut self, - is_name_required: impl Copy + Fn(&token::Token) -> bool, - ) -> PResult<'a, P> { - // Parse the arguments, starting out with `self` being allowed... - let mut is_self_allowed = true; - let (mut inputs, _): (Vec<_>, _) = self.parse_paren_comma_seq(|p| { - let res = p.parse_param_general(is_self_allowed, true, false, is_name_required); - // ...but now that we've parsed the first argument, `self` is no longer allowed. - is_self_allowed = false; - res - })?; - - // Replace duplicated recovered params with `_` pattern to avoid unecessary errors. - self.deduplicate_recovered_params_names(&mut inputs); - - Ok(P(FnDecl { - inputs, - output: self.parse_ret_ty(true)?, - })) - } - /// Skips unexpected attributes and doc comments in this position and emits an appropriate /// error. /// This version of parse param doesn't necessarily require identifier names. - fn parse_param_general( - &mut self, - is_self_allowed: bool, - is_trait_item: bool, - allow_c_variadic: bool, - is_name_required: impl Fn(&token::Token) -> bool, - ) -> PResult<'a, Param> { + fn parse_param_general(&mut self, cfg: &ParamCfg, is_trait_item: bool) -> PResult<'a, Param> { let lo = self.token.span; let attrs = self.parse_outer_attributes()?; // Possibly parse `self`. Recover if we parsed it and it wasn't allowed here. if let Some(mut param) = self.parse_self_param()? { param.attrs = attrs.into(); - return if is_self_allowed { + return if cfg.is_self_allowed { Ok(param) } else { self.recover_bad_self_param(param, is_trait_item) }; } - let is_name_required = is_name_required(&self.token); + let is_name_required = match self.token.kind { + token::DotDotDot => false, + _ => (cfg.is_name_required)(&self.token), + }; let (pat, ty) = if is_name_required || self.is_named_param() { debug!("parse_param_general parse_pat (is_name_required:{})", is_name_required); let pat = self.parse_fn_param_pat()?; if let Err(mut err) = self.expect(&token::Colon) { - if let Some(ident) = self.parameter_without_type( + return if let Some(ident) = self.parameter_without_type( &mut err, pat, is_name_required, - is_self_allowed, + cfg.is_self_allowed, is_trait_item, ) { err.emit(); - return Ok(dummy_arg(ident)); + Ok(dummy_arg(ident)) } else { - return Err(err); - } + Err(err) + }; } self.eat_incorrect_doc_comment_for_param_type(); - (pat, self.parse_ty_common(true, true, allow_c_variadic)?) + (pat, self.parse_ty_common(true, true, cfg.allow_c_variadic)?) } else { debug!("parse_param_general ident_to_pat"); let parser_snapshot_before_ty = self.clone(); self.eat_incorrect_doc_comment_for_param_type(); - let mut ty = self.parse_ty_common(true, true, allow_c_variadic); + let mut ty = self.parse_ty_common(true, true, cfg.allow_c_variadic); if ty.is_ok() && self.token != token::Comma && self.token != token::CloseDelim(token::Paren) { // This wasn't actually a type, but a pattern looking like a type, diff --git a/src/libsyntax/parse/parser/item.rs b/src/libsyntax/parse/parser/item.rs index 17b23651e80..d2ea0829595 100644 --- a/src/libsyntax/parse/parser/item.rs +++ b/src/libsyntax/parse/parser/item.rs @@ -1,4 +1,4 @@ -use super::{Parser, PResult, PathStyle, SemiColonMode, BlockMode}; +use super::{Parser, PResult, PathStyle, SemiColonMode, BlockMode, ParamCfg}; use crate::maybe_whole; use crate::ptr::P; @@ -805,14 +805,15 @@ impl<'a> Parser<'a> { /// of a method. The body is not parsed as that differs between `trait`s and `impl`s. fn parse_method_sig( &mut self, - is_name_required: impl Copy + Fn(&token::Token) -> bool, + is_name_required: fn(&token::Token) -> bool, ) -> PResult<'a, (Ident, MethodSig, Generics)> { let header = self.parse_fn_front_matter()?; - let (ident, mut generics) = self.parse_fn_header()?; - let decl = self.parse_fn_decl_with_self(is_name_required)?; - let sig = MethodSig { header, decl }; - generics.where_clause = self.parse_where_clause()?; - Ok((ident, sig, generics)) + let (ident, decl, generics) = self.parse_fn_sig(ParamCfg { + is_self_allowed: true, + allow_c_variadic: false, + is_name_required, + })?; + Ok((ident, MethodSig { header, decl }, generics)) } /// Parses all the "front matter" for a `fn` declaration, up to @@ -1200,36 +1201,34 @@ impl<'a> Parser<'a> { attrs: Vec, header: FnHeader, ) -> PResult<'a, Option>> { - let allow_c_variadic = header.abi == Abi::C && header.unsafety == Unsafety::Unsafe; - let (ident, decl, generics) = self.parse_fn_sig(allow_c_variadic)?; + let (ident, decl, generics) = self.parse_fn_sig(ParamCfg { + is_self_allowed: false, + allow_c_variadic: header.abi == Abi::C && header.unsafety == Unsafety::Unsafe, + is_name_required: |_| true, + })?; let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; let kind = ItemKind::Fn(decl, header, generics, body); self.mk_item_with_info(attrs, lo, vis, (ident, kind, Some(inner_attrs))) } /// Parse the "signature", including the identifier, parameters, and generics of a function. - fn parse_fn_sig( - &mut self, - allow_c_variadic: bool, - ) -> PResult<'a, (Ident, P, Generics)> { - let (ident, mut generics) = self.parse_fn_header()?; - let decl = self.parse_fn_decl(allow_c_variadic)?; + fn parse_fn_sig(&mut self, cfg: ParamCfg) -> PResult<'a, (Ident, P, Generics)> { + let ident = self.parse_ident()?; + let mut generics = self.parse_generics()?; + let decl = self.parse_fn_decl(cfg, true)?; generics.where_clause = self.parse_where_clause()?; Ok((ident, decl, generics)) } - /// Parses the name and optional generic types of a function header. - fn parse_fn_header(&mut self) -> PResult<'a, (Ident, Generics)> { - let id = self.parse_ident()?; - let generics = self.parse_generics()?; - Ok((id, generics)) - } - /// Parses the parameter list and result type of a function declaration. - fn parse_fn_decl(&mut self, allow_c_variadic: bool) -> PResult<'a, P> { + pub(super) fn parse_fn_decl( + &mut self, + cfg: ParamCfg, + ret_allow_plus: bool, + ) -> PResult<'a, P> { Ok(P(FnDecl { - inputs: self.parse_fn_params(true, allow_c_variadic)?, - output: self.parse_ret_ty(true)?, + inputs: self.parse_fn_params(cfg)?, + output: self.parse_ret_ty(ret_allow_plus)?, })) } @@ -1353,7 +1352,11 @@ impl<'a> Parser<'a> { extern_sp: Span, ) -> PResult<'a, ForeignItem> { self.expect_keyword(kw::Fn)?; - let (ident, decl, generics) = self.parse_fn_sig(true)?; + let (ident, decl, generics) = self.parse_fn_sig(super::ParamCfg { + is_self_allowed: false, + allow_c_variadic: true, + is_name_required: |_| true, + })?; let span = lo.to(self.token.span); self.parse_semi_or_incorrect_foreign_fn_body(&ident, extern_sp)?; Ok(ast::ForeignItem { diff --git a/src/libsyntax/parse/parser/ty.rs b/src/libsyntax/parse/parser/ty.rs index 41ee2a1599d..c9446a880b0 100644 --- a/src/libsyntax/parse/parser/ty.rs +++ b/src/libsyntax/parse/parser/ty.rs @@ -4,7 +4,7 @@ use crate::{maybe_whole, maybe_recover_from_interpolated_ty_qpath}; use crate::ptr::P; use crate::ast::{self, Ty, TyKind, MutTy, BareFnTy, FunctionRetTy, GenericParam, Lifetime, Ident}; use crate::ast::{TraitBoundModifier, TraitObjectSyntax, GenericBound, GenericBounds, PolyTraitRef}; -use crate::ast::{Mutability, AnonConst, FnDecl, Mac}; +use crate::ast::{Mutability, AnonConst, Mac}; use crate::parse::token::{self, Token}; use crate::source_map::Span; use crate::symbol::{kw}; @@ -288,12 +288,12 @@ impl<'a> Parser<'a> { }; self.expect_keyword(kw::Fn)?; - let inputs = self.parse_fn_params(false, true)?; - let ret_ty = self.parse_ret_ty(false)?; - let decl = P(FnDecl { - inputs, - output: ret_ty, - }); + let cfg = super::ParamCfg { + is_self_allowed: false, + allow_c_variadic: true, + is_name_required: |_| false, + }; + let decl = self.parse_fn_decl(cfg, false)?; Ok(TyKind::BareFn(P(BareFnTy { abi, unsafety, diff --git a/src/test/ui/parser/issue-33413.rs b/src/test/ui/parser/issue-33413.rs index 22f80a8aae8..7291732cebe 100644 --- a/src/test/ui/parser/issue-33413.rs +++ b/src/test/ui/parser/issue-33413.rs @@ -3,6 +3,7 @@ struct S; impl S { fn f(*, a: u8) -> u8 {} //~^ ERROR expected parameter name, found `*` + //~| ERROR mismatched types } fn main() {} diff --git a/src/test/ui/parser/issue-33413.stderr b/src/test/ui/parser/issue-33413.stderr index 9e1178e8ac1..7e5c348e36c 100644 --- a/src/test/ui/parser/issue-33413.stderr +++ b/src/test/ui/parser/issue-33413.stderr @@ -4,5 +4,17 @@ error: expected parameter name, found `*` LL | fn f(*, a: u8) -> u8 {} | ^ expected parameter name -error: aborting due to previous error +error[E0308]: mismatched types + --> $DIR/issue-33413.rs:4:23 + | +LL | fn f(*, a: u8) -> u8 {} + | - ^^ expected u8, found () + | | + | implicitly returns `()` as its body has no tail or `return` expression + | + = note: expected type `u8` + found type `()` + +error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0308`. -- cgit 1.4.1-3-g733a5 From 9c6582a2c0c5a527e3fc3ce581244d85b3b71761 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 7 Oct 2019 06:18:47 +0200 Subject: syntax: use `parse_extern_abi` more. --- src/libsyntax/parse/parser/ty.rs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/parser/ty.rs b/src/libsyntax/parse/parser/ty.rs index c9446a880b0..018b5951e6e 100644 --- a/src/libsyntax/parse/parser/ty.rs +++ b/src/libsyntax/parse/parser/ty.rs @@ -9,8 +9,6 @@ use crate::parse::token::{self, Token}; use crate::source_map::Span; use crate::symbol::{kw}; -use rustc_target::spec::abi::Abi; - use errors::{Applicability, pluralise}; /// Returns `true` if `IDENT t` can start a type -- `IDENT::a::b`, `IDENT`, @@ -281,12 +279,7 @@ impl<'a> Parser<'a> { */ let unsafety = self.parse_unsafety(); - let abi = if self.eat_keyword(kw::Extern) { - self.parse_opt_abi()?.unwrap_or(Abi::C) - } else { - Abi::Rust - }; - + let abi = self.parse_extern_abi()?; self.expect_keyword(kw::Fn)?; let cfg = super::ParamCfg { is_self_allowed: false, -- cgit 1.4.1-3-g733a5 From 6b23c22ccad4044476b65fc8f3e32794f1884781 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 7 Oct 2019 06:31:02 +0200 Subject: syntax: refactor with new `fn parse_use_tree_glob_or_nested`. --- src/libsyntax/parse/parser/item.rs | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/parser/item.rs b/src/libsyntax/parse/parser/item.rs index d2ea0829595..3c60c88e2aa 100644 --- a/src/libsyntax/parse/parser/item.rs +++ b/src/libsyntax/parse/parser/item.rs @@ -1077,21 +1077,13 @@ impl<'a> Parser<'a> { ); } - if self.eat(&token::BinOp(token::Star)) { - UseTreeKind::Glob - } else { - UseTreeKind::Nested(self.parse_use_tree_list()?) - } + self.parse_use_tree_glob_or_nested()? } else { // `use path::*;` or `use path::{...};` or `use path;` or `use path as bar;` prefix = self.parse_path(PathStyle::Mod)?; if self.eat(&token::ModSep) { - if self.eat(&token::BinOp(token::Star)) { - UseTreeKind::Glob - } else { - UseTreeKind::Nested(self.parse_use_tree_list()?) - } + self.parse_use_tree_glob_or_nested()? } else { UseTreeKind::Simple(self.parse_rename()?, DUMMY_NODE_ID, DUMMY_NODE_ID) } @@ -1100,6 +1092,15 @@ impl<'a> Parser<'a> { Ok(UseTree { prefix, kind, span: lo.to(self.prev_span) }) } + /// Parses `*` or `{...}`. + fn parse_use_tree_glob_or_nested(&mut self) -> PResult<'a, UseTreeKind> { + Ok(if self.eat(&token::BinOp(token::Star)) { + UseTreeKind::Glob + } else { + UseTreeKind::Nested(self.parse_use_tree_list()?) + }) + } + /// Parses a `UseTreeKind::Nested(list)`. /// /// ``` -- cgit 1.4.1-3-g733a5 From 9f09387f53792740edcb5dd0eea49ab02d3fe891 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 8 Oct 2019 10:46:08 +0200 Subject: syntax: simplify maybe_annotate_with_ascription --- src/libsyntax/parse/diagnostics.rs | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/diagnostics.rs b/src/libsyntax/parse/diagnostics.rs index f376c19a66c..42cbe28fc17 100644 --- a/src/libsyntax/parse/diagnostics.rs +++ b/src/libsyntax/parse/diagnostics.rs @@ -2,7 +2,7 @@ use crate::ast::{ self, Param, BinOpKind, BindingMode, BlockCheckMode, Expr, ExprKind, Ident, Item, ItemKind, Mutability, Pat, PatKind, PathSegment, QSelf, Ty, TyKind, VariantData, }; -use crate::feature_gate::{feature_err, UnstableFeatures}; +use crate::feature_gate::feature_err; use crate::parse::{SeqSep, PResult, Parser, ParseSess}; use crate::parse::parser::{BlockMode, PathStyle, SemiColonMode, TokenType, TokenExpectType}; use crate::parse::token::{self, TokenKind}; @@ -387,14 +387,17 @@ impl<'a> Parser<'a> { let next_pos = sm.lookup_char_pos(self.token.span.lo()); let op_pos = sm.lookup_char_pos(sp.hi()); + let allow_unstable = self.sess.unstable_features.is_nightly_build(); + if likely_path { err.span_suggestion( sp, "maybe write a path separator here", "::".to_string(), - match self.sess.unstable_features { - UnstableFeatures::Disallow => Applicability::MachineApplicable, - _ => Applicability::MaybeIncorrect, + if allow_unstable { + Applicability::MaybeIncorrect + } else { + Applicability::MachineApplicable }, ); } else if op_pos.line != next_pos.line && maybe_expected_semicolon { @@ -404,14 +407,13 @@ impl<'a> Parser<'a> { ";".to_string(), Applicability::MaybeIncorrect, ); - } else if let UnstableFeatures::Disallow = self.sess.unstable_features { - err.span_label(sp, "tried to parse a type due to this"); - } else { + } else if allow_unstable { err.span_label(sp, "tried to parse a type due to this type ascription"); + } else { + err.span_label(sp, "tried to parse a type due to this"); } - if let UnstableFeatures::Disallow = self.sess.unstable_features { + if allow_unstable { // Give extra information about type ascription only if it's a nightly compiler. - } else { err.note("`#![feature(type_ascription)]` lets you annotate an expression with a \ type: `: `"); err.note("for more information, see \ -- cgit 1.4.1-3-g733a5 From 7effe633b0a729b641c7b8f1f8a21b97f9154b14 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 8 Oct 2019 10:59:05 +0200 Subject: simplify integer_lit --- src/libsyntax/lib.rs | 1 + src/libsyntax/parse/literal.rs | 15 ++++++--------- 2 files changed, 7 insertions(+), 9 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 03b00188e25..09a47795a82 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -17,6 +17,7 @@ #![feature(proc_macro_internals)] #![feature(proc_macro_span)] #![feature(try_trait)] +#![feature(slice_patterns)] #![feature(unicode_internals)] #![recursion_limit="256"] diff --git a/src/libsyntax/parse/literal.rs b/src/libsyntax/parse/literal.rs index fcd5b2782fd..56a79bfe5d5 100644 --- a/src/libsyntax/parse/literal.rs +++ b/src/libsyntax/parse/literal.rs @@ -426,15 +426,12 @@ fn integer_lit(symbol: Symbol, suffix: Option) -> Result 1 && s.as_bytes()[0] == b'0' { - match s.as_bytes()[1] { - b'x' => base = 16, - b'o' => base = 8, - b'b' => base = 2, - _ => {} - } - } + let base = match s.as_bytes() { + [b'0', b'x', ..] => 16, + [b'0', b'o', ..] => 8, + [b'0', b'b', ..] => 2, + _ => 10, + }; let ty = match suffix { Some(suf) => match suf { -- cgit 1.4.1-3-g733a5 From 742ec4b9bf7ae7d693da7fe75e5f974e0fafb9d0 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 8 Oct 2019 22:17:46 +0200 Subject: ast: remove implicit pprust dependency via Display. Instead just use `pprust::path_to_string(..)` where needed. This has two benefits: a) The AST definition is now independent of printing it. (Therefore we get closer to extracting a data-crate.) b) Debugging should be easier as program flow is clearer. --- src/librustc/lint/levels.rs | 3 ++- src/librustc_lint/builtin.rs | 5 +++-- src/librustc_mir/dataflow/mod.rs | 6 ++--- src/librustc_passes/ast_validation.rs | 3 ++- src/librustc_resolve/build_reduced_graph.rs | 3 ++- src/librustc_resolve/lib.rs | 5 +++-- src/librustc_resolve/macros.rs | 10 ++++++--- src/librustdoc/html/render.rs | 3 ++- src/libsyntax/ast.rs | 7 ------ src/libsyntax/attr/builtin.rs | 34 +++++++++++++++++++++-------- src/libsyntax/ext/expand.rs | 13 +++++++---- src/libsyntax/parse/diagnostics.rs | 2 +- src/libsyntax/parse/parser.rs | 6 +++-- src/libsyntax/parse/parser/expr.rs | 7 ++++-- src/libsyntax_ext/proc_macro_harness.rs | 28 +++++++++++++++++------- 15 files changed, 88 insertions(+), 47 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/librustc/lint/levels.rs b/src/librustc/lint/levels.rs index 28afe9730a0..60b1b192d10 100644 --- a/src/librustc/lint/levels.rs +++ b/src/librustc/lint/levels.rs @@ -12,6 +12,7 @@ use rustc_data_structures::stable_hasher::{HashStable, ToStableHashKey, StableHa use syntax::ast; use syntax::attr; use syntax::feature_gate; +use syntax::print::pprust; use syntax::source_map::MultiSpan; use syntax::symbol::{Symbol, sym}; @@ -285,7 +286,7 @@ impl<'a> LintLevelsBuilder<'a> { tool_ident.span, E0710, "an unknown tool name found in scoped lint: `{}`", - meta_item.path + pprust::path_to_string(&meta_item.path), ); continue; } diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index d0a7eab071c..9a16d0a0715 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -45,7 +45,7 @@ use syntax::feature_gate::{Stability, deprecated_attributes}; use syntax_pos::{BytePos, Span}; use syntax::symbol::{Symbol, kw, sym}; use syntax::errors::{Applicability, DiagnosticBuilder}; -use syntax::print::pprust::expr_to_string; +use syntax::print::pprust::{self, expr_to_string}; use syntax::visit::FnKind; use rustc::hir::{self, GenericParamKind, PatKind}; @@ -701,7 +701,8 @@ impl EarlyLintPass for DeprecatedAttr { } } if attr.check_name(sym::no_start) || attr.check_name(sym::crate_id) { - let msg = format!("use of deprecated attribute `{}`: no longer used.", attr.path); + let path_str = pprust::path_to_string(&attr.path); + let msg = format!("use of deprecated attribute `{}`: no longer used.", path_str); lint_deprecated_attr(cx, attr, &msg, None); } } diff --git a/src/librustc_mir/dataflow/mod.rs b/src/librustc_mir/dataflow/mod.rs index 06999abdc8b..ad0f75d7725 100644 --- a/src/librustc_mir/dataflow/mod.rs +++ b/src/librustc_mir/dataflow/mod.rs @@ -1,4 +1,5 @@ use syntax::ast::{self, MetaItem}; +use syntax::print::pprust; use syntax::symbol::{Symbol, sym}; use rustc_index::bit_set::{BitSet, HybridBitSet}; @@ -159,9 +160,8 @@ where if let Some(s) = item.value_str() { return Some(s.to_string()) } else { - sess.span_err( - item.span, - &format!("{} attribute requires a path", item.path)); + let path = pprust::path_to_string(&item.path); + sess.span_err(item.span, &format!("{} attribute requires a path", path)); return None; } } diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index 0339b85ca55..43c4f720ad4 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -263,7 +263,8 @@ impl<'a> AstValidator<'a> { let mut err = self.err_handler().struct_span_err(poly.span, &format!("`?Trait` is not permitted in {}", where_)); if is_trait { - err.note(&format!("traits are `?{}` by default", poly.trait_ref.path)); + let path_str = pprust::path_to_string(&poly.trait_ref.path); + err.note(&format!("traits are `?{}` by default", path_str)); } err.emit(); } diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 030f9b97eb8..2b8965aa5d4 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -37,6 +37,7 @@ use syntax::ext::expand::AstFragment; use syntax::ext::hygiene::ExpnId; use syntax::feature_gate::is_builtin_attr; use syntax::parse::token::{self, Token}; +use syntax::print::pprust; use syntax::{span_err, struct_span_err}; use syntax::source_map::{respan, Spanned}; use syntax::symbol::{kw, sym}; @@ -228,7 +229,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { .span_suggestion( path.span, "try", - format!("crate::{}", path), + format!("crate::{}", pprust::path_to_string(&path)), Applicability::MaybeIncorrect, ) .emit(); diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 6aa85820ba8..ff8f7fc7aa4 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -38,6 +38,7 @@ use rustc_metadata::cstore::CStore; use syntax::ext::hygiene::{ExpnId, Transparency, SyntaxContext}; use syntax::ast::{self, Name, NodeId, Ident, FloatTy, IntTy, UintTy}; use syntax::ext::base::{SyntaxExtension, MacroKind, SpecialDerives}; +use syntax::print::pprust; use syntax::symbol::{kw, sym}; use syntax::visit::{self, Visitor}; @@ -2011,13 +2012,13 @@ impl<'a> Resolver<'a> { let mut candidates = self.lookup_import_candidates(ident, TypeNS, is_mod); candidates.sort_by_cached_key(|c| { - (c.path.segments.len(), c.path.to_string()) + (c.path.segments.len(), pprust::path_to_string(&c.path)) }); if let Some(candidate) = candidates.get(0) { ( String::from("unresolved import"), Some(( - vec![(ident.span, candidate.path.to_string())], + vec![(ident.span, pprust::path_to_string(&candidate.path))], String::from("a similar path exists"), Applicability::MaybeIncorrect, )), diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 2b87bba8386..49186088fa0 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -21,6 +21,7 @@ use syntax::ext::hygiene::{self, ExpnId, ExpnData, ExpnKind}; use syntax::ext::compile_declarative_macro; use syntax::feature_gate::{emit_feature_err, is_builtin_attr_name}; use syntax::feature_gate::GateIssue; +use syntax::print::pprust; use syntax::symbol::{Symbol, kw, sym}; use syntax_pos::{Span, DUMMY_SP}; @@ -324,7 +325,8 @@ impl<'a> Resolver<'a> { Ok(if ext.macro_kind() != kind { let expected = kind.descr_expected(); - let msg = format!("expected {}, found {} `{}`", expected, res.descr(), path); + let path_str = pprust::path_to_string(path); + let msg = format!("expected {}, found {} `{}`", expected, res.descr(), path_str); self.session.struct_span_err(path.span, &msg) .span_label(path.span, format!("not {} {}", kind.article(), expected)) .emit(); @@ -805,14 +807,16 @@ impl<'a> Resolver<'a> { } } if let Some(depr) = &stability.rustc_depr { - let (message, lint) = stability::rustc_deprecation_message(depr, &path.to_string()); + let path = pprust::path_to_string(path); + let (message, lint) = stability::rustc_deprecation_message(depr, &path); stability::early_report_deprecation( self.session, &message, depr.suggestion, lint, span ); } } if let Some(depr) = &ext.deprecation { - let (message, lint) = stability::deprecation_message(depr, &path.to_string()); + let path = pprust::path_to_string(&path); + let (message, lint) = stability::deprecation_message(depr, &path); stability::early_report_deprecation(self.session, &message, None, lint, span); } } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 1ff71a0024b..b726ad1e0d6 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -46,6 +46,7 @@ use serialize::json::{ToJson, Json, as_json}; use syntax::ast; use syntax::edition::Edition; use syntax::ext::base::MacroKind; +use syntax::print::pprust; use syntax::source_map::FileName; use syntax::feature_gate::UnstableFeatures; use syntax::symbol::{Symbol, sym}; @@ -2957,7 +2958,7 @@ fn item_enum(w: &mut Buffer, cx: &Context, it: &clean::Item, e: &clean::Enum) { } fn render_attribute(attr: &ast::MetaItem) -> Option { - let path = attr.path.to_string(); + let path = pprust::path_to_string(&attr.path); if attr.is_word() { Some(path) diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 1c78672da1a..79d91125ec4 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -7,7 +7,6 @@ pub use crate::util::parser::ExprPrecedence; use crate::ext::hygiene::ExpnId; use crate::parse::token::{self, DelimToken}; -use crate::print::pprust; use crate::ptr::P; use crate::source_map::{dummy_spanned, respan, Spanned}; use crate::symbol::{kw, sym, Symbol}; @@ -86,12 +85,6 @@ impl PartialEq for Path { } } -impl fmt::Display for Path { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", pprust::path_to_string(self)) - } -} - impl Path { // Convert a span and an identifier to the corresponding // one-segment path. diff --git a/src/libsyntax/attr/builtin.rs b/src/libsyntax/attr/builtin.rs index 2a8e6b2cc95..efc48256e7c 100644 --- a/src/libsyntax/attr/builtin.rs +++ b/src/libsyntax/attr/builtin.rs @@ -5,6 +5,7 @@ use crate::early_buffered_lints::BufferedEarlyLintId; use crate::ext::base::ExtCtxt; use crate::feature_gate::{Features, GatedCfg}; use crate::parse::ParseSess; +use crate::print::pprust; use errors::{Applicability, Handler}; use syntax_pos::hygiene::Transparency; @@ -243,7 +244,11 @@ fn find_stability_generic<'a, I>(sess: &ParseSess, let meta = meta.as_ref().unwrap(); let get = |meta: &MetaItem, item: &mut Option| { if item.is_some() { - handle_errors(sess, meta.span, AttrError::MultipleItem(meta.path.to_string())); + handle_errors( + sess, + meta.span, + AttrError::MultipleItem(pprust::path_to_string(&meta.path)), + ); return false } if let Some(v) = meta.value_str() { @@ -271,7 +276,10 @@ fn find_stability_generic<'a, I>(sess: &ParseSess, handle_errors( sess, mi.span, - AttrError::UnknownMetaItem(mi.path.to_string(), expected), + AttrError::UnknownMetaItem( + pprust::path_to_string(&mi.path), + expected, + ), ); continue 'outer } @@ -362,7 +370,7 @@ fn find_stability_generic<'a, I>(sess: &ParseSess, sess, meta.span(), AttrError::UnknownMetaItem( - mi.path.to_string(), + pprust::path_to_string(&mi.path), &["feature", "reason", "issue", "soft"] ), ); @@ -434,7 +442,8 @@ fn find_stability_generic<'a, I>(sess: &ParseSess, sess, meta.span(), AttrError::UnknownMetaItem( - mi.path.to_string(), &["since", "note"], + pprust::path_to_string(&mi.path), + &["since", "note"], ), ); continue 'outer @@ -597,8 +606,11 @@ pub fn eval_condition(cfg: &ast::MetaItem, sess: &ParseSess, eval: &mut F) !eval_condition(mis[0].meta_item().unwrap(), sess, eval) }, _ => { - span_err!(sess.span_diagnostic, cfg.span, E0537, - "invalid predicate `{}`", cfg.path); + span_err!( + sess.span_diagnostic, cfg.span, E0537, + "invalid predicate `{}`", + pprust::path_to_string(&cfg.path) + ); false } } @@ -653,7 +665,9 @@ fn find_deprecation_generic<'a, I>(sess: &ParseSess, let get = |meta: &MetaItem, item: &mut Option| { if item.is_some() { handle_errors( - sess, meta.span, AttrError::MultipleItem(meta.path.to_string()) + sess, + meta.span, + AttrError::MultipleItem(pprust::path_to_string(&meta.path)), ); return false } @@ -691,8 +705,10 @@ fn find_deprecation_generic<'a, I>(sess: &ParseSess, handle_errors( sess, meta.span(), - AttrError::UnknownMetaItem(mi.path.to_string(), - &["since", "note"]), + AttrError::UnknownMetaItem( + pprust::path_to_string(&mi.path), + &["since", "note"], + ), ); continue 'outer } diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index bbd8da2acef..1e44f3dd5e5 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -13,6 +13,7 @@ use crate::mut_visit::*; use crate::parse::{DirectoryOwnership, PResult, ParseSess}; use crate::parse::token; use crate::parse::parser::Parser; +use crate::print::pprust; use crate::ptr::P; use crate::symbol::{sym, Symbol}; use crate::tokenstream::{TokenStream, TokenTree}; @@ -388,7 +389,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> { "`derive` may only be applied to structs, enums and unions"); if let ast::AttrStyle::Inner = attr.style { let trait_list = derives.iter() - .map(|t| t.to_string()).collect::>(); + .map(|t| pprust::path_to_string(t)) + .collect::>(); let suggestion = format!("#[derive({})]", trait_list.join(", ")); err.span_suggestion( span, "try an outer attribute", suggestion, @@ -587,8 +589,11 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let result = if let Some(result) = fragment_kind.make_from(tok_result) { result } else { - let msg = format!("non-{kind} macro in {kind} position: {path}", - kind = fragment_kind.name(), path = mac.path); + let msg = format!( + "non-{kind} macro in {kind} position: {path}", + kind = fragment_kind.name(), + path = pprust::path_to_string(&mac.path), + ); self.cx.span_err(span, &msg); self.cx.trace_macros_diag(); fragment_kind.dummy(span) @@ -878,7 +883,7 @@ impl<'a> Parser<'a> { err.span_label(span, "caused by the macro expansion here"); let msg = format!( "the usage of `{}!` is likely invalid in {} context", - macro_path, + pprust::path_to_string(¯o_path), kind_name, ); err.note(&msg); diff --git a/src/libsyntax/parse/diagnostics.rs b/src/libsyntax/parse/diagnostics.rs index f376c19a66c..df744e403d8 100644 --- a/src/libsyntax/parse/diagnostics.rs +++ b/src/libsyntax/parse/diagnostics.rs @@ -854,7 +854,7 @@ impl<'a> Parser<'a> { // This is a best-effort recovery. path.span, "try", - format!("<{}>::{}", ty_str, path), + format!("<{}>::{}", ty_str, pprust::path_to_string(&path)), Applicability::MaybeIncorrect, ) .emit(); diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 4a457f5a43c..a19380657fd 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1454,12 +1454,14 @@ impl<'a> Parser<'a> { `pub(super)`: visible only in the current module's parent `pub(in path::to::module)`: visible only on the specified path"##; + let path_str = pprust::path_to_string(&path); + struct_span_err!(self.sess.span_diagnostic, path.span, E0704, "{}", msg) .help(suggestion) .span_suggestion( path.span, - &format!("make this visible only to module `{}` with `in`", path), - format!("in {}", path), + &format!("make this visible only to module `{}` with `in`", path_str), + format!("in {}", path_str), Applicability::MachineApplicable, ) .emit(); diff --git a/src/libsyntax/parse/parser/expr.rs b/src/libsyntax/parse/parser/expr.rs index b459782d237..660bf9b7d65 100644 --- a/src/libsyntax/parse/parser/expr.rs +++ b/src/libsyntax/parse/parser/expr.rs @@ -552,8 +552,11 @@ impl<'a> Parser<'a> { // Report non-fatal diagnostics, keep `x as usize` as an expression // in AST and continue parsing. - let msg = format!("`<` is interpreted as a start of generic \ - arguments for `{}`, not a {}", path, op_noun); + let msg = format!( + "`<` is interpreted as a start of generic arguments for `{}`, not a {}", + pprust::path_to_string(&path), + op_noun, + ); let span_after_type = parser_snapshot_after_type.token.span; let expr = mk_expr(self, P(Ty { span: path.span, diff --git a/src/libsyntax_ext/proc_macro_harness.rs b/src/libsyntax_ext/proc_macro_harness.rs index 9b53bcb841c..1d48e8231b4 100644 --- a/src/libsyntax_ext/proc_macro_harness.rs +++ b/src/libsyntax_ext/proc_macro_harness.rs @@ -7,6 +7,7 @@ use syntax::ext::base::ExtCtxt; use syntax::ext::expand::{AstFragment, ExpansionConfig}; use syntax::ext::proc_macro::is_proc_macro_attr; use syntax::parse::ParseSess; +use syntax::print::pprust; use syntax::ptr::P; use syntax::symbol::{kw, sym}; use syntax::visit::{self, Visitor}; @@ -248,13 +249,20 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> { for attr in &item.attrs { if is_proc_macro_attr(&attr) { if let Some(prev_attr) = found_attr { + let path_str = pprust::path_to_string(&attr.path); let msg = if attr.path.segments[0].ident.name == prev_attr.path.segments[0].ident.name { - format!("only one `#[{}]` attribute is allowed on any given function", - attr.path) + format!( + "only one `#[{}]` attribute is allowed on any given function", + path_str, + ) } else { - format!("`#[{}]` and `#[{}]` attributes cannot both be applied \ - to the same function", attr.path, prev_attr.path) + format!( + "`#[{}]` and `#[{}]` attributes cannot both be applied + to the same function", + path_str, + pprust::path_to_string(&prev_attr.path), + ) }; self.handler.struct_span_err(attr.span, &msg) @@ -280,8 +288,10 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> { }; if !is_fn { - let msg = format!("the `#[{}]` attribute may only be used on bare functions", - attr.path); + let msg = format!( + "the `#[{}]` attribute may only be used on bare functions", + pprust::path_to_string(&attr.path), + ); self.handler.span_err(attr.span, &msg); return; @@ -292,8 +302,10 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> { } if !self.is_proc_macro_crate { - let msg = format!("the `#[{}]` attribute is only usable with crates of the \ - `proc-macro` crate type", attr.path); + let msg = format!( + "the `#[{}]` attribute is only usable with crates of the `proc-macro` crate type", + pprust::path_to_string(&attr.path), + ); self.handler.span_err(attr.span, &msg); return; -- cgit 1.4.1-3-g733a5 From e6ce3ef80aad6df7e9971d126bb22619ab34927e Mon Sep 17 00:00:00 2001 From: wangxiangqing Date: Sun, 13 Oct 2019 12:59:23 +0800 Subject: Collect occurrences of for mismatched braces diagnostic Change-Id: I20ba0b62308370ee961141fa1aefc4b9c9f0cb3a --- src/libsyntax/parse/lexer/tokentrees.rs | 18 ++++++++++++++++-- src/libsyntax/parse/token.rs | 2 +- .../ui/parser/mismatched-delim-brace-empty-block.rs | 3 +++ .../parser/mismatched-delim-brace-empty-block.stderr | 11 +++++++++++ 4 files changed, 31 insertions(+), 3 deletions(-) create mode 100644 src/test/ui/parser/mismatched-delim-brace-empty-block.rs create mode 100644 src/test/ui/parser/mismatched-delim-brace-empty-block.stderr (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/lexer/tokentrees.rs b/src/libsyntax/parse/lexer/tokentrees.rs index e5ba7e45309..fa494db2f9f 100644 --- a/src/libsyntax/parse/lexer/tokentrees.rs +++ b/src/libsyntax/parse/lexer/tokentrees.rs @@ -1,3 +1,4 @@ +use rustc_data_structures::fx::FxHashMap; use syntax_pos::Span; use crate::print::pprust::token_to_string; @@ -16,6 +17,7 @@ impl<'a> StringReader<'a> { unmatched_braces: Vec::new(), matching_delim_spans: Vec::new(), last_unclosed_found_span: None, + last_delim_empty_block_spans: FxHashMap::default() }; let res = tt_reader.parse_all_token_trees(); (res, tt_reader.unmatched_braces) @@ -34,6 +36,7 @@ struct TokenTreesReader<'a> { /// Used only for error recovery when arriving to EOF with mismatched braces. matching_delim_spans: Vec<(token::DelimToken, Span, Span)>, last_unclosed_found_span: Option, + last_delim_empty_block_spans: FxHashMap } impl<'a> TokenTreesReader<'a> { @@ -121,13 +124,20 @@ impl<'a> TokenTreesReader<'a> { // Correct delimiter. token::CloseDelim(d) if d == delim => { let (open_brace, open_brace_span) = self.open_braces.pop().unwrap(); + let close_brace_span = self.token.span; + + if close_brace_span.lo() == open_brace_span.hi() { + let empty_block_span = open_brace_span.to(close_brace_span); + self.last_delim_empty_block_spans.insert(delim, empty_block_span); + } + if self.open_braces.len() == 0 { // Clear up these spans to avoid suggesting them as we've found // properly matched delimiters so far for an entire block. self.matching_delim_spans.clear(); } else { self.matching_delim_spans.push( - (open_brace, open_brace_span, self.token.span), + (open_brace, open_brace_span, close_brace_span), ); } // Parse the close delimiter. @@ -193,13 +203,17 @@ impl<'a> TokenTreesReader<'a> { tts.into() ).into()) }, - token::CloseDelim(_) => { + token::CloseDelim(delim) => { // An unexpected closing delimiter (i.e., there is no // matching opening delimiter). let token_str = token_to_string(&self.token); let msg = format!("unexpected close delimiter: `{}`", token_str); let mut err = self.string_reader.sess.span_diagnostic .struct_span_err(self.token.span, &msg); + + if let Some(span) = self.last_delim_empty_block_spans.remove(&delim) { + err.span_label(span, "this block is empty, you might have not meant to close it"); + } err.span_label(self.token.span, "unexpected close delimiter"); Err(err) }, diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index fd78a2bd534..6038bcae5ae 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -36,7 +36,7 @@ pub enum BinOpToken { } /// A delimiter token. -#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] pub enum DelimToken { /// A round parenthesis (i.e., `(` or `)`). Paren, diff --git a/src/test/ui/parser/mismatched-delim-brace-empty-block.rs b/src/test/ui/parser/mismatched-delim-brace-empty-block.rs new file mode 100644 index 00000000000..bcc95c09e1e --- /dev/null +++ b/src/test/ui/parser/mismatched-delim-brace-empty-block.rs @@ -0,0 +1,3 @@ +fn main() {} + let _ = (); +} //~ ERROR unexpected close delimiter diff --git a/src/test/ui/parser/mismatched-delim-brace-empty-block.stderr b/src/test/ui/parser/mismatched-delim-brace-empty-block.stderr new file mode 100644 index 00000000000..82fe8930c32 --- /dev/null +++ b/src/test/ui/parser/mismatched-delim-brace-empty-block.stderr @@ -0,0 +1,11 @@ +error: unexpected close delimiter: `}` + --> $DIR/mismatched-delim-brace-empty-block.rs:3:1 + | +LL | fn main() {} + | -- this block is empty, you might have not meant to close it +LL | let _ = (); +LL | } + | ^ unexpected close delimiter + +error: aborting due to previous error + -- cgit 1.4.1-3-g733a5 From 888d0ba8df38681c08ac25f30ff4cbfad8168d90 Mon Sep 17 00:00:00 2001 From: wangxiangqing Date: Sun, 13 Oct 2019 12:59:23 +0800 Subject: Collect occurrences of for mismatched braces diagnostic Change-Id: I20ba0b62308370ee961141fa1aefc4b9c9f0cb3a --- src/libsyntax/parse/lexer/tokentrees.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/lexer/tokentrees.rs b/src/libsyntax/parse/lexer/tokentrees.rs index fa494db2f9f..b088d160b92 100644 --- a/src/libsyntax/parse/lexer/tokentrees.rs +++ b/src/libsyntax/parse/lexer/tokentrees.rs @@ -212,7 +212,10 @@ impl<'a> TokenTreesReader<'a> { .struct_span_err(self.token.span, &msg); if let Some(span) = self.last_delim_empty_block_spans.remove(&delim) { - err.span_label(span, "this block is empty, you might have not meant to close it"); + err.span_label( + span, + "this block is empty, you might have not meant to close it" + ); } err.span_label(self.token.span, "unexpected close delimiter"); Err(err) -- cgit 1.4.1-3-g733a5 From 4a0c487d1bfe483a9341a8e477475dbc4a72b3a6 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Fri, 11 Oct 2019 10:54:26 +0200 Subject: syntax: consolidate function parsing in `item.rs` --- src/libsyntax/parse/parser.rs | 285 +-------------- src/libsyntax/parse/parser/item.rs | 690 ++++++++++++++++++++++++++----------- src/libsyntax/parse/parser/ty.rs | 3 +- 3 files changed, 491 insertions(+), 487 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 4a457f5a43c..920208c8fd9 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -9,20 +9,19 @@ mod path; pub use path::PathStyle; mod stmt; mod generics; +use super::diagnostics::Error; use crate::ast::{ - self, DUMMY_NODE_ID, AttrStyle, Attribute, BindingMode, CrateSugar, Ident, - IsAsync, MacDelimiter, Mutability, Param, StrStyle, SelfKind, TyKind, Visibility, - VisibilityKind, Unsafety, + self, DUMMY_NODE_ID, AttrStyle, Attribute, CrateSugar, Ident, + IsAsync, MacDelimiter, Mutability, StrStyle, Visibility, VisibilityKind, Unsafety, }; use crate::parse::{ParseSess, PResult, Directory, DirectoryOwnership, SeqSep, literal, token}; -use crate::parse::diagnostics::{Error, dummy_arg}; use crate::parse::lexer::UnmatchedBrace; use crate::parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration}; use crate::parse::token::{Token, TokenKind, DelimToken}; use crate::print::pprust; use crate::ptr::P; -use crate::source_map::{self, respan}; +use crate::source_map::respan; use crate::symbol::{kw, sym, Symbol}; use crate::tokenstream::{self, DelimSpan, TokenTree, TokenStream, TreeAndJoint}; use crate::ThinVec; @@ -56,17 +55,6 @@ crate enum BlockMode { Ignore, } -/// The parsing configuration used to parse a parameter list (see `parse_fn_params`). -struct ParamCfg { - /// Is `self` is allowed as the first parameter? - is_self_allowed: bool, - /// Is `...` allowed as the tail of the parameter list? - allow_c_variadic: bool, - /// `is_name_required` decides if, per-parameter, - /// the parameter must have a pattern or just a type. - is_name_required: fn(&token::Token) -> bool, -} - /// Like `maybe_whole_expr`, but for things other than expressions. #[macro_export] macro_rules! maybe_whole { @@ -1105,271 +1093,6 @@ impl<'a> Parser<'a> { res } - /// Parses the parameter list of a function, including the `(` and `)` delimiters. - fn parse_fn_params(&mut self, mut cfg: ParamCfg) -> PResult<'a, Vec> { - let sp = self.token.span; - let is_trait_item = cfg.is_self_allowed; - let mut c_variadic = false; - // Parse the arguments, starting out with `self` being possibly allowed... - let (params, _) = self.parse_paren_comma_seq(|p| { - let param = p.parse_param_general(&cfg, is_trait_item); - // ...now that we've parsed the first argument, `self` is no longer allowed. - cfg.is_self_allowed = false; - - match param { - Ok(param) => Ok( - if let TyKind::CVarArgs = param.ty.kind { - c_variadic = true; - if p.token != token::CloseDelim(token::Paren) { - p.span_err( - p.token.span, - "`...` must be the last argument of a C-variadic function", - ); - // FIXME(eddyb) this should probably still push `CVarArgs`. - // Maybe AST validation/HIR lowering should emit the above error? - None - } else { - Some(param) - } - } else { - Some(param) - } - ), - 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)]); - // Create a placeholder argument for proper arg count (issue #34264). - let span = lo.to(p.prev_span); - Ok(Some(dummy_arg(Ident::new(kw::Invalid, span)))) - } - } - })?; - - let mut params: Vec<_> = params.into_iter().filter_map(|x| x).collect(); - - // Replace duplicated recovered params with `_` pattern to avoid unecessary errors. - self.deduplicate_recovered_params_names(&mut params); - - if c_variadic && params.len() <= 1 { - self.span_err( - sp, - "C-variadic function must be declared with at least one named argument", - ); - } - - Ok(params) - } - - /// Skips unexpected attributes and doc comments in this position and emits an appropriate - /// error. - /// This version of parse param doesn't necessarily require identifier names. - fn parse_param_general(&mut self, cfg: &ParamCfg, is_trait_item: bool) -> PResult<'a, Param> { - let lo = self.token.span; - let attrs = self.parse_outer_attributes()?; - - // Possibly parse `self`. Recover if we parsed it and it wasn't allowed here. - if let Some(mut param) = self.parse_self_param()? { - param.attrs = attrs.into(); - return if cfg.is_self_allowed { - Ok(param) - } else { - self.recover_bad_self_param(param, is_trait_item) - }; - } - - let is_name_required = match self.token.kind { - token::DotDotDot => false, - _ => (cfg.is_name_required)(&self.token), - }; - let (pat, ty) = if is_name_required || self.is_named_param() { - debug!("parse_param_general parse_pat (is_name_required:{})", is_name_required); - - let pat = self.parse_fn_param_pat()?; - if let Err(mut err) = self.expect(&token::Colon) { - return if let Some(ident) = self.parameter_without_type( - &mut err, - pat, - is_name_required, - cfg.is_self_allowed, - is_trait_item, - ) { - err.emit(); - Ok(dummy_arg(ident)) - } else { - Err(err) - }; - } - - self.eat_incorrect_doc_comment_for_param_type(); - (pat, self.parse_ty_common(true, true, cfg.allow_c_variadic)?) - } else { - debug!("parse_param_general ident_to_pat"); - let parser_snapshot_before_ty = self.clone(); - self.eat_incorrect_doc_comment_for_param_type(); - let mut ty = self.parse_ty_common(true, true, cfg.allow_c_variadic); - if ty.is_ok() && self.token != token::Comma && - self.token != token::CloseDelim(token::Paren) { - // This wasn't actually a type, but a pattern looking like a type, - // so we are going to rollback and re-parse for recovery. - ty = self.unexpected(); - } - match ty { - Ok(ty) => { - let ident = Ident::new(kw::Invalid, self.prev_span); - let bm = BindingMode::ByValue(Mutability::Immutable); - let pat = self.mk_pat_ident(ty.span, bm, ident); - (pat, ty) - } - // If this is a C-variadic argument and we hit an error, return the error. - Err(err) if self.token == token::DotDotDot => return Err(err), - // Recover from attempting to parse the argument as a type without pattern. - Err(mut err) => { - err.cancel(); - mem::replace(self, parser_snapshot_before_ty); - self.recover_arg_parse()? - } - } - }; - - let span = lo.to(self.token.span); - - Ok(Param { - attrs: attrs.into(), - id: ast::DUMMY_NODE_ID, - is_placeholder: false, - pat, - span, - ty, - }) - } - - /// Returns the parsed optional self parameter and whether a self shortcut was used. - /// - /// See `parse_self_param_with_attrs` to collect attributes. - fn parse_self_param(&mut self) -> PResult<'a, Option> { - // Extract an identifier *after* having confirmed that the token is one. - let expect_self_ident = |this: &mut Self| { - match this.token.kind { - // Preserve hygienic context. - token::Ident(name, _) => { - let span = this.token.span; - this.bump(); - Ident::new(name, span) - } - _ => unreachable!(), - } - }; - // Is `self` `n` tokens ahead? - let is_isolated_self = |this: &Self, n| { - this.is_keyword_ahead(n, &[kw::SelfLower]) - && this.look_ahead(n + 1, |t| t != &token::ModSep) - }; - // Is `mut self` `n` tokens ahead? - let is_isolated_mut_self = |this: &Self, n| { - this.is_keyword_ahead(n, &[kw::Mut]) - && is_isolated_self(this, n + 1) - }; - // Parse `self` or `self: TYPE`. We already know the current token is `self`. - let parse_self_possibly_typed = |this: &mut Self, m| { - let eself_ident = expect_self_ident(this); - let eself_hi = this.prev_span; - let eself = if this.eat(&token::Colon) { - SelfKind::Explicit(this.parse_ty()?, m) - } else { - SelfKind::Value(m) - }; - Ok((eself, eself_ident, eself_hi)) - }; - // Recover for the grammar `*self`, `*const self`, and `*mut self`. - let recover_self_ptr = |this: &mut Self| { - let msg = "cannot pass `self` by raw pointer"; - let span = this.token.span; - this.struct_span_err(span, msg) - .span_label(span, msg) - .emit(); - - Ok((SelfKind::Value(Mutability::Immutable), expect_self_ident(this), this.prev_span)) - }; - - // Parse optional `self` parameter of a method. - // Only a limited set of initial token sequences is considered `self` parameters; anything - // else is parsed as a normal function parameter list, so some lookahead is required. - let eself_lo = self.token.span; - let (eself, eself_ident, eself_hi) = match self.token.kind { - token::BinOp(token::And) => { - let eself = if is_isolated_self(self, 1) { - // `&self` - self.bump(); - SelfKind::Region(None, Mutability::Immutable) - } else if is_isolated_mut_self(self, 1) { - // `&mut self` - self.bump(); - self.bump(); - SelfKind::Region(None, Mutability::Mutable) - } else if self.look_ahead(1, |t| t.is_lifetime()) && is_isolated_self(self, 2) { - // `&'lt self` - self.bump(); - let lt = self.expect_lifetime(); - SelfKind::Region(Some(lt), Mutability::Immutable) - } else if self.look_ahead(1, |t| t.is_lifetime()) && is_isolated_mut_self(self, 2) { - // `&'lt mut self` - self.bump(); - let lt = self.expect_lifetime(); - self.bump(); - SelfKind::Region(Some(lt), Mutability::Mutable) - } else { - // `¬_self` - return Ok(None); - }; - (eself, expect_self_ident(self), self.prev_span) - } - // `*self` - token::BinOp(token::Star) if is_isolated_self(self, 1) => { - self.bump(); - recover_self_ptr(self)? - } - // `*mut self` and `*const self` - token::BinOp(token::Star) if - self.look_ahead(1, |t| t.is_mutability()) - && is_isolated_self(self, 2) => - { - self.bump(); - self.bump(); - recover_self_ptr(self)? - } - // `self` and `self: TYPE` - token::Ident(..) if is_isolated_self(self, 0) => { - parse_self_possibly_typed(self, Mutability::Immutable)? - } - // `mut self` and `mut self: TYPE` - token::Ident(..) if is_isolated_mut_self(self, 0) => { - self.bump(); - parse_self_possibly_typed(self, Mutability::Mutable)? - } - _ => return Ok(None), - }; - - let eself = source_map::respan(eself_lo.to(eself_hi), eself); - Ok(Some(Param::from_self(ThinVec::default(), eself, eself_ident))) - } - - fn is_named_param(&self) -> bool { - let offset = match self.token.kind { - token::Interpolated(ref nt) => match **nt { - token::NtPat(..) => return self.look_ahead(1, |t| t == &token::Colon), - _ => 0, - } - token::BinOp(token::And) | token::AndAnd => 1, - _ if self.token.is_keyword(kw::Mut) => 1, - _ => 0, - }; - - self.look_ahead(offset, |t| t.is_ident()) && - self.look_ahead(offset + 1, |t| t == &token::Colon) - } - fn is_crate_vis(&self) -> bool { self.token.is_keyword(kw::Crate) && self.look_ahead(1, |t| t != &token::ModSep) } diff --git a/src/libsyntax/parse/parser/item.rs b/src/libsyntax/parse/parser/item.rs index 3c60c88e2aa..08c624b5539 100644 --- a/src/libsyntax/parse/parser/item.rs +++ b/src/libsyntax/parse/parser/item.rs @@ -1,28 +1,23 @@ -use super::{Parser, PResult, PathStyle, SemiColonMode, BlockMode, ParamCfg}; - +use super::{Parser, PResult, PathStyle, SemiColonMode, BlockMode}; use crate::maybe_whole; use crate::ptr::P; -use crate::ast::{ - self, DUMMY_NODE_ID, Ident, Attribute, AttrStyle, - Item, ItemKind, ImplItem, ImplItemKind, TraitItem, TraitItemKind, - UseTree, UseTreeKind, PathSegment, - IsAuto, Constness, IsAsync, Unsafety, Defaultness, - Visibility, VisibilityKind, Mutability, FnDecl, FnHeader, MethodSig, Block, - ForeignItem, ForeignItemKind, - Ty, TyKind, Generics, GenericBounds, TraitRef, - EnumDef, VariantData, StructField, AnonConst, - Mac, MacDelimiter, -}; +use crate::ast::{self, DUMMY_NODE_ID, Ident, Attribute, AttrStyle, AnonConst, Item, ItemKind}; +use crate::ast::{ImplItem, ImplItemKind, TraitItem, TraitItemKind, UseTree, UseTreeKind}; +use crate::ast::{PathSegment, IsAuto, Constness, IsAsync, Unsafety, Defaultness}; +use crate::ast::{Visibility, VisibilityKind, Mutability, FnHeader, ForeignItem, ForeignItemKind}; +use crate::ast::{Ty, TyKind, Generics, GenericBounds, TraitRef, EnumDef, VariantData, StructField}; +use crate::ast::{Mac, MacDelimiter, Block, BindingMode, FnDecl, MethodSig, SelfKind, Param}; use crate::ext::base::DummyResult; use crate::parse::token; use crate::parse::parser::maybe_append; -use crate::parse::diagnostics::Error; +use crate::parse::diagnostics::{Error, dummy_arg}; use crate::tokenstream::{TokenTree, TokenStream}; -use crate::source_map::{respan, Span}; use crate::symbol::{kw, sym}; +use crate::source_map::{self, respan, Span}; +use crate::ThinVec; -use std::mem; use log::debug; +use std::mem; use rustc_target::spec::abi::Abi; use errors::{Applicability, DiagnosticBuilder, DiagnosticId, StashKey}; @@ -412,7 +407,7 @@ impl<'a> Parser<'a> { self.parse_macro_use_or_failure(attrs, macros_allowed, attributes_allowed, lo, vis) } - fn mk_item_with_info( + pub(super) fn mk_item_with_info( &self, attrs: Vec, lo: Span, @@ -425,16 +420,6 @@ impl<'a> Parser<'a> { Ok(Some(self.mk_item(span, ident, item, vis, attrs))) } - fn recover_first_param(&mut self) -> &'static str { - match self.parse_outer_attributes() - .and_then(|_| self.parse_self_param()) - .map_err(|mut e| e.cancel()) - { - Ok(Some(_)) => "method", - _ => "function", - } - } - /// This is the fall-through for parsing items. fn parse_macro_use_or_failure( &mut self, @@ -707,9 +692,11 @@ impl<'a> Parser<'a> { Ok(item) } - fn parse_impl_item_(&mut self, - at_end: &mut bool, - mut attrs: Vec) -> PResult<'a, ImplItem> { + fn parse_impl_item_( + &mut self, + at_end: &mut bool, + mut attrs: Vec, + ) -> PResult<'a, ImplItem> { let lo = self.token.span; let vis = self.parse_visibility(false)?; let defaultness = self.parse_defaultness(); @@ -722,8 +709,11 @@ impl<'a> Parser<'a> { (name, kind, generics) } else if self.is_const_item() { self.parse_impl_const()? + } else if let Some(mac) = self.parse_assoc_macro_invoc("impl", Some(&vis), at_end)? { + // FIXME: code copied from `parse_macro_use_or_failure` -- use abstraction! + (Ident::invalid(), ast::ImplItemKind::Macro(mac), Generics::default()) } else { - let (name, inner_attrs, generics, kind) = self.parse_impl_method(&vis, at_end)?; + let (name, inner_attrs, generics, kind) = self.parse_impl_method(at_end)?; attrs.extend(inner_attrs); (name, kind, generics) }; @@ -783,71 +773,6 @@ impl<'a> Parser<'a> { Ok((name, ImplItemKind::Const(typ, expr), Generics::default())) } - /// Parses a method or a macro invocation in a trait impl. - fn parse_impl_method( - &mut self, - vis: &Visibility, - at_end: &mut bool - ) -> PResult<'a, (Ident, Vec, Generics, ImplItemKind)> { - // FIXME: code copied from `parse_macro_use_or_failure` -- use abstraction! - if let Some(mac) = self.parse_assoc_macro_invoc("impl", Some(vis), at_end)? { - // method macro - Ok((Ident::invalid(), vec![], Generics::default(), ast::ImplItemKind::Macro(mac))) - } else { - let (ident, sig, generics) = self.parse_method_sig(|_| true)?; - *at_end = true; - let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; - Ok((ident, inner_attrs, generics, ast::ImplItemKind::Method(sig, body))) - } - } - - /// Parse the "signature", including the identifier, parameters, and generics - /// of a method. The body is not parsed as that differs between `trait`s and `impl`s. - fn parse_method_sig( - &mut self, - is_name_required: fn(&token::Token) -> bool, - ) -> PResult<'a, (Ident, MethodSig, Generics)> { - let header = self.parse_fn_front_matter()?; - let (ident, decl, generics) = self.parse_fn_sig(ParamCfg { - is_self_allowed: true, - allow_c_variadic: false, - is_name_required, - })?; - Ok((ident, MethodSig { header, decl }, generics)) - } - - /// Parses all the "front matter" for a `fn` declaration, up to - /// and including the `fn` keyword: - /// - /// - `const fn` - /// - `unsafe fn` - /// - `const unsafe fn` - /// - `extern fn` - /// - etc. - fn parse_fn_front_matter(&mut self) -> PResult<'a, FnHeader> { - let is_const_fn = self.eat_keyword(kw::Const); - let const_span = self.prev_span; - let asyncness = self.parse_asyncness(); - if let IsAsync::Async { .. } = asyncness { - self.ban_async_in_2015(self.prev_span); - } - let asyncness = respan(self.prev_span, asyncness); - let unsafety = self.parse_unsafety(); - let (constness, unsafety, abi) = if is_const_fn { - (respan(const_span, Constness::Const), unsafety, Abi::Rust) - } else { - let abi = self.parse_extern_abi()?; - (respan(self.prev_span, Constness::NotConst), unsafety, abi) - }; - if !self.eat_keyword(kw::Fn) { - // It is possible for `expect_one_of` to recover given the contents of - // `self.expected_tokens`, therefore, do not use `self.unexpected()` which doesn't - // account for this. - if !self.expect_one_of(&[], &[])? { unreachable!() } - } - Ok(FnHeader { constness, unsafety, asyncness, abi }) - } - /// Parses `auto? trait Foo { ... }` or `trait Foo = Bar;`. fn parse_item_trait(&mut self, unsafety: Unsafety) -> PResult<'a, ItemInfo> { // Parse optional `auto` prefix. @@ -957,13 +882,7 @@ impl<'a> Parser<'a> { // trait item macro. (Ident::invalid(), TraitItemKind::Macro(mac), Generics::default()) } else { - // This is somewhat dubious; We don't want to allow - // argument names to be left off if there is a definition... - // - // We don't allow argument names to be left off in edition 2018. - let (ident, sig, generics) = self.parse_method_sig(|t| t.span.rust_2018())?; - let body = self.parse_trait_method_body(at_end, &mut attrs)?; - (ident, TraitItemKind::Method(sig, body), generics) + self.parse_trait_item_method(at_end, &mut attrs)? }; Ok(TraitItem { @@ -991,43 +910,6 @@ impl<'a> Parser<'a> { Ok((ident, TraitItemKind::Const(ty, default), Generics::default())) } - /// Parse the "body" of a method in a trait item definition. - /// This can either be `;` when there's no body, - /// or e.g. a block when the method is a provided one. - fn parse_trait_method_body( - &mut self, - at_end: &mut bool, - attrs: &mut Vec, - ) -> PResult<'a, Option>> { - Ok(match self.token.kind { - token::Semi => { - debug!("parse_trait_method_body(): parsing required method"); - self.bump(); - *at_end = true; - None - } - token::OpenDelim(token::Brace) => { - debug!("parse_trait_method_body(): parsing provided method"); - *at_end = true; - let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; - attrs.extend(inner_attrs.iter().cloned()); - Some(body) - } - token::Interpolated(ref nt) => { - match **nt { - token::NtBlock(..) => { - *at_end = true; - let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; - attrs.extend(inner_attrs.iter().cloned()); - Some(body) - } - _ => return self.expected_semi_or_open_brace(), - } - } - _ => return self.expected_semi_or_open_brace(), - }) - } - /// Parses the following grammar: /// /// TraitItemAssocTy = Ident ["<"...">"] [":" [GenericBounds]] ["where" ...] ["=" Ty] @@ -1194,45 +1076,6 @@ impl<'a> Parser<'a> { Ok(ident) } - /// Parses an item-position function declaration. - fn parse_item_fn( - &mut self, - lo: Span, - vis: Visibility, - attrs: Vec, - header: FnHeader, - ) -> PResult<'a, Option>> { - let (ident, decl, generics) = self.parse_fn_sig(ParamCfg { - is_self_allowed: false, - allow_c_variadic: header.abi == Abi::C && header.unsafety == Unsafety::Unsafe, - is_name_required: |_| true, - })?; - let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; - let kind = ItemKind::Fn(decl, header, generics, body); - self.mk_item_with_info(attrs, lo, vis, (ident, kind, Some(inner_attrs))) - } - - /// Parse the "signature", including the identifier, parameters, and generics of a function. - fn parse_fn_sig(&mut self, cfg: ParamCfg) -> PResult<'a, (Ident, P, Generics)> { - let ident = self.parse_ident()?; - let mut generics = self.parse_generics()?; - let decl = self.parse_fn_decl(cfg, true)?; - generics.where_clause = self.parse_where_clause()?; - Ok((ident, decl, generics)) - } - - /// Parses the parameter list and result type of a function declaration. - pub(super) fn parse_fn_decl( - &mut self, - cfg: ParamCfg, - ret_allow_plus: bool, - ) -> PResult<'a, P> { - Ok(P(FnDecl { - inputs: self.parse_fn_params(cfg)?, - output: self.parse_ret_ty(ret_allow_plus)?, - })) - } - /// Parses `extern` for foreign ABIs modules. /// /// `extern` is expected to have been @@ -1344,32 +1187,6 @@ impl<'a> Parser<'a> { } } - /// Parses a function declaration from a foreign module. - fn parse_item_foreign_fn( - &mut self, - vis: ast::Visibility, - lo: Span, - attrs: Vec, - extern_sp: Span, - ) -> PResult<'a, ForeignItem> { - self.expect_keyword(kw::Fn)?; - let (ident, decl, generics) = self.parse_fn_sig(super::ParamCfg { - is_self_allowed: false, - allow_c_variadic: true, - is_name_required: |_| true, - })?; - let span = lo.to(self.token.span); - self.parse_semi_or_incorrect_foreign_fn_body(&ident, extern_sp)?; - Ok(ast::ForeignItem { - ident, - attrs, - kind: ForeignItemKind::Fn(decl, generics), - id: DUMMY_NODE_ID, - span, - vis, - }) - } - /// Parses a static item from a foreign module. /// Assumes that the `static` keyword is already parsed. fn parse_item_foreign_static(&mut self, vis: ast::Visibility, lo: Span, attrs: Vec) @@ -1910,3 +1727,466 @@ impl<'a> Parser<'a> { }) } } + +/// The parsing configuration used to parse a parameter list (see `parse_fn_params`). +pub(super) struct ParamCfg { + /// Is `self` is allowed as the first parameter? + pub is_self_allowed: bool, + /// Is `...` allowed as the tail of the parameter list? + pub allow_c_variadic: bool, + /// `is_name_required` decides if, per-parameter, + /// the parameter must have a pattern or just a type. + pub is_name_required: fn(&token::Token) -> bool, +} + +/// Parsing of functions and methods. +impl<'a> Parser<'a> { + /// Parses an item-position function declaration. + fn parse_item_fn( + &mut self, + lo: Span, + vis: Visibility, + attrs: Vec, + header: FnHeader, + ) -> PResult<'a, Option>> { + let (ident, decl, generics) = self.parse_fn_sig(ParamCfg { + is_self_allowed: false, + allow_c_variadic: header.abi == Abi::C && header.unsafety == Unsafety::Unsafe, + is_name_required: |_| true, + })?; + let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; + let kind = ItemKind::Fn(decl, header, generics, body); + self.mk_item_with_info(attrs, lo, vis, (ident, kind, Some(inner_attrs))) + } + + /// Parses a function declaration from a foreign module. + fn parse_item_foreign_fn( + &mut self, + vis: ast::Visibility, + lo: Span, + attrs: Vec, + extern_sp: Span, + ) -> PResult<'a, ForeignItem> { + self.expect_keyword(kw::Fn)?; + let (ident, decl, generics) = self.parse_fn_sig(ParamCfg { + is_self_allowed: false, + allow_c_variadic: true, + is_name_required: |_| true, + })?; + let span = lo.to(self.token.span); + self.parse_semi_or_incorrect_foreign_fn_body(&ident, extern_sp)?; + Ok(ast::ForeignItem { + ident, + attrs, + kind: ForeignItemKind::Fn(decl, generics), + id: DUMMY_NODE_ID, + span, + vis, + }) + } + + /// Parses a method or a macro invocation in a trait impl. + fn parse_impl_method( + &mut self, + at_end: &mut bool, + ) -> PResult<'a, (Ident, Vec, Generics, ImplItemKind)> { + let (ident, sig, generics) = self.parse_method_sig(|_| true)?; + *at_end = true; + let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; + Ok((ident, inner_attrs, generics, ast::ImplItemKind::Method(sig, body))) + } + + fn parse_trait_item_method( + &mut self, + at_end: &mut bool, + attrs: &mut Vec, + ) -> PResult<'a, (Ident, TraitItemKind, Generics)> { + // This is somewhat dubious; We don't want to allow + // argument names to be left off if there is a definition... + // + // We don't allow argument names to be left off in edition 2018. + let (ident, sig, generics) = self.parse_method_sig(|t| t.span.rust_2018())?; + let body = self.parse_trait_method_body(at_end, attrs)?; + Ok((ident, TraitItemKind::Method(sig, body), generics)) + } + + /// Parse the "body" of a method in a trait item definition. + /// This can either be `;` when there's no body, + /// or e.g. a block when the method is a provided one. + fn parse_trait_method_body( + &mut self, + at_end: &mut bool, + attrs: &mut Vec, + ) -> PResult<'a, Option>> { + Ok(match self.token.kind { + token::Semi => { + debug!("parse_trait_method_body(): parsing required method"); + self.bump(); + *at_end = true; + None + } + token::OpenDelim(token::Brace) => { + debug!("parse_trait_method_body(): parsing provided method"); + *at_end = true; + let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; + attrs.extend(inner_attrs.iter().cloned()); + Some(body) + } + token::Interpolated(ref nt) => { + match **nt { + token::NtBlock(..) => { + *at_end = true; + let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; + attrs.extend(inner_attrs.iter().cloned()); + Some(body) + } + _ => return self.expected_semi_or_open_brace(), + } + } + _ => return self.expected_semi_or_open_brace(), + }) + } + + /// Parse the "signature", including the identifier, parameters, and generics + /// of a method. The body is not parsed as that differs between `trait`s and `impl`s. + fn parse_method_sig( + &mut self, + is_name_required: fn(&token::Token) -> bool, + ) -> PResult<'a, (Ident, MethodSig, Generics)> { + let header = self.parse_fn_front_matter()?; + let (ident, decl, generics) = self.parse_fn_sig(ParamCfg { + is_self_allowed: true, + allow_c_variadic: false, + is_name_required, + })?; + Ok((ident, MethodSig { header, decl }, generics)) + } + + /// Parses all the "front matter" for a `fn` declaration, up to + /// and including the `fn` keyword: + /// + /// - `const fn` + /// - `unsafe fn` + /// - `const unsafe fn` + /// - `extern fn` + /// - etc. + fn parse_fn_front_matter(&mut self) -> PResult<'a, FnHeader> { + let is_const_fn = self.eat_keyword(kw::Const); + let const_span = self.prev_span; + let asyncness = self.parse_asyncness(); + if let IsAsync::Async { .. } = asyncness { + self.ban_async_in_2015(self.prev_span); + } + let asyncness = respan(self.prev_span, asyncness); + let unsafety = self.parse_unsafety(); + let (constness, unsafety, abi) = if is_const_fn { + (respan(const_span, Constness::Const), unsafety, Abi::Rust) + } else { + let abi = self.parse_extern_abi()?; + (respan(self.prev_span, Constness::NotConst), unsafety, abi) + }; + if !self.eat_keyword(kw::Fn) { + // It is possible for `expect_one_of` to recover given the contents of + // `self.expected_tokens`, therefore, do not use `self.unexpected()` which doesn't + // account for this. + if !self.expect_one_of(&[], &[])? { unreachable!() } + } + Ok(FnHeader { constness, unsafety, asyncness, abi }) + } + + /// Parse the "signature", including the identifier, parameters, and generics of a function. + fn parse_fn_sig(&mut self, cfg: ParamCfg) -> PResult<'a, (Ident, P, Generics)> { + let ident = self.parse_ident()?; + let mut generics = self.parse_generics()?; + let decl = self.parse_fn_decl(cfg, true)?; + generics.where_clause = self.parse_where_clause()?; + Ok((ident, decl, generics)) + } + + /// Parses the parameter list and result type of a function declaration. + pub(super) fn parse_fn_decl( + &mut self, + cfg: ParamCfg, + ret_allow_plus: bool, + ) -> PResult<'a, P> { + Ok(P(FnDecl { + inputs: self.parse_fn_params(cfg)?, + output: self.parse_ret_ty(ret_allow_plus)?, + })) + } + + /// Parses the parameter list of a function, including the `(` and `)` delimiters. + fn parse_fn_params(&mut self, mut cfg: ParamCfg) -> PResult<'a, Vec> { + let sp = self.token.span; + let is_trait_item = cfg.is_self_allowed; + let mut c_variadic = false; + // Parse the arguments, starting out with `self` being possibly allowed... + let (params, _) = self.parse_paren_comma_seq(|p| { + let param = p.parse_param_general(&cfg, is_trait_item); + // ...now that we've parsed the first argument, `self` is no longer allowed. + cfg.is_self_allowed = false; + + match param { + Ok(param) => Ok( + if let TyKind::CVarArgs = param.ty.kind { + c_variadic = true; + if p.token != token::CloseDelim(token::Paren) { + p.span_err( + p.token.span, + "`...` must be the last argument of a C-variadic function", + ); + // FIXME(eddyb) this should probably still push `CVarArgs`. + // Maybe AST validation/HIR lowering should emit the above error? + None + } else { + Some(param) + } + } else { + Some(param) + } + ), + 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)]); + // Create a placeholder argument for proper arg count (issue #34264). + let span = lo.to(p.prev_span); + Ok(Some(dummy_arg(Ident::new(kw::Invalid, span)))) + } + } + })?; + + let mut params: Vec<_> = params.into_iter().filter_map(|x| x).collect(); + + // Replace duplicated recovered params with `_` pattern to avoid unecessary errors. + self.deduplicate_recovered_params_names(&mut params); + + if c_variadic && params.len() <= 1 { + self.span_err( + sp, + "C-variadic function must be declared with at least one named argument", + ); + } + + Ok(params) + } + + /// Skips unexpected attributes and doc comments in this position and emits an appropriate + /// error. + /// This version of parse param doesn't necessarily require identifier names. + fn parse_param_general(&mut self, cfg: &ParamCfg, is_trait_item: bool) -> PResult<'a, Param> { + let lo = self.token.span; + let attrs = self.parse_outer_attributes()?; + + // Possibly parse `self`. Recover if we parsed it and it wasn't allowed here. + if let Some(mut param) = self.parse_self_param()? { + param.attrs = attrs.into(); + return if cfg.is_self_allowed { + Ok(param) + } else { + self.recover_bad_self_param(param, is_trait_item) + }; + } + + let is_name_required = match self.token.kind { + token::DotDotDot => false, + _ => (cfg.is_name_required)(&self.token), + }; + let (pat, ty) = if is_name_required || self.is_named_param() { + debug!("parse_param_general parse_pat (is_name_required:{})", is_name_required); + + let pat = self.parse_fn_param_pat()?; + if let Err(mut err) = self.expect(&token::Colon) { + return if let Some(ident) = self.parameter_without_type( + &mut err, + pat, + is_name_required, + cfg.is_self_allowed, + is_trait_item, + ) { + err.emit(); + Ok(dummy_arg(ident)) + } else { + Err(err) + }; + } + + self.eat_incorrect_doc_comment_for_param_type(); + (pat, self.parse_ty_common(true, true, cfg.allow_c_variadic)?) + } else { + debug!("parse_param_general ident_to_pat"); + let parser_snapshot_before_ty = self.clone(); + self.eat_incorrect_doc_comment_for_param_type(); + let mut ty = self.parse_ty_common(true, true, cfg.allow_c_variadic); + if ty.is_ok() && self.token != token::Comma && + self.token != token::CloseDelim(token::Paren) { + // This wasn't actually a type, but a pattern looking like a type, + // so we are going to rollback and re-parse for recovery. + ty = self.unexpected(); + } + match ty { + Ok(ty) => { + let ident = Ident::new(kw::Invalid, self.prev_span); + let bm = BindingMode::ByValue(Mutability::Immutable); + let pat = self.mk_pat_ident(ty.span, bm, ident); + (pat, ty) + } + // If this is a C-variadic argument and we hit an error, return the error. + Err(err) if self.token == token::DotDotDot => return Err(err), + // Recover from attempting to parse the argument as a type without pattern. + Err(mut err) => { + err.cancel(); + mem::replace(self, parser_snapshot_before_ty); + self.recover_arg_parse()? + } + } + }; + + let span = lo.to(self.token.span); + + Ok(Param { + attrs: attrs.into(), + id: ast::DUMMY_NODE_ID, + is_placeholder: false, + pat, + span, + ty, + }) + } + + /// Returns the parsed optional self parameter and whether a self shortcut was used. + /// + /// See `parse_self_param_with_attrs` to collect attributes. + fn parse_self_param(&mut self) -> PResult<'a, Option> { + // Extract an identifier *after* having confirmed that the token is one. + let expect_self_ident = |this: &mut Self| { + match this.token.kind { + // Preserve hygienic context. + token::Ident(name, _) => { + let span = this.token.span; + this.bump(); + Ident::new(name, span) + } + _ => unreachable!(), + } + }; + // Is `self` `n` tokens ahead? + let is_isolated_self = |this: &Self, n| { + this.is_keyword_ahead(n, &[kw::SelfLower]) + && this.look_ahead(n + 1, |t| t != &token::ModSep) + }; + // Is `mut self` `n` tokens ahead? + let is_isolated_mut_self = |this: &Self, n| { + this.is_keyword_ahead(n, &[kw::Mut]) + && is_isolated_self(this, n + 1) + }; + // Parse `self` or `self: TYPE`. We already know the current token is `self`. + let parse_self_possibly_typed = |this: &mut Self, m| { + let eself_ident = expect_self_ident(this); + let eself_hi = this.prev_span; + let eself = if this.eat(&token::Colon) { + SelfKind::Explicit(this.parse_ty()?, m) + } else { + SelfKind::Value(m) + }; + Ok((eself, eself_ident, eself_hi)) + }; + // Recover for the grammar `*self`, `*const self`, and `*mut self`. + let recover_self_ptr = |this: &mut Self| { + let msg = "cannot pass `self` by raw pointer"; + let span = this.token.span; + this.struct_span_err(span, msg) + .span_label(span, msg) + .emit(); + + Ok((SelfKind::Value(Mutability::Immutable), expect_self_ident(this), this.prev_span)) + }; + + // Parse optional `self` parameter of a method. + // Only a limited set of initial token sequences is considered `self` parameters; anything + // else is parsed as a normal function parameter list, so some lookahead is required. + let eself_lo = self.token.span; + let (eself, eself_ident, eself_hi) = match self.token.kind { + token::BinOp(token::And) => { + let eself = if is_isolated_self(self, 1) { + // `&self` + self.bump(); + SelfKind::Region(None, Mutability::Immutable) + } else if is_isolated_mut_self(self, 1) { + // `&mut self` + self.bump(); + self.bump(); + SelfKind::Region(None, Mutability::Mutable) + } else if self.look_ahead(1, |t| t.is_lifetime()) && is_isolated_self(self, 2) { + // `&'lt self` + self.bump(); + let lt = self.expect_lifetime(); + SelfKind::Region(Some(lt), Mutability::Immutable) + } else if self.look_ahead(1, |t| t.is_lifetime()) && is_isolated_mut_self(self, 2) { + // `&'lt mut self` + self.bump(); + let lt = self.expect_lifetime(); + self.bump(); + SelfKind::Region(Some(lt), Mutability::Mutable) + } else { + // `¬_self` + return Ok(None); + }; + (eself, expect_self_ident(self), self.prev_span) + } + // `*self` + token::BinOp(token::Star) if is_isolated_self(self, 1) => { + self.bump(); + recover_self_ptr(self)? + } + // `*mut self` and `*const self` + token::BinOp(token::Star) if + self.look_ahead(1, |t| t.is_mutability()) + && is_isolated_self(self, 2) => + { + self.bump(); + self.bump(); + recover_self_ptr(self)? + } + // `self` and `self: TYPE` + token::Ident(..) if is_isolated_self(self, 0) => { + parse_self_possibly_typed(self, Mutability::Immutable)? + } + // `mut self` and `mut self: TYPE` + token::Ident(..) if is_isolated_mut_self(self, 0) => { + self.bump(); + parse_self_possibly_typed(self, Mutability::Mutable)? + } + _ => return Ok(None), + }; + + let eself = source_map::respan(eself_lo.to(eself_hi), eself); + Ok(Some(Param::from_self(ThinVec::default(), eself, eself_ident))) + } + + fn is_named_param(&self) -> bool { + let offset = match self.token.kind { + token::Interpolated(ref nt) => match **nt { + token::NtPat(..) => return self.look_ahead(1, |t| t == &token::Colon), + _ => 0, + } + token::BinOp(token::And) | token::AndAnd => 1, + _ if self.token.is_keyword(kw::Mut) => 1, + _ => 0, + }; + + self.look_ahead(offset, |t| t.is_ident()) && + self.look_ahead(offset + 1, |t| t == &token::Colon) + } + + fn recover_first_param(&mut self) -> &'static str { + match self.parse_outer_attributes() + .and_then(|_| self.parse_self_param()) + .map_err(|mut e| e.cancel()) + { + Ok(Some(_)) => "method", + _ => "function", + } + } +} diff --git a/src/libsyntax/parse/parser/ty.rs b/src/libsyntax/parse/parser/ty.rs index 018b5951e6e..e696ab0804d 100644 --- a/src/libsyntax/parse/parser/ty.rs +++ b/src/libsyntax/parse/parser/ty.rs @@ -1,4 +1,5 @@ use super::{Parser, PResult, PathStyle, PrevTokenKind, TokenType}; +use super::item::ParamCfg; use crate::{maybe_whole, maybe_recover_from_interpolated_ty_qpath}; use crate::ptr::P; @@ -281,7 +282,7 @@ impl<'a> Parser<'a> { let unsafety = self.parse_unsafety(); let abi = self.parse_extern_abi()?; self.expect_keyword(kw::Fn)?; - let cfg = super::ParamCfg { + let cfg = ParamCfg { is_self_allowed: false, allow_c_variadic: true, is_name_required: |_| false, -- cgit 1.4.1-3-g733a5 From 42f32f06d63b9947db63f0c739483e0294f588b2 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Wed, 9 Oct 2019 02:34:22 +0200 Subject: token: extract Nonterminal::to_tokenstream to parser. --- src/librustc/hir/lowering.rs | 6 +- src/libsyntax/ext/proc_macro_server.rs | 2 +- src/libsyntax/parse/mod.rs | 138 ++++++++++++++++++++++++++++++++- src/libsyntax/parse/token.rs | 137 +------------------------------- 4 files changed, 143 insertions(+), 140 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 72fd054ee8a..513512b9f6b 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -70,6 +70,7 @@ use syntax::print::pprust; use syntax::source_map::{respan, ExpnData, ExpnKind, DesugaringKind, Spanned}; use syntax::symbol::{kw, sym, Symbol}; use syntax::tokenstream::{TokenStream, TokenTree}; +use syntax::parse; use syntax::parse::token::{self, Token}; use syntax::visit::{self, Visitor}; use syntax_pos::Span; @@ -1022,7 +1023,10 @@ impl<'a> LoweringContext<'a> { fn lower_token(&mut self, token: Token) -> TokenStream { match token.kind { token::Interpolated(nt) => { - let tts = nt.to_tokenstream(&self.sess.parse_sess, token.span); + // FIXME(Centril): Consider indirection `(parse_sess.nt_to_tokenstream)(...)` + // to hack around the current hack that requires `nt_to_tokenstream` to live + // in the parser. + let tts = parse::nt_to_tokenstream(&nt, &self.sess.parse_sess, token.span); self.lower_token_stream(tts) } _ => TokenTree::Token(token).into(), diff --git a/src/libsyntax/ext/proc_macro_server.rs b/src/libsyntax/ext/proc_macro_server.rs index 021ec46d987..0647c2fa313 100644 --- a/src/libsyntax/ext/proc_macro_server.rs +++ b/src/libsyntax/ext/proc_macro_server.rs @@ -174,7 +174,7 @@ impl FromInternal<(TreeAndJoint, &'_ ParseSess, &'_ mut Vec)> } Interpolated(nt) => { - let stream = nt.to_tokenstream(sess, span); + let stream = parse::nt_to_tokenstream(&nt, sess, span); TokenTree::Group(Group { delimiter: Delimiter::None, stream, diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 1518da23b09..0df695d37b9 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -4,10 +4,9 @@ use crate::ast::{self, CrateConfig, NodeId}; use crate::early_buffered_lints::{BufferedEarlyLint, BufferedEarlyLintId}; use crate::source_map::{SourceMap, FilePathMapping}; use crate::feature_gate::UnstableFeatures; -use crate::parse::parser::Parser; -use crate::parse::parser::emit_unclosed_delims; -use crate::parse::token::TokenKind; -use crate::tokenstream::{TokenStream, TokenTree}; +use crate::parse::parser::{Parser, emit_unclosed_delims}; +use crate::parse::token::{Nonterminal, TokenKind}; +use crate::tokenstream::{self, TokenStream, TokenTree}; use crate::print::pprust; use crate::symbol::Symbol; @@ -24,6 +23,8 @@ use std::borrow::Cow; use std::path::{Path, PathBuf}; use std::str; +use log::info; + #[cfg(test)] mod tests; @@ -407,3 +408,132 @@ impl SeqSep { } } } + +// NOTE(Centril): The following probably shouldn't be here but it acknowledges the +// fact that architecturally, we are using parsing (read on below to understand why). + +pub fn nt_to_tokenstream(nt: &Nonterminal, sess: &ParseSess, span: Span) -> TokenStream { + // A `Nonterminal` is often a parsed AST item. At this point we now + // need to convert the parsed AST to an actual token stream, e.g. + // un-parse it basically. + // + // Unfortunately there's not really a great way to do that in a + // guaranteed lossless fashion right now. The fallback here is to just + // stringify the AST node and reparse it, but this loses all span + // information. + // + // As a result, some AST nodes are annotated with the token stream they + // came from. Here we attempt to extract these lossless token streams + // before we fall back to the stringification. + let tokens = match *nt { + Nonterminal::NtItem(ref item) => { + prepend_attrs(sess, &item.attrs, item.tokens.as_ref(), span) + } + Nonterminal::NtTraitItem(ref item) => { + prepend_attrs(sess, &item.attrs, item.tokens.as_ref(), span) + } + Nonterminal::NtImplItem(ref item) => { + prepend_attrs(sess, &item.attrs, item.tokens.as_ref(), span) + } + Nonterminal::NtIdent(ident, is_raw) => { + Some(tokenstream::TokenTree::token(token::Ident(ident.name, is_raw), ident.span).into()) + } + Nonterminal::NtLifetime(ident) => { + Some(tokenstream::TokenTree::token(token::Lifetime(ident.name), ident.span).into()) + } + Nonterminal::NtTT(ref tt) => { + Some(tt.clone().into()) + } + _ => None, + }; + + // FIXME(#43081): Avoid this pretty-print + reparse hack + let source = pprust::nonterminal_to_string(nt); + let filename = FileName::macro_expansion_source_code(&source); + let tokens_for_real = parse_stream_from_source_str(filename, source, sess, Some(span)); + + // During early phases of the compiler the AST could get modified + // directly (e.g., attributes added or removed) and the internal cache + // of tokens my not be invalidated or updated. Consequently if the + // "lossless" token stream disagrees with our actual stringification + // (which has historically been much more battle-tested) then we go + // with the lossy stream anyway (losing span information). + // + // Note that the comparison isn't `==` here to avoid comparing spans, + // but it *also* is a "probable" equality which is a pretty weird + // definition. We mostly want to catch actual changes to the AST + // like a `#[cfg]` being processed or some weird `macro_rules!` + // expansion. + // + // What we *don't* want to catch is the fact that a user-defined + // literal like `0xf` is stringified as `15`, causing the cached token + // stream to not be literal `==` token-wise (ignoring spans) to the + // token stream we got from stringification. + // + // Instead the "probably equal" check here is "does each token + // recursively have the same discriminant?" We basically don't look at + // the token values here and assume that such fine grained token stream + // modifications, including adding/removing typically non-semantic + // tokens such as extra braces and commas, don't happen. + if let Some(tokens) = tokens { + if tokens.probably_equal_for_proc_macro(&tokens_for_real) { + return tokens + } + info!("cached tokens found, but they're not \"probably equal\", \ + going with stringified version"); + } + return tokens_for_real +} + +fn prepend_attrs( + sess: &ParseSess, + attrs: &[ast::Attribute], + tokens: Option<&tokenstream::TokenStream>, + span: syntax_pos::Span +) -> Option { + let tokens = tokens?; + if attrs.len() == 0 { + return Some(tokens.clone()) + } + let mut builder = tokenstream::TokenStreamBuilder::new(); + for attr in attrs { + assert_eq!(attr.style, ast::AttrStyle::Outer, + "inner attributes should prevent cached tokens from existing"); + + let source = pprust::attribute_to_string(attr); + let macro_filename = FileName::macro_expansion_source_code(&source); + if attr.is_sugared_doc { + let stream = parse_stream_from_source_str(macro_filename, source, sess, Some(span)); + builder.push(stream); + continue + } + + // synthesize # [ $path $tokens ] manually here + let mut brackets = tokenstream::TokenStreamBuilder::new(); + + // For simple paths, push the identifier directly + if attr.path.segments.len() == 1 && attr.path.segments[0].args.is_none() { + let ident = attr.path.segments[0].ident; + let token = token::Ident(ident.name, ident.as_str().starts_with("r#")); + brackets.push(tokenstream::TokenTree::token(token, ident.span)); + + // ... and for more complicated paths, fall back to a reparse hack that + // should eventually be removed. + } else { + let stream = parse_stream_from_source_str(macro_filename, source, sess, Some(span)); + brackets.push(stream); + } + + brackets.push(attr.tokens.clone()); + + // The span we list here for `#` and for `[ ... ]` are both wrong in + // that it encompasses more than each token, but it hopefully is "good + // enough" for now at least. + builder.push(tokenstream::TokenTree::token(token::Pound, attr.span)); + let delim_span = tokenstream::DelimSpan::from_single(attr.span); + builder.push(tokenstream::TokenTree::Delimited( + delim_span, token::DelimToken::Bracket, brackets.build().into())); + } + builder.push(tokens.clone()); + Some(builder.build()) +} diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index fd78a2bd534..eb74ab2b919 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -4,16 +4,13 @@ pub use DelimToken::*; pub use LitKind::*; pub use TokenKind::*; -use crate::ast::{self}; -use crate::parse::{parse_stream_from_source_str, ParseSess}; -use crate::print::pprust; +use crate::ast; use crate::ptr::P; use crate::symbol::kw; -use crate::tokenstream::{self, DelimSpan, TokenStream, TokenTree}; +use crate::tokenstream::TokenTree; use syntax_pos::symbol::Symbol; -use syntax_pos::{self, Span, FileName, DUMMY_SP}; -use log::info; +use syntax_pos::{self, Span, DUMMY_SP}; use std::fmt; use std::mem; @@ -737,131 +734,3 @@ impl fmt::Debug for Nonterminal { } } } - -impl Nonterminal { - pub fn to_tokenstream(&self, sess: &ParseSess, span: Span) -> TokenStream { - // A `Nonterminal` is often a parsed AST item. At this point we now - // need to convert the parsed AST to an actual token stream, e.g. - // un-parse it basically. - // - // Unfortunately there's not really a great way to do that in a - // guaranteed lossless fashion right now. The fallback here is to just - // stringify the AST node and reparse it, but this loses all span - // information. - // - // As a result, some AST nodes are annotated with the token stream they - // came from. Here we attempt to extract these lossless token streams - // before we fall back to the stringification. - let tokens = match *self { - Nonterminal::NtItem(ref item) => { - prepend_attrs(sess, &item.attrs, item.tokens.as_ref(), span) - } - Nonterminal::NtTraitItem(ref item) => { - prepend_attrs(sess, &item.attrs, item.tokens.as_ref(), span) - } - Nonterminal::NtImplItem(ref item) => { - prepend_attrs(sess, &item.attrs, item.tokens.as_ref(), span) - } - Nonterminal::NtIdent(ident, is_raw) => { - Some(TokenTree::token(Ident(ident.name, is_raw), ident.span).into()) - } - Nonterminal::NtLifetime(ident) => { - Some(TokenTree::token(Lifetime(ident.name), ident.span).into()) - } - Nonterminal::NtTT(ref tt) => { - Some(tt.clone().into()) - } - _ => None, - }; - - // FIXME(#43081): Avoid this pretty-print + reparse hack - let source = pprust::nonterminal_to_string(self); - let filename = FileName::macro_expansion_source_code(&source); - let tokens_for_real = parse_stream_from_source_str(filename, source, sess, Some(span)); - - // During early phases of the compiler the AST could get modified - // directly (e.g., attributes added or removed) and the internal cache - // of tokens my not be invalidated or updated. Consequently if the - // "lossless" token stream disagrees with our actual stringification - // (which has historically been much more battle-tested) then we go - // with the lossy stream anyway (losing span information). - // - // Note that the comparison isn't `==` here to avoid comparing spans, - // but it *also* is a "probable" equality which is a pretty weird - // definition. We mostly want to catch actual changes to the AST - // like a `#[cfg]` being processed or some weird `macro_rules!` - // expansion. - // - // What we *don't* want to catch is the fact that a user-defined - // literal like `0xf` is stringified as `15`, causing the cached token - // stream to not be literal `==` token-wise (ignoring spans) to the - // token stream we got from stringification. - // - // Instead the "probably equal" check here is "does each token - // recursively have the same discriminant?" We basically don't look at - // the token values here and assume that such fine grained token stream - // modifications, including adding/removing typically non-semantic - // tokens such as extra braces and commas, don't happen. - if let Some(tokens) = tokens { - if tokens.probably_equal_for_proc_macro(&tokens_for_real) { - return tokens - } - info!("cached tokens found, but they're not \"probably equal\", \ - going with stringified version"); - } - return tokens_for_real - } -} - -fn prepend_attrs(sess: &ParseSess, - attrs: &[ast::Attribute], - tokens: Option<&tokenstream::TokenStream>, - span: syntax_pos::Span) - -> Option -{ - let tokens = tokens?; - if attrs.len() == 0 { - return Some(tokens.clone()) - } - let mut builder = tokenstream::TokenStreamBuilder::new(); - for attr in attrs { - assert_eq!(attr.style, ast::AttrStyle::Outer, - "inner attributes should prevent cached tokens from existing"); - - let source = pprust::attribute_to_string(attr); - let macro_filename = FileName::macro_expansion_source_code(&source); - if attr.is_sugared_doc { - let stream = parse_stream_from_source_str(macro_filename, source, sess, Some(span)); - builder.push(stream); - continue - } - - // synthesize # [ $path $tokens ] manually here - let mut brackets = tokenstream::TokenStreamBuilder::new(); - - // For simple paths, push the identifier directly - if attr.path.segments.len() == 1 && attr.path.segments[0].args.is_none() { - let ident = attr.path.segments[0].ident; - let token = Ident(ident.name, ident.as_str().starts_with("r#")); - brackets.push(tokenstream::TokenTree::token(token, ident.span)); - - // ... and for more complicated paths, fall back to a reparse hack that - // should eventually be removed. - } else { - let stream = parse_stream_from_source_str(macro_filename, source, sess, Some(span)); - brackets.push(stream); - } - - brackets.push(attr.tokens.clone()); - - // The span we list here for `#` and for `[ ... ]` are both wrong in - // that it encompasses more than each token, but it hopefully is "good - // enough" for now at least. - builder.push(tokenstream::TokenTree::token(Pound, attr.span)); - let delim_span = DelimSpan::from_single(attr.span); - builder.push(tokenstream::TokenTree::Delimited( - delim_span, DelimToken::Bracket, brackets.build().into())); - } - builder.push(tokens.clone()); - Some(builder.build()) -} -- cgit 1.4.1-3-g733a5 From 5c93492da914f972fb549e95db778adcbdf70480 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 10 Oct 2019 07:29:02 +1100 Subject: Remove the `Option` in `TokenStream`. It means an allocation is required to create an empty `TokenStream`, but all other operations are simpler and marginally faster due to not having to check for `None`. Overall it simplifies the code for a negligible performance effect. The commit also removes `TokenStream::empty` by implementing `Default`, which is now possible. --- src/libsyntax/attr/mod.rs | 2 +- src/libsyntax/ext/expand.rs | 4 +- src/libsyntax/ext/mbe/transcribe.rs | 2 +- src/libsyntax/ext/placeholders.rs | 2 +- src/libsyntax/ext/proc_macro_server.rs | 2 +- src/libsyntax/mut_visit.rs | 6 +- src/libsyntax/parse/attr.rs | 2 +- src/libsyntax/tokenstream.rs | 224 ++++++++++++++------------------- src/libsyntax_ext/plugin_macro_defs.rs | 2 +- 9 files changed, 101 insertions(+), 145 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/attr/mod.rs b/src/libsyntax/attr/mod.rs index 7bef693a5be..c2c883fd20e 100644 --- a/src/libsyntax/attr/mod.rs +++ b/src/libsyntax/attr/mod.rs @@ -551,7 +551,7 @@ impl MetaItem { impl MetaItemKind { pub fn tokens(&self, span: Span) -> TokenStream { match *self { - MetaItemKind::Word => TokenStream::empty(), + MetaItemKind::Word => TokenStream::default(), MetaItemKind::NameValue(ref lit) => { let mut vec = vec![TokenTree::token(token::Eq, span).into()]; lit.tokens().append_to_tree_and_joint_vec(&mut vec); diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index bbd8da2acef..ec87451edbd 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -671,12 +671,12 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } } Some(TokenTree::Token(..)) => {} - None => return TokenStream::empty(), + None => return TokenStream::default(), } self.cx.span_err(span, "custom attribute invocations must be \ of the form `#[foo]` or `#[foo(..)]`, the macro name must only be \ followed by a delimiter token"); - TokenStream::empty() + TokenStream::default() } fn gate_proc_macro_attr_item(&self, span: Span, item: &Annotatable) { diff --git a/src/libsyntax/ext/mbe/transcribe.rs b/src/libsyntax/ext/mbe/transcribe.rs index ba818ebd35c..da930436d81 100644 --- a/src/libsyntax/ext/mbe/transcribe.rs +++ b/src/libsyntax/ext/mbe/transcribe.rs @@ -95,7 +95,7 @@ pub(super) fn transcribe( ) -> TokenStream { // Nothing for us to transcribe... if src.is_empty() { - return TokenStream::empty(); + return TokenStream::default(); } // We descend into the RHS (`src`), expanding things as we go. This stack contains the things diff --git a/src/libsyntax/ext/placeholders.rs b/src/libsyntax/ext/placeholders.rs index 8eecef1020d..43a49dbeb51 100644 --- a/src/libsyntax/ext/placeholders.rs +++ b/src/libsyntax/ext/placeholders.rs @@ -15,7 +15,7 @@ pub fn placeholder(kind: AstFragmentKind, id: ast::NodeId) -> AstFragment { fn mac_placeholder() -> ast::Mac { ast::Mac { path: ast::Path { span: DUMMY_SP, segments: Vec::new() }, - tts: TokenStream::empty().into(), + tts: TokenStream::default().into(), delim: ast::MacDelimiter::Brace, span: DUMMY_SP, prior_type_ascription: None, diff --git a/src/libsyntax/ext/proc_macro_server.rs b/src/libsyntax/ext/proc_macro_server.rs index 021ec46d987..27ac8a2b78e 100644 --- a/src/libsyntax/ext/proc_macro_server.rs +++ b/src/libsyntax/ext/proc_macro_server.rs @@ -393,7 +393,7 @@ impl server::Types for Rustc<'_> { impl server::TokenStream for Rustc<'_> { fn new(&mut self) -> Self::TokenStream { - TokenStream::empty() + TokenStream::default() } fn is_empty(&mut self, stream: &Self::TokenStream) -> bool { stream.is_empty() diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs index 3923b9f297b..60ee17d09b7 100644 --- a/src/libsyntax/mut_visit.rs +++ b/src/libsyntax/mut_visit.rs @@ -610,10 +610,8 @@ pub fn noop_visit_tt(tt: &mut TokenTree, vis: &mut T) { } pub fn noop_visit_tts(TokenStream(tts): &mut TokenStream, vis: &mut T) { - visit_opt(tts, |tts| { - let tts = Lrc::make_mut(tts); - visit_vec(tts, |(tree, _is_joint)| vis.visit_tt(tree)); - }) + let tts = Lrc::make_mut(tts); + visit_vec(tts, |(tree, _is_joint)| vis.visit_tt(tree)); } // Applies ident visitor if it's an ident; applies other visits to interpolated nodes. diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/attr.rs index e74f3045db8..0963efcfc8a 100644 --- a/src/libsyntax/parse/attr.rs +++ b/src/libsyntax/parse/attr.rs @@ -203,7 +203,7 @@ impl<'a> Parser<'a> { }; TokenStream::from_streams(smallvec![eq.into(), tokens]) } else { - TokenStream::empty() + TokenStream::default() }; ast::AttrItem { path, tokens } }) diff --git a/src/libsyntax/tokenstream.rs b/src/libsyntax/tokenstream.rs index bef12ed4fad..d2def5630e6 100644 --- a/src/libsyntax/tokenstream.rs +++ b/src/libsyntax/tokenstream.rs @@ -137,13 +137,8 @@ impl TokenTree { /// The goal is for procedural macros to work with `TokenStream`s and `TokenTree`s /// instead of a representation of the abstract syntax tree. /// Today's `TokenTree`s can still contain AST via `token::Interpolated` for back-compat. -/// -/// The use of `Option` is an optimization that avoids the need for an -/// allocation when the stream is empty. However, it is not guaranteed that an -/// empty stream is represented with `None`; it may be represented as a `Some` -/// around an empty `Vec`. -#[derive(Clone, Debug)] -pub struct TokenStream(pub Option>>); +#[derive(Clone, Debug, Default)] +pub struct TokenStream(pub Lrc>); pub type TreeAndJoint = (TokenTree, IsJoint); @@ -164,36 +159,34 @@ impl TokenStream { /// separating the two arguments with a comma for diagnostic suggestions. pub(crate) fn add_comma(&self) -> Option<(TokenStream, Span)> { // Used to suggest if a user writes `foo!(a b);` - if let Some(ref stream) = self.0 { - let mut suggestion = None; - let mut iter = stream.iter().enumerate().peekable(); - while let Some((pos, ts)) = iter.next() { - if let Some((_, next)) = iter.peek() { - let sp = match (&ts, &next) { - (_, (TokenTree::Token(Token { kind: token::Comma, .. }), _)) => continue, - ((TokenTree::Token(token_left), NonJoint), - (TokenTree::Token(token_right), _)) - if ((token_left.is_ident() && !token_left.is_reserved_ident()) - || token_left.is_lit()) && - ((token_right.is_ident() && !token_right.is_reserved_ident()) - || token_right.is_lit()) => token_left.span, - ((TokenTree::Delimited(sp, ..), NonJoint), _) => sp.entire(), - _ => continue, - }; - let sp = sp.shrink_to_hi(); - let comma = (TokenTree::token(token::Comma, sp), NonJoint); - suggestion = Some((pos, comma, sp)); - } - } - if let Some((pos, comma, sp)) = suggestion { - let mut new_stream = vec![]; - let parts = stream.split_at(pos + 1); - new_stream.extend_from_slice(parts.0); - new_stream.push(comma); - new_stream.extend_from_slice(parts.1); - return Some((TokenStream::new(new_stream), sp)); + let mut suggestion = None; + let mut iter = self.0.iter().enumerate().peekable(); + while let Some((pos, ts)) = iter.next() { + if let Some((_, next)) = iter.peek() { + let sp = match (&ts, &next) { + (_, (TokenTree::Token(Token { kind: token::Comma, .. }), _)) => continue, + ((TokenTree::Token(token_left), NonJoint), + (TokenTree::Token(token_right), _)) + if ((token_left.is_ident() && !token_left.is_reserved_ident()) + || token_left.is_lit()) && + ((token_right.is_ident() && !token_right.is_reserved_ident()) + || token_right.is_lit()) => token_left.span, + ((TokenTree::Delimited(sp, ..), NonJoint), _) => sp.entire(), + _ => continue, + }; + let sp = sp.shrink_to_hi(); + let comma = (TokenTree::token(token::Comma, sp), NonJoint); + suggestion = Some((pos, comma, sp)); } } + if let Some((pos, comma, sp)) = suggestion { + let mut new_stream = vec![]; + let parts = self.0.split_at(pos + 1); + new_stream.extend_from_slice(parts.0); + new_stream.push(comma); + new_stream.extend_from_slice(parts.1); + return Some((TokenStream::new(new_stream), sp)); + } None } } @@ -225,28 +218,21 @@ impl PartialEq for TokenStream { } impl TokenStream { - pub fn len(&self) -> usize { - if let Some(ref slice) = self.0 { - slice.len() - } else { - 0 - } + pub fn new(streams: Vec) -> TokenStream { + TokenStream(Lrc::new(streams)) } - pub fn empty() -> TokenStream { - TokenStream(None) + pub fn is_empty(&self) -> bool { + self.0.is_empty() } - pub fn is_empty(&self) -> bool { - match self.0 { - None => true, - Some(ref stream) => stream.is_empty(), - } + pub fn len(&self) -> usize { + self.0.len() } pub(crate) fn from_streams(mut streams: SmallVec<[TokenStream; 2]>) -> TokenStream { match streams.len() { - 0 => TokenStream::empty(), + 0 => TokenStream::default(), 1 => streams.pop().unwrap(), _ => { // We are going to extend the first stream in `streams` with @@ -270,41 +256,24 @@ impl TokenStream { // Get the first stream. If it's `None`, create an empty // stream. let mut iter = streams.drain(); - let mut first_stream_lrc = match iter.next().unwrap().0 { - Some(first_stream_lrc) => first_stream_lrc, - None => Lrc::new(vec![]), - }; + let mut first_stream_lrc = iter.next().unwrap().0; // Append the elements to the first stream, after reserving // space for them. let first_vec_mut = Lrc::make_mut(&mut first_stream_lrc); first_vec_mut.reserve(num_appends); for stream in iter { - if let Some(stream) = stream.0 { - first_vec_mut.extend(stream.iter().cloned()); - } + first_vec_mut.extend(stream.0.iter().cloned()); } // Create the final `TokenStream`. - match first_vec_mut.len() { - 0 => TokenStream(None), - _ => TokenStream(Some(first_stream_lrc)), - } + TokenStream(first_stream_lrc) } } } - pub fn new(streams: Vec) -> TokenStream { - match streams.len() { - 0 => TokenStream(None), - _ => TokenStream(Some(Lrc::new(streams))), - } - } - pub fn append_to_tree_and_joint_vec(self, vec: &mut Vec) { - if let Some(stream) = self.0 { - vec.extend(stream.iter().cloned()); - } + vec.extend(self.0.iter().cloned()); } pub fn trees(&self) -> Cursor { @@ -371,24 +340,22 @@ impl TokenStream { } pub fn map_enumerated TokenTree>(self, mut f: F) -> TokenStream { - TokenStream(self.0.map(|stream| { - Lrc::new( - stream - .iter() - .enumerate() - .map(|(i, (tree, is_joint))| (f(i, tree.clone()), *is_joint)) - .collect()) - })) + TokenStream(Lrc::new( + self.0 + .iter() + .enumerate() + .map(|(i, (tree, is_joint))| (f(i, tree.clone()), *is_joint)) + .collect() + )) } pub fn map TokenTree>(self, mut f: F) -> TokenStream { - TokenStream(self.0.map(|stream| { - Lrc::new( - stream - .iter() - .map(|(tree, is_joint)| (f(tree.clone()), *is_joint)) - .collect()) - })) + TokenStream(Lrc::new( + self.0 + .iter() + .map(|(tree, is_joint)| (f(tree.clone()), *is_joint)) + .collect() + )) } } @@ -406,44 +373,43 @@ impl TokenStreamBuilder { // If `self` is not empty and the last tree within the last stream is a // token tree marked with `Joint`... - if let Some(TokenStream(Some(ref mut last_stream_lrc))) = self.0.last_mut() { + if let Some(TokenStream(ref mut last_stream_lrc)) = self.0.last_mut() { if let Some((TokenTree::Token(last_token), Joint)) = last_stream_lrc.last() { // ...and `stream` is not empty and the first tree within it is // a token tree... - if let TokenStream(Some(ref mut stream_lrc)) = stream { - if let Some((TokenTree::Token(token), is_joint)) = stream_lrc.first() { - - // ...and the two tokens can be glued together... - if let Some(glued_tok) = last_token.glue(&token) { - - // ...then do so, by overwriting the last token - // tree in `self` and removing the first token tree - // from `stream`. This requires using `make_mut()` - // on the last stream in `self` and on `stream`, - // and in practice this doesn't cause cloning 99.9% - // of the time. - - // Overwrite the last token tree with the merged - // token. - let last_vec_mut = Lrc::make_mut(last_stream_lrc); - *last_vec_mut.last_mut().unwrap() = - (TokenTree::Token(glued_tok), *is_joint); - - // Remove the first token tree from `stream`. (This - // is almost always the only tree in `stream`.) - let stream_vec_mut = Lrc::make_mut(stream_lrc); - stream_vec_mut.remove(0); - - // Don't push `stream` if it's empty -- that could - // block subsequent token gluing, by getting - // between two token trees that should be glued - // together. - if !stream.is_empty() { - self.0.push(stream); - } - return; + let TokenStream(ref mut stream_lrc) = stream; + if let Some((TokenTree::Token(token), is_joint)) = stream_lrc.first() { + + // ...and the two tokens can be glued together... + if let Some(glued_tok) = last_token.glue(&token) { + + // ...then do so, by overwriting the last token + // tree in `self` and removing the first token tree + // from `stream`. This requires using `make_mut()` + // on the last stream in `self` and on `stream`, + // and in practice this doesn't cause cloning 99.9% + // of the time. + + // Overwrite the last token tree with the merged + // token. + let last_vec_mut = Lrc::make_mut(last_stream_lrc); + *last_vec_mut.last_mut().unwrap() = + (TokenTree::Token(glued_tok), *is_joint); + + // Remove the first token tree from `stream`. (This + // is almost always the only tree in `stream`.) + let stream_vec_mut = Lrc::make_mut(stream_lrc); + stream_vec_mut.remove(0); + + // Don't push `stream` if it's empty -- that could + // block subsequent token gluing, by getting + // between two token trees that should be glued + // together. + if !stream.is_empty() { + self.0.push(stream); } + return; } } } @@ -476,16 +442,11 @@ impl Cursor { } pub fn next_with_joint(&mut self) -> Option { - match self.stream.0 { - None => None, - Some(ref stream) => { - if self.index < stream.len() { - self.index += 1; - Some(stream[self.index - 1].clone()) - } else { - None - } - } + if self.index < self.stream.len() { + self.index += 1; + Some(self.stream.0[self.index - 1].clone()) + } else { + None } } @@ -494,16 +455,13 @@ impl Cursor { return; } let index = self.index; - let stream = mem::replace(&mut self.stream, TokenStream(None)); + let stream = mem::take(&mut self.stream); *self = TokenStream::from_streams(smallvec![stream, new_stream]).into_trees(); self.index = index; } pub fn look_ahead(&self, n: usize) -> Option { - match self.stream.0 { - None => None, - Some(ref stream) => stream[self.index ..].get(n).map(|(tree, _)| tree.clone()), - } + self.stream.0[self.index ..].get(n).map(|(tree, _)| tree.clone()) } } diff --git a/src/libsyntax_ext/plugin_macro_defs.rs b/src/libsyntax_ext/plugin_macro_defs.rs index 315babceae3..62c7e188eba 100644 --- a/src/libsyntax_ext/plugin_macro_defs.rs +++ b/src/libsyntax_ext/plugin_macro_defs.rs @@ -20,7 +20,7 @@ fn plugin_macro_def(name: Name, span: Span) -> P { attr::mk_word_item(Ident::new(sym::rustc_builtin_macro, span))); let parens: TreeAndJoint = TokenTree::Delimited( - DelimSpan::from_single(span), token::Paren, TokenStream::empty() + DelimSpan::from_single(span), token::Paren, TokenStream::default() ).into(); let trees = vec![parens.clone(), TokenTree::token(token::FatArrow, span).into(), parens]; -- cgit 1.4.1-3-g733a5 From 1ce0347fd475424d66d4c26fb8ac70f1437982aa Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 10 Oct 2019 12:01:12 +1100 Subject: Use `TokenStream::default()` in more places. --- src/libsyntax/parse/parser.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 4a457f5a43c..83a4acbe702 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1548,7 +1548,7 @@ impl<'a> Parser<'a> { // This can happen due to a bad interaction of two unrelated recovery mechanisms with // mismatched delimiters *and* recovery lookahead on the likely typo `pub ident(` // (#62881). - return Ok((ret?, TokenStream::new(vec![]))); + return Ok((ret?, TokenStream::default())); } else { &mut self.token_cursor.stack[prev].last_token }; @@ -1563,7 +1563,7 @@ impl<'a> Parser<'a> { // This can happen due to a bad interaction of two unrelated recovery mechanisms // with mismatched delimiters *and* recovery lookahead on the likely typo // `pub ident(` (#62895, different but similar to the case above). - return Ok((ret?, TokenStream::new(vec![]))); + return Ok((ret?, TokenStream::default())); } }; -- cgit 1.4.1-3-g733a5 From 29fb07d2451035cce7fbe99bc854cb3d71b5f1a1 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 14 Oct 2019 16:47:12 +0200 Subject: syntax: add recovery for intersection patterns `p1 @ p2` --- src/libsyntax/parse/parser/pat.rs | 60 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index 48f9e301610..c0e577bd58b 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -367,6 +367,7 @@ impl<'a> Parser<'a> { let pat = self.mk_pat(lo.to(self.prev_span), pat); let pat = self.maybe_recover_from_bad_qpath(pat, true)?; + let pat = self.recover_intersection_pat(pat)?; if !allow_range_pat { self.ban_pat_range_if_ambiguous(&pat)? @@ -375,6 +376,65 @@ impl<'a> Parser<'a> { Ok(pat) } + /// Try to recover the more general form `intersect ::= $pat_lhs @ $pat_rhs`. + /// + /// Allowed binding patterns generated by `binding ::= ref? mut? $ident @ $pat_rhs` + /// should already have been parsed by now at this point, + /// if the next token is `@` then we can try to parse the more general form. + /// + /// Consult `parse_pat_ident` for the `binding` grammar. + /// + /// The notion of intersection patterns are found in + /// e.g. [F#][and] where they are called AND-patterns. + /// + /// [and]: https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/pattern-matching + fn recover_intersection_pat(&mut self, lhs: P) -> PResult<'a, P> { + if self.token.kind != token::At { + // Next token is not `@` so it's not going to be an intersection pattern. + return Ok(lhs); + } + + // At this point we attempt to parse `@ $pat_rhs` and emit an error. + self.bump(); // `@` + let mut rhs = self.parse_pat(None)?; + let sp = lhs.span.to(rhs.span); + + if let PatKind::Ident(_, _, ref mut sub @ None) = rhs.kind { + // The user inverted the order, so help them fix that. + let mut applicability = Applicability::MachineApplicable; + lhs.walk(&mut |p| match p.kind { + // `check_match` is unhappy if the subpattern has a binding anywhere. + PatKind::Ident(..) => { + applicability = Applicability::MaybeIncorrect; + false // Short-circuit. + }, + _ => true, + }); + + let lhs_span = lhs.span; + // Move the LHS into the RHS as a subpattern. + // The RHS is now the full pattern. + *sub = Some(lhs); + + self.struct_span_err(sp, "pattern on wrong side of `@`") + .span_label(lhs_span, "pattern on the left, should be to the right") + .span_label(rhs.span, "binding on the right, should be to the left") + .span_suggestion(sp, "switch the order", pprust::pat_to_string(&rhs), applicability) + .emit(); + + rhs.span = sp; + return Ok(rhs); + } + + // The special case above doesn't apply so we may have e.g. `A(x) @ B(y)`. + let mut err = self.struct_span_err(sp, "left-hand side of `@` must be a binding pattern"); + err.span_label(lhs.span, "interpreted as a pattern, not a binding") + .span_label(rhs.span, "also a pattern") + .note("bindings are `x`, `mut x`, `ref x`, and `ref mut x`"); + // FIXME(Centril): Introduce `PatKind::Err` and use that instead. + Err(err) + } + /// Ban a range pattern if it has an ambiguous interpretation. fn ban_pat_range_if_ambiguous(&self, pat: &Pat) -> PResult<'a, ()> { match pat.kind { -- cgit 1.4.1-3-g733a5 From 72ad8f716bc2591fba72d7107a9938952214f485 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 14 Oct 2019 17:25:50 +0200 Subject: syntax: use `PatKind::Wild` as our `::Err` equivalent. --- src/libsyntax/parse/parser/pat.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index c0e577bd58b..55c534e56ce 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -421,18 +421,18 @@ impl<'a> Parser<'a> { .span_label(rhs.span, "binding on the right, should be to the left") .span_suggestion(sp, "switch the order", pprust::pat_to_string(&rhs), applicability) .emit(); - - rhs.span = sp; - return Ok(rhs); + } else { + // The special case above doesn't apply so we may have e.g. `A(x) @ B(y)`. + rhs.kind = PatKind::Wild; + self.struct_span_err(sp, "left-hand side of `@` must be a binding pattern") + .span_label(lhs.span, "interpreted as a pattern, not a binding") + .span_label(rhs.span, "also a pattern") + .note("bindings are `x`, `mut x`, `ref x`, and `ref mut x`") + .emit(); } - // The special case above doesn't apply so we may have e.g. `A(x) @ B(y)`. - let mut err = self.struct_span_err(sp, "left-hand side of `@` must be a binding pattern"); - err.span_label(lhs.span, "interpreted as a pattern, not a binding") - .span_label(rhs.span, "also a pattern") - .note("bindings are `x`, `mut x`, `ref x`, and `ref mut x`"); - // FIXME(Centril): Introduce `PatKind::Err` and use that instead. - Err(err) + rhs.span = sp; + Ok(rhs) } /// Ban a range pattern if it has an ambiguous interpretation. -- cgit 1.4.1-3-g733a5 From 3a9f8deb1d568baeb2cac503cf8667e3170fb2f8 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 14 Oct 2019 18:02:49 +0200 Subject: recover_intersection_pat: adjust wording --- src/libsyntax/parse/parser/pat.rs | 6 +++--- src/test/ui/parser/intersection-patterns.rs | 10 +++++----- src/test/ui/parser/intersection-patterns.stderr | 10 +++++----- 3 files changed, 13 insertions(+), 13 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index 55c534e56ce..e288346a329 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -417,14 +417,14 @@ impl<'a> Parser<'a> { *sub = Some(lhs); self.struct_span_err(sp, "pattern on wrong side of `@`") - .span_label(lhs_span, "pattern on the left, should be to the right") - .span_label(rhs.span, "binding on the right, should be to the left") + .span_label(lhs_span, "pattern on the left, should be on the right") + .span_label(rhs.span, "binding on the right, should be on the left") .span_suggestion(sp, "switch the order", pprust::pat_to_string(&rhs), applicability) .emit(); } else { // The special case above doesn't apply so we may have e.g. `A(x) @ B(y)`. rhs.kind = PatKind::Wild; - self.struct_span_err(sp, "left-hand side of `@` must be a binding pattern") + self.struct_span_err(sp, "left-hand side of `@` must be a binding") .span_label(lhs.span, "interpreted as a pattern, not a binding") .span_label(rhs.span, "also a pattern") .note("bindings are `x`, `mut x`, `ref x`, and `ref mut x`") diff --git a/src/test/ui/parser/intersection-patterns.rs b/src/test/ui/parser/intersection-patterns.rs index 1dda21519e3..3b0dfd1ee99 100644 --- a/src/test/ui/parser/intersection-patterns.rs +++ b/src/test/ui/parser/intersection-patterns.rs @@ -12,8 +12,8 @@ fn main() { match s { Some(x) @ y => {} //~^ ERROR pattern on wrong side of `@` - //~| pattern on the left, should be to the right - //~| binding on the right, should be to the left + //~| pattern on the left, should be on the right + //~| binding on the right, should be on the left //~| HELP switch the order //~| SUGGESTION y@Some(x) _ => {} @@ -21,7 +21,7 @@ fn main() { match s { Some(x) @ Some(y) => {} - //~^ ERROR left-hand side of `@` must be a binding pattern + //~^ ERROR left-hand side of `@` must be a binding //~| interpreted as a pattern, not a binding //~| also a pattern //~| NOTE bindings are `x`, `mut x`, `ref x`, and `ref mut x` @@ -31,8 +31,8 @@ fn main() { match 2 { 1 ..= 5 @ e => {} //~^ ERROR pattern on wrong side of `@` - //~| pattern on the left, should be to the right - //~| binding on the right, should be to the left + //~| pattern on the left, should be on the right + //~| binding on the right, should be on the left //~| HELP switch the order //~| SUGGESTION e@1 ..=5 _ => {} diff --git a/src/test/ui/parser/intersection-patterns.stderr b/src/test/ui/parser/intersection-patterns.stderr index 03781f8fdee..39fc9b9475d 100644 --- a/src/test/ui/parser/intersection-patterns.stderr +++ b/src/test/ui/parser/intersection-patterns.stderr @@ -4,11 +4,11 @@ error: pattern on wrong side of `@` LL | Some(x) @ y => {} | -------^^^- | | | - | | binding on the right, should be to the left - | pattern on the left, should be to the right + | | binding on the right, should be on the left + | pattern on the left, should be on the right | help: switch the order: `y@Some(x)` -error: left-hand side of `@` must be a binding pattern +error: left-hand side of `@` must be a binding --> $DIR/intersection-patterns.rs:23:9 | LL | Some(x) @ Some(y) => {} @@ -25,8 +25,8 @@ error: pattern on wrong side of `@` LL | 1 ..= 5 @ e => {} | -------^^^- | | | - | | binding on the right, should be to the left - | pattern on the left, should be to the right + | | binding on the right, should be on the left + | pattern on the left, should be on the right | help: switch the order: `e@1 ..=5` error: aborting due to 3 previous errors -- cgit 1.4.1-3-g733a5 From 57d33b155f31ca8c9d17371416d085c66ab4e61c Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 5 Sep 2019 15:52:47 +1000 Subject: Remove custom `PartialEq` impls for `LocalInternedString`. This is on-trend with the recent changes simplifying `LocalInternedString` and reducing its use. --- src/libsyntax/feature_gate/check.rs | 2 +- src/libsyntax/parse/literal.rs | 2 +- src/libsyntax_pos/symbol.rs | 24 ------------------------ 3 files changed, 2 insertions(+), 26 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/feature_gate/check.rs b/src/libsyntax/feature_gate/check.rs index 9e40b1a26ac..5f79050c5b8 100644 --- a/src/libsyntax/feature_gate/check.rs +++ b/src/libsyntax/feature_gate/check.rs @@ -769,7 +769,7 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute], } if let Some(allowed) = allow_features.as_ref() { - if allowed.iter().find(|f| *f == name.as_str()).is_none() { + if allowed.iter().find(|&f| f == &name.as_str() as &str).is_none() { span_err!(span_handler, mi.span(), E0725, "the feature `{}` is not in the list of allowed features", name); diff --git a/src/libsyntax/parse/literal.rs b/src/libsyntax/parse/literal.rs index fcd5b2782fd..95588d84f38 100644 --- a/src/libsyntax/parse/literal.rs +++ b/src/libsyntax/parse/literal.rs @@ -204,7 +204,7 @@ impl LitKind { let (kind, symbol, suffix) = match *self { LitKind::Str(symbol, ast::StrStyle::Cooked) => { // Don't re-intern unless the escaped string is different. - let s = &symbol.as_str(); + let s: &str = &symbol.as_str(); let escaped = s.escape_default().to_string(); let symbol = if escaped == *s { symbol } else { Symbol::intern(&escaped) }; (token::Str, symbol, None) diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs index 2b005c3fc42..c57a933721f 100644 --- a/src/libsyntax_pos/symbol.rs +++ b/src/libsyntax_pos/symbol.rs @@ -1201,30 +1201,6 @@ impl> std::cmp::PartialEq for LocalInternedS } } -impl std::cmp::PartialEq for str { - fn eq(&self, other: &LocalInternedString) -> bool { - self == other.string - } -} - -impl<'a> std::cmp::PartialEq for &'a str { - fn eq(&self, other: &LocalInternedString) -> bool { - *self == other.string - } -} - -impl std::cmp::PartialEq for String { - fn eq(&self, other: &LocalInternedString) -> bool { - self == other.string - } -} - -impl<'a> std::cmp::PartialEq for &'a String { - fn eq(&self, other: &LocalInternedString) -> bool { - *self == other.string - } -} - impl !Send for LocalInternedString {} impl !Sync for LocalInternedString {} -- cgit 1.4.1-3-g733a5 From c29fe81ec42a89a5aadd8496855dc7dc43be7668 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 8 Oct 2019 10:27:32 +0200 Subject: move maybe_report_invalid_custom_discriminants to feature_gate --- src/libsyntax/feature_gate/check.rs | 50 +++++++++++++++++++++++++++++++-- src/libsyntax/parse/diagnostics.rs | 55 ++----------------------------------- 2 files changed, 50 insertions(+), 55 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/feature_gate/check.rs b/src/libsyntax/feature_gate/check.rs index 6008f8f3005..2f6d98213e5 100644 --- a/src/libsyntax/feature_gate/check.rs +++ b/src/libsyntax/feature_gate/check.rs @@ -5,14 +5,13 @@ use super::builtin_attrs::{AttributeGate, BUILTIN_ATTRIBUTE_MAP}; use crate::ast::{ self, AssocTyConstraint, AssocTyConstraintKind, NodeId, GenericParam, GenericParamKind, - PatKind, RangeEnd, + PatKind, RangeEnd, VariantData, }; use crate::attr::{self, check_builtin_attribute}; use crate::source_map::Spanned; use crate::edition::{ALL_EDITIONS, Edition}; use crate::visit::{self, FnKind, Visitor}; use crate::parse::{token, ParseSess}; -use crate::parse::parser::Parser; use crate::symbol::{Symbol, sym}; use crate::tokenstream::TokenTree; @@ -246,6 +245,51 @@ impl<'a> PostExpansionVisitor<'a> { Abi::System => {} } } + + fn maybe_report_invalid_custom_discriminants(&self, variants: &[ast::Variant]) { + let has_fields = variants.iter().any(|variant| match variant.data { + VariantData::Tuple(..) | VariantData::Struct(..) => true, + VariantData::Unit(..) => false, + }); + + let discriminant_spans = variants.iter().filter(|variant| match variant.data { + VariantData::Tuple(..) | VariantData::Struct(..) => false, + VariantData::Unit(..) => true, + }) + .filter_map(|variant| variant.disr_expr.as_ref().map(|c| c.value.span)) + .collect::>(); + + if !discriminant_spans.is_empty() && has_fields { + let mut err = feature_err( + self.parse_sess, + sym::arbitrary_enum_discriminant, + discriminant_spans.clone(), + crate::feature_gate::GateIssue::Language, + "custom discriminant values are not allowed in enums with tuple or struct variants", + ); + for sp in discriminant_spans { + err.span_label(sp, "disallowed custom discriminant"); + } + for variant in variants.iter() { + match &variant.data { + VariantData::Struct(..) => { + err.span_label( + variant.span, + "struct variant defined here", + ); + } + VariantData::Tuple(..) => { + err.span_label( + variant.span, + "tuple variant defined here", + ); + } + VariantData::Unit(..) => {} + } + } + err.emit(); + } + } } impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { @@ -353,7 +397,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { let has_feature = self.features.arbitrary_enum_discriminant; if !has_feature && !i.span.allows_unstable(sym::arbitrary_enum_discriminant) { - Parser::maybe_report_invalid_custom_discriminants(self.parse_sess, &variants); + self.maybe_report_invalid_custom_discriminants(&variants); } } diff --git a/src/libsyntax/parse/diagnostics.rs b/src/libsyntax/parse/diagnostics.rs index 0bbd67589dd..943838d9dda 100644 --- a/src/libsyntax/parse/diagnostics.rs +++ b/src/libsyntax/parse/diagnostics.rs @@ -1,9 +1,8 @@ use crate::ast::{ self, Param, BinOpKind, BindingMode, BlockCheckMode, Expr, ExprKind, Ident, Item, ItemKind, - Mutability, Pat, PatKind, PathSegment, QSelf, Ty, TyKind, VariantData, + Mutability, Pat, PatKind, PathSegment, QSelf, Ty, TyKind, }; -use crate::feature_gate::feature_err; -use crate::parse::{SeqSep, PResult, Parser, ParseSess}; +use crate::parse::{SeqSep, PResult, Parser}; use crate::parse::parser::{BlockMode, PathStyle, SemiColonMode, TokenType, TokenExpectType}; use crate::parse::token::{self, TokenKind}; use crate::print::pprust; @@ -715,55 +714,7 @@ impl<'a> Parser<'a> { } } - crate fn maybe_report_invalid_custom_discriminants( - sess: &ParseSess, - variants: &[ast::Variant], - ) { - let has_fields = variants.iter().any(|variant| match variant.data { - VariantData::Tuple(..) | VariantData::Struct(..) => true, - VariantData::Unit(..) => false, - }); - - let discriminant_spans = variants.iter().filter(|variant| match variant.data { - VariantData::Tuple(..) | VariantData::Struct(..) => false, - VariantData::Unit(..) => true, - }) - .filter_map(|variant| variant.disr_expr.as_ref().map(|c| c.value.span)) - .collect::>(); - - if !discriminant_spans.is_empty() && has_fields { - let mut err = feature_err( - sess, - sym::arbitrary_enum_discriminant, - discriminant_spans.clone(), - crate::feature_gate::GateIssue::Language, - "custom discriminant values are not allowed in enums with tuple or struct variants", - ); - for sp in discriminant_spans { - err.span_label(sp, "disallowed custom discriminant"); - } - for variant in variants.iter() { - match &variant.data { - VariantData::Struct(..) => { - err.span_label( - variant.span, - "struct variant defined here", - ); - } - VariantData::Tuple(..) => { - err.span_label( - variant.span, - "tuple variant defined here", - ); - } - VariantData::Unit(..) => {} - } - } - err.emit(); - } - } - - crate fn maybe_recover_from_bad_type_plus( + pub(super) fn maybe_recover_from_bad_type_plus( &mut self, allow_plus: bool, ty: &Ty, -- cgit 1.4.1-3-g733a5 From 52d0e86b9a46ab74f76c0bc7b2b9df3d32fcfbc1 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Wed, 9 Oct 2019 03:23:10 +0200 Subject: syntax: extract sess.rs for ParseSess --- src/libsyntax/parse/mod.rs | 125 +++--------------------------------------- src/libsyntax/parse/parser.rs | 2 +- src/libsyntax/parse/sess.rs | 124 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 132 insertions(+), 119 deletions(-) create mode 100644 src/libsyntax/parse/sess.rs (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 0df695d37b9..53ba9b20690 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -1,26 +1,19 @@ //! The main parser interface. -use crate::ast::{self, CrateConfig, NodeId}; -use crate::early_buffered_lints::{BufferedEarlyLint, BufferedEarlyLintId}; -use crate::source_map::{SourceMap, FilePathMapping}; -use crate::feature_gate::UnstableFeatures; +use crate::ast; use crate::parse::parser::{Parser, emit_unclosed_delims}; use crate::parse::token::{Nonterminal, TokenKind}; use crate::tokenstream::{self, TokenStream, TokenTree}; use crate::print::pprust; -use crate::symbol::Symbol; -use errors::{Applicability, FatalError, Level, Handler, ColorConfig, Diagnostic, DiagnosticBuilder}; -use rustc_data_structures::fx::{FxHashSet, FxHashMap}; +use errors::{FatalError, Level, Diagnostic, DiagnosticBuilder}; #[cfg(target_arch = "x86_64")] use rustc_data_structures::static_assert_size; -use rustc_data_structures::sync::{Lrc, Lock, Once}; -use syntax_pos::{Span, SourceFile, FileName, MultiSpan}; -use syntax_pos::edition::Edition; -use syntax_pos::hygiene::ExpnId; +use rustc_data_structures::sync::Lrc; +use syntax_pos::{Span, SourceFile, FileName}; use std::borrow::Cow; -use std::path::{Path, PathBuf}; +use std::path::Path; use std::str; use log::info; @@ -33,6 +26,8 @@ pub mod parser; pub mod attr; pub mod lexer; pub mod token; +mod sess; +pub use sess::ParseSess; crate mod classify; crate mod diagnostics; @@ -46,112 +41,6 @@ pub type PResult<'a, T> = Result>; #[cfg(target_arch = "x86_64")] static_assert_size!(PResult<'_, bool>, 16); -/// Collected spans during parsing for places where a certain feature was -/// used and should be feature gated accordingly in `check_crate`. -#[derive(Default)] -pub struct GatedSpans { - /// Spans collected for gating `let_chains`, e.g. `if a && let b = c {}`. - pub let_chains: Lock>, - /// Spans collected for gating `async_closure`, e.g. `async || ..`. - pub async_closure: Lock>, - /// Spans collected for gating `yield e?` expressions (`generators` gate). - pub yields: Lock>, - /// Spans collected for gating `or_patterns`, e.g. `Some(Foo | Bar)`. - pub or_patterns: Lock>, - /// Spans collected for gating `const_extern_fn`, e.g. `const extern fn foo`. - pub const_extern_fn: Lock>, -} - -/// Info about a parsing session. -pub struct ParseSess { - pub span_diagnostic: Handler, - pub unstable_features: UnstableFeatures, - pub config: CrateConfig, - pub edition: Edition, - pub missing_fragment_specifiers: Lock>, - /// Places where raw identifiers were used. This is used for feature-gating raw identifiers. - pub raw_identifier_spans: Lock>, - /// Used to determine and report recursive module inclusions. - included_mod_stack: Lock>, - source_map: Lrc, - pub buffered_lints: Lock>, - /// Contains the spans of block expressions that could have been incomplete based on the - /// operation token that followed it, but that the parser cannot identify without further - /// analysis. - pub ambiguous_block_expr_parse: Lock>, - pub injected_crate_name: Once, - pub gated_spans: GatedSpans, -} - -impl ParseSess { - pub fn new(file_path_mapping: FilePathMapping) -> Self { - let cm = Lrc::new(SourceMap::new(file_path_mapping)); - let handler = Handler::with_tty_emitter( - ColorConfig::Auto, - true, - None, - Some(cm.clone()), - ); - ParseSess::with_span_handler(handler, cm) - } - - pub fn with_span_handler(handler: Handler, source_map: Lrc) -> Self { - Self { - span_diagnostic: handler, - unstable_features: UnstableFeatures::from_environment(), - config: FxHashSet::default(), - edition: ExpnId::root().expn_data().edition, - missing_fragment_specifiers: Lock::new(FxHashSet::default()), - raw_identifier_spans: Lock::new(Vec::new()), - included_mod_stack: Lock::new(vec![]), - source_map, - buffered_lints: Lock::new(vec![]), - ambiguous_block_expr_parse: Lock::new(FxHashMap::default()), - injected_crate_name: Once::new(), - gated_spans: GatedSpans::default(), - } - } - - #[inline] - pub fn source_map(&self) -> &SourceMap { - &self.source_map - } - - pub fn buffer_lint>(&self, - lint_id: BufferedEarlyLintId, - span: S, - id: NodeId, - msg: &str, - ) { - self.buffered_lints.with_lock(|buffered_lints| { - buffered_lints.push(BufferedEarlyLint{ - span: span.into(), - id, - msg: msg.into(), - lint_id, - }); - }); - } - - /// Extend an error with a suggestion to wrap an expression with parentheses to allow the - /// parser to continue parsing the following operation as part of the same expression. - pub fn expr_parentheses_needed( - &self, - err: &mut DiagnosticBuilder<'_>, - span: Span, - alt_snippet: Option, - ) { - if let Some(snippet) = self.source_map().span_to_snippet(span).ok().or(alt_snippet) { - err.span_suggestion( - span, - "parentheses are required to parse this as an expression", - format!("({})", snippet), - Applicability::MachineApplicable, - ); - } - } -} - #[derive(Clone)] pub struct Directory<'a> { pub path: Cow<'a, Path>, diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 478cfefc224..2b973479833 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1366,7 +1366,7 @@ impl<'a> Parser<'a> { ], Applicability::MaybeIncorrect, ).span_suggestion( - self.sess.source_map.next_point(self.prev_span), + self.sess.source_map().next_point(self.prev_span), "add a semicolon", ';'.to_string(), Applicability::MaybeIncorrect, diff --git a/src/libsyntax/parse/sess.rs b/src/libsyntax/parse/sess.rs new file mode 100644 index 00000000000..e49d3954f8e --- /dev/null +++ b/src/libsyntax/parse/sess.rs @@ -0,0 +1,124 @@ +//! Contains `ParseSess` which holds state living beyond what one `Parser` might. +//! It also serves as an input to the parser itself. + +use crate::ast::{CrateConfig, NodeId}; +use crate::early_buffered_lints::{BufferedEarlyLint, BufferedEarlyLintId}; +use crate::source_map::{SourceMap, FilePathMapping}; +use crate::feature_gate::UnstableFeatures; + +use errors::{Applicability, Handler, ColorConfig, DiagnosticBuilder}; +use rustc_data_structures::fx::{FxHashSet, FxHashMap}; +use rustc_data_structures::sync::{Lrc, Lock, Once}; +use syntax_pos::{Symbol, Span, MultiSpan}; +use syntax_pos::edition::Edition; +use syntax_pos::hygiene::ExpnId; + +use std::path::PathBuf; +use std::str; + +/// Collected spans during parsing for places where a certain feature was +/// used and should be feature gated accordingly in `check_crate`. +#[derive(Default)] +crate struct GatedSpans { + /// Spans collected for gating `let_chains`, e.g. `if a && let b = c {}`. + crate let_chains: Lock>, + /// Spans collected for gating `async_closure`, e.g. `async || ..`. + crate async_closure: Lock>, + /// Spans collected for gating `yield e?` expressions (`generators` gate). + crate yields: Lock>, + /// Spans collected for gating `or_patterns`, e.g. `Some(Foo | Bar)`. + crate or_patterns: Lock>, + /// Spans collected for gating `const_extern_fn`, e.g. `const extern fn foo`. + crate const_extern_fn: Lock>, +} + +/// Info about a parsing session. +pub struct ParseSess { + pub span_diagnostic: Handler, + crate unstable_features: UnstableFeatures, + pub config: CrateConfig, + pub edition: Edition, + pub missing_fragment_specifiers: Lock>, + /// Places where raw identifiers were used. This is used for feature-gating raw identifiers. + pub raw_identifier_spans: Lock>, + /// Used to determine and report recursive module inclusions. + pub(super) included_mod_stack: Lock>, + source_map: Lrc, + pub buffered_lints: Lock>, + /// Contains the spans of block expressions that could have been incomplete based on the + /// operation token that followed it, but that the parser cannot identify without further + /// analysis. + pub ambiguous_block_expr_parse: Lock>, + pub injected_crate_name: Once, + crate gated_spans: GatedSpans, +} + +impl ParseSess { + pub fn new(file_path_mapping: FilePathMapping) -> Self { + let cm = Lrc::new(SourceMap::new(file_path_mapping)); + let handler = Handler::with_tty_emitter( + ColorConfig::Auto, + true, + None, + Some(cm.clone()), + ); + ParseSess::with_span_handler(handler, cm) + } + + pub fn with_span_handler(handler: Handler, source_map: Lrc) -> Self { + Self { + span_diagnostic: handler, + unstable_features: UnstableFeatures::from_environment(), + config: FxHashSet::default(), + edition: ExpnId::root().expn_data().edition, + missing_fragment_specifiers: Lock::new(FxHashSet::default()), + raw_identifier_spans: Lock::new(Vec::new()), + included_mod_stack: Lock::new(vec![]), + source_map, + buffered_lints: Lock::new(vec![]), + ambiguous_block_expr_parse: Lock::new(FxHashMap::default()), + injected_crate_name: Once::new(), + gated_spans: GatedSpans::default(), + } + } + + #[inline] + pub fn source_map(&self) -> &SourceMap { + &self.source_map + } + + pub fn buffer_lint( + &self, + lint_id: BufferedEarlyLintId, + span: impl Into, + id: NodeId, + msg: &str, + ) { + self.buffered_lints.with_lock(|buffered_lints| { + buffered_lints.push(BufferedEarlyLint{ + span: span.into(), + id, + msg: msg.into(), + lint_id, + }); + }); + } + + /// Extend an error with a suggestion to wrap an expression with parentheses to allow the + /// parser to continue parsing the following operation as part of the same expression. + pub fn expr_parentheses_needed( + &self, + err: &mut DiagnosticBuilder<'_>, + span: Span, + alt_snippet: Option, + ) { + if let Some(snippet) = self.source_map().span_to_snippet(span).ok().or(alt_snippet) { + err.span_suggestion( + span, + "parentheses are required to parse this as an expression", + format!("({})", snippet), + Applicability::MachineApplicable, + ); + } + } +} -- cgit 1.4.1-3-g733a5 From 79d02867b89ffabaf6db700e2eb63a3ef2610a97 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Fri, 11 Oct 2019 18:40:56 +0200 Subject: move parse_lit to expr.rs --- src/libsyntax/parse/literal.rs | 167 +---------------------------------- src/libsyntax/parse/parser.rs | 8 +- src/libsyntax/parse/parser/expr.rs | 172 +++++++++++++++++++++++++++++++++++-- 3 files changed, 170 insertions(+), 177 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/literal.rs b/src/libsyntax/parse/literal.rs index 56a79bfe5d5..fbd409b0de4 100644 --- a/src/libsyntax/parse/literal.rs +++ b/src/libsyntax/parse/literal.rs @@ -1,14 +1,10 @@ //! Code related to parsing literals. use crate::ast::{self, Lit, LitKind}; -use crate::parse::parser::Parser; -use crate::parse::PResult; -use crate::parse::token::{self, Token, TokenKind}; -use crate::print::pprust; +use crate::parse::token::{self, Token}; use crate::symbol::{kw, sym, Symbol}; use crate::tokenstream::{TokenStream, TokenTree}; -use errors::{Applicability, Handler}; use log::debug; use rustc_data_structures::sync::Lrc; use syntax_pos::Span; @@ -28,72 +24,6 @@ crate enum LitError { IntTooLarge, } -impl LitError { - fn report(&self, diag: &Handler, lit: token::Lit, span: Span) { - let token::Lit { kind, suffix, .. } = lit; - match *self { - // `NotLiteral` is not an error by itself, so we don't report - // it and give the parser opportunity to try something else. - LitError::NotLiteral => {} - // `LexerError` *is* an error, but it was already reported - // by lexer, so here we don't report it the second time. - LitError::LexerError => {} - LitError::InvalidSuffix => { - expect_no_suffix( - diag, span, &format!("{} {} literal", kind.article(), kind.descr()), suffix - ); - } - LitError::InvalidIntSuffix => { - let suf = suffix.expect("suffix error with no suffix").as_str(); - if looks_like_width_suffix(&['i', 'u'], &suf) { - // If it looks like a width, try to be helpful. - let msg = format!("invalid width `{}` for integer literal", &suf[1..]); - diag.struct_span_err(span, &msg) - .help("valid widths are 8, 16, 32, 64 and 128") - .emit(); - } else { - let msg = format!("invalid suffix `{}` for integer literal", suf); - diag.struct_span_err(span, &msg) - .span_label(span, format!("invalid suffix `{}`", suf)) - .help("the suffix must be one of the integral types (`u32`, `isize`, etc)") - .emit(); - } - } - LitError::InvalidFloatSuffix => { - let suf = suffix.expect("suffix error with no suffix").as_str(); - if looks_like_width_suffix(&['f'], &suf) { - // If it looks like a width, try to be helpful. - let msg = format!("invalid width `{}` for float literal", &suf[1..]); - diag.struct_span_err(span, &msg) - .help("valid widths are 32 and 64") - .emit(); - } else { - let msg = format!("invalid suffix `{}` for float literal", suf); - diag.struct_span_err(span, &msg) - .span_label(span, format!("invalid suffix `{}`", suf)) - .help("valid suffixes are `f32` and `f64`") - .emit(); - } - } - LitError::NonDecimalFloat(base) => { - let descr = match base { - 16 => "hexadecimal", - 8 => "octal", - 2 => "binary", - _ => unreachable!(), - }; - diag.struct_span_err(span, &format!("{} float literal is not supported", descr)) - .span_label(span, "not supported") - .emit(); - } - LitError::IntTooLarge => { - diag.struct_span_err(span, "integer literal is too large") - .emit(); - } - } - } -} - impl LitKind { /// Converts literal token into a semantic literal. fn from_lit_token(lit: token::Lit) -> Result { @@ -254,7 +184,7 @@ impl LitKind { impl Lit { /// Converts literal token into an AST literal. - fn from_lit_token(token: token::Lit, span: Span) -> Result { + crate fn from_lit_token(token: token::Lit, span: Span) -> Result { Ok(Lit { token, kind: LitKind::from_lit_token(token)?, span }) } @@ -296,99 +226,6 @@ impl Lit { } } -impl<'a> Parser<'a> { - /// Matches `lit = true | false | token_lit`. - crate fn parse_lit(&mut self) -> PResult<'a, Lit> { - let mut recovered = None; - if self.token == token::Dot { - // Attempt to recover `.4` as `0.4`. - recovered = self.look_ahead(1, |next_token| { - if let token::Literal(token::Lit { kind: token::Integer, symbol, suffix }) - = next_token.kind { - if self.token.span.hi() == next_token.span.lo() { - let s = String::from("0.") + &symbol.as_str(); - let kind = TokenKind::lit(token::Float, Symbol::intern(&s), suffix); - return Some(Token::new(kind, self.token.span.to(next_token.span))); - } - } - None - }); - if let Some(token) = &recovered { - self.bump(); - self.diagnostic() - .struct_span_err(token.span, "float literals must have an integer part") - .span_suggestion( - token.span, - "must have an integer part", - pprust::token_to_string(token), - Applicability::MachineApplicable, - ) - .emit(); - } - } - - let token = recovered.as_ref().unwrap_or(&self.token); - match Lit::from_token(token) { - Ok(lit) => { - self.bump(); - Ok(lit) - } - Err(LitError::NotLiteral) => { - let msg = format!("unexpected token: {}", self.this_token_descr()); - Err(self.span_fatal(token.span, &msg)) - } - Err(err) => { - let (lit, span) = (token.expect_lit(), token.span); - self.bump(); - err.report(&self.sess.span_diagnostic, lit, span); - // Pack possible quotes and prefixes from the original literal into - // the error literal's symbol so they can be pretty-printed faithfully. - let suffixless_lit = token::Lit::new(lit.kind, lit.symbol, None); - let symbol = Symbol::intern(&suffixless_lit.to_string()); - let lit = token::Lit::new(token::Err, symbol, lit.suffix); - Lit::from_lit_token(lit, span).map_err(|_| unreachable!()) - } - } - } -} - -crate fn expect_no_suffix(diag: &Handler, sp: Span, kind: &str, suffix: Option) { - if let Some(suf) = suffix { - let mut err = if kind == "a tuple index" && - [sym::i32, sym::u32, sym::isize, sym::usize].contains(&suf) { - // #59553: warn instead of reject out of hand to allow the fix to percolate - // through the ecosystem when people fix their macros - let mut err = diag.struct_span_warn( - sp, - &format!("suffixes on {} are invalid", kind), - ); - err.note(&format!( - "`{}` is *temporarily* accepted on tuple index fields as it was \ - incorrectly accepted on stable for a few releases", - suf, - )); - err.help( - "on proc macros, you'll want to use `syn::Index::from` or \ - `proc_macro::Literal::*_unsuffixed` for code that will desugar \ - to tuple field access", - ); - err.note( - "for more context, see https://github.com/rust-lang/rust/issues/60210", - ); - err - } else { - diag.struct_span_err(sp, &format!("suffixes on {} are invalid", kind)) - }; - err.span_label(sp, format!("invalid suffix `{}`", suf)); - err.emit(); - } -} - -// Checks if `s` looks like i32 or u1234 etc. -fn looks_like_width_suffix(first_chars: &[char], s: &str) -> bool { - s.len() > 1 && s.starts_with(first_chars) && s[1..].chars().all(|c| c.is_ascii_digit()) -} - fn strip_underscores(symbol: Symbol) -> Symbol { // Do not allocate a new string unless necessary. let s = symbol.as_str(); diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 2b973479833..a3ac6d0c81f 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -15,10 +15,10 @@ use crate::ast::{ self, DUMMY_NODE_ID, AttrStyle, Attribute, CrateSugar, Ident, IsAsync, MacDelimiter, Mutability, StrStyle, Visibility, VisibilityKind, Unsafety, }; -use crate::parse::{ParseSess, PResult, Directory, DirectoryOwnership, SeqSep, literal, token}; +use crate::parse::{ParseSess, PResult, Directory, DirectoryOwnership, SeqSep}; use crate::parse::lexer::UnmatchedBrace; use crate::parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration}; -use crate::parse::token::{Token, TokenKind, DelimToken}; +use crate::parse::token::{self, Token, TokenKind, DelimToken}; use crate::print::pprust; use crate::ptr::P; use crate::source_map::respan; @@ -637,10 +637,6 @@ impl<'a> Parser<'a> { } } - fn expect_no_suffix(&self, sp: Span, kind: &str, suffix: Option) { - literal::expect_no_suffix(&self.sess.span_diagnostic, sp, kind, suffix) - } - /// Attempts to consume a `<`. If `<<` is seen, replaces it with a single /// `<` and continue. If `<-` is seen, replaces it with a single `<` /// and continue. If a `<` is not seen, returns false. diff --git a/src/libsyntax/parse/parser/expr.rs b/src/libsyntax/parse/parser/expr.rs index 660bf9b7d65..dd0fd834fb0 100644 --- a/src/libsyntax/parse/parser/expr.rs +++ b/src/libsyntax/parse/parser/expr.rs @@ -1,17 +1,17 @@ -use super::{ - Parser, PResult, Restrictions, PrevTokenKind, TokenType, PathStyle, BlockMode, SemiColonMode, - SeqSep, TokenExpectType, -}; +use super::{Parser, PResult, Restrictions, PrevTokenKind, TokenType, PathStyle, BlockMode}; +use super::{SemiColonMode, SeqSep, TokenExpectType}; use super::pat::{GateOr, PARAM_EXPECTED}; +use crate::parse::literal::LitError; + use crate::ast::{ self, DUMMY_NODE_ID, Attribute, AttrStyle, Ident, CaptureBy, BlockCheckMode, Expr, ExprKind, RangeLimits, Label, Movability, IsAsync, Arm, Ty, TyKind, - FunctionRetTy, Param, FnDecl, BinOpKind, BinOp, UnOp, Mac, AnonConst, Field, + FunctionRetTy, Param, FnDecl, BinOpKind, BinOp, UnOp, Mac, AnonConst, Field, Lit, }; use crate::maybe_recover_from_interpolated_ty_qpath; use crate::parse::classify; -use crate::parse::token::{self, Token}; +use crate::parse::token::{self, Token, TokenKind}; use crate::parse::diagnostics::Error; use crate::print::pprust; use crate::ptr::P; @@ -20,6 +20,7 @@ use crate::symbol::{kw, sym}; use crate::util::parser::{AssocOp, Fixity, prec_let_scrutinee_needs_par}; use errors::Applicability; +use syntax_pos::Symbol; use std::mem; use rustc_data_structures::thin_vec::ThinVec; @@ -1072,6 +1073,165 @@ impl<'a> Parser<'a> { self.maybe_recover_from_bad_qpath(expr, true) } + /// Matches `lit = true | false | token_lit`. + crate fn parse_lit(&mut self) -> PResult<'a, Lit> { + let mut recovered = None; + if self.token == token::Dot { + // Attempt to recover `.4` as `0.4`. + recovered = self.look_ahead(1, |next_token| { + if let token::Literal(token::Lit { kind: token::Integer, symbol, suffix }) + = next_token.kind { + if self.token.span.hi() == next_token.span.lo() { + let s = String::from("0.") + &symbol.as_str(); + let kind = TokenKind::lit(token::Float, Symbol::intern(&s), suffix); + return Some(Token::new(kind, self.token.span.to(next_token.span))); + } + } + None + }); + if let Some(token) = &recovered { + self.bump(); + self.struct_span_err(token.span, "float literals must have an integer part") + .span_suggestion( + token.span, + "must have an integer part", + pprust::token_to_string(token), + Applicability::MachineApplicable, + ) + .emit(); + } + } + + let token = recovered.as_ref().unwrap_or(&self.token); + match Lit::from_token(token) { + Ok(lit) => { + self.bump(); + Ok(lit) + } + Err(LitError::NotLiteral) => { + let msg = format!("unexpected token: {}", self.this_token_descr()); + Err(self.span_fatal(token.span, &msg)) + } + Err(err) => { + let (lit, span) = (token.expect_lit(), token.span); + self.bump(); + self.error_literal_from_token(err, lit, span); + // Pack possible quotes and prefixes from the original literal into + // the error literal's symbol so they can be pretty-printed faithfully. + let suffixless_lit = token::Lit::new(lit.kind, lit.symbol, None); + let symbol = Symbol::intern(&suffixless_lit.to_string()); + let lit = token::Lit::new(token::Err, symbol, lit.suffix); + Lit::from_lit_token(lit, span).map_err(|_| unreachable!()) + } + } + } + + fn error_literal_from_token(&self, err: LitError, lit: token::Lit, span: Span) { + // Checks if `s` looks like i32 or u1234 etc. + fn looks_like_width_suffix(first_chars: &[char], s: &str) -> bool { + s.len() > 1 + && s.starts_with(first_chars) + && s[1..].chars().all(|c| c.is_ascii_digit()) + } + + let token::Lit { kind, suffix, .. } = lit; + match err { + // `NotLiteral` is not an error by itself, so we don't report + // it and give the parser opportunity to try something else. + LitError::NotLiteral => {} + // `LexerError` *is* an error, but it was already reported + // by lexer, so here we don't report it the second time. + LitError::LexerError => {} + LitError::InvalidSuffix => { + self.expect_no_suffix( + span, + &format!("{} {} literal", kind.article(), kind.descr()), + suffix, + ); + } + LitError::InvalidIntSuffix => { + let suf = suffix.expect("suffix error with no suffix").as_str(); + if looks_like_width_suffix(&['i', 'u'], &suf) { + // If it looks like a width, try to be helpful. + let msg = format!("invalid width `{}` for integer literal", &suf[1..]); + self.struct_span_err(span, &msg) + .help("valid widths are 8, 16, 32, 64 and 128") + .emit(); + } else { + let msg = format!("invalid suffix `{}` for integer literal", suf); + self.struct_span_err(span, &msg) + .span_label(span, format!("invalid suffix `{}`", suf)) + .help("the suffix must be one of the integral types (`u32`, `isize`, etc)") + .emit(); + } + } + LitError::InvalidFloatSuffix => { + let suf = suffix.expect("suffix error with no suffix").as_str(); + if looks_like_width_suffix(&['f'], &suf) { + // If it looks like a width, try to be helpful. + let msg = format!("invalid width `{}` for float literal", &suf[1..]); + self.struct_span_err(span, &msg) + .help("valid widths are 32 and 64") + .emit(); + } else { + let msg = format!("invalid suffix `{}` for float literal", suf); + self.struct_span_err(span, &msg) + .span_label(span, format!("invalid suffix `{}`", suf)) + .help("valid suffixes are `f32` and `f64`") + .emit(); + } + } + LitError::NonDecimalFloat(base) => { + let descr = match base { + 16 => "hexadecimal", + 8 => "octal", + 2 => "binary", + _ => unreachable!(), + }; + self.struct_span_err(span, &format!("{} float literal is not supported", descr)) + .span_label(span, "not supported") + .emit(); + } + LitError::IntTooLarge => { + self.struct_span_err(span, "integer literal is too large") + .emit(); + } + } + } + + pub(super) fn expect_no_suffix(&self, sp: Span, kind: &str, suffix: Option) { + if let Some(suf) = suffix { + let mut err = if kind == "a tuple index" + && [sym::i32, sym::u32, sym::isize, sym::usize].contains(&suf) + { + // #59553: warn instead of reject out of hand to allow the fix to percolate + // through the ecosystem when people fix their macros + let mut err = self.sess.span_diagnostic.struct_span_warn( + sp, + &format!("suffixes on {} are invalid", kind), + ); + err.note(&format!( + "`{}` is *temporarily* accepted on tuple index fields as it was \ + incorrectly accepted on stable for a few releases", + suf, + )); + err.help( + "on proc macros, you'll want to use `syn::Index::from` or \ + `proc_macro::Literal::*_unsuffixed` for code that will desugar \ + to tuple field access", + ); + err.note( + "for more context, see https://github.com/rust-lang/rust/issues/60210", + ); + err + } else { + self.struct_span_err(sp, &format!("suffixes on {} are invalid", kind)) + }; + err.span_label(sp, format!("invalid suffix `{}`", suf)); + err.emit(); + } + } + /// Matches `'-' lit | lit` (cf. `ast_validation::AstValidator::check_expr_within_pat`). crate fn parse_literal_maybe_minus(&mut self) -> PResult<'a, P> { maybe_whole_expr!(self); -- cgit 1.4.1-3-g733a5 From ae156a56d4ae27e2fca8d51aa63d5322b500c91f Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 14 Oct 2019 10:08:26 +0200 Subject: syntax::parse::sess -> syntax::sess --- src/librustc/hir/lowering.rs | 6 +- src/librustc/hir/print.rs | 2 +- src/librustc/session/config.rs | 3 +- src/librustc/session/mod.rs | 4 +- src/librustdoc/clean/cfg.rs | 2 +- src/librustdoc/html/highlight.rs | 4 +- src/librustdoc/passes/check_code_block_syntax.rs | 3 +- src/librustdoc/test.rs | 2 +- src/libsyntax/attr/builtin.rs | 2 +- src/libsyntax/attr/mod.rs | 3 +- src/libsyntax/config.rs | 3 +- src/libsyntax/ext/base.rs | 9 +- src/libsyntax/ext/expand.rs | 3 +- src/libsyntax/ext/mbe/macro_check.rs | 2 +- src/libsyntax/ext/mbe/macro_parser.rs | 3 +- src/libsyntax/ext/mbe/macro_rules.rs | 3 +- src/libsyntax/ext/mbe/quoted.rs | 2 +- src/libsyntax/ext/proc_macro_server.rs | 3 +- src/libsyntax/feature_gate/builtin_attrs.rs | 2 +- src/libsyntax/feature_gate/check.rs | 3 +- src/libsyntax/lib.rs | 1 + src/libsyntax/parse/lexer/mod.rs | 2 +- src/libsyntax/parse/mod.rs | 3 +- src/libsyntax/parse/parser.rs | 3 +- src/libsyntax/parse/sess.rs | 124 --------------------- src/libsyntax/print/pprust.rs | 3 +- src/libsyntax/sess.rs | 124 +++++++++++++++++++++ src/libsyntax/tests.rs | 3 +- src/libsyntax_ext/cmdline_attrs.rs | 3 +- src/libsyntax_ext/deriving/generic/mod.rs | 2 +- src/libsyntax_ext/proc_macro_harness.rs | 2 +- src/libsyntax_ext/standard_library_imports.rs | 2 +- src/libsyntax_ext/test_harness.rs | 2 +- src/test/ui-fulldeps/ast_stmt_expr_attr.rs | 3 +- src/test/ui-fulldeps/mod_dir_path_canonicalized.rs | 3 +- src/test/ui-fulldeps/pprust-expr-roundtrip.rs | 4 +- 36 files changed, 182 insertions(+), 166 deletions(-) delete mode 100644 src/libsyntax/parse/sess.rs create mode 100644 src/libsyntax/sess.rs (limited to 'src/libsyntax/parse') diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 747848edc7a..ab5a3c06510 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -67,11 +67,11 @@ use syntax::errors; use syntax::ext::base::SpecialDerives; use syntax::ext::hygiene::ExpnId; use syntax::print::pprust; -use syntax::source_map::{respan, ExpnData, ExpnKind, DesugaringKind, Spanned}; -use syntax::symbol::{kw, sym, Symbol}; use syntax::tokenstream::{TokenStream, TokenTree}; use syntax::parse::token::{self, Nonterminal, Token}; -use syntax::parse::ParseSess; +use syntax::sess::ParseSess; +use syntax::source_map::{respan, ExpnData, ExpnKind, DesugaringKind, Spanned}; +use syntax::symbol::{kw, sym, Symbol}; use syntax::visit::{self, Visitor}; use syntax_pos::Span; diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index 6cffaa8a494..b852098d4ce 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -1,10 +1,10 @@ use rustc_target::spec::abi::Abi; use syntax::ast; use syntax::source_map::{SourceMap, Spanned}; -use syntax::parse::ParseSess; use syntax::print::pp::{self, Breaks}; use syntax::print::pp::Breaks::{Consistent, Inconsistent}; use syntax::print::pprust::{self, Comments, PrintState}; +use syntax::sess::ParseSess; use syntax::symbol::kw; use syntax::util::parser::{self, AssocOp, Fixity}; use syntax_pos::{self, BytePos, FileName}; diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 2517141542d..675e3bbd002 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -16,8 +16,9 @@ use syntax; use syntax::ast::{self, IntTy, UintTy, MetaItemKind}; use syntax::source_map::{FileName, FilePathMapping}; use syntax::edition::{Edition, EDITION_NAME_LIST, DEFAULT_EDITION}; -use syntax::parse::{ParseSess, new_parser_from_source_str}; +use syntax::parse::new_parser_from_source_str; use syntax::parse::token; +use syntax::sess::ParseSess; use syntax::symbol::{sym, Symbol}; use syntax::feature_gate::UnstableFeatures; use syntax::source_map::SourceMap; diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index fa2902e4f0e..c59df146629 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -28,7 +28,7 @@ use syntax::ext::allocator::AllocatorKind; use syntax::feature_gate::{self, AttributeType}; use syntax::json::JsonEmitter; use syntax::source_map; -use syntax::parse::{self, ParseSess}; +use syntax::sess::ParseSess; use syntax::symbol::Symbol; use syntax_pos::{MultiSpan, Span}; use crate::util::profiling::{SelfProfiler, SelfProfilerRef}; @@ -1159,7 +1159,7 @@ fn build_session_( ); let target_cfg = config::build_target_config(&sopts, &span_diagnostic); - let parse_sess = parse::ParseSess::with_span_handler( + let parse_sess = ParseSess::with_span_handler( span_diagnostic, source_map, ); diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index da3b52afadf..706f52d0322 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -9,7 +9,7 @@ use std::ops; use syntax::symbol::{Symbol, sym}; use syntax::ast::{MetaItem, MetaItemKind, NestedMetaItem, LitKind}; -use syntax::parse::ParseSess; +use syntax::sess::ParseSess; use syntax::feature_gate::Features; use syntax_pos::Span; diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 5d86ee9721b..30c9453a643 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -14,7 +14,7 @@ use std::io::prelude::*; use syntax::source_map::{SourceMap, FilePathMapping}; use syntax::parse::lexer; use syntax::parse::token::{self, Token}; -use syntax::parse; +use syntax::sess::ParseSess; use syntax::symbol::{kw, sym}; use syntax_pos::{Span, FileName}; @@ -33,7 +33,7 @@ pub fn render_with_highlighting( class, tooltip).unwrap(); } - let sess = parse::ParseSess::new(FilePathMapping::empty()); + let sess = ParseSess::new(FilePathMapping::empty()); let fm = sess.source_map().new_source_file( FileName::Custom(String::from("rustdoc-highlighting")), src.to_owned(), diff --git a/src/librustdoc/passes/check_code_block_syntax.rs b/src/librustdoc/passes/check_code_block_syntax.rs index 32044e48b6f..10e15ab8881 100644 --- a/src/librustdoc/passes/check_code_block_syntax.rs +++ b/src/librustdoc/passes/check_code_block_syntax.rs @@ -1,6 +1,7 @@ use errors::Applicability; use syntax::parse::lexer::{StringReader as Lexer}; -use syntax::parse::{ParseSess, token}; +use syntax::parse::token; +use syntax::sess::ParseSess; use syntax::source_map::FilePathMapping; use syntax_pos::{InnerSpan, FileName}; diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 05e6f36c958..0be6340df96 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -394,7 +394,7 @@ pub fn make_test(s: &str, // Uses libsyntax to parse the doctest and find if there's a main fn and the extern // crate already is included. let (already_has_main, already_has_extern_crate, found_macro) = with_globals(edition, || { - use crate::syntax::{parse::{self, ParseSess}, source_map::FilePathMapping}; + use crate::syntax::{parse, sess::ParseSess, source_map::FilePathMapping}; use errors::emitter::EmitterWriter; use errors::Handler; diff --git a/src/libsyntax/attr/builtin.rs b/src/libsyntax/attr/builtin.rs index efc48256e7c..1fe698c2572 100644 --- a/src/libsyntax/attr/builtin.rs +++ b/src/libsyntax/attr/builtin.rs @@ -4,8 +4,8 @@ use crate::ast::{self, Attribute, MetaItem, NestedMetaItem}; use crate::early_buffered_lints::BufferedEarlyLintId; use crate::ext::base::ExtCtxt; use crate::feature_gate::{Features, GatedCfg}; -use crate::parse::ParseSess; use crate::print::pprust; +use crate::sess::ParseSess; use errors::{Applicability, Handler}; use syntax_pos::hygiene::Transparency; diff --git a/src/libsyntax/attr/mod.rs b/src/libsyntax/attr/mod.rs index c2c883fd20e..d291e502c25 100644 --- a/src/libsyntax/attr/mod.rs +++ b/src/libsyntax/attr/mod.rs @@ -16,9 +16,10 @@ use crate::mut_visit::visit_clobber; use crate::source_map::{BytePos, Spanned, DUMMY_SP}; use crate::parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration}; use crate::parse::parser::Parser; -use crate::parse::{ParseSess, PResult}; +use crate::parse::PResult; use crate::parse::token::{self, Token}; use crate::ptr::P; +use crate::sess::ParseSess; use crate::symbol::{sym, Symbol}; use crate::ThinVec; use crate::tokenstream::{TokenStream, TokenTree, DelimSpan}; diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index 2923cc86ba0..2099d018b7b 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -10,8 +10,9 @@ use crate::attr; use crate::ast; use crate::edition::Edition; use crate::mut_visit::*; -use crate::parse::{token, ParseSess}; +use crate::parse::token; use crate::ptr::P; +use crate::sess::ParseSess; use crate::symbol::sym; use crate::util::map_in_place::MapInPlace; diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 583fb3f7701..01be5642d5c 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -5,9 +5,10 @@ use crate::edition::Edition; use crate::ext::expand::{self, AstFragment, Invocation}; use crate::ext::hygiene::ExpnId; use crate::mut_visit::{self, MutVisitor}; -use crate::parse::{self, parser, ParseSess, DirectoryOwnership}; +use crate::parse::{self, parser, DirectoryOwnership}; use crate::parse::token; use crate::ptr::P; +use crate::sess::ParseSess; use crate::symbol::{kw, sym, Ident, Symbol}; use crate::{ThinVec, MACRO_ARGUMENTS}; use crate::tokenstream::{self, TokenStream}; @@ -892,7 +893,7 @@ pub struct ExpansionData { /// when a macro expansion occurs, the resulting nodes have the `backtrace() /// -> expn_data` of their expansion context stored into their span. pub struct ExtCtxt<'a> { - pub parse_sess: &'a parse::ParseSess, + pub parse_sess: &'a ParseSess, pub ecfg: expand::ExpansionConfig<'a>, pub root_path: PathBuf, pub resolver: &'a mut dyn Resolver, @@ -901,7 +902,7 @@ pub struct ExtCtxt<'a> { } impl<'a> ExtCtxt<'a> { - pub fn new(parse_sess: &'a parse::ParseSess, + pub fn new(parse_sess: &'a ParseSess, ecfg: expand::ExpansionConfig<'a>, resolver: &'a mut dyn Resolver) -> ExtCtxt<'a> { @@ -935,7 +936,7 @@ impl<'a> ExtCtxt<'a> { parse::stream_to_parser(self.parse_sess, stream, MACRO_ARGUMENTS) } pub fn source_map(&self) -> &'a SourceMap { self.parse_sess.source_map() } - pub fn parse_sess(&self) -> &'a parse::ParseSess { self.parse_sess } + pub fn parse_sess(&self) -> &'a ParseSess { self.parse_sess } pub fn cfg(&self) -> &ast::CrateConfig { &self.parse_sess.config } pub fn call_site(&self) -> Span { self.current_expansion.id.expn_data().call_site diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 9fcd918cef1..9ef59778f07 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -10,11 +10,12 @@ use crate::ext::mbe::macro_rules::annotate_err_with_kind; use crate::ext::placeholders::{placeholder, PlaceholderExpander}; use crate::feature_gate::{self, Features, GateIssue, is_builtin_attr, emit_feature_err}; use crate::mut_visit::*; -use crate::parse::{DirectoryOwnership, PResult, ParseSess}; +use crate::parse::{DirectoryOwnership, PResult}; use crate::parse::token; use crate::parse::parser::Parser; use crate::print::pprust; use crate::ptr::P; +use crate::sess::ParseSess; use crate::symbol::{sym, Symbol}; use crate::tokenstream::{TokenStream, TokenTree}; use crate::visit::{self, Visitor}; diff --git a/src/libsyntax/ext/mbe/macro_check.rs b/src/libsyntax/ext/mbe/macro_check.rs index 97074f5cbe4..aabaff4e1c3 100644 --- a/src/libsyntax/ext/mbe/macro_check.rs +++ b/src/libsyntax/ext/mbe/macro_check.rs @@ -109,7 +109,7 @@ use crate::early_buffered_lints::BufferedEarlyLintId; use crate::ext::mbe::{KleeneToken, TokenTree}; use crate::parse::token::TokenKind; use crate::parse::token::{DelimToken, Token}; -use crate::parse::ParseSess; +use crate::sess::ParseSess; use crate::symbol::{kw, sym}; use rustc_data_structures::fx::FxHashMap; diff --git a/src/libsyntax/ext/mbe/macro_parser.rs b/src/libsyntax/ext/mbe/macro_parser.rs index 0cb5eff1ef2..ff382c316ff 100644 --- a/src/libsyntax/ext/mbe/macro_parser.rs +++ b/src/libsyntax/ext/mbe/macro_parser.rs @@ -76,10 +76,11 @@ use TokenTreeOrTokenTreeSlice::*; use crate::ast::{Ident, Name}; use crate::ext::mbe::{self, TokenTree}; -use crate::parse::{Directory, ParseSess, PResult}; +use crate::parse::{Directory, PResult}; use crate::parse::parser::{Parser, PathStyle}; use crate::parse::token::{self, DocComment, Nonterminal, Token}; use crate::print::pprust; +use crate::sess::ParseSess; use crate::symbol::{kw, sym, Symbol}; use crate::tokenstream::{DelimSpan, TokenStream}; diff --git a/src/libsyntax/ext/mbe/macro_rules.rs b/src/libsyntax/ext/mbe/macro_rules.rs index e4fc269d147..b4223298422 100644 --- a/src/libsyntax/ext/mbe/macro_rules.rs +++ b/src/libsyntax/ext/mbe/macro_rules.rs @@ -14,8 +14,9 @@ use crate::feature_gate::Features; use crate::parse::parser::Parser; use crate::parse::token::TokenKind::*; use crate::parse::token::{self, NtTT, Token}; -use crate::parse::{Directory, ParseSess}; +use crate::parse::Directory; use crate::print::pprust; +use crate::sess::ParseSess; use crate::symbol::{kw, sym, Symbol}; use crate::tokenstream::{DelimSpan, TokenStream, TokenTree}; diff --git a/src/libsyntax/ext/mbe/quoted.rs b/src/libsyntax/ext/mbe/quoted.rs index 8cb85bdef76..3cec4bc60e7 100644 --- a/src/libsyntax/ext/mbe/quoted.rs +++ b/src/libsyntax/ext/mbe/quoted.rs @@ -2,8 +2,8 @@ use crate::ast; use crate::ext::mbe::macro_parser; use crate::ext::mbe::{TokenTree, KleeneOp, KleeneToken, SequenceRepetition, Delimited}; use crate::parse::token::{self, Token}; -use crate::parse::ParseSess; use crate::print::pprust; +use crate::sess::ParseSess; use crate::symbol::kw; use crate::tokenstream; diff --git a/src/libsyntax/ext/proc_macro_server.rs b/src/libsyntax/ext/proc_macro_server.rs index 08142ba6c58..300523c1b0a 100644 --- a/src/libsyntax/ext/proc_macro_server.rs +++ b/src/libsyntax/ext/proc_macro_server.rs @@ -1,8 +1,9 @@ use crate::ast; use crate::ext::base::ExtCtxt; -use crate::parse::{self, token, ParseSess}; +use crate::parse::{self, token}; use crate::parse::lexer::comments; use crate::print::pprust; +use crate::sess::ParseSess; use crate::tokenstream::{self, DelimSpan, IsJoint::*, TokenStream, TreeAndJoint}; use errors::Diagnostic; diff --git a/src/libsyntax/feature_gate/builtin_attrs.rs b/src/libsyntax/feature_gate/builtin_attrs.rs index ab1620b9524..043a2ffb5a4 100644 --- a/src/libsyntax/feature_gate/builtin_attrs.rs +++ b/src/libsyntax/feature_gate/builtin_attrs.rs @@ -9,8 +9,8 @@ use super::active::Features; use crate::ast; use crate::attr::AttributeTemplate; +use crate::sess::ParseSess; use crate::symbol::{Symbol, sym}; -use crate::parse::ParseSess; use syntax_pos::Span; use rustc_data_structures::fx::FxHashMap; diff --git a/src/libsyntax/feature_gate/check.rs b/src/libsyntax/feature_gate/check.rs index 2f6d98213e5..700ce26171a 100644 --- a/src/libsyntax/feature_gate/check.rs +++ b/src/libsyntax/feature_gate/check.rs @@ -11,7 +11,8 @@ use crate::attr::{self, check_builtin_attribute}; use crate::source_map::Spanned; use crate::edition::{ALL_EDITIONS, Edition}; use crate::visit::{self, FnKind, Visitor}; -use crate::parse::{token, ParseSess}; +use crate::parse::token; +use crate::sess::ParseSess; use crate::symbol::{Symbol, sym}; use crate::tokenstream::TokenTree; diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 09a47795a82..fa75f5624f8 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -147,6 +147,7 @@ pub mod ptr; pub mod show_span; pub use syntax_pos::edition; pub use syntax_pos::symbol; +pub mod sess; pub mod tokenstream; pub mod visit; diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index ac3feadce3a..e6dc9a4c134 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -1,5 +1,5 @@ -use crate::parse::ParseSess; use crate::parse::token::{self, Token, TokenKind}; +use crate::sess::ParseSess; use crate::symbol::{sym, Symbol}; use crate::parse::unescape_error_reporting::{emit_unescape_error, push_escaped_char}; diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 53ba9b20690..cb90caab77a 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -5,6 +5,7 @@ use crate::parse::parser::{Parser, emit_unclosed_delims}; use crate::parse::token::{Nonterminal, TokenKind}; use crate::tokenstream::{self, TokenStream, TokenTree}; use crate::print::pprust; +use crate::sess::ParseSess; use errors::{FatalError, Level, Diagnostic, DiagnosticBuilder}; #[cfg(target_arch = "x86_64")] @@ -26,8 +27,6 @@ pub mod parser; pub mod attr; pub mod lexer; pub mod token; -mod sess; -pub use sess::ParseSess; crate mod classify; crate mod diagnostics; diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index a3ac6d0c81f..86383761484 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -15,12 +15,13 @@ use crate::ast::{ self, DUMMY_NODE_ID, AttrStyle, Attribute, CrateSugar, Ident, IsAsync, MacDelimiter, Mutability, StrStyle, Visibility, VisibilityKind, Unsafety, }; -use crate::parse::{ParseSess, PResult, Directory, DirectoryOwnership, SeqSep}; +use crate::parse::{PResult, Directory, DirectoryOwnership, SeqSep}; use crate::parse::lexer::UnmatchedBrace; use crate::parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration}; use crate::parse::token::{self, Token, TokenKind, DelimToken}; use crate::print::pprust; use crate::ptr::P; +use crate::sess::ParseSess; use crate::source_map::respan; use crate::symbol::{kw, sym, Symbol}; use crate::tokenstream::{self, DelimSpan, TokenTree, TokenStream, TreeAndJoint}; diff --git a/src/libsyntax/parse/sess.rs b/src/libsyntax/parse/sess.rs deleted file mode 100644 index e49d3954f8e..00000000000 --- a/src/libsyntax/parse/sess.rs +++ /dev/null @@ -1,124 +0,0 @@ -//! Contains `ParseSess` which holds state living beyond what one `Parser` might. -//! It also serves as an input to the parser itself. - -use crate::ast::{CrateConfig, NodeId}; -use crate::early_buffered_lints::{BufferedEarlyLint, BufferedEarlyLintId}; -use crate::source_map::{SourceMap, FilePathMapping}; -use crate::feature_gate::UnstableFeatures; - -use errors::{Applicability, Handler, ColorConfig, DiagnosticBuilder}; -use rustc_data_structures::fx::{FxHashSet, FxHashMap}; -use rustc_data_structures::sync::{Lrc, Lock, Once}; -use syntax_pos::{Symbol, Span, MultiSpan}; -use syntax_pos::edition::Edition; -use syntax_pos::hygiene::ExpnId; - -use std::path::PathBuf; -use std::str; - -/// Collected spans during parsing for places where a certain feature was -/// used and should be feature gated accordingly in `check_crate`. -#[derive(Default)] -crate struct GatedSpans { - /// Spans collected for gating `let_chains`, e.g. `if a && let b = c {}`. - crate let_chains: Lock>, - /// Spans collected for gating `async_closure`, e.g. `async || ..`. - crate async_closure: Lock>, - /// Spans collected for gating `yield e?` expressions (`generators` gate). - crate yields: Lock>, - /// Spans collected for gating `or_patterns`, e.g. `Some(Foo | Bar)`. - crate or_patterns: Lock>, - /// Spans collected for gating `const_extern_fn`, e.g. `const extern fn foo`. - crate const_extern_fn: Lock>, -} - -/// Info about a parsing session. -pub struct ParseSess { - pub span_diagnostic: Handler, - crate unstable_features: UnstableFeatures, - pub config: CrateConfig, - pub edition: Edition, - pub missing_fragment_specifiers: Lock>, - /// Places where raw identifiers were used. This is used for feature-gating raw identifiers. - pub raw_identifier_spans: Lock>, - /// Used to determine and report recursive module inclusions. - pub(super) included_mod_stack: Lock>, - source_map: Lrc, - pub buffered_lints: Lock>, - /// Contains the spans of block expressions that could have been incomplete based on the - /// operation token that followed it, but that the parser cannot identify without further - /// analysis. - pub ambiguous_block_expr_parse: Lock>, - pub injected_crate_name: Once, - crate gated_spans: GatedSpans, -} - -impl ParseSess { - pub fn new(file_path_mapping: FilePathMapping) -> Self { - let cm = Lrc::new(SourceMap::new(file_path_mapping)); - let handler = Handler::with_tty_emitter( - ColorConfig::Auto, - true, - None, - Some(cm.clone()), - ); - ParseSess::with_span_handler(handler, cm) - } - - pub fn with_span_handler(handler: Handler, source_map: Lrc) -> Self { - Self { - span_diagnostic: handler, - unstable_features: UnstableFeatures::from_environment(), - config: FxHashSet::default(), - edition: ExpnId::root().expn_data().edition, - missing_fragment_specifiers: Lock::new(FxHashSet::default()), - raw_identifier_spans: Lock::new(Vec::new()), - included_mod_stack: Lock::new(vec![]), - source_map, - buffered_lints: Lock::new(vec![]), - ambiguous_block_expr_parse: Lock::new(FxHashMap::default()), - injected_crate_name: Once::new(), - gated_spans: GatedSpans::default(), - } - } - - #[inline] - pub fn source_map(&self) -> &SourceMap { - &self.source_map - } - - pub fn buffer_lint( - &self, - lint_id: BufferedEarlyLintId, - span: impl Into, - id: NodeId, - msg: &str, - ) { - self.buffered_lints.with_lock(|buffered_lints| { - buffered_lints.push(BufferedEarlyLint{ - span: span.into(), - id, - msg: msg.into(), - lint_id, - }); - }); - } - - /// Extend an error with a suggestion to wrap an expression with parentheses to allow the - /// parser to continue parsing the following operation as part of the same expression. - pub fn expr_parentheses_needed( - &self, - err: &mut DiagnosticBuilder<'_>, - span: Span, - alt_snippet: Option, - ) { - if let Some(snippet) = self.source_map().span_to_snippet(span).ok().or(alt_snippet) { - err.span_suggestion( - span, - "parentheses are required to parse this as an expression", - format!("({})", snippet), - Applicability::MachineApplicable, - ); - } - } -} diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 68dd90b54ab..136fc355f89 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -6,10 +6,11 @@ use crate::attr; use crate::source_map::{self, SourceMap, Spanned}; use crate::parse::token::{self, BinOpToken, DelimToken, Nonterminal, Token, TokenKind}; use crate::parse::lexer::comments; -use crate::parse::{self, ParseSess}; +use crate::parse; use crate::print::pp::{self, Breaks}; use crate::print::pp::Breaks::{Consistent, Inconsistent}; use crate::ptr::P; +use crate::sess::ParseSess; use crate::symbol::{kw, sym}; use crate::tokenstream::{self, TokenStream, TokenTree}; diff --git a/src/libsyntax/sess.rs b/src/libsyntax/sess.rs new file mode 100644 index 00000000000..e49d3954f8e --- /dev/null +++ b/src/libsyntax/sess.rs @@ -0,0 +1,124 @@ +//! Contains `ParseSess` which holds state living beyond what one `Parser` might. +//! It also serves as an input to the parser itself. + +use crate::ast::{CrateConfig, NodeId}; +use crate::early_buffered_lints::{BufferedEarlyLint, BufferedEarlyLintId}; +use crate::source_map::{SourceMap, FilePathMapping}; +use crate::feature_gate::UnstableFeatures; + +use errors::{Applicability, Handler, ColorConfig, DiagnosticBuilder}; +use rustc_data_structures::fx::{FxHashSet, FxHashMap}; +use rustc_data_structures::sync::{Lrc, Lock, Once}; +use syntax_pos::{Symbol, Span, MultiSpan}; +use syntax_pos::edition::Edition; +use syntax_pos::hygiene::ExpnId; + +use std::path::PathBuf; +use std::str; + +/// Collected spans during parsing for places where a certain feature was +/// used and should be feature gated accordingly in `check_crate`. +#[derive(Default)] +crate struct GatedSpans { + /// Spans collected for gating `let_chains`, e.g. `if a && let b = c {}`. + crate let_chains: Lock>, + /// Spans collected for gating `async_closure`, e.g. `async || ..`. + crate async_closure: Lock>, + /// Spans collected for gating `yield e?` expressions (`generators` gate). + crate yields: Lock>, + /// Spans collected for gating `or_patterns`, e.g. `Some(Foo | Bar)`. + crate or_patterns: Lock>, + /// Spans collected for gating `const_extern_fn`, e.g. `const extern fn foo`. + crate const_extern_fn: Lock>, +} + +/// Info about a parsing session. +pub struct ParseSess { + pub span_diagnostic: Handler, + crate unstable_features: UnstableFeatures, + pub config: CrateConfig, + pub edition: Edition, + pub missing_fragment_specifiers: Lock>, + /// Places where raw identifiers were used. This is used for feature-gating raw identifiers. + pub raw_identifier_spans: Lock>, + /// Used to determine and report recursive module inclusions. + pub(super) included_mod_stack: Lock>, + source_map: Lrc, + pub buffered_lints: Lock>, + /// Contains the spans of block expressions that could have been incomplete based on the + /// operation token that followed it, but that the parser cannot identify without further + /// analysis. + pub ambiguous_block_expr_parse: Lock>, + pub injected_crate_name: Once, + crate gated_spans: GatedSpans, +} + +impl ParseSess { + pub fn new(file_path_mapping: FilePathMapping) -> Self { + let cm = Lrc::new(SourceMap::new(file_path_mapping)); + let handler = Handler::with_tty_emitter( + ColorConfig::Auto, + true, + None, + Some(cm.clone()), + ); + ParseSess::with_span_handler(handler, cm) + } + + pub fn with_span_handler(handler: Handler, source_map: Lrc) -> Self { + Self { + span_diagnostic: handler, + unstable_features: UnstableFeatures::from_environment(), + config: FxHashSet::default(), + edition: ExpnId::root().expn_data().edition, + missing_fragment_specifiers: Lock::new(FxHashSet::default()), + raw_identifier_spans: Lock::new(Vec::new()), + included_mod_stack: Lock::new(vec![]), + source_map, + buffered_lints: Lock::new(vec![]), + ambiguous_block_expr_parse: Lock::new(FxHashMap::default()), + injected_crate_name: Once::new(), + gated_spans: GatedSpans::default(), + } + } + + #[inline] + pub fn source_map(&self) -> &SourceMap { + &self.source_map + } + + pub fn buffer_lint( + &self, + lint_id: BufferedEarlyLintId, + span: impl Into, + id: NodeId, + msg: &str, + ) { + self.buffered_lints.with_lock(|buffered_lints| { + buffered_lints.push(BufferedEarlyLint{ + span: span.into(), + id, + msg: msg.into(), + lint_id, + }); + }); + } + + /// Extend an error with a suggestion to wrap an expression with parentheses to allow the + /// parser to continue parsing the following operation as part of the same expression. + pub fn expr_parentheses_needed( + &self, + err: &mut DiagnosticBuilder<'_>, + span: Span, + alt_snippet: Option, + ) { + if let Some(snippet) = self.source_map().span_to_snippet(span).ok().or(alt_snippet) { + err.span_suggestion( + span, + "parentheses are required to parse this as an expression", + format!("({})", snippet), + Applicability::MachineApplicable, + ); + } + } +} diff --git a/src/libsyntax/tests.rs b/src/libsyntax/tests.rs index f510ac9273d..fbcf368ccb7 100644 --- a/src/libsyntax/tests.rs +++ b/src/libsyntax/tests.rs @@ -1,7 +1,8 @@ use crate::{ast, panictry}; -use crate::parse::{ParseSess, PResult, source_file_to_stream}; +use crate::parse::{PResult, source_file_to_stream}; use crate::parse::new_parser_from_source_str; use crate::parse::parser::Parser; +use crate::sess::ParseSess; use crate::source_map::{SourceMap, FilePathMapping}; use crate::tokenstream::TokenStream; use crate::with_default_globals; diff --git a/src/libsyntax_ext/cmdline_attrs.rs b/src/libsyntax_ext/cmdline_attrs.rs index 203c4a83489..2c3159739e2 100644 --- a/src/libsyntax_ext/cmdline_attrs.rs +++ b/src/libsyntax_ext/cmdline_attrs.rs @@ -3,7 +3,8 @@ use syntax::ast::{self, AttrItem, AttrStyle}; use syntax::attr::mk_attr; use syntax::panictry; -use syntax::parse::{self, token, ParseSess}; +use syntax::parse::{self, token}; +use syntax::sess::ParseSess; use syntax_pos::FileName; pub fn inject(mut krate: ast::Crate, parse_sess: &ParseSess, attrs: &[String]) -> ast::Crate { diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index abdcb6c8e3d..9c3ec06d59a 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -190,8 +190,8 @@ use syntax::ext::base::{Annotatable, ExtCtxt, SpecialDerives}; use syntax::source_map::respan; use syntax::util::map_in_place::MapInPlace; use syntax::ptr::P; +use syntax::sess::ParseSess; use syntax::symbol::{Symbol, kw, sym}; -use syntax::parse::ParseSess; use syntax_pos::{Span}; use ty::{LifetimeBounds, Path, Ptr, PtrTy, Self_, Ty}; diff --git a/src/libsyntax_ext/proc_macro_harness.rs b/src/libsyntax_ext/proc_macro_harness.rs index 1d48e8231b4..1b7068818b0 100644 --- a/src/libsyntax_ext/proc_macro_harness.rs +++ b/src/libsyntax_ext/proc_macro_harness.rs @@ -6,9 +6,9 @@ use syntax::attr; use syntax::ext::base::ExtCtxt; use syntax::ext::expand::{AstFragment, ExpansionConfig}; use syntax::ext::proc_macro::is_proc_macro_attr; -use syntax::parse::ParseSess; use syntax::print::pprust; use syntax::ptr::P; +use syntax::sess::ParseSess; use syntax::symbol::{kw, sym}; use syntax::visit::{self, Visitor}; use syntax_pos::{Span, DUMMY_SP}; diff --git a/src/libsyntax_ext/standard_library_imports.rs b/src/libsyntax_ext/standard_library_imports.rs index c577b1e33cf..4f17acf2d0f 100644 --- a/src/libsyntax_ext/standard_library_imports.rs +++ b/src/libsyntax_ext/standard_library_imports.rs @@ -3,8 +3,8 @@ use syntax::edition::Edition; use syntax::ext::expand::ExpansionConfig; use syntax::ext::hygiene::AstPass; use syntax::ext::base::{ExtCtxt, Resolver}; -use syntax::parse::ParseSess; use syntax::ptr::P; +use syntax::sess::ParseSess; use syntax::symbol::{Ident, Symbol, kw, sym}; use syntax_pos::DUMMY_SP; diff --git a/src/libsyntax_ext/test_harness.rs b/src/libsyntax_ext/test_harness.rs index f79ad1419e0..0bb279c0cb0 100644 --- a/src/libsyntax_ext/test_harness.rs +++ b/src/libsyntax_ext/test_harness.rs @@ -10,8 +10,8 @@ use syntax::ext::base::{ExtCtxt, Resolver}; use syntax::ext::expand::{AstFragment, ExpansionConfig}; use syntax::feature_gate::Features; use syntax::mut_visit::{*, ExpectOne}; -use syntax::parse::ParseSess; use syntax::ptr::P; +use syntax::sess::ParseSess; use syntax::source_map::respan; use syntax::symbol::{sym, Symbol}; use syntax_pos::{Span, DUMMY_SP}; diff --git a/src/test/ui-fulldeps/ast_stmt_expr_attr.rs b/src/test/ui-fulldeps/ast_stmt_expr_attr.rs index 6c5f539b871..5479119d812 100644 --- a/src/test/ui-fulldeps/ast_stmt_expr_attr.rs +++ b/src/test/ui-fulldeps/ast_stmt_expr_attr.rs @@ -10,9 +10,10 @@ extern crate syntax; use syntax::ast::*; use syntax::attr::*; use syntax::ast; +use syntax::sess::ParseSess; use syntax::source_map::{FilePathMapping, FileName}; use syntax::parse; -use syntax::parse::{ParseSess, PResult}; +use syntax::parse::PResult; use syntax::parse::new_parser_from_source_str; use syntax::parse::parser::Parser; use syntax::parse::token; diff --git a/src/test/ui-fulldeps/mod_dir_path_canonicalized.rs b/src/test/ui-fulldeps/mod_dir_path_canonicalized.rs index 8631bcca6d2..ac97ec70be2 100644 --- a/src/test/ui-fulldeps/mod_dir_path_canonicalized.rs +++ b/src/test/ui-fulldeps/mod_dir_path_canonicalized.rs @@ -7,8 +7,9 @@ extern crate syntax; use std::path::Path; +use syntax::sess::ParseSess; use syntax::source_map::FilePathMapping; -use syntax::parse::{self, ParseSess}; +use syntax::parse; #[path = "mod_dir_simple/test.rs"] mod gravy; diff --git a/src/test/ui-fulldeps/pprust-expr-roundtrip.rs b/src/test/ui-fulldeps/pprust-expr-roundtrip.rs index d4aff735907..932a173bc67 100644 --- a/src/test/ui-fulldeps/pprust-expr-roundtrip.rs +++ b/src/test/ui-fulldeps/pprust-expr-roundtrip.rs @@ -24,14 +24,14 @@ extern crate syntax; use rustc_data_structures::thin_vec::ThinVec; use syntax::ast::*; +use syntax::sess::ParseSess; use syntax::source_map::{Spanned, DUMMY_SP, FileName}; use syntax::source_map::FilePathMapping; use syntax::mut_visit::{self, MutVisitor, visit_clobber}; -use syntax::parse::{self, ParseSess}; +use syntax::parse; use syntax::print::pprust; use syntax::ptr::P; - fn parse_expr(ps: &ParseSess, src: &str) -> Option> { let src_as_string = src.to_string(); -- cgit 1.4.1-3-g733a5 From fe819a074c748fd3d11fcc0be8164645a7cd58db Mon Sep 17 00:00:00 2001 From: wangxiangqing Date: Sun, 13 Oct 2019 12:59:23 +0800 Subject: Collect occurrences of for mismatched braces diagnostic Change-Id: I20ba0b62308370ee961141fa1aefc4b9c9f0cb3a --- src/libsyntax/parse/lexer/tokentrees.rs | 2 +- src/test/ui/parser/mismatched-delim-brace-empty-block.rs | 4 +++- .../ui/parser/mismatched-delim-brace-empty-block.stderr | 15 +++++++++------ 3 files changed, 13 insertions(+), 8 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/lexer/tokentrees.rs b/src/libsyntax/parse/lexer/tokentrees.rs index b088d160b92..b4dd23c9f9b 100644 --- a/src/libsyntax/parse/lexer/tokentrees.rs +++ b/src/libsyntax/parse/lexer/tokentrees.rs @@ -126,7 +126,7 @@ impl<'a> TokenTreesReader<'a> { let (open_brace, open_brace_span) = self.open_braces.pop().unwrap(); let close_brace_span = self.token.span; - if close_brace_span.lo() == open_brace_span.hi() { + if tts.is_empty() { let empty_block_span = open_brace_span.to(close_brace_span); self.last_delim_empty_block_spans.insert(delim, empty_block_span); } diff --git a/src/test/ui/parser/mismatched-delim-brace-empty-block.rs b/src/test/ui/parser/mismatched-delim-brace-empty-block.rs index bcc95c09e1e..0f5a2cb09ec 100644 --- a/src/test/ui/parser/mismatched-delim-brace-empty-block.rs +++ b/src/test/ui/parser/mismatched-delim-brace-empty-block.rs @@ -1,3 +1,5 @@ -fn main() {} +fn main() { + +} let _ = (); } //~ ERROR unexpected close delimiter diff --git a/src/test/ui/parser/mismatched-delim-brace-empty-block.stderr b/src/test/ui/parser/mismatched-delim-brace-empty-block.stderr index 82fe8930c32..5ae5fc91a4e 100644 --- a/src/test/ui/parser/mismatched-delim-brace-empty-block.stderr +++ b/src/test/ui/parser/mismatched-delim-brace-empty-block.stderr @@ -1,11 +1,14 @@ error: unexpected close delimiter: `}` - --> $DIR/mismatched-delim-brace-empty-block.rs:3:1 + --> $DIR/mismatched-delim-brace-empty-block.rs:5:1 | -LL | fn main() {} - | -- this block is empty, you might have not meant to close it -LL | let _ = (); -LL | } - | ^ unexpected close delimiter +LL | fn main() { + | ___________- +LL | | +LL | | } + | |_- this block is empty, you might have not meant to close it +LL | let _ = (); +LL | } + | ^ unexpected close delimiter error: aborting due to previous error -- cgit 1.4.1-3-g733a5 From 9dba03f6cd8b51db9423f1d2fc9c94acd72b6183 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 8 Oct 2019 07:39:29 +0200 Subject: move parse::attr -> parse::parser::attr --- src/libsyntax/parse/attr.rs | 330 ------------------------------------- src/libsyntax/parse/mod.rs | 1 - src/libsyntax/parse/parser.rs | 1 + src/libsyntax/parse/parser/attr.rs | 330 +++++++++++++++++++++++++++++++++++++ 4 files changed, 331 insertions(+), 331 deletions(-) delete mode 100644 src/libsyntax/parse/attr.rs create mode 100644 src/libsyntax/parse/parser/attr.rs (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/attr.rs deleted file mode 100644 index 0963efcfc8a..00000000000 --- a/src/libsyntax/parse/attr.rs +++ /dev/null @@ -1,330 +0,0 @@ -use crate::attr; -use crate::ast; -use crate::parse::{SeqSep, PResult}; -use crate::parse::token::{self, Nonterminal, DelimToken}; -use crate::parse::parser::{Parser, TokenType, PathStyle}; -use crate::tokenstream::{TokenStream, TokenTree}; -use crate::source_map::Span; - -use log::debug; -use smallvec::smallvec; - -#[derive(Debug)] -enum InnerAttributeParsePolicy<'a> { - Permitted, - NotPermitted { reason: &'a str, saw_doc_comment: bool, prev_attr_sp: Option }, -} - -const DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG: &str = "an inner attribute is not \ - permitted in this context"; - -impl<'a> Parser<'a> { - /// Parses attributes that appear before an item. - crate fn parse_outer_attributes(&mut self) -> PResult<'a, Vec> { - let mut attrs: Vec = Vec::new(); - let mut just_parsed_doc_comment = false; - loop { - debug!("parse_outer_attributes: self.token={:?}", self.token); - match self.token.kind { - token::Pound => { - let inner_error_reason = if just_parsed_doc_comment { - "an inner attribute is not permitted following an outer doc comment" - } else if !attrs.is_empty() { - "an inner attribute is not permitted following an outer attribute" - } else { - DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG - }; - let inner_parse_policy = - InnerAttributeParsePolicy::NotPermitted { - reason: inner_error_reason, - saw_doc_comment: just_parsed_doc_comment, - prev_attr_sp: attrs.last().and_then(|a| Some(a.span)) - }; - let attr = self.parse_attribute_with_inner_parse_policy(inner_parse_policy)?; - attrs.push(attr); - just_parsed_doc_comment = false; - } - token::DocComment(s) => { - let attr = attr::mk_sugared_doc_attr(s, self.token.span); - if attr.style != ast::AttrStyle::Outer { - let mut err = self.fatal("expected outer doc comment"); - err.note("inner doc comments like this (starting with \ - `//!` or `/*!`) can only appear before items"); - return Err(err); - } - attrs.push(attr); - self.bump(); - just_parsed_doc_comment = true; - } - _ => break, - } - } - Ok(attrs) - } - - /// Matches `attribute = # ! [ meta_item ]`. - /// - /// If `permit_inner` is `true`, then a leading `!` indicates an inner - /// attribute. - pub fn parse_attribute(&mut self, permit_inner: bool) -> PResult<'a, ast::Attribute> { - debug!("parse_attribute: permit_inner={:?} self.token={:?}", - permit_inner, - self.token); - let inner_parse_policy = if permit_inner { - InnerAttributeParsePolicy::Permitted - } else { - InnerAttributeParsePolicy::NotPermitted { - reason: DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG, - saw_doc_comment: false, - prev_attr_sp: None - } - }; - self.parse_attribute_with_inner_parse_policy(inner_parse_policy) - } - - /// The same as `parse_attribute`, except it takes in an `InnerAttributeParsePolicy` - /// that prescribes how to handle inner attributes. - fn parse_attribute_with_inner_parse_policy(&mut self, - inner_parse_policy: InnerAttributeParsePolicy<'_>) - -> PResult<'a, ast::Attribute> { - debug!("parse_attribute_with_inner_parse_policy: inner_parse_policy={:?} self.token={:?}", - inner_parse_policy, - self.token); - let (span, item, style) = match self.token.kind { - token::Pound => { - let lo = self.token.span; - self.bump(); - - if let InnerAttributeParsePolicy::Permitted = inner_parse_policy { - self.expected_tokens.push(TokenType::Token(token::Not)); - } - - let style = if self.token == token::Not { - self.bump(); - ast::AttrStyle::Inner - } else { - ast::AttrStyle::Outer - }; - - self.expect(&token::OpenDelim(token::Bracket))?; - let item = self.parse_attr_item()?; - self.expect(&token::CloseDelim(token::Bracket))?; - let hi = self.prev_span; - - let attr_sp = lo.to(hi); - - // Emit error if inner attribute is encountered and not permitted - if style == ast::AttrStyle::Inner { - if let InnerAttributeParsePolicy::NotPermitted { reason, - saw_doc_comment, prev_attr_sp } = inner_parse_policy { - let prev_attr_note = if saw_doc_comment { - "previous doc comment" - } else { - "previous outer attribute" - }; - - let mut diagnostic = self - .diagnostic() - .struct_span_err(attr_sp, reason); - - if let Some(prev_attr_sp) = prev_attr_sp { - diagnostic - .span_label(attr_sp, "not permitted following an outer attibute") - .span_label(prev_attr_sp, prev_attr_note); - } - - diagnostic - .note("inner attributes, like `#![no_std]`, annotate the item \ - enclosing them, and are usually found at the beginning of \ - source files. Outer attributes, like `#[test]`, annotate the \ - item following them.") - .emit() - } - } - - (attr_sp, item, style) - } - _ => { - let token_str = self.this_token_to_string(); - return Err(self.fatal(&format!("expected `#`, found `{}`", token_str))); - } - }; - - Ok(ast::Attribute { - item, - id: attr::mk_attr_id(), - style, - is_sugared_doc: false, - span, - }) - } - - /// Parses an inner part of an attribute (the path and following tokens). - /// The tokens must be either a delimited token stream, or empty token stream, - /// or the "legacy" key-value form. - /// PATH `(` TOKEN_STREAM `)` - /// PATH `[` TOKEN_STREAM `]` - /// PATH `{` TOKEN_STREAM `}` - /// PATH - /// PATH `=` UNSUFFIXED_LIT - /// The delimiters or `=` are still put into the resulting token stream. - pub fn parse_attr_item(&mut self) -> PResult<'a, ast::AttrItem> { - let item = match self.token.kind { - token::Interpolated(ref nt) => match **nt { - Nonterminal::NtMeta(ref item) => Some(item.clone()), - _ => None, - }, - _ => None, - }; - Ok(if let Some(item) = item { - self.bump(); - item - } else { - let path = self.parse_path(PathStyle::Mod)?; - let tokens = if self.check(&token::OpenDelim(DelimToken::Paren)) || - self.check(&token::OpenDelim(DelimToken::Bracket)) || - self.check(&token::OpenDelim(DelimToken::Brace)) { - self.parse_token_tree().into() - } else if self.eat(&token::Eq) { - let eq = TokenTree::token(token::Eq, self.prev_span); - let mut is_interpolated_expr = false; - if let token::Interpolated(nt) = &self.token.kind { - if let token::NtExpr(..) = **nt { - is_interpolated_expr = true; - } - } - let tokens = if is_interpolated_expr { - // We need to accept arbitrary interpolated expressions to continue - // supporting things like `doc = $expr` that work on stable. - // Non-literal interpolated expressions are rejected after expansion. - self.parse_token_tree().into() - } else { - self.parse_unsuffixed_lit()?.tokens() - }; - TokenStream::from_streams(smallvec![eq.into(), tokens]) - } else { - TokenStream::default() - }; - ast::AttrItem { path, tokens } - }) - } - - /// Parses attributes that appear after the opening of an item. These should - /// be preceded by an exclamation mark, but we accept and warn about one - /// terminated by a semicolon. - /// - /// Matches `inner_attrs*`. - crate fn parse_inner_attributes(&mut self) -> PResult<'a, Vec> { - let mut attrs: Vec = vec![]; - loop { - match self.token.kind { - token::Pound => { - // Don't even try to parse if it's not an inner attribute. - if !self.look_ahead(1, |t| t == &token::Not) { - break; - } - - let attr = self.parse_attribute(true)?; - assert_eq!(attr.style, ast::AttrStyle::Inner); - attrs.push(attr); - } - token::DocComment(s) => { - // We need to get the position of this token before we bump. - let attr = attr::mk_sugared_doc_attr(s, self.token.span); - if attr.style == ast::AttrStyle::Inner { - attrs.push(attr); - self.bump(); - } else { - break; - } - } - _ => break, - } - } - Ok(attrs) - } - - fn parse_unsuffixed_lit(&mut self) -> PResult<'a, ast::Lit> { - let lit = self.parse_lit()?; - debug!("checking if {:?} is unusuffixed", lit); - - if !lit.kind.is_unsuffixed() { - let msg = "suffixed literals are not allowed in attributes"; - self.diagnostic().struct_span_err(lit.span, msg) - .help("instead of using a suffixed literal \ - (1u8, 1.0f32, etc.), use an unsuffixed version \ - (1, 1.0, etc.).") - .emit() - } - - Ok(lit) - } - - /// Matches the following grammar (per RFC 1559). - /// - /// meta_item : PATH ( '=' UNSUFFIXED_LIT | '(' meta_item_inner? ')' )? ; - /// meta_item_inner : (meta_item | UNSUFFIXED_LIT) (',' meta_item_inner)? ; - pub fn parse_meta_item(&mut self) -> PResult<'a, ast::MetaItem> { - let nt_meta = match self.token.kind { - token::Interpolated(ref nt) => match **nt { - token::NtMeta(ref e) => Some(e.clone()), - _ => None, - }, - _ => None, - }; - - if let Some(item) = nt_meta { - return match item.meta(item.path.span) { - Some(meta) => { - self.bump(); - Ok(meta) - } - None => self.unexpected(), - } - } - - let lo = self.token.span; - let path = self.parse_path(PathStyle::Mod)?; - let kind = self.parse_meta_item_kind()?; - let span = lo.to(self.prev_span); - Ok(ast::MetaItem { path, kind, span }) - } - - crate fn parse_meta_item_kind(&mut self) -> PResult<'a, ast::MetaItemKind> { - Ok(if self.eat(&token::Eq) { - ast::MetaItemKind::NameValue(self.parse_unsuffixed_lit()?) - } else if self.eat(&token::OpenDelim(token::Paren)) { - ast::MetaItemKind::List(self.parse_meta_seq()?) - } else { - ast::MetaItemKind::Word - }) - } - - /// Matches `meta_item_inner : (meta_item | UNSUFFIXED_LIT) ;`. - fn parse_meta_item_inner(&mut self) -> PResult<'a, ast::NestedMetaItem> { - match self.parse_unsuffixed_lit() { - Ok(lit) => { - return Ok(ast::NestedMetaItem::Literal(lit)) - } - Err(ref mut err) => err.cancel(), - } - - match self.parse_meta_item() { - Ok(mi) => { - return Ok(ast::NestedMetaItem::MetaItem(mi)) - } - Err(ref mut err) => err.cancel(), - } - - let found = self.this_token_to_string(); - let msg = format!("expected unsuffixed literal or identifier, found `{}`", found); - Err(self.diagnostic().struct_span_err(self.token.span, &msg)) - } - - /// Matches `meta_seq = ( COMMASEP(meta_item_inner) )`. - fn parse_meta_seq(&mut self) -> PResult<'a, Vec> { - self.parse_seq_to_end(&token::CloseDelim(token::Paren), - SeqSep::trailing_allowed(token::Comma), - |p: &mut Parser<'a>| p.parse_meta_item_inner()) - } -} diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index cb90caab77a..6bcd9cd9b63 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -24,7 +24,6 @@ mod tests; #[macro_use] pub mod parser; -pub mod attr; pub mod lexer; pub mod token; diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 86383761484..b710fcff65b 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1,3 +1,4 @@ +mod attr; mod expr; mod pat; mod item; diff --git a/src/libsyntax/parse/parser/attr.rs b/src/libsyntax/parse/parser/attr.rs new file mode 100644 index 00000000000..0963efcfc8a --- /dev/null +++ b/src/libsyntax/parse/parser/attr.rs @@ -0,0 +1,330 @@ +use crate::attr; +use crate::ast; +use crate::parse::{SeqSep, PResult}; +use crate::parse::token::{self, Nonterminal, DelimToken}; +use crate::parse::parser::{Parser, TokenType, PathStyle}; +use crate::tokenstream::{TokenStream, TokenTree}; +use crate::source_map::Span; + +use log::debug; +use smallvec::smallvec; + +#[derive(Debug)] +enum InnerAttributeParsePolicy<'a> { + Permitted, + NotPermitted { reason: &'a str, saw_doc_comment: bool, prev_attr_sp: Option }, +} + +const DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG: &str = "an inner attribute is not \ + permitted in this context"; + +impl<'a> Parser<'a> { + /// Parses attributes that appear before an item. + crate fn parse_outer_attributes(&mut self) -> PResult<'a, Vec> { + let mut attrs: Vec = Vec::new(); + let mut just_parsed_doc_comment = false; + loop { + debug!("parse_outer_attributes: self.token={:?}", self.token); + match self.token.kind { + token::Pound => { + let inner_error_reason = if just_parsed_doc_comment { + "an inner attribute is not permitted following an outer doc comment" + } else if !attrs.is_empty() { + "an inner attribute is not permitted following an outer attribute" + } else { + DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG + }; + let inner_parse_policy = + InnerAttributeParsePolicy::NotPermitted { + reason: inner_error_reason, + saw_doc_comment: just_parsed_doc_comment, + prev_attr_sp: attrs.last().and_then(|a| Some(a.span)) + }; + let attr = self.parse_attribute_with_inner_parse_policy(inner_parse_policy)?; + attrs.push(attr); + just_parsed_doc_comment = false; + } + token::DocComment(s) => { + let attr = attr::mk_sugared_doc_attr(s, self.token.span); + if attr.style != ast::AttrStyle::Outer { + let mut err = self.fatal("expected outer doc comment"); + err.note("inner doc comments like this (starting with \ + `//!` or `/*!`) can only appear before items"); + return Err(err); + } + attrs.push(attr); + self.bump(); + just_parsed_doc_comment = true; + } + _ => break, + } + } + Ok(attrs) + } + + /// Matches `attribute = # ! [ meta_item ]`. + /// + /// If `permit_inner` is `true`, then a leading `!` indicates an inner + /// attribute. + pub fn parse_attribute(&mut self, permit_inner: bool) -> PResult<'a, ast::Attribute> { + debug!("parse_attribute: permit_inner={:?} self.token={:?}", + permit_inner, + self.token); + let inner_parse_policy = if permit_inner { + InnerAttributeParsePolicy::Permitted + } else { + InnerAttributeParsePolicy::NotPermitted { + reason: DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG, + saw_doc_comment: false, + prev_attr_sp: None + } + }; + self.parse_attribute_with_inner_parse_policy(inner_parse_policy) + } + + /// The same as `parse_attribute`, except it takes in an `InnerAttributeParsePolicy` + /// that prescribes how to handle inner attributes. + fn parse_attribute_with_inner_parse_policy(&mut self, + inner_parse_policy: InnerAttributeParsePolicy<'_>) + -> PResult<'a, ast::Attribute> { + debug!("parse_attribute_with_inner_parse_policy: inner_parse_policy={:?} self.token={:?}", + inner_parse_policy, + self.token); + let (span, item, style) = match self.token.kind { + token::Pound => { + let lo = self.token.span; + self.bump(); + + if let InnerAttributeParsePolicy::Permitted = inner_parse_policy { + self.expected_tokens.push(TokenType::Token(token::Not)); + } + + let style = if self.token == token::Not { + self.bump(); + ast::AttrStyle::Inner + } else { + ast::AttrStyle::Outer + }; + + self.expect(&token::OpenDelim(token::Bracket))?; + let item = self.parse_attr_item()?; + self.expect(&token::CloseDelim(token::Bracket))?; + let hi = self.prev_span; + + let attr_sp = lo.to(hi); + + // Emit error if inner attribute is encountered and not permitted + if style == ast::AttrStyle::Inner { + if let InnerAttributeParsePolicy::NotPermitted { reason, + saw_doc_comment, prev_attr_sp } = inner_parse_policy { + let prev_attr_note = if saw_doc_comment { + "previous doc comment" + } else { + "previous outer attribute" + }; + + let mut diagnostic = self + .diagnostic() + .struct_span_err(attr_sp, reason); + + if let Some(prev_attr_sp) = prev_attr_sp { + diagnostic + .span_label(attr_sp, "not permitted following an outer attibute") + .span_label(prev_attr_sp, prev_attr_note); + } + + diagnostic + .note("inner attributes, like `#![no_std]`, annotate the item \ + enclosing them, and are usually found at the beginning of \ + source files. Outer attributes, like `#[test]`, annotate the \ + item following them.") + .emit() + } + } + + (attr_sp, item, style) + } + _ => { + let token_str = self.this_token_to_string(); + return Err(self.fatal(&format!("expected `#`, found `{}`", token_str))); + } + }; + + Ok(ast::Attribute { + item, + id: attr::mk_attr_id(), + style, + is_sugared_doc: false, + span, + }) + } + + /// Parses an inner part of an attribute (the path and following tokens). + /// The tokens must be either a delimited token stream, or empty token stream, + /// or the "legacy" key-value form. + /// PATH `(` TOKEN_STREAM `)` + /// PATH `[` TOKEN_STREAM `]` + /// PATH `{` TOKEN_STREAM `}` + /// PATH + /// PATH `=` UNSUFFIXED_LIT + /// The delimiters or `=` are still put into the resulting token stream. + pub fn parse_attr_item(&mut self) -> PResult<'a, ast::AttrItem> { + let item = match self.token.kind { + token::Interpolated(ref nt) => match **nt { + Nonterminal::NtMeta(ref item) => Some(item.clone()), + _ => None, + }, + _ => None, + }; + Ok(if let Some(item) = item { + self.bump(); + item + } else { + let path = self.parse_path(PathStyle::Mod)?; + let tokens = if self.check(&token::OpenDelim(DelimToken::Paren)) || + self.check(&token::OpenDelim(DelimToken::Bracket)) || + self.check(&token::OpenDelim(DelimToken::Brace)) { + self.parse_token_tree().into() + } else if self.eat(&token::Eq) { + let eq = TokenTree::token(token::Eq, self.prev_span); + let mut is_interpolated_expr = false; + if let token::Interpolated(nt) = &self.token.kind { + if let token::NtExpr(..) = **nt { + is_interpolated_expr = true; + } + } + let tokens = if is_interpolated_expr { + // We need to accept arbitrary interpolated expressions to continue + // supporting things like `doc = $expr` that work on stable. + // Non-literal interpolated expressions are rejected after expansion. + self.parse_token_tree().into() + } else { + self.parse_unsuffixed_lit()?.tokens() + }; + TokenStream::from_streams(smallvec![eq.into(), tokens]) + } else { + TokenStream::default() + }; + ast::AttrItem { path, tokens } + }) + } + + /// Parses attributes that appear after the opening of an item. These should + /// be preceded by an exclamation mark, but we accept and warn about one + /// terminated by a semicolon. + /// + /// Matches `inner_attrs*`. + crate fn parse_inner_attributes(&mut self) -> PResult<'a, Vec> { + let mut attrs: Vec = vec![]; + loop { + match self.token.kind { + token::Pound => { + // Don't even try to parse if it's not an inner attribute. + if !self.look_ahead(1, |t| t == &token::Not) { + break; + } + + let attr = self.parse_attribute(true)?; + assert_eq!(attr.style, ast::AttrStyle::Inner); + attrs.push(attr); + } + token::DocComment(s) => { + // We need to get the position of this token before we bump. + let attr = attr::mk_sugared_doc_attr(s, self.token.span); + if attr.style == ast::AttrStyle::Inner { + attrs.push(attr); + self.bump(); + } else { + break; + } + } + _ => break, + } + } + Ok(attrs) + } + + fn parse_unsuffixed_lit(&mut self) -> PResult<'a, ast::Lit> { + let lit = self.parse_lit()?; + debug!("checking if {:?} is unusuffixed", lit); + + if !lit.kind.is_unsuffixed() { + let msg = "suffixed literals are not allowed in attributes"; + self.diagnostic().struct_span_err(lit.span, msg) + .help("instead of using a suffixed literal \ + (1u8, 1.0f32, etc.), use an unsuffixed version \ + (1, 1.0, etc.).") + .emit() + } + + Ok(lit) + } + + /// Matches the following grammar (per RFC 1559). + /// + /// meta_item : PATH ( '=' UNSUFFIXED_LIT | '(' meta_item_inner? ')' )? ; + /// meta_item_inner : (meta_item | UNSUFFIXED_LIT) (',' meta_item_inner)? ; + pub fn parse_meta_item(&mut self) -> PResult<'a, ast::MetaItem> { + let nt_meta = match self.token.kind { + token::Interpolated(ref nt) => match **nt { + token::NtMeta(ref e) => Some(e.clone()), + _ => None, + }, + _ => None, + }; + + if let Some(item) = nt_meta { + return match item.meta(item.path.span) { + Some(meta) => { + self.bump(); + Ok(meta) + } + None => self.unexpected(), + } + } + + let lo = self.token.span; + let path = self.parse_path(PathStyle::Mod)?; + let kind = self.parse_meta_item_kind()?; + let span = lo.to(self.prev_span); + Ok(ast::MetaItem { path, kind, span }) + } + + crate fn parse_meta_item_kind(&mut self) -> PResult<'a, ast::MetaItemKind> { + Ok(if self.eat(&token::Eq) { + ast::MetaItemKind::NameValue(self.parse_unsuffixed_lit()?) + } else if self.eat(&token::OpenDelim(token::Paren)) { + ast::MetaItemKind::List(self.parse_meta_seq()?) + } else { + ast::MetaItemKind::Word + }) + } + + /// Matches `meta_item_inner : (meta_item | UNSUFFIXED_LIT) ;`. + fn parse_meta_item_inner(&mut self) -> PResult<'a, ast::NestedMetaItem> { + match self.parse_unsuffixed_lit() { + Ok(lit) => { + return Ok(ast::NestedMetaItem::Literal(lit)) + } + Err(ref mut err) => err.cancel(), + } + + match self.parse_meta_item() { + Ok(mi) => { + return Ok(ast::NestedMetaItem::MetaItem(mi)) + } + Err(ref mut err) => err.cancel(), + } + + let found = self.this_token_to_string(); + let msg = format!("expected unsuffixed literal or identifier, found `{}`", found); + Err(self.diagnostic().struct_span_err(self.token.span, &msg)) + } + + /// Matches `meta_seq = ( COMMASEP(meta_item_inner) )`. + fn parse_meta_seq(&mut self) -> PResult<'a, Vec> { + self.parse_seq_to_end(&token::CloseDelim(token::Paren), + SeqSep::trailing_allowed(token::Comma), + |p: &mut Parser<'a>| p.parse_meta_item_inner()) + } +} -- cgit 1.4.1-3-g733a5 From 7d7969d065c438399cde2ebdcd411e5225a31b88 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 8 Oct 2019 09:06:07 +0200 Subject: syntax: extract parse_derive_paths --- src/libsyntax/attr/mod.rs | 18 +++--------------- src/libsyntax/ext/proc_macro.rs | 4 +--- src/libsyntax/parse/parser/path.rs | 17 ++++++++++++++++- 3 files changed, 20 insertions(+), 19 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/attr/mod.rs b/src/libsyntax/attr/mod.rs index d291e502c25..965d4597430 100644 --- a/src/libsyntax/attr/mod.rs +++ b/src/libsyntax/attr/mod.rs @@ -298,24 +298,12 @@ impl Attribute { Ok(result) } - pub fn parse_list<'a, T, F>(&self, sess: &'a ParseSess, mut f: F) -> PResult<'a, Vec> - where F: FnMut(&mut Parser<'a>) -> PResult<'a, T>, - { + pub fn parse_derive_paths<'a>(&self, sess: &'a ParseSess) -> PResult<'a, Vec> { if self.tokens.is_empty() { return Ok(Vec::new()); } - self.parse(sess, |parser| { - parser.expect(&token::OpenDelim(token::Paren))?; - let mut list = Vec::new(); - while !parser.eat(&token::CloseDelim(token::Paren)) { - list.push(f(parser)?); - if !parser.eat(&token::Comma) { - parser.expect(&token::CloseDelim(token::Paren))?; - break - } - } - Ok(list) - }) + + self.parse(sess, |p| p.parse_derive_paths()) } pub fn parse_meta<'a>(&self, sess: &'a ParseSess) -> PResult<'a, MetaItem> { diff --git a/src/libsyntax/ext/proc_macro.rs b/src/libsyntax/ext/proc_macro.rs index e17bbf79fd5..72062d2ffbf 100644 --- a/src/libsyntax/ext/proc_macro.rs +++ b/src/libsyntax/ext/proc_macro.rs @@ -4,7 +4,6 @@ use crate::errors::{Applicability, FatalError}; use crate::ext::base::{self, *}; use crate::ext::proc_macro_server; use crate::parse::{self, token}; -use crate::parse::parser::PathStyle; use crate::symbol::sym; use crate::tokenstream::{self, TokenStream}; use crate::visit::Visitor; @@ -205,8 +204,7 @@ crate fn collect_derives(cx: &mut ExtCtxt<'_>, attrs: &mut Vec) return false; } - match attr.parse_list(cx.parse_sess, - |parser| parser.parse_path_allowing_meta(PathStyle::Mod)) { + match attr.parse_derive_paths(cx.parse_sess) { Ok(traits) => { result.extend(traits); true diff --git a/src/libsyntax/parse/parser/path.rs b/src/libsyntax/parse/parser/path.rs index ca823991a2e..1f48cc75304 100644 --- a/src/libsyntax/parse/parser/path.rs +++ b/src/libsyntax/parse/parser/path.rs @@ -111,7 +111,7 @@ impl<'a> Parser<'a> { /// Like `parse_path`, but also supports parsing `Word` meta items into paths for /// backwards-compatibility. This is used when parsing derive macro paths in `#[derive]` /// attributes. - pub fn parse_path_allowing_meta(&mut self, style: PathStyle) -> PResult<'a, Path> { + fn parse_path_allowing_meta(&mut self, style: PathStyle) -> PResult<'a, Path> { let meta_ident = match self.token.kind { token::Interpolated(ref nt) => match **nt { token::NtMeta(ref item) => match item.tokens.is_empty() { @@ -129,6 +129,21 @@ impl<'a> Parser<'a> { self.parse_path(style) } + /// Parse a list of paths inside `#[derive(path_0, ..., path_n)]`. + crate fn parse_derive_paths(&mut self) -> PResult<'a, Vec> { + self.expect(&token::OpenDelim(token::Paren))?; + let mut list = Vec::new(); + while !self.eat(&token::CloseDelim(token::Paren)) { + let path = self.parse_path_allowing_meta(PathStyle::Mod)?; + list.push(path); + if !self.eat(&token::Comma) { + self.expect(&token::CloseDelim(token::Paren))?; + break + } + } + Ok(list) + } + crate fn parse_path_segments( &mut self, segments: &mut Vec, -- cgit 1.4.1-3-g733a5 From 41bfe94d404c69f0f2e7ebad7383940cf0ac1cb3 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 8 Oct 2019 09:14:07 +0200 Subject: syntax: extract parse_cfg_attr --- src/libsyntax/attr/mod.rs | 1 - src/libsyntax/config.rs | 21 +-------------------- src/libsyntax/parse/parser/attr.rs | 21 +++++++++++++++++++++ 3 files changed, 22 insertions(+), 21 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/attr/mod.rs b/src/libsyntax/attr/mod.rs index 965d4597430..9c1e0bcaa4a 100644 --- a/src/libsyntax/attr/mod.rs +++ b/src/libsyntax/attr/mod.rs @@ -302,7 +302,6 @@ impl Attribute { if self.tokens.is_empty() { return Ok(Vec::new()); } - self.parse(sess, |p| p.parse_derive_paths()) } diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index 2099d018b7b..ee5a4eeb3a3 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -10,7 +10,6 @@ use crate::attr; use crate::ast; use crate::edition::Edition; use crate::mut_visit::*; -use crate::parse::token; use crate::ptr::P; use crate::sess::ParseSess; use crate::symbol::sym; @@ -112,25 +111,7 @@ impl<'a> StripUnconfigured<'a> { return vec![]; } - let (cfg_predicate, expanded_attrs) = match attr.parse(self.sess, |parser| { - parser.expect(&token::OpenDelim(token::Paren))?; - - let cfg_predicate = parser.parse_meta_item()?; - parser.expect(&token::Comma)?; - - // Presumably, the majority of the time there will only be one attr. - let mut expanded_attrs = Vec::with_capacity(1); - - while !parser.check(&token::CloseDelim(token::Paren)) { - let lo = parser.token.span.lo(); - let item = parser.parse_attr_item()?; - expanded_attrs.push((item, parser.prev_span.with_lo(lo))); - parser.expect_one_of(&[token::Comma], &[token::CloseDelim(token::Paren)])?; - } - - parser.expect(&token::CloseDelim(token::Paren))?; - Ok((cfg_predicate, expanded_attrs)) - }) { + let (cfg_predicate, expanded_attrs) = match attr.parse(self.sess, |p| p.parse_cfg_attr()) { Ok(result) => result, Err(mut e) => { e.emit(); diff --git a/src/libsyntax/parse/parser/attr.rs b/src/libsyntax/parse/parser/attr.rs index 0963efcfc8a..07689df389c 100644 --- a/src/libsyntax/parse/parser/attr.rs +++ b/src/libsyntax/parse/parser/attr.rs @@ -260,6 +260,27 @@ impl<'a> Parser<'a> { Ok(lit) } + /// Parses `cfg_attr(pred, attr_item_list)` where `attr_item_list` is comma-delimited. + crate fn parse_cfg_attr(&mut self) -> PResult<'a, (ast::MetaItem, Vec<(ast::AttrItem, Span)>)> { + self.expect(&token::OpenDelim(token::Paren))?; + + let cfg_predicate = self.parse_meta_item()?; + self.expect(&token::Comma)?; + + // Presumably, the majority of the time there will only be one attr. + let mut expanded_attrs = Vec::with_capacity(1); + + while !self.check(&token::CloseDelim(token::Paren)) { + let lo = self.token.span.lo(); + let item = self.parse_attr_item()?; + expanded_attrs.push((item, self.prev_span.with_lo(lo))); + self.expect_one_of(&[token::Comma], &[token::CloseDelim(token::Paren)])?; + } + + self.expect(&token::CloseDelim(token::Paren))?; + Ok((cfg_predicate, expanded_attrs)) + } + /// Matches the following grammar (per RFC 1559). /// /// meta_item : PATH ( '=' UNSUFFIXED_LIT | '(' meta_item_inner? ')' )? ; -- cgit 1.4.1-3-g733a5 From 98017ca53a0c3ac6a10f60b47462bd3546baaaa1 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 8 Oct 2019 09:46:06 +0200 Subject: move diagnostics.rs into parser/ --- src/libsyntax/parse/diagnostics.rs | 1483 ----------------------------- src/libsyntax/parse/mod.rs | 1 - src/libsyntax/parse/parser.rs | 3 +- src/libsyntax/parse/parser/diagnostics.rs | 1483 +++++++++++++++++++++++++++++ src/libsyntax/parse/parser/expr.rs | 2 +- src/libsyntax/parse/parser/item.rs | 3 +- src/libsyntax/parse/parser/module.rs | 2 +- src/libsyntax/parse/parser/stmt.rs | 2 +- 8 files changed, 1490 insertions(+), 1489 deletions(-) delete mode 100644 src/libsyntax/parse/diagnostics.rs create mode 100644 src/libsyntax/parse/parser/diagnostics.rs (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/diagnostics.rs b/src/libsyntax/parse/diagnostics.rs deleted file mode 100644 index 943838d9dda..00000000000 --- a/src/libsyntax/parse/diagnostics.rs +++ /dev/null @@ -1,1483 +0,0 @@ -use crate::ast::{ - self, Param, BinOpKind, BindingMode, BlockCheckMode, Expr, ExprKind, Ident, Item, ItemKind, - Mutability, Pat, PatKind, PathSegment, QSelf, Ty, TyKind, -}; -use crate::parse::{SeqSep, PResult, Parser}; -use crate::parse::parser::{BlockMode, PathStyle, SemiColonMode, TokenType, TokenExpectType}; -use crate::parse::token::{self, TokenKind}; -use crate::print::pprust; -use crate::ptr::P; -use crate::symbol::{kw, sym}; -use crate::ThinVec; -use crate::util::parser::AssocOp; -use errors::{Applicability, DiagnosticBuilder, DiagnosticId, pluralise}; -use rustc_data_structures::fx::FxHashSet; -use syntax_pos::{Span, DUMMY_SP, MultiSpan, SpanSnippetError}; -use log::{debug, trace}; -use std::mem; - -const TURBOFISH: &'static str = "use `::<...>` instead of `<...>` to specify type arguments"; -/// Creates a placeholder argument. -crate fn dummy_arg(ident: Ident) -> Param { - let pat = P(Pat { - id: ast::DUMMY_NODE_ID, - kind: PatKind::Ident(BindingMode::ByValue(Mutability::Immutable), ident, None), - span: ident.span, - }); - let ty = Ty { - kind: TyKind::Err, - span: ident.span, - id: ast::DUMMY_NODE_ID - }; - Param { - attrs: ThinVec::default(), - id: ast::DUMMY_NODE_ID, - pat, - span: ident.span, - ty: P(ty), - is_placeholder: false, - } -} - -pub enum Error { - FileNotFoundForModule { - mod_name: String, - default_path: String, - secondary_path: String, - dir_path: String, - }, - DuplicatePaths { - mod_name: String, - default_path: String, - secondary_path: String, - }, - UselessDocComment, - InclusiveRangeWithNoEnd, -} - -impl Error { - fn span_err>( - self, - sp: S, - handler: &errors::Handler, - ) -> DiagnosticBuilder<'_> { - match self { - Error::FileNotFoundForModule { - ref mod_name, - ref default_path, - ref secondary_path, - ref dir_path, - } => { - let mut err = struct_span_err!( - handler, - sp, - E0583, - "file not found for module `{}`", - mod_name, - ); - err.help(&format!( - "name the file either {} or {} inside the directory \"{}\"", - default_path, - secondary_path, - dir_path, - )); - err - } - Error::DuplicatePaths { ref mod_name, ref default_path, ref secondary_path } => { - let mut err = struct_span_err!( - handler, - sp, - E0584, - "file for module `{}` found at both {} and {}", - mod_name, - default_path, - secondary_path, - ); - err.help("delete or rename one of them to remove the ambiguity"); - err - } - Error::UselessDocComment => { - let mut err = struct_span_err!( - handler, - sp, - E0585, - "found a documentation comment that doesn't document anything", - ); - err.help("doc comments must come before what they document, maybe a comment was \ - intended with `//`?"); - err - } - Error::InclusiveRangeWithNoEnd => { - let mut err = struct_span_err!( - handler, - sp, - E0586, - "inclusive range with no end", - ); - err.help("inclusive ranges must be bounded at the end (`..=b` or `a..=b`)"); - err - } - } - } -} - -pub trait RecoverQPath: Sized + 'static { - const PATH_STYLE: PathStyle = PathStyle::Expr; - fn to_ty(&self) -> Option>; - fn recovered(qself: Option, path: ast::Path) -> Self; -} - -impl RecoverQPath for Ty { - const PATH_STYLE: PathStyle = PathStyle::Type; - fn to_ty(&self) -> Option> { - Some(P(self.clone())) - } - fn recovered(qself: Option, path: ast::Path) -> Self { - Self { - span: path.span, - kind: TyKind::Path(qself, path), - id: ast::DUMMY_NODE_ID, - } - } -} - -impl RecoverQPath for Pat { - fn to_ty(&self) -> Option> { - self.to_ty() - } - fn recovered(qself: Option, path: ast::Path) -> Self { - Self { - span: path.span, - kind: PatKind::Path(qself, path), - id: ast::DUMMY_NODE_ID, - } - } -} - -impl RecoverQPath for Expr { - fn to_ty(&self) -> Option> { - self.to_ty() - } - fn recovered(qself: Option, path: ast::Path) -> Self { - Self { - span: path.span, - kind: ExprKind::Path(qself, path), - attrs: ThinVec::new(), - id: ast::DUMMY_NODE_ID, - } - } -} - -impl<'a> Parser<'a> { - pub fn fatal(&self, m: &str) -> DiagnosticBuilder<'a> { - self.span_fatal(self.token.span, m) - } - - pub fn span_fatal>(&self, sp: S, m: &str) -> DiagnosticBuilder<'a> { - self.sess.span_diagnostic.struct_span_fatal(sp, m) - } - - pub fn span_fatal_err>(&self, sp: S, err: Error) -> DiagnosticBuilder<'a> { - err.span_err(sp, self.diagnostic()) - } - - pub fn bug(&self, m: &str) -> ! { - self.sess.span_diagnostic.span_bug(self.token.span, m) - } - - pub fn span_err>(&self, sp: S, m: &str) { - self.sess.span_diagnostic.span_err(sp, m) - } - - crate fn struct_span_err>(&self, sp: S, m: &str) -> DiagnosticBuilder<'a> { - self.sess.span_diagnostic.struct_span_err(sp, m) - } - - crate fn span_bug>(&self, sp: S, m: &str) -> ! { - self.sess.span_diagnostic.span_bug(sp, m) - } - - crate fn diagnostic(&self) -> &'a errors::Handler { - &self.sess.span_diagnostic - } - - crate fn span_to_snippet(&self, span: Span) -> Result { - self.sess.source_map().span_to_snippet(span) - } - - crate fn expected_ident_found(&self) -> DiagnosticBuilder<'a> { - let mut err = self.struct_span_err( - self.token.span, - &format!("expected identifier, found {}", self.this_token_descr()), - ); - if let token::Ident(name, false) = self.token.kind { - if Ident::new(name, self.token.span).is_raw_guess() { - err.span_suggestion( - self.token.span, - "you can escape reserved keywords to use them as identifiers", - format!("r#{}", name), - Applicability::MaybeIncorrect, - ); - } - } - if let Some(token_descr) = self.token_descr() { - err.span_label(self.token.span, format!("expected identifier, found {}", token_descr)); - } else { - err.span_label(self.token.span, "expected identifier"); - if self.token == token::Comma && self.look_ahead(1, |t| t.is_ident()) { - err.span_suggestion( - self.token.span, - "remove this comma", - String::new(), - Applicability::MachineApplicable, - ); - } - } - err - } - - pub fn expected_one_of_not_found( - &mut self, - edible: &[TokenKind], - inedible: &[TokenKind], - ) -> PResult<'a, bool /* recovered */> { - fn tokens_to_string(tokens: &[TokenType]) -> String { - let mut i = tokens.iter(); - // This might be a sign we need a connect method on `Iterator`. - let b = i.next() - .map_or(String::new(), |t| t.to_string()); - i.enumerate().fold(b, |mut b, (i, a)| { - if tokens.len() > 2 && i == tokens.len() - 2 { - b.push_str(", or "); - } else if tokens.len() == 2 && i == tokens.len() - 2 { - b.push_str(" or "); - } else { - b.push_str(", "); - } - b.push_str(&a.to_string()); - b - }) - } - - let mut expected = edible.iter() - .map(|x| TokenType::Token(x.clone())) - .chain(inedible.iter().map(|x| TokenType::Token(x.clone()))) - .chain(self.expected_tokens.iter().cloned()) - .collect::>(); - expected.sort_by_cached_key(|x| x.to_string()); - expected.dedup(); - let expect = tokens_to_string(&expected[..]); - let actual = self.this_token_to_string(); - let (msg_exp, (label_sp, label_exp)) = if expected.len() > 1 { - let short_expect = if expected.len() > 6 { - format!("{} possible tokens", expected.len()) - } else { - expect.clone() - }; - (format!("expected one of {}, found `{}`", expect, actual), - (self.sess.source_map().next_point(self.prev_span), - format!("expected one of {} here", short_expect))) - } else if expected.is_empty() { - (format!("unexpected token: `{}`", actual), - (self.prev_span, "unexpected token after this".to_string())) - } else { - (format!("expected {}, found `{}`", expect, actual), - (self.sess.source_map().next_point(self.prev_span), - format!("expected {} here", expect))) - }; - self.last_unexpected_token_span = Some(self.token.span); - let mut err = self.fatal(&msg_exp); - if self.token.is_ident_named(sym::and) { - err.span_suggestion_short( - self.token.span, - "use `&&` instead of `and` for the boolean operator", - "&&".to_string(), - Applicability::MaybeIncorrect, - ); - } - if self.token.is_ident_named(sym::or) { - err.span_suggestion_short( - self.token.span, - "use `||` instead of `or` for the boolean operator", - "||".to_string(), - Applicability::MaybeIncorrect, - ); - } - let sp = if self.token == token::Eof { - // This is EOF; don't want to point at the following char, but rather the last token. - self.prev_span - } else { - label_sp - }; - match self.recover_closing_delimiter(&expected.iter().filter_map(|tt| match tt { - TokenType::Token(t) => Some(t.clone()), - _ => None, - }).collect::>(), err) { - Err(e) => err = e, - Ok(recovered) => { - return Ok(recovered); - } - } - - let is_semi_suggestable = expected.iter().any(|t| match t { - TokenType::Token(token::Semi) => true, // We expect a `;` here. - _ => false, - }) && ( // A `;` would be expected before the current keyword. - self.token.is_keyword(kw::Break) || - self.token.is_keyword(kw::Continue) || - self.token.is_keyword(kw::For) || - self.token.is_keyword(kw::If) || - self.token.is_keyword(kw::Let) || - self.token.is_keyword(kw::Loop) || - self.token.is_keyword(kw::Match) || - self.token.is_keyword(kw::Return) || - self.token.is_keyword(kw::While) - ); - let sm = self.sess.source_map(); - match (sm.lookup_line(self.token.span.lo()), sm.lookup_line(sp.lo())) { - (Ok(ref a), Ok(ref b)) if a.line != b.line && is_semi_suggestable => { - // The spans are in different lines, expected `;` and found `let` or `return`. - // High likelihood that it is only a missing `;`. - err.span_suggestion_short( - label_sp, - "a semicolon may be missing here", - ";".to_string(), - Applicability::MaybeIncorrect, - ); - err.emit(); - return Ok(true); - } - (Ok(ref a), Ok(ref b)) if a.line == b.line => { - // When the spans are in the same line, it means that the only content between - // them is whitespace, point at the found token in that case: - // - // X | () => { syntax error }; - // | ^^^^^ expected one of 8 possible tokens here - // - // instead of having: - // - // X | () => { syntax error }; - // | -^^^^^ unexpected token - // | | - // | expected one of 8 possible tokens here - err.span_label(self.token.span, label_exp); - } - _ if self.prev_span == syntax_pos::DUMMY_SP => { - // Account for macro context where the previous span might not be - // available to avoid incorrect output (#54841). - err.span_label(self.token.span, "unexpected token"); - } - _ => { - err.span_label(sp, label_exp); - err.span_label(self.token.span, "unexpected token"); - } - } - self.maybe_annotate_with_ascription(&mut err, false); - Err(err) - } - - pub fn maybe_annotate_with_ascription( - &self, - err: &mut DiagnosticBuilder<'_>, - maybe_expected_semicolon: bool, - ) { - if let Some((sp, likely_path)) = self.last_type_ascription { - let sm = self.sess.source_map(); - let next_pos = sm.lookup_char_pos(self.token.span.lo()); - let op_pos = sm.lookup_char_pos(sp.hi()); - - let allow_unstable = self.sess.unstable_features.is_nightly_build(); - - if likely_path { - err.span_suggestion( - sp, - "maybe write a path separator here", - "::".to_string(), - if allow_unstable { - Applicability::MaybeIncorrect - } else { - Applicability::MachineApplicable - }, - ); - } else if op_pos.line != next_pos.line && maybe_expected_semicolon { - err.span_suggestion( - sp, - "try using a semicolon", - ";".to_string(), - Applicability::MaybeIncorrect, - ); - } else if allow_unstable { - err.span_label(sp, "tried to parse a type due to this type ascription"); - } else { - err.span_label(sp, "tried to parse a type due to this"); - } - if allow_unstable { - // Give extra information about type ascription only if it's a nightly compiler. - err.note("`#![feature(type_ascription)]` lets you annotate an expression with a \ - type: `: `"); - err.note("for more information, see \ - https://github.com/rust-lang/rust/issues/23416"); - } - } - } - - /// Eats and discards tokens until one of `kets` is encountered. Respects token trees, - /// passes through any errors encountered. Used for error recovery. - crate fn eat_to_tokens(&mut self, kets: &[&TokenKind]) { - if let Err(ref mut err) = self.parse_seq_to_before_tokens( - kets, - SeqSep::none(), - TokenExpectType::Expect, - |p| Ok(p.parse_token_tree()), - ) { - err.cancel(); - } - } - - /// This function checks if there are trailing angle brackets and produces - /// a diagnostic to suggest removing them. - /// - /// ```ignore (diagnostic) - /// let _ = vec![1, 2, 3].into_iter().collect::>>>(); - /// ^^ help: remove extra angle brackets - /// ``` - crate fn check_trailing_angle_brackets(&mut self, segment: &PathSegment, end: TokenKind) { - // This function is intended to be invoked after parsing a path segment where there are two - // cases: - // - // 1. A specific token is expected after the path segment. - // eg. `x.foo(`, `x.foo::(` (parenthesis - method call), - // `Foo::`, or `Foo::::` (mod sep - continued path). - // 2. No specific token is expected after the path segment. - // eg. `x.foo` (field access) - // - // This function is called after parsing `.foo` and before parsing the token `end` (if - // present). This includes any angle bracket arguments, such as `.foo::` or - // `Foo::`. - - // We only care about trailing angle brackets if we previously parsed angle bracket - // arguments. This helps stop us incorrectly suggesting that extra angle brackets be - // removed in this case: - // - // `x.foo >> (3)` (where `x.foo` is a `u32` for example) - // - // This case is particularly tricky as we won't notice it just looking at the tokens - - // it will appear the same (in terms of upcoming tokens) as below (since the `::` will - // have already been parsed): - // - // `x.foo::>>(3)` - let parsed_angle_bracket_args = segment.args - .as_ref() - .map(|args| args.is_angle_bracketed()) - .unwrap_or(false); - - debug!( - "check_trailing_angle_brackets: parsed_angle_bracket_args={:?}", - parsed_angle_bracket_args, - ); - if !parsed_angle_bracket_args { - return; - } - - // Keep the span at the start so we can highlight the sequence of `>` characters to be - // removed. - let lo = self.token.span; - - // We need to look-ahead to see if we have `>` characters without moving the cursor forward - // (since we might have the field access case and the characters we're eating are - // actual operators and not trailing characters - ie `x.foo >> 3`). - let mut position = 0; - - // We can encounter `>` or `>>` tokens in any order, so we need to keep track of how - // many of each (so we can correctly pluralize our error messages) and continue to - // advance. - let mut number_of_shr = 0; - let mut number_of_gt = 0; - while self.look_ahead(position, |t| { - trace!("check_trailing_angle_brackets: t={:?}", t); - if *t == token::BinOp(token::BinOpToken::Shr) { - number_of_shr += 1; - true - } else if *t == token::Gt { - number_of_gt += 1; - true - } else { - false - } - }) { - position += 1; - } - - // If we didn't find any trailing `>` characters, then we have nothing to error about. - debug!( - "check_trailing_angle_brackets: number_of_gt={:?} number_of_shr={:?}", - number_of_gt, number_of_shr, - ); - if number_of_gt < 1 && number_of_shr < 1 { - return; - } - - // Finally, double check that we have our end token as otherwise this is the - // second case. - if self.look_ahead(position, |t| { - trace!("check_trailing_angle_brackets: t={:?}", t); - *t == end - }) { - // Eat from where we started until the end token so that parsing can continue - // as if we didn't have those extra angle brackets. - self.eat_to_tokens(&[&end]); - let span = lo.until(self.token.span); - - let total_num_of_gt = number_of_gt + number_of_shr * 2; - self.diagnostic() - .struct_span_err( - span, - &format!("unmatched angle bracket{}", pluralise!(total_num_of_gt)), - ) - .span_suggestion( - span, - &format!("remove extra angle bracket{}", pluralise!(total_num_of_gt)), - String::new(), - Applicability::MachineApplicable, - ) - .emit(); - } - } - - /// Produces an error if comparison operators are chained (RFC #558). - /// We only need to check the LHS, not the RHS, because all comparison ops have same - /// precedence (see `fn precedence`) and are left-associative (see `fn fixity`). - /// - /// This can also be hit if someone incorrectly writes `foo()` when they should have used - /// the turbofish (`foo::()`) syntax. We attempt some heuristic recovery if that is the - /// case. - /// - /// Keep in mind that given that `outer_op.is_comparison()` holds and comparison ops are left - /// associative we can infer that we have: - /// - /// outer_op - /// / \ - /// inner_op r2 - /// / \ - /// l1 r1 - crate fn check_no_chained_comparison( - &mut self, - lhs: &Expr, - outer_op: &AssocOp, - ) -> PResult<'a, Option>> { - debug_assert!( - outer_op.is_comparison(), - "check_no_chained_comparison: {:?} is not comparison", - outer_op, - ); - - let mk_err_expr = |this: &Self, span| { - Ok(Some(this.mk_expr(span, ExprKind::Err, ThinVec::new()))) - }; - - match lhs.kind { - ExprKind::Binary(op, _, _) if op.node.is_comparison() => { - // Respan to include both operators. - let op_span = op.span.to(self.prev_span); - let mut err = self.struct_span_err( - op_span, - "chained comparison operators require parentheses", - ); - - let suggest = |err: &mut DiagnosticBuilder<'_>| { - err.span_suggestion_verbose( - op_span.shrink_to_lo(), - TURBOFISH, - "::".to_string(), - Applicability::MaybeIncorrect, - ); - }; - - if op.node == BinOpKind::Lt && - *outer_op == AssocOp::Less || // Include `<` to provide this recommendation - *outer_op == AssocOp::Greater // even in a case like the following: - { // Foo>> - if *outer_op == AssocOp::Less { - let snapshot = self.clone(); - self.bump(); - // So far we have parsed `foo(` or `foo< bar >::`, so we rewind the - // parser and bail out. - mem::replace(self, snapshot.clone()); - } - } - return if token::ModSep == self.token.kind { - // We have some certainty that this was a bad turbofish at this point. - // `foo< bar >::` - suggest(&mut err); - - let snapshot = self.clone(); - self.bump(); // `::` - - // Consume the rest of the likely `foo::new()` or return at `foo`. - match self.parse_expr() { - Ok(_) => { - // 99% certain that the suggestion is correct, continue parsing. - err.emit(); - // FIXME: actually check that the two expressions in the binop are - // paths and resynthesize new fn call expression instead of using - // `ExprKind::Err` placeholder. - mk_err_expr(self, lhs.span.to(self.prev_span)) - } - Err(mut expr_err) => { - expr_err.cancel(); - // Not entirely sure now, but we bubble the error up with the - // suggestion. - mem::replace(self, snapshot); - Err(err) - } - } - } else if token::OpenDelim(token::Paren) == self.token.kind { - // We have high certainty that this was a bad turbofish at this point. - // `foo< bar >(` - suggest(&mut err); - // Consume the fn call arguments. - match self.consume_fn_args() { - Err(()) => Err(err), - Ok(()) => { - err.emit(); - // FIXME: actually check that the two expressions in the binop are - // paths and resynthesize new fn call expression instead of using - // `ExprKind::Err` placeholder. - mk_err_expr(self, lhs.span.to(self.prev_span)) - } - } - } else { - // All we know is that this is `foo < bar >` and *nothing* else. Try to - // be helpful, but don't attempt to recover. - err.help(TURBOFISH); - err.help("or use `(...)` if you meant to specify fn arguments"); - // These cases cause too many knock-down errors, bail out (#61329). - Err(err) - }; - } - err.emit(); - } - _ => {} - } - Ok(None) - } - - fn consume_fn_args(&mut self) -> Result<(), ()> { - let snapshot = self.clone(); - self.bump(); // `(` - - // Consume the fn call arguments. - let modifiers = [ - (token::OpenDelim(token::Paren), 1), - (token::CloseDelim(token::Paren), -1), - ]; - self.consume_tts(1, &modifiers[..]); - - if self.token.kind == token::Eof { - // Not entirely sure that what we consumed were fn arguments, rollback. - mem::replace(self, snapshot); - Err(()) - } else { - // 99% certain that the suggestion is correct, continue parsing. - Ok(()) - } - } - - crate fn maybe_report_ambiguous_plus( - &mut self, - allow_plus: bool, - impl_dyn_multi: bool, - ty: &Ty, - ) { - if !allow_plus && impl_dyn_multi { - let sum_with_parens = format!("({})", pprust::ty_to_string(&ty)); - self.struct_span_err(ty.span, "ambiguous `+` in a type") - .span_suggestion( - ty.span, - "use parentheses to disambiguate", - sum_with_parens, - Applicability::MachineApplicable, - ) - .emit(); - } - } - - pub(super) fn maybe_recover_from_bad_type_plus( - &mut self, - allow_plus: bool, - ty: &Ty, - ) -> PResult<'a, ()> { - // Do not add `+` to expected tokens. - if !allow_plus || !self.token.is_like_plus() { - return Ok(()); - } - - self.bump(); // `+` - let bounds = self.parse_generic_bounds(None)?; - let sum_span = ty.span.to(self.prev_span); - - let mut err = struct_span_err!( - self.sess.span_diagnostic, - sum_span, - E0178, - "expected a path on the left-hand side of `+`, not `{}`", - pprust::ty_to_string(ty) - ); - - match ty.kind { - TyKind::Rptr(ref lifetime, ref mut_ty) => { - let sum_with_parens = pprust::to_string(|s| { - s.s.word("&"); - s.print_opt_lifetime(lifetime); - s.print_mutability(mut_ty.mutbl); - s.popen(); - s.print_type(&mut_ty.ty); - s.print_type_bounds(" +", &bounds); - s.pclose() - }); - err.span_suggestion( - sum_span, - "try adding parentheses", - sum_with_parens, - Applicability::MachineApplicable, - ); - } - TyKind::Ptr(..) | TyKind::BareFn(..) => { - err.span_label(sum_span, "perhaps you forgot parentheses?"); - } - _ => { - err.span_label(sum_span, "expected a path"); - } - } - err.emit(); - Ok(()) - } - - /// Tries to recover from associated item paths like `[T]::AssocItem` / `(T, U)::AssocItem`. - /// Attempts to convert the base expression/pattern/type into a type, parses the `::AssocItem` - /// tail, and combines them into a `::AssocItem` expression/pattern/type. - crate fn maybe_recover_from_bad_qpath( - &mut self, - base: P, - allow_recovery: bool, - ) -> PResult<'a, P> { - // Do not add `::` to expected tokens. - if allow_recovery && self.token == token::ModSep { - if let Some(ty) = base.to_ty() { - return self.maybe_recover_from_bad_qpath_stage_2(ty.span, ty); - } - } - Ok(base) - } - - /// Given an already parsed `Ty`, parses the `::AssocItem` tail and - /// combines them into a `::AssocItem` expression/pattern/type. - crate fn maybe_recover_from_bad_qpath_stage_2( - &mut self, - ty_span: Span, - ty: P, - ) -> PResult<'a, P> { - self.expect(&token::ModSep)?; - - let mut path = ast::Path { - segments: Vec::new(), - span: DUMMY_SP, - }; - self.parse_path_segments(&mut path.segments, T::PATH_STYLE)?; - path.span = ty_span.to(self.prev_span); - - let ty_str = self - .span_to_snippet(ty_span) - .unwrap_or_else(|_| pprust::ty_to_string(&ty)); - self.diagnostic() - .struct_span_err(path.span, "missing angle brackets in associated item path") - .span_suggestion( - // This is a best-effort recovery. - path.span, - "try", - format!("<{}>::{}", ty_str, pprust::path_to_string(&path)), - Applicability::MaybeIncorrect, - ) - .emit(); - - let path_span = ty_span.shrink_to_hi(); // Use an empty path since `position == 0`. - Ok(P(T::recovered( - Some(QSelf { - ty, - path_span, - position: 0, - }), - path, - ))) - } - - crate fn maybe_consume_incorrect_semicolon(&mut self, items: &[P]) -> bool { - if self.eat(&token::Semi) { - let mut err = self.struct_span_err(self.prev_span, "expected item, found `;`"); - err.span_suggestion_short( - self.prev_span, - "remove this semicolon", - String::new(), - Applicability::MachineApplicable, - ); - if !items.is_empty() { - let previous_item = &items[items.len() - 1]; - let previous_item_kind_name = match previous_item.kind { - // Say "braced struct" because tuple-structs and - // braceless-empty-struct declarations do take a semicolon. - ItemKind::Struct(..) => Some("braced struct"), - ItemKind::Enum(..) => Some("enum"), - ItemKind::Trait(..) => Some("trait"), - ItemKind::Union(..) => Some("union"), - _ => None, - }; - if let Some(name) = previous_item_kind_name { - err.help(&format!( - "{} declarations are not followed by a semicolon", - name - )); - } - } - err.emit(); - true - } else { - false - } - } - - /// Creates a `DiagnosticBuilder` for an unexpected token `t` and tries to recover if it is a - /// closing delimiter. - pub fn unexpected_try_recover( - &mut self, - t: &TokenKind, - ) -> PResult<'a, bool /* recovered */> { - let token_str = pprust::token_kind_to_string(t); - let this_token_str = self.this_token_descr(); - let (prev_sp, sp) = match (&self.token.kind, self.subparser_name) { - // Point at the end of the macro call when reaching end of macro arguments. - (token::Eof, Some(_)) => { - let sp = self.sess.source_map().next_point(self.token.span); - (sp, sp) - } - // We don't want to point at the following span after DUMMY_SP. - // This happens when the parser finds an empty TokenStream. - _ if self.prev_span == DUMMY_SP => (self.token.span, self.token.span), - // EOF, don't want to point at the following char, but rather the last token. - (token::Eof, None) => (self.prev_span, self.token.span), - _ => (self.sess.source_map().next_point(self.prev_span), self.token.span), - }; - let msg = format!( - "expected `{}`, found {}", - token_str, - match (&self.token.kind, self.subparser_name) { - (token::Eof, Some(origin)) => format!("end of {}", origin), - _ => this_token_str, - }, - ); - let mut err = self.struct_span_err(sp, &msg); - let label_exp = format!("expected `{}`", token_str); - match self.recover_closing_delimiter(&[t.clone()], err) { - Err(e) => err = e, - Ok(recovered) => { - return Ok(recovered); - } - } - let sm = self.sess.source_map(); - match (sm.lookup_line(prev_sp.lo()), sm.lookup_line(sp.lo())) { - (Ok(ref a), Ok(ref b)) if a.line == b.line => { - // When the spans are in the same line, it means that the only content - // between them is whitespace, point only at the found token. - err.span_label(sp, label_exp); - } - _ => { - err.span_label(prev_sp, label_exp); - err.span_label(sp, "unexpected token"); - } - } - Err(err) - } - - crate fn parse_semi_or_incorrect_foreign_fn_body( - &mut self, - ident: &Ident, - extern_sp: Span, - ) -> PResult<'a, ()> { - if self.token != token::Semi { - // This might be an incorrect fn definition (#62109). - let parser_snapshot = self.clone(); - match self.parse_inner_attrs_and_block() { - Ok((_, body)) => { - self.struct_span_err(ident.span, "incorrect `fn` inside `extern` block") - .span_label(ident.span, "can't have a body") - .span_label(body.span, "this body is invalid here") - .span_label( - extern_sp, - "`extern` blocks define existing foreign functions and `fn`s \ - inside of them cannot have a body") - .help("you might have meant to write a function accessible through ffi, \ - which can be done by writing `extern fn` outside of the \ - `extern` block") - .note("for more information, visit \ - https://doc.rust-lang.org/std/keyword.extern.html") - .emit(); - } - Err(mut err) => { - err.cancel(); - mem::replace(self, parser_snapshot); - self.expect(&token::Semi)?; - } - } - } else { - self.bump(); - } - Ok(()) - } - - /// Consumes alternative await syntaxes like `await!()`, `await `, - /// `await? `, `await()`, and `await { }`. - crate fn parse_incorrect_await_syntax( - &mut self, - lo: Span, - await_sp: Span, - ) -> PResult<'a, (Span, ExprKind)> { - if self.token == token::Not { - // Handle `await!()`. - self.expect(&token::Not)?; - self.expect(&token::OpenDelim(token::Paren))?; - let expr = self.parse_expr()?; - self.expect(&token::CloseDelim(token::Paren))?; - let sp = self.error_on_incorrect_await(lo, self.prev_span, &expr, false); - return Ok((sp, ExprKind::Await(expr))) - } - - let is_question = self.eat(&token::Question); // Handle `await? `. - let expr = if self.token == token::OpenDelim(token::Brace) { - // Handle `await { }`. - // This needs to be handled separatedly from the next arm to avoid - // interpreting `await { }?` as `?.await`. - self.parse_block_expr( - None, - self.token.span, - BlockCheckMode::Default, - ThinVec::new(), - ) - } else { - self.parse_expr() - }.map_err(|mut err| { - err.span_label(await_sp, "while parsing this incorrect await expression"); - err - })?; - let sp = self.error_on_incorrect_await(lo, expr.span, &expr, is_question); - Ok((sp, ExprKind::Await(expr))) - } - - fn error_on_incorrect_await(&self, lo: Span, hi: Span, expr: &Expr, is_question: bool) -> Span { - let expr_str = self.span_to_snippet(expr.span) - .unwrap_or_else(|_| pprust::expr_to_string(&expr)); - let suggestion = format!("{}.await{}", expr_str, if is_question { "?" } else { "" }); - let sp = lo.to(hi); - let app = match expr.kind { - ExprKind::Try(_) => Applicability::MaybeIncorrect, // `await ?` - _ => Applicability::MachineApplicable, - }; - self.struct_span_err(sp, "incorrect use of `await`") - .span_suggestion(sp, "`await` is a postfix operation", suggestion, app) - .emit(); - sp - } - - /// If encountering `future.await()`, consumes and emits an error. - crate fn recover_from_await_method_call(&mut self) { - if self.token == token::OpenDelim(token::Paren) && - self.look_ahead(1, |t| t == &token::CloseDelim(token::Paren)) - { - // future.await() - let lo = self.token.span; - self.bump(); // ( - let sp = lo.to(self.token.span); - self.bump(); // ) - self.struct_span_err(sp, "incorrect use of `await`") - .span_suggestion( - sp, - "`await` is not a method call, remove the parentheses", - String::new(), - Applicability::MachineApplicable, - ).emit() - } - } - - /// Recovers a situation like `for ( $pat in $expr )` - /// and suggest writing `for $pat in $expr` instead. - /// - /// This should be called before parsing the `$block`. - crate fn recover_parens_around_for_head( - &mut self, - pat: P, - expr: &Expr, - begin_paren: Option, - ) -> P { - match (&self.token.kind, begin_paren) { - (token::CloseDelim(token::Paren), Some(begin_par_sp)) => { - self.bump(); - - let pat_str = self - // Remove the `(` from the span of the pattern: - .span_to_snippet(pat.span.trim_start(begin_par_sp).unwrap()) - .unwrap_or_else(|_| pprust::pat_to_string(&pat)); - - self.struct_span_err(self.prev_span, "unexpected closing `)`") - .span_label(begin_par_sp, "opening `(`") - .span_suggestion( - begin_par_sp.to(self.prev_span), - "remove parenthesis in `for` loop", - format!("{} in {}", pat_str, pprust::expr_to_string(&expr)), - // With e.g. `for (x) in y)` this would replace `(x) in y)` - // with `x) in y)` which is syntactically invalid. - // However, this is prevented before we get here. - Applicability::MachineApplicable, - ) - .emit(); - - // Unwrap `(pat)` into `pat` to avoid the `unused_parens` lint. - pat.and_then(|pat| match pat.kind { - PatKind::Paren(pat) => pat, - _ => P(pat), - }) - } - _ => pat, - } - } - - crate fn could_ascription_be_path(&self, node: &ast::ExprKind) -> bool { - self.token.is_ident() && - if let ast::ExprKind::Path(..) = node { true } else { false } && - !self.token.is_reserved_ident() && // v `foo:bar(baz)` - self.look_ahead(1, |t| t == &token::OpenDelim(token::Paren)) || - self.look_ahead(1, |t| t == &token::Lt) && // `foo:bar` - } - - crate fn recover_seq_parse_error( - &mut self, - delim: token::DelimToken, - lo: Span, - result: PResult<'a, P>, - ) -> P { - match result { - Ok(x) => x, - Err(mut err) => { - err.emit(); - // Recover from parse error. - self.consume_block(delim); - self.mk_expr(lo.to(self.prev_span), ExprKind::Err, ThinVec::new()) - } - } - } - - crate fn recover_closing_delimiter( - &mut self, - tokens: &[TokenKind], - mut err: DiagnosticBuilder<'a>, - ) -> PResult<'a, bool> { - let mut pos = None; - // We want to use the last closing delim that would apply. - for (i, unmatched) in self.unclosed_delims.iter().enumerate().rev() { - if tokens.contains(&token::CloseDelim(unmatched.expected_delim)) - && Some(self.token.span) > unmatched.unclosed_span - { - pos = Some(i); - } - } - match pos { - Some(pos) => { - // Recover and assume that the detected unclosed delimiter was meant for - // this location. Emit the diagnostic and act as if the delimiter was - // present for the parser's sake. - - // Don't attempt to recover from this unclosed delimiter more than once. - let unmatched = self.unclosed_delims.remove(pos); - let delim = TokenType::Token(token::CloseDelim(unmatched.expected_delim)); - - // We want to suggest the inclusion of the closing delimiter where it makes - // the most sense, which is immediately after the last token: - // - // {foo(bar {}} - // - ^ - // | | - // | help: `)` may belong here - // | - // unclosed delimiter - if let Some(sp) = unmatched.unclosed_span { - err.span_label(sp, "unclosed delimiter"); - } - err.span_suggestion_short( - self.sess.source_map().next_point(self.prev_span), - &format!("{} may belong here", delim.to_string()), - delim.to_string(), - Applicability::MaybeIncorrect, - ); - err.emit(); - self.expected_tokens.clear(); // reduce errors - Ok(true) - } - _ => Err(err), - } - } - - /// Recovers from `pub` keyword in places where it seems _reasonable_ but isn't valid. - crate fn eat_bad_pub(&mut self) { - if self.token.is_keyword(kw::Pub) { - match self.parse_visibility(false) { - Ok(vis) => { - self.diagnostic() - .struct_span_err(vis.span, "unnecessary visibility qualifier") - .span_label(vis.span, "`pub` not permitted here") - .emit(); - } - Err(mut err) => err.emit(), - } - } - } - - /// Eats tokens until we can be relatively sure we reached the end of the - /// statement. This is something of a best-effort heuristic. - /// - /// We terminate when we find an unmatched `}` (without consuming it). - crate fn recover_stmt(&mut self) { - self.recover_stmt_(SemiColonMode::Ignore, BlockMode::Ignore) - } - - /// If `break_on_semi` is `Break`, then we will stop consuming tokens after - /// finding (and consuming) a `;` outside of `{}` or `[]` (note that this is - /// approximate -- it can mean we break too early due to macros, but that - /// should only lead to sub-optimal recovery, not inaccurate parsing). - /// - /// If `break_on_block` is `Break`, then we will stop consuming tokens - /// after finding (and consuming) a brace-delimited block. - crate fn recover_stmt_(&mut self, break_on_semi: SemiColonMode, break_on_block: BlockMode) { - let mut brace_depth = 0; - let mut bracket_depth = 0; - let mut in_block = false; - debug!("recover_stmt_ enter loop (semi={:?}, block={:?})", - break_on_semi, break_on_block); - loop { - debug!("recover_stmt_ loop {:?}", self.token); - match self.token.kind { - token::OpenDelim(token::DelimToken::Brace) => { - brace_depth += 1; - self.bump(); - if break_on_block == BlockMode::Break && - brace_depth == 1 && - bracket_depth == 0 { - in_block = true; - } - } - token::OpenDelim(token::DelimToken::Bracket) => { - bracket_depth += 1; - self.bump(); - } - token::CloseDelim(token::DelimToken::Brace) => { - if brace_depth == 0 { - debug!("recover_stmt_ return - close delim {:?}", self.token); - break; - } - brace_depth -= 1; - self.bump(); - if in_block && bracket_depth == 0 && brace_depth == 0 { - debug!("recover_stmt_ return - block end {:?}", self.token); - break; - } - } - token::CloseDelim(token::DelimToken::Bracket) => { - bracket_depth -= 1; - if bracket_depth < 0 { - bracket_depth = 0; - } - self.bump(); - } - token::Eof => { - debug!("recover_stmt_ return - Eof"); - break; - } - token::Semi => { - self.bump(); - if break_on_semi == SemiColonMode::Break && - brace_depth == 0 && - bracket_depth == 0 { - debug!("recover_stmt_ return - Semi"); - break; - } - } - token::Comma if break_on_semi == SemiColonMode::Comma && - brace_depth == 0 && - bracket_depth == 0 => - { - debug!("recover_stmt_ return - Semi"); - break; - } - _ => { - self.bump() - } - } - } - } - - crate fn check_for_for_in_in_typo(&mut self, in_span: Span) { - if self.eat_keyword(kw::In) { - // a common typo: `for _ in in bar {}` - self.struct_span_err(self.prev_span, "expected iterable, found keyword `in`") - .span_suggestion_short( - in_span.until(self.prev_span), - "remove the duplicated `in`", - String::new(), - Applicability::MachineApplicable, - ) - .emit(); - } - } - - crate fn expected_semi_or_open_brace(&mut self) -> PResult<'a, T> { - let token_str = self.this_token_descr(); - let mut err = self.fatal(&format!("expected `;` or `{{`, found {}", token_str)); - err.span_label(self.token.span, "expected `;` or `{`"); - Err(err) - } - - crate fn eat_incorrect_doc_comment_for_param_type(&mut self) { - if let token::DocComment(_) = self.token.kind { - self.struct_span_err( - self.token.span, - "documentation comments cannot be applied to a function parameter's type", - ) - .span_label(self.token.span, "doc comments are not allowed here") - .emit(); - self.bump(); - } else if self.token == token::Pound && self.look_ahead(1, |t| { - *t == token::OpenDelim(token::Bracket) - }) { - let lo = self.token.span; - // Skip every token until next possible arg. - while self.token != token::CloseDelim(token::Bracket) { - self.bump(); - } - let sp = lo.to(self.token.span); - self.bump(); - self.struct_span_err( - sp, - "attributes cannot be applied to a function parameter's type", - ) - .span_label(sp, "attributes are not allowed here") - .emit(); - } - } - - crate fn parameter_without_type( - &mut self, - err: &mut DiagnosticBuilder<'_>, - pat: P, - require_name: bool, - is_self_allowed: bool, - is_trait_item: bool, - ) -> Option { - // 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()); - - err.span_suggestion( - span, - "declare the type after the parameter binding", - String::from(": "), - Applicability::HasPlaceholders, - ); - return Some(ident); - } else if let PatKind::Ident(_, ident, _) = pat.kind { - if require_name && ( - is_trait_item || - self.token == token::Comma || - self.token == token::Lt || - self.token == token::CloseDelim(token::Paren) - ) { // `fn foo(a, b) {}`, `fn foo(a, b) {}` or `fn foo(usize, usize) {}` - if is_self_allowed { - err.span_suggestion( - pat.span, - "if this is a `self` type, give it a parameter name", - format!("self: {}", ident), - Applicability::MaybeIncorrect, - ); - } - // Avoid suggesting that `fn foo(HashMap)` is fixed with a change to - // `fn foo(HashMap: TypeName)`. - if self.token != token::Lt { - 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, - "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)"); - - // Don't attempt to recover by using the `X` in `X` as the parameter name. - return if self.token == token::Lt { None } else { Some(ident) }; - } - } - None - } - - crate fn recover_arg_parse(&mut self) -> PResult<'a, (P, P)> { - let pat = self.parse_pat(Some("argument name"))?; - self.expect(&token::Colon)?; - let ty = self.parse_ty()?; - - self.diagnostic() - .struct_span_err_with_code( - pat.span, - "patterns aren't allowed in methods without bodies", - DiagnosticId::Error("E0642".into()), - ) - .span_suggestion_short( - pat.span, - "give this argument a name or use an underscore to ignore it", - "_".to_owned(), - Applicability::MachineApplicable, - ) - .emit(); - - // Pretend the pattern is `_`, to avoid duplicate errors from AST validation. - let pat = P(Pat { - kind: PatKind::Wild, - span: pat.span, - id: ast::DUMMY_NODE_ID - }); - Ok((pat, ty)) - } - - crate fn recover_bad_self_param( - &mut self, - mut param: ast::Param, - is_trait_item: bool, - ) -> PResult<'a, ast::Param> { - let sp = param.pat.span; - param.ty.kind = TyKind::Err; - let mut err = self.struct_span_err(sp, "unexpected `self` parameter in function"); - if is_trait_item { - err.span_label(sp, "must be the first associated function parameter"); - } else { - err.span_label(sp, "not valid as function parameter"); - err.note("`self` is only valid as the first parameter of an associated function"); - } - err.emit(); - Ok(param) - } - - crate fn consume_block(&mut self, delim: token::DelimToken) { - let mut brace_depth = 0; - loop { - if self.eat(&token::OpenDelim(delim)) { - brace_depth += 1; - } else if self.eat(&token::CloseDelim(delim)) { - if brace_depth == 0 { - return; - } else { - brace_depth -= 1; - continue; - } - } else if self.token == token::Eof || self.eat(&token::CloseDelim(token::NoDelim)) { - return; - } else { - self.bump(); - } - } - } - - crate fn expected_expression_found(&self) -> DiagnosticBuilder<'a> { - let (span, msg) = match (&self.token.kind, self.subparser_name) { - (&token::Eof, Some(origin)) => { - let sp = self.sess.source_map().next_point(self.token.span); - (sp, format!("expected expression, found end of {}", origin)) - } - _ => (self.token.span, format!( - "expected expression, found {}", - self.this_token_descr(), - )), - }; - let mut err = self.struct_span_err(span, &msg); - let sp = self.sess.source_map().start_point(self.token.span); - if let Some(sp) = self.sess.ambiguous_block_expr_parse.borrow().get(&sp) { - self.sess.expr_parentheses_needed(&mut err, *sp, None); - } - err.span_label(span, "expected expression"); - err - } - - fn consume_tts( - &mut self, - mut acc: i64, // `i64` because malformed code can have more closing delims than opening. - // Not using `FxHashMap` due to `token::TokenKind: !Eq + !Hash`. - modifier: &[(token::TokenKind, i64)], - ) { - while acc > 0 { - if let Some((_, val)) = modifier.iter().find(|(t, _)| *t == self.token.kind) { - acc += *val; - } - if self.token.kind == token::Eof { - break; - } - self.bump(); - } - } - - /// Replace duplicated recovered parameters with `_` pattern to avoid unecessary errors. - /// - /// This is necessary because at this point we don't know whether we parsed a function with - /// anonymous parameters or a function with names but no types. In order to minimize - /// unecessary errors, we assume the parameters are in the shape of `fn foo(a, b, c)` where - /// the parameters are *names* (so we don't emit errors about not being able to find `b` in - /// the local scope), but if we find the same name multiple times, like in `fn foo(i8, i8)`, - /// we deduplicate them to not complain about duplicated parameter names. - crate fn deduplicate_recovered_params_names(&self, fn_inputs: &mut Vec) { - let mut seen_inputs = FxHashSet::default(); - for input in fn_inputs.iter_mut() { - let opt_ident = if let (PatKind::Ident(_, ident, _), TyKind::Err) = ( - &input.pat.kind, &input.ty.kind, - ) { - Some(*ident) - } else { - None - }; - if let Some(ident) = opt_ident { - if seen_inputs.contains(&ident) { - input.pat.kind = PatKind::Wild; - } - seen_inputs.insert(ident); - } - } - } -} diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 6bcd9cd9b63..1eaee46a3c2 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -28,7 +28,6 @@ pub mod lexer; pub mod token; crate mod classify; -crate mod diagnostics; crate mod literal; crate mod unescape_error_reporting; diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index b710fcff65b..6f55fd23e6e 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -10,7 +10,8 @@ mod path; pub use path::PathStyle; mod stmt; mod generics; -use super::diagnostics::Error; +mod diagnostics; +use diagnostics::Error; use crate::ast::{ self, DUMMY_NODE_ID, AttrStyle, Attribute, CrateSugar, Ident, diff --git a/src/libsyntax/parse/parser/diagnostics.rs b/src/libsyntax/parse/parser/diagnostics.rs new file mode 100644 index 00000000000..943838d9dda --- /dev/null +++ b/src/libsyntax/parse/parser/diagnostics.rs @@ -0,0 +1,1483 @@ +use crate::ast::{ + self, Param, BinOpKind, BindingMode, BlockCheckMode, Expr, ExprKind, Ident, Item, ItemKind, + Mutability, Pat, PatKind, PathSegment, QSelf, Ty, TyKind, +}; +use crate::parse::{SeqSep, PResult, Parser}; +use crate::parse::parser::{BlockMode, PathStyle, SemiColonMode, TokenType, TokenExpectType}; +use crate::parse::token::{self, TokenKind}; +use crate::print::pprust; +use crate::ptr::P; +use crate::symbol::{kw, sym}; +use crate::ThinVec; +use crate::util::parser::AssocOp; +use errors::{Applicability, DiagnosticBuilder, DiagnosticId, pluralise}; +use rustc_data_structures::fx::FxHashSet; +use syntax_pos::{Span, DUMMY_SP, MultiSpan, SpanSnippetError}; +use log::{debug, trace}; +use std::mem; + +const TURBOFISH: &'static str = "use `::<...>` instead of `<...>` to specify type arguments"; +/// Creates a placeholder argument. +crate fn dummy_arg(ident: Ident) -> Param { + let pat = P(Pat { + id: ast::DUMMY_NODE_ID, + kind: PatKind::Ident(BindingMode::ByValue(Mutability::Immutable), ident, None), + span: ident.span, + }); + let ty = Ty { + kind: TyKind::Err, + span: ident.span, + id: ast::DUMMY_NODE_ID + }; + Param { + attrs: ThinVec::default(), + id: ast::DUMMY_NODE_ID, + pat, + span: ident.span, + ty: P(ty), + is_placeholder: false, + } +} + +pub enum Error { + FileNotFoundForModule { + mod_name: String, + default_path: String, + secondary_path: String, + dir_path: String, + }, + DuplicatePaths { + mod_name: String, + default_path: String, + secondary_path: String, + }, + UselessDocComment, + InclusiveRangeWithNoEnd, +} + +impl Error { + fn span_err>( + self, + sp: S, + handler: &errors::Handler, + ) -> DiagnosticBuilder<'_> { + match self { + Error::FileNotFoundForModule { + ref mod_name, + ref default_path, + ref secondary_path, + ref dir_path, + } => { + let mut err = struct_span_err!( + handler, + sp, + E0583, + "file not found for module `{}`", + mod_name, + ); + err.help(&format!( + "name the file either {} or {} inside the directory \"{}\"", + default_path, + secondary_path, + dir_path, + )); + err + } + Error::DuplicatePaths { ref mod_name, ref default_path, ref secondary_path } => { + let mut err = struct_span_err!( + handler, + sp, + E0584, + "file for module `{}` found at both {} and {}", + mod_name, + default_path, + secondary_path, + ); + err.help("delete or rename one of them to remove the ambiguity"); + err + } + Error::UselessDocComment => { + let mut err = struct_span_err!( + handler, + sp, + E0585, + "found a documentation comment that doesn't document anything", + ); + err.help("doc comments must come before what they document, maybe a comment was \ + intended with `//`?"); + err + } + Error::InclusiveRangeWithNoEnd => { + let mut err = struct_span_err!( + handler, + sp, + E0586, + "inclusive range with no end", + ); + err.help("inclusive ranges must be bounded at the end (`..=b` or `a..=b`)"); + err + } + } + } +} + +pub trait RecoverQPath: Sized + 'static { + const PATH_STYLE: PathStyle = PathStyle::Expr; + fn to_ty(&self) -> Option>; + fn recovered(qself: Option, path: ast::Path) -> Self; +} + +impl RecoverQPath for Ty { + const PATH_STYLE: PathStyle = PathStyle::Type; + fn to_ty(&self) -> Option> { + Some(P(self.clone())) + } + fn recovered(qself: Option, path: ast::Path) -> Self { + Self { + span: path.span, + kind: TyKind::Path(qself, path), + id: ast::DUMMY_NODE_ID, + } + } +} + +impl RecoverQPath for Pat { + fn to_ty(&self) -> Option> { + self.to_ty() + } + fn recovered(qself: Option, path: ast::Path) -> Self { + Self { + span: path.span, + kind: PatKind::Path(qself, path), + id: ast::DUMMY_NODE_ID, + } + } +} + +impl RecoverQPath for Expr { + fn to_ty(&self) -> Option> { + self.to_ty() + } + fn recovered(qself: Option, path: ast::Path) -> Self { + Self { + span: path.span, + kind: ExprKind::Path(qself, path), + attrs: ThinVec::new(), + id: ast::DUMMY_NODE_ID, + } + } +} + +impl<'a> Parser<'a> { + pub fn fatal(&self, m: &str) -> DiagnosticBuilder<'a> { + self.span_fatal(self.token.span, m) + } + + pub fn span_fatal>(&self, sp: S, m: &str) -> DiagnosticBuilder<'a> { + self.sess.span_diagnostic.struct_span_fatal(sp, m) + } + + pub fn span_fatal_err>(&self, sp: S, err: Error) -> DiagnosticBuilder<'a> { + err.span_err(sp, self.diagnostic()) + } + + pub fn bug(&self, m: &str) -> ! { + self.sess.span_diagnostic.span_bug(self.token.span, m) + } + + pub fn span_err>(&self, sp: S, m: &str) { + self.sess.span_diagnostic.span_err(sp, m) + } + + crate fn struct_span_err>(&self, sp: S, m: &str) -> DiagnosticBuilder<'a> { + self.sess.span_diagnostic.struct_span_err(sp, m) + } + + crate fn span_bug>(&self, sp: S, m: &str) -> ! { + self.sess.span_diagnostic.span_bug(sp, m) + } + + crate fn diagnostic(&self) -> &'a errors::Handler { + &self.sess.span_diagnostic + } + + crate fn span_to_snippet(&self, span: Span) -> Result { + self.sess.source_map().span_to_snippet(span) + } + + crate fn expected_ident_found(&self) -> DiagnosticBuilder<'a> { + let mut err = self.struct_span_err( + self.token.span, + &format!("expected identifier, found {}", self.this_token_descr()), + ); + if let token::Ident(name, false) = self.token.kind { + if Ident::new(name, self.token.span).is_raw_guess() { + err.span_suggestion( + self.token.span, + "you can escape reserved keywords to use them as identifiers", + format!("r#{}", name), + Applicability::MaybeIncorrect, + ); + } + } + if let Some(token_descr) = self.token_descr() { + err.span_label(self.token.span, format!("expected identifier, found {}", token_descr)); + } else { + err.span_label(self.token.span, "expected identifier"); + if self.token == token::Comma && self.look_ahead(1, |t| t.is_ident()) { + err.span_suggestion( + self.token.span, + "remove this comma", + String::new(), + Applicability::MachineApplicable, + ); + } + } + err + } + + pub fn expected_one_of_not_found( + &mut self, + edible: &[TokenKind], + inedible: &[TokenKind], + ) -> PResult<'a, bool /* recovered */> { + fn tokens_to_string(tokens: &[TokenType]) -> String { + let mut i = tokens.iter(); + // This might be a sign we need a connect method on `Iterator`. + let b = i.next() + .map_or(String::new(), |t| t.to_string()); + i.enumerate().fold(b, |mut b, (i, a)| { + if tokens.len() > 2 && i == tokens.len() - 2 { + b.push_str(", or "); + } else if tokens.len() == 2 && i == tokens.len() - 2 { + b.push_str(" or "); + } else { + b.push_str(", "); + } + b.push_str(&a.to_string()); + b + }) + } + + let mut expected = edible.iter() + .map(|x| TokenType::Token(x.clone())) + .chain(inedible.iter().map(|x| TokenType::Token(x.clone()))) + .chain(self.expected_tokens.iter().cloned()) + .collect::>(); + expected.sort_by_cached_key(|x| x.to_string()); + expected.dedup(); + let expect = tokens_to_string(&expected[..]); + let actual = self.this_token_to_string(); + let (msg_exp, (label_sp, label_exp)) = if expected.len() > 1 { + let short_expect = if expected.len() > 6 { + format!("{} possible tokens", expected.len()) + } else { + expect.clone() + }; + (format!("expected one of {}, found `{}`", expect, actual), + (self.sess.source_map().next_point(self.prev_span), + format!("expected one of {} here", short_expect))) + } else if expected.is_empty() { + (format!("unexpected token: `{}`", actual), + (self.prev_span, "unexpected token after this".to_string())) + } else { + (format!("expected {}, found `{}`", expect, actual), + (self.sess.source_map().next_point(self.prev_span), + format!("expected {} here", expect))) + }; + self.last_unexpected_token_span = Some(self.token.span); + let mut err = self.fatal(&msg_exp); + if self.token.is_ident_named(sym::and) { + err.span_suggestion_short( + self.token.span, + "use `&&` instead of `and` for the boolean operator", + "&&".to_string(), + Applicability::MaybeIncorrect, + ); + } + if self.token.is_ident_named(sym::or) { + err.span_suggestion_short( + self.token.span, + "use `||` instead of `or` for the boolean operator", + "||".to_string(), + Applicability::MaybeIncorrect, + ); + } + let sp = if self.token == token::Eof { + // This is EOF; don't want to point at the following char, but rather the last token. + self.prev_span + } else { + label_sp + }; + match self.recover_closing_delimiter(&expected.iter().filter_map(|tt| match tt { + TokenType::Token(t) => Some(t.clone()), + _ => None, + }).collect::>(), err) { + Err(e) => err = e, + Ok(recovered) => { + return Ok(recovered); + } + } + + let is_semi_suggestable = expected.iter().any(|t| match t { + TokenType::Token(token::Semi) => true, // We expect a `;` here. + _ => false, + }) && ( // A `;` would be expected before the current keyword. + self.token.is_keyword(kw::Break) || + self.token.is_keyword(kw::Continue) || + self.token.is_keyword(kw::For) || + self.token.is_keyword(kw::If) || + self.token.is_keyword(kw::Let) || + self.token.is_keyword(kw::Loop) || + self.token.is_keyword(kw::Match) || + self.token.is_keyword(kw::Return) || + self.token.is_keyword(kw::While) + ); + let sm = self.sess.source_map(); + match (sm.lookup_line(self.token.span.lo()), sm.lookup_line(sp.lo())) { + (Ok(ref a), Ok(ref b)) if a.line != b.line && is_semi_suggestable => { + // The spans are in different lines, expected `;` and found `let` or `return`. + // High likelihood that it is only a missing `;`. + err.span_suggestion_short( + label_sp, + "a semicolon may be missing here", + ";".to_string(), + Applicability::MaybeIncorrect, + ); + err.emit(); + return Ok(true); + } + (Ok(ref a), Ok(ref b)) if a.line == b.line => { + // When the spans are in the same line, it means that the only content between + // them is whitespace, point at the found token in that case: + // + // X | () => { syntax error }; + // | ^^^^^ expected one of 8 possible tokens here + // + // instead of having: + // + // X | () => { syntax error }; + // | -^^^^^ unexpected token + // | | + // | expected one of 8 possible tokens here + err.span_label(self.token.span, label_exp); + } + _ if self.prev_span == syntax_pos::DUMMY_SP => { + // Account for macro context where the previous span might not be + // available to avoid incorrect output (#54841). + err.span_label(self.token.span, "unexpected token"); + } + _ => { + err.span_label(sp, label_exp); + err.span_label(self.token.span, "unexpected token"); + } + } + self.maybe_annotate_with_ascription(&mut err, false); + Err(err) + } + + pub fn maybe_annotate_with_ascription( + &self, + err: &mut DiagnosticBuilder<'_>, + maybe_expected_semicolon: bool, + ) { + if let Some((sp, likely_path)) = self.last_type_ascription { + let sm = self.sess.source_map(); + let next_pos = sm.lookup_char_pos(self.token.span.lo()); + let op_pos = sm.lookup_char_pos(sp.hi()); + + let allow_unstable = self.sess.unstable_features.is_nightly_build(); + + if likely_path { + err.span_suggestion( + sp, + "maybe write a path separator here", + "::".to_string(), + if allow_unstable { + Applicability::MaybeIncorrect + } else { + Applicability::MachineApplicable + }, + ); + } else if op_pos.line != next_pos.line && maybe_expected_semicolon { + err.span_suggestion( + sp, + "try using a semicolon", + ";".to_string(), + Applicability::MaybeIncorrect, + ); + } else if allow_unstable { + err.span_label(sp, "tried to parse a type due to this type ascription"); + } else { + err.span_label(sp, "tried to parse a type due to this"); + } + if allow_unstable { + // Give extra information about type ascription only if it's a nightly compiler. + err.note("`#![feature(type_ascription)]` lets you annotate an expression with a \ + type: `: `"); + err.note("for more information, see \ + https://github.com/rust-lang/rust/issues/23416"); + } + } + } + + /// Eats and discards tokens until one of `kets` is encountered. Respects token trees, + /// passes through any errors encountered. Used for error recovery. + crate fn eat_to_tokens(&mut self, kets: &[&TokenKind]) { + if let Err(ref mut err) = self.parse_seq_to_before_tokens( + kets, + SeqSep::none(), + TokenExpectType::Expect, + |p| Ok(p.parse_token_tree()), + ) { + err.cancel(); + } + } + + /// This function checks if there are trailing angle brackets and produces + /// a diagnostic to suggest removing them. + /// + /// ```ignore (diagnostic) + /// let _ = vec![1, 2, 3].into_iter().collect::>>>(); + /// ^^ help: remove extra angle brackets + /// ``` + crate fn check_trailing_angle_brackets(&mut self, segment: &PathSegment, end: TokenKind) { + // This function is intended to be invoked after parsing a path segment where there are two + // cases: + // + // 1. A specific token is expected after the path segment. + // eg. `x.foo(`, `x.foo::(` (parenthesis - method call), + // `Foo::`, or `Foo::::` (mod sep - continued path). + // 2. No specific token is expected after the path segment. + // eg. `x.foo` (field access) + // + // This function is called after parsing `.foo` and before parsing the token `end` (if + // present). This includes any angle bracket arguments, such as `.foo::` or + // `Foo::`. + + // We only care about trailing angle brackets if we previously parsed angle bracket + // arguments. This helps stop us incorrectly suggesting that extra angle brackets be + // removed in this case: + // + // `x.foo >> (3)` (where `x.foo` is a `u32` for example) + // + // This case is particularly tricky as we won't notice it just looking at the tokens - + // it will appear the same (in terms of upcoming tokens) as below (since the `::` will + // have already been parsed): + // + // `x.foo::>>(3)` + let parsed_angle_bracket_args = segment.args + .as_ref() + .map(|args| args.is_angle_bracketed()) + .unwrap_or(false); + + debug!( + "check_trailing_angle_brackets: parsed_angle_bracket_args={:?}", + parsed_angle_bracket_args, + ); + if !parsed_angle_bracket_args { + return; + } + + // Keep the span at the start so we can highlight the sequence of `>` characters to be + // removed. + let lo = self.token.span; + + // We need to look-ahead to see if we have `>` characters without moving the cursor forward + // (since we might have the field access case and the characters we're eating are + // actual operators and not trailing characters - ie `x.foo >> 3`). + let mut position = 0; + + // We can encounter `>` or `>>` tokens in any order, so we need to keep track of how + // many of each (so we can correctly pluralize our error messages) and continue to + // advance. + let mut number_of_shr = 0; + let mut number_of_gt = 0; + while self.look_ahead(position, |t| { + trace!("check_trailing_angle_brackets: t={:?}", t); + if *t == token::BinOp(token::BinOpToken::Shr) { + number_of_shr += 1; + true + } else if *t == token::Gt { + number_of_gt += 1; + true + } else { + false + } + }) { + position += 1; + } + + // If we didn't find any trailing `>` characters, then we have nothing to error about. + debug!( + "check_trailing_angle_brackets: number_of_gt={:?} number_of_shr={:?}", + number_of_gt, number_of_shr, + ); + if number_of_gt < 1 && number_of_shr < 1 { + return; + } + + // Finally, double check that we have our end token as otherwise this is the + // second case. + if self.look_ahead(position, |t| { + trace!("check_trailing_angle_brackets: t={:?}", t); + *t == end + }) { + // Eat from where we started until the end token so that parsing can continue + // as if we didn't have those extra angle brackets. + self.eat_to_tokens(&[&end]); + let span = lo.until(self.token.span); + + let total_num_of_gt = number_of_gt + number_of_shr * 2; + self.diagnostic() + .struct_span_err( + span, + &format!("unmatched angle bracket{}", pluralise!(total_num_of_gt)), + ) + .span_suggestion( + span, + &format!("remove extra angle bracket{}", pluralise!(total_num_of_gt)), + String::new(), + Applicability::MachineApplicable, + ) + .emit(); + } + } + + /// Produces an error if comparison operators are chained (RFC #558). + /// We only need to check the LHS, not the RHS, because all comparison ops have same + /// precedence (see `fn precedence`) and are left-associative (see `fn fixity`). + /// + /// This can also be hit if someone incorrectly writes `foo()` when they should have used + /// the turbofish (`foo::()`) syntax. We attempt some heuristic recovery if that is the + /// case. + /// + /// Keep in mind that given that `outer_op.is_comparison()` holds and comparison ops are left + /// associative we can infer that we have: + /// + /// outer_op + /// / \ + /// inner_op r2 + /// / \ + /// l1 r1 + crate fn check_no_chained_comparison( + &mut self, + lhs: &Expr, + outer_op: &AssocOp, + ) -> PResult<'a, Option>> { + debug_assert!( + outer_op.is_comparison(), + "check_no_chained_comparison: {:?} is not comparison", + outer_op, + ); + + let mk_err_expr = |this: &Self, span| { + Ok(Some(this.mk_expr(span, ExprKind::Err, ThinVec::new()))) + }; + + match lhs.kind { + ExprKind::Binary(op, _, _) if op.node.is_comparison() => { + // Respan to include both operators. + let op_span = op.span.to(self.prev_span); + let mut err = self.struct_span_err( + op_span, + "chained comparison operators require parentheses", + ); + + let suggest = |err: &mut DiagnosticBuilder<'_>| { + err.span_suggestion_verbose( + op_span.shrink_to_lo(), + TURBOFISH, + "::".to_string(), + Applicability::MaybeIncorrect, + ); + }; + + if op.node == BinOpKind::Lt && + *outer_op == AssocOp::Less || // Include `<` to provide this recommendation + *outer_op == AssocOp::Greater // even in a case like the following: + { // Foo>> + if *outer_op == AssocOp::Less { + let snapshot = self.clone(); + self.bump(); + // So far we have parsed `foo(` or `foo< bar >::`, so we rewind the + // parser and bail out. + mem::replace(self, snapshot.clone()); + } + } + return if token::ModSep == self.token.kind { + // We have some certainty that this was a bad turbofish at this point. + // `foo< bar >::` + suggest(&mut err); + + let snapshot = self.clone(); + self.bump(); // `::` + + // Consume the rest of the likely `foo::new()` or return at `foo`. + match self.parse_expr() { + Ok(_) => { + // 99% certain that the suggestion is correct, continue parsing. + err.emit(); + // FIXME: actually check that the two expressions in the binop are + // paths and resynthesize new fn call expression instead of using + // `ExprKind::Err` placeholder. + mk_err_expr(self, lhs.span.to(self.prev_span)) + } + Err(mut expr_err) => { + expr_err.cancel(); + // Not entirely sure now, but we bubble the error up with the + // suggestion. + mem::replace(self, snapshot); + Err(err) + } + } + } else if token::OpenDelim(token::Paren) == self.token.kind { + // We have high certainty that this was a bad turbofish at this point. + // `foo< bar >(` + suggest(&mut err); + // Consume the fn call arguments. + match self.consume_fn_args() { + Err(()) => Err(err), + Ok(()) => { + err.emit(); + // FIXME: actually check that the two expressions in the binop are + // paths and resynthesize new fn call expression instead of using + // `ExprKind::Err` placeholder. + mk_err_expr(self, lhs.span.to(self.prev_span)) + } + } + } else { + // All we know is that this is `foo < bar >` and *nothing* else. Try to + // be helpful, but don't attempt to recover. + err.help(TURBOFISH); + err.help("or use `(...)` if you meant to specify fn arguments"); + // These cases cause too many knock-down errors, bail out (#61329). + Err(err) + }; + } + err.emit(); + } + _ => {} + } + Ok(None) + } + + fn consume_fn_args(&mut self) -> Result<(), ()> { + let snapshot = self.clone(); + self.bump(); // `(` + + // Consume the fn call arguments. + let modifiers = [ + (token::OpenDelim(token::Paren), 1), + (token::CloseDelim(token::Paren), -1), + ]; + self.consume_tts(1, &modifiers[..]); + + if self.token.kind == token::Eof { + // Not entirely sure that what we consumed were fn arguments, rollback. + mem::replace(self, snapshot); + Err(()) + } else { + // 99% certain that the suggestion is correct, continue parsing. + Ok(()) + } + } + + crate fn maybe_report_ambiguous_plus( + &mut self, + allow_plus: bool, + impl_dyn_multi: bool, + ty: &Ty, + ) { + if !allow_plus && impl_dyn_multi { + let sum_with_parens = format!("({})", pprust::ty_to_string(&ty)); + self.struct_span_err(ty.span, "ambiguous `+` in a type") + .span_suggestion( + ty.span, + "use parentheses to disambiguate", + sum_with_parens, + Applicability::MachineApplicable, + ) + .emit(); + } + } + + pub(super) fn maybe_recover_from_bad_type_plus( + &mut self, + allow_plus: bool, + ty: &Ty, + ) -> PResult<'a, ()> { + // Do not add `+` to expected tokens. + if !allow_plus || !self.token.is_like_plus() { + return Ok(()); + } + + self.bump(); // `+` + let bounds = self.parse_generic_bounds(None)?; + let sum_span = ty.span.to(self.prev_span); + + let mut err = struct_span_err!( + self.sess.span_diagnostic, + sum_span, + E0178, + "expected a path on the left-hand side of `+`, not `{}`", + pprust::ty_to_string(ty) + ); + + match ty.kind { + TyKind::Rptr(ref lifetime, ref mut_ty) => { + let sum_with_parens = pprust::to_string(|s| { + s.s.word("&"); + s.print_opt_lifetime(lifetime); + s.print_mutability(mut_ty.mutbl); + s.popen(); + s.print_type(&mut_ty.ty); + s.print_type_bounds(" +", &bounds); + s.pclose() + }); + err.span_suggestion( + sum_span, + "try adding parentheses", + sum_with_parens, + Applicability::MachineApplicable, + ); + } + TyKind::Ptr(..) | TyKind::BareFn(..) => { + err.span_label(sum_span, "perhaps you forgot parentheses?"); + } + _ => { + err.span_label(sum_span, "expected a path"); + } + } + err.emit(); + Ok(()) + } + + /// Tries to recover from associated item paths like `[T]::AssocItem` / `(T, U)::AssocItem`. + /// Attempts to convert the base expression/pattern/type into a type, parses the `::AssocItem` + /// tail, and combines them into a `::AssocItem` expression/pattern/type. + crate fn maybe_recover_from_bad_qpath( + &mut self, + base: P, + allow_recovery: bool, + ) -> PResult<'a, P> { + // Do not add `::` to expected tokens. + if allow_recovery && self.token == token::ModSep { + if let Some(ty) = base.to_ty() { + return self.maybe_recover_from_bad_qpath_stage_2(ty.span, ty); + } + } + Ok(base) + } + + /// Given an already parsed `Ty`, parses the `::AssocItem` tail and + /// combines them into a `::AssocItem` expression/pattern/type. + crate fn maybe_recover_from_bad_qpath_stage_2( + &mut self, + ty_span: Span, + ty: P, + ) -> PResult<'a, P> { + self.expect(&token::ModSep)?; + + let mut path = ast::Path { + segments: Vec::new(), + span: DUMMY_SP, + }; + self.parse_path_segments(&mut path.segments, T::PATH_STYLE)?; + path.span = ty_span.to(self.prev_span); + + let ty_str = self + .span_to_snippet(ty_span) + .unwrap_or_else(|_| pprust::ty_to_string(&ty)); + self.diagnostic() + .struct_span_err(path.span, "missing angle brackets in associated item path") + .span_suggestion( + // This is a best-effort recovery. + path.span, + "try", + format!("<{}>::{}", ty_str, pprust::path_to_string(&path)), + Applicability::MaybeIncorrect, + ) + .emit(); + + let path_span = ty_span.shrink_to_hi(); // Use an empty path since `position == 0`. + Ok(P(T::recovered( + Some(QSelf { + ty, + path_span, + position: 0, + }), + path, + ))) + } + + crate fn maybe_consume_incorrect_semicolon(&mut self, items: &[P]) -> bool { + if self.eat(&token::Semi) { + let mut err = self.struct_span_err(self.prev_span, "expected item, found `;`"); + err.span_suggestion_short( + self.prev_span, + "remove this semicolon", + String::new(), + Applicability::MachineApplicable, + ); + if !items.is_empty() { + let previous_item = &items[items.len() - 1]; + let previous_item_kind_name = match previous_item.kind { + // Say "braced struct" because tuple-structs and + // braceless-empty-struct declarations do take a semicolon. + ItemKind::Struct(..) => Some("braced struct"), + ItemKind::Enum(..) => Some("enum"), + ItemKind::Trait(..) => Some("trait"), + ItemKind::Union(..) => Some("union"), + _ => None, + }; + if let Some(name) = previous_item_kind_name { + err.help(&format!( + "{} declarations are not followed by a semicolon", + name + )); + } + } + err.emit(); + true + } else { + false + } + } + + /// Creates a `DiagnosticBuilder` for an unexpected token `t` and tries to recover if it is a + /// closing delimiter. + pub fn unexpected_try_recover( + &mut self, + t: &TokenKind, + ) -> PResult<'a, bool /* recovered */> { + let token_str = pprust::token_kind_to_string(t); + let this_token_str = self.this_token_descr(); + let (prev_sp, sp) = match (&self.token.kind, self.subparser_name) { + // Point at the end of the macro call when reaching end of macro arguments. + (token::Eof, Some(_)) => { + let sp = self.sess.source_map().next_point(self.token.span); + (sp, sp) + } + // We don't want to point at the following span after DUMMY_SP. + // This happens when the parser finds an empty TokenStream. + _ if self.prev_span == DUMMY_SP => (self.token.span, self.token.span), + // EOF, don't want to point at the following char, but rather the last token. + (token::Eof, None) => (self.prev_span, self.token.span), + _ => (self.sess.source_map().next_point(self.prev_span), self.token.span), + }; + let msg = format!( + "expected `{}`, found {}", + token_str, + match (&self.token.kind, self.subparser_name) { + (token::Eof, Some(origin)) => format!("end of {}", origin), + _ => this_token_str, + }, + ); + let mut err = self.struct_span_err(sp, &msg); + let label_exp = format!("expected `{}`", token_str); + match self.recover_closing_delimiter(&[t.clone()], err) { + Err(e) => err = e, + Ok(recovered) => { + return Ok(recovered); + } + } + let sm = self.sess.source_map(); + match (sm.lookup_line(prev_sp.lo()), sm.lookup_line(sp.lo())) { + (Ok(ref a), Ok(ref b)) if a.line == b.line => { + // When the spans are in the same line, it means that the only content + // between them is whitespace, point only at the found token. + err.span_label(sp, label_exp); + } + _ => { + err.span_label(prev_sp, label_exp); + err.span_label(sp, "unexpected token"); + } + } + Err(err) + } + + crate fn parse_semi_or_incorrect_foreign_fn_body( + &mut self, + ident: &Ident, + extern_sp: Span, + ) -> PResult<'a, ()> { + if self.token != token::Semi { + // This might be an incorrect fn definition (#62109). + let parser_snapshot = self.clone(); + match self.parse_inner_attrs_and_block() { + Ok((_, body)) => { + self.struct_span_err(ident.span, "incorrect `fn` inside `extern` block") + .span_label(ident.span, "can't have a body") + .span_label(body.span, "this body is invalid here") + .span_label( + extern_sp, + "`extern` blocks define existing foreign functions and `fn`s \ + inside of them cannot have a body") + .help("you might have meant to write a function accessible through ffi, \ + which can be done by writing `extern fn` outside of the \ + `extern` block") + .note("for more information, visit \ + https://doc.rust-lang.org/std/keyword.extern.html") + .emit(); + } + Err(mut err) => { + err.cancel(); + mem::replace(self, parser_snapshot); + self.expect(&token::Semi)?; + } + } + } else { + self.bump(); + } + Ok(()) + } + + /// Consumes alternative await syntaxes like `await!()`, `await `, + /// `await? `, `await()`, and `await { }`. + crate fn parse_incorrect_await_syntax( + &mut self, + lo: Span, + await_sp: Span, + ) -> PResult<'a, (Span, ExprKind)> { + if self.token == token::Not { + // Handle `await!()`. + self.expect(&token::Not)?; + self.expect(&token::OpenDelim(token::Paren))?; + let expr = self.parse_expr()?; + self.expect(&token::CloseDelim(token::Paren))?; + let sp = self.error_on_incorrect_await(lo, self.prev_span, &expr, false); + return Ok((sp, ExprKind::Await(expr))) + } + + let is_question = self.eat(&token::Question); // Handle `await? `. + let expr = if self.token == token::OpenDelim(token::Brace) { + // Handle `await { }`. + // This needs to be handled separatedly from the next arm to avoid + // interpreting `await { }?` as `?.await`. + self.parse_block_expr( + None, + self.token.span, + BlockCheckMode::Default, + ThinVec::new(), + ) + } else { + self.parse_expr() + }.map_err(|mut err| { + err.span_label(await_sp, "while parsing this incorrect await expression"); + err + })?; + let sp = self.error_on_incorrect_await(lo, expr.span, &expr, is_question); + Ok((sp, ExprKind::Await(expr))) + } + + fn error_on_incorrect_await(&self, lo: Span, hi: Span, expr: &Expr, is_question: bool) -> Span { + let expr_str = self.span_to_snippet(expr.span) + .unwrap_or_else(|_| pprust::expr_to_string(&expr)); + let suggestion = format!("{}.await{}", expr_str, if is_question { "?" } else { "" }); + let sp = lo.to(hi); + let app = match expr.kind { + ExprKind::Try(_) => Applicability::MaybeIncorrect, // `await ?` + _ => Applicability::MachineApplicable, + }; + self.struct_span_err(sp, "incorrect use of `await`") + .span_suggestion(sp, "`await` is a postfix operation", suggestion, app) + .emit(); + sp + } + + /// If encountering `future.await()`, consumes and emits an error. + crate fn recover_from_await_method_call(&mut self) { + if self.token == token::OpenDelim(token::Paren) && + self.look_ahead(1, |t| t == &token::CloseDelim(token::Paren)) + { + // future.await() + let lo = self.token.span; + self.bump(); // ( + let sp = lo.to(self.token.span); + self.bump(); // ) + self.struct_span_err(sp, "incorrect use of `await`") + .span_suggestion( + sp, + "`await` is not a method call, remove the parentheses", + String::new(), + Applicability::MachineApplicable, + ).emit() + } + } + + /// Recovers a situation like `for ( $pat in $expr )` + /// and suggest writing `for $pat in $expr` instead. + /// + /// This should be called before parsing the `$block`. + crate fn recover_parens_around_for_head( + &mut self, + pat: P, + expr: &Expr, + begin_paren: Option, + ) -> P { + match (&self.token.kind, begin_paren) { + (token::CloseDelim(token::Paren), Some(begin_par_sp)) => { + self.bump(); + + let pat_str = self + // Remove the `(` from the span of the pattern: + .span_to_snippet(pat.span.trim_start(begin_par_sp).unwrap()) + .unwrap_or_else(|_| pprust::pat_to_string(&pat)); + + self.struct_span_err(self.prev_span, "unexpected closing `)`") + .span_label(begin_par_sp, "opening `(`") + .span_suggestion( + begin_par_sp.to(self.prev_span), + "remove parenthesis in `for` loop", + format!("{} in {}", pat_str, pprust::expr_to_string(&expr)), + // With e.g. `for (x) in y)` this would replace `(x) in y)` + // with `x) in y)` which is syntactically invalid. + // However, this is prevented before we get here. + Applicability::MachineApplicable, + ) + .emit(); + + // Unwrap `(pat)` into `pat` to avoid the `unused_parens` lint. + pat.and_then(|pat| match pat.kind { + PatKind::Paren(pat) => pat, + _ => P(pat), + }) + } + _ => pat, + } + } + + crate fn could_ascription_be_path(&self, node: &ast::ExprKind) -> bool { + self.token.is_ident() && + if let ast::ExprKind::Path(..) = node { true } else { false } && + !self.token.is_reserved_ident() && // v `foo:bar(baz)` + self.look_ahead(1, |t| t == &token::OpenDelim(token::Paren)) || + self.look_ahead(1, |t| t == &token::Lt) && // `foo:bar` + } + + crate fn recover_seq_parse_error( + &mut self, + delim: token::DelimToken, + lo: Span, + result: PResult<'a, P>, + ) -> P { + match result { + Ok(x) => x, + Err(mut err) => { + err.emit(); + // Recover from parse error. + self.consume_block(delim); + self.mk_expr(lo.to(self.prev_span), ExprKind::Err, ThinVec::new()) + } + } + } + + crate fn recover_closing_delimiter( + &mut self, + tokens: &[TokenKind], + mut err: DiagnosticBuilder<'a>, + ) -> PResult<'a, bool> { + let mut pos = None; + // We want to use the last closing delim that would apply. + for (i, unmatched) in self.unclosed_delims.iter().enumerate().rev() { + if tokens.contains(&token::CloseDelim(unmatched.expected_delim)) + && Some(self.token.span) > unmatched.unclosed_span + { + pos = Some(i); + } + } + match pos { + Some(pos) => { + // Recover and assume that the detected unclosed delimiter was meant for + // this location. Emit the diagnostic and act as if the delimiter was + // present for the parser's sake. + + // Don't attempt to recover from this unclosed delimiter more than once. + let unmatched = self.unclosed_delims.remove(pos); + let delim = TokenType::Token(token::CloseDelim(unmatched.expected_delim)); + + // We want to suggest the inclusion of the closing delimiter where it makes + // the most sense, which is immediately after the last token: + // + // {foo(bar {}} + // - ^ + // | | + // | help: `)` may belong here + // | + // unclosed delimiter + if let Some(sp) = unmatched.unclosed_span { + err.span_label(sp, "unclosed delimiter"); + } + err.span_suggestion_short( + self.sess.source_map().next_point(self.prev_span), + &format!("{} may belong here", delim.to_string()), + delim.to_string(), + Applicability::MaybeIncorrect, + ); + err.emit(); + self.expected_tokens.clear(); // reduce errors + Ok(true) + } + _ => Err(err), + } + } + + /// Recovers from `pub` keyword in places where it seems _reasonable_ but isn't valid. + crate fn eat_bad_pub(&mut self) { + if self.token.is_keyword(kw::Pub) { + match self.parse_visibility(false) { + Ok(vis) => { + self.diagnostic() + .struct_span_err(vis.span, "unnecessary visibility qualifier") + .span_label(vis.span, "`pub` not permitted here") + .emit(); + } + Err(mut err) => err.emit(), + } + } + } + + /// Eats tokens until we can be relatively sure we reached the end of the + /// statement. This is something of a best-effort heuristic. + /// + /// We terminate when we find an unmatched `}` (without consuming it). + crate fn recover_stmt(&mut self) { + self.recover_stmt_(SemiColonMode::Ignore, BlockMode::Ignore) + } + + /// If `break_on_semi` is `Break`, then we will stop consuming tokens after + /// finding (and consuming) a `;` outside of `{}` or `[]` (note that this is + /// approximate -- it can mean we break too early due to macros, but that + /// should only lead to sub-optimal recovery, not inaccurate parsing). + /// + /// If `break_on_block` is `Break`, then we will stop consuming tokens + /// after finding (and consuming) a brace-delimited block. + crate fn recover_stmt_(&mut self, break_on_semi: SemiColonMode, break_on_block: BlockMode) { + let mut brace_depth = 0; + let mut bracket_depth = 0; + let mut in_block = false; + debug!("recover_stmt_ enter loop (semi={:?}, block={:?})", + break_on_semi, break_on_block); + loop { + debug!("recover_stmt_ loop {:?}", self.token); + match self.token.kind { + token::OpenDelim(token::DelimToken::Brace) => { + brace_depth += 1; + self.bump(); + if break_on_block == BlockMode::Break && + brace_depth == 1 && + bracket_depth == 0 { + in_block = true; + } + } + token::OpenDelim(token::DelimToken::Bracket) => { + bracket_depth += 1; + self.bump(); + } + token::CloseDelim(token::DelimToken::Brace) => { + if brace_depth == 0 { + debug!("recover_stmt_ return - close delim {:?}", self.token); + break; + } + brace_depth -= 1; + self.bump(); + if in_block && bracket_depth == 0 && brace_depth == 0 { + debug!("recover_stmt_ return - block end {:?}", self.token); + break; + } + } + token::CloseDelim(token::DelimToken::Bracket) => { + bracket_depth -= 1; + if bracket_depth < 0 { + bracket_depth = 0; + } + self.bump(); + } + token::Eof => { + debug!("recover_stmt_ return - Eof"); + break; + } + token::Semi => { + self.bump(); + if break_on_semi == SemiColonMode::Break && + brace_depth == 0 && + bracket_depth == 0 { + debug!("recover_stmt_ return - Semi"); + break; + } + } + token::Comma if break_on_semi == SemiColonMode::Comma && + brace_depth == 0 && + bracket_depth == 0 => + { + debug!("recover_stmt_ return - Semi"); + break; + } + _ => { + self.bump() + } + } + } + } + + crate fn check_for_for_in_in_typo(&mut self, in_span: Span) { + if self.eat_keyword(kw::In) { + // a common typo: `for _ in in bar {}` + self.struct_span_err(self.prev_span, "expected iterable, found keyword `in`") + .span_suggestion_short( + in_span.until(self.prev_span), + "remove the duplicated `in`", + String::new(), + Applicability::MachineApplicable, + ) + .emit(); + } + } + + crate fn expected_semi_or_open_brace(&mut self) -> PResult<'a, T> { + let token_str = self.this_token_descr(); + let mut err = self.fatal(&format!("expected `;` or `{{`, found {}", token_str)); + err.span_label(self.token.span, "expected `;` or `{`"); + Err(err) + } + + crate fn eat_incorrect_doc_comment_for_param_type(&mut self) { + if let token::DocComment(_) = self.token.kind { + self.struct_span_err( + self.token.span, + "documentation comments cannot be applied to a function parameter's type", + ) + .span_label(self.token.span, "doc comments are not allowed here") + .emit(); + self.bump(); + } else if self.token == token::Pound && self.look_ahead(1, |t| { + *t == token::OpenDelim(token::Bracket) + }) { + let lo = self.token.span; + // Skip every token until next possible arg. + while self.token != token::CloseDelim(token::Bracket) { + self.bump(); + } + let sp = lo.to(self.token.span); + self.bump(); + self.struct_span_err( + sp, + "attributes cannot be applied to a function parameter's type", + ) + .span_label(sp, "attributes are not allowed here") + .emit(); + } + } + + crate fn parameter_without_type( + &mut self, + err: &mut DiagnosticBuilder<'_>, + pat: P, + require_name: bool, + is_self_allowed: bool, + is_trait_item: bool, + ) -> Option { + // 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()); + + err.span_suggestion( + span, + "declare the type after the parameter binding", + String::from(": "), + Applicability::HasPlaceholders, + ); + return Some(ident); + } else if let PatKind::Ident(_, ident, _) = pat.kind { + if require_name && ( + is_trait_item || + self.token == token::Comma || + self.token == token::Lt || + self.token == token::CloseDelim(token::Paren) + ) { // `fn foo(a, b) {}`, `fn foo(a, b) {}` or `fn foo(usize, usize) {}` + if is_self_allowed { + err.span_suggestion( + pat.span, + "if this is a `self` type, give it a parameter name", + format!("self: {}", ident), + Applicability::MaybeIncorrect, + ); + } + // Avoid suggesting that `fn foo(HashMap)` is fixed with a change to + // `fn foo(HashMap: TypeName)`. + if self.token != token::Lt { + 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, + "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)"); + + // Don't attempt to recover by using the `X` in `X` as the parameter name. + return if self.token == token::Lt { None } else { Some(ident) }; + } + } + None + } + + crate fn recover_arg_parse(&mut self) -> PResult<'a, (P, P)> { + let pat = self.parse_pat(Some("argument name"))?; + self.expect(&token::Colon)?; + let ty = self.parse_ty()?; + + self.diagnostic() + .struct_span_err_with_code( + pat.span, + "patterns aren't allowed in methods without bodies", + DiagnosticId::Error("E0642".into()), + ) + .span_suggestion_short( + pat.span, + "give this argument a name or use an underscore to ignore it", + "_".to_owned(), + Applicability::MachineApplicable, + ) + .emit(); + + // Pretend the pattern is `_`, to avoid duplicate errors from AST validation. + let pat = P(Pat { + kind: PatKind::Wild, + span: pat.span, + id: ast::DUMMY_NODE_ID + }); + Ok((pat, ty)) + } + + crate fn recover_bad_self_param( + &mut self, + mut param: ast::Param, + is_trait_item: bool, + ) -> PResult<'a, ast::Param> { + let sp = param.pat.span; + param.ty.kind = TyKind::Err; + let mut err = self.struct_span_err(sp, "unexpected `self` parameter in function"); + if is_trait_item { + err.span_label(sp, "must be the first associated function parameter"); + } else { + err.span_label(sp, "not valid as function parameter"); + err.note("`self` is only valid as the first parameter of an associated function"); + } + err.emit(); + Ok(param) + } + + crate fn consume_block(&mut self, delim: token::DelimToken) { + let mut brace_depth = 0; + loop { + if self.eat(&token::OpenDelim(delim)) { + brace_depth += 1; + } else if self.eat(&token::CloseDelim(delim)) { + if brace_depth == 0 { + return; + } else { + brace_depth -= 1; + continue; + } + } else if self.token == token::Eof || self.eat(&token::CloseDelim(token::NoDelim)) { + return; + } else { + self.bump(); + } + } + } + + crate fn expected_expression_found(&self) -> DiagnosticBuilder<'a> { + let (span, msg) = match (&self.token.kind, self.subparser_name) { + (&token::Eof, Some(origin)) => { + let sp = self.sess.source_map().next_point(self.token.span); + (sp, format!("expected expression, found end of {}", origin)) + } + _ => (self.token.span, format!( + "expected expression, found {}", + self.this_token_descr(), + )), + }; + let mut err = self.struct_span_err(span, &msg); + let sp = self.sess.source_map().start_point(self.token.span); + if let Some(sp) = self.sess.ambiguous_block_expr_parse.borrow().get(&sp) { + self.sess.expr_parentheses_needed(&mut err, *sp, None); + } + err.span_label(span, "expected expression"); + err + } + + fn consume_tts( + &mut self, + mut acc: i64, // `i64` because malformed code can have more closing delims than opening. + // Not using `FxHashMap` due to `token::TokenKind: !Eq + !Hash`. + modifier: &[(token::TokenKind, i64)], + ) { + while acc > 0 { + if let Some((_, val)) = modifier.iter().find(|(t, _)| *t == self.token.kind) { + acc += *val; + } + if self.token.kind == token::Eof { + break; + } + self.bump(); + } + } + + /// Replace duplicated recovered parameters with `_` pattern to avoid unecessary errors. + /// + /// This is necessary because at this point we don't know whether we parsed a function with + /// anonymous parameters or a function with names but no types. In order to minimize + /// unecessary errors, we assume the parameters are in the shape of `fn foo(a, b, c)` where + /// the parameters are *names* (so we don't emit errors about not being able to find `b` in + /// the local scope), but if we find the same name multiple times, like in `fn foo(i8, i8)`, + /// we deduplicate them to not complain about duplicated parameter names. + crate fn deduplicate_recovered_params_names(&self, fn_inputs: &mut Vec) { + let mut seen_inputs = FxHashSet::default(); + for input in fn_inputs.iter_mut() { + let opt_ident = if let (PatKind::Ident(_, ident, _), TyKind::Err) = ( + &input.pat.kind, &input.ty.kind, + ) { + Some(*ident) + } else { + None + }; + if let Some(ident) = opt_ident { + if seen_inputs.contains(&ident) { + input.pat.kind = PatKind::Wild; + } + seen_inputs.insert(ident); + } + } + } +} diff --git a/src/libsyntax/parse/parser/expr.rs b/src/libsyntax/parse/parser/expr.rs index dd0fd834fb0..6e52a07c61d 100644 --- a/src/libsyntax/parse/parser/expr.rs +++ b/src/libsyntax/parse/parser/expr.rs @@ -1,6 +1,7 @@ use super::{Parser, PResult, Restrictions, PrevTokenKind, TokenType, PathStyle, BlockMode}; use super::{SemiColonMode, SeqSep, TokenExpectType}; use super::pat::{GateOr, PARAM_EXPECTED}; +use super::diagnostics::Error; use crate::parse::literal::LitError; @@ -12,7 +13,6 @@ use crate::ast::{ use crate::maybe_recover_from_interpolated_ty_qpath; use crate::parse::classify; use crate::parse::token::{self, Token, TokenKind}; -use crate::parse::diagnostics::Error; use crate::print::pprust; use crate::ptr::P; use crate::source_map::{self, Span}; diff --git a/src/libsyntax/parse/parser/item.rs b/src/libsyntax/parse/parser/item.rs index 08c624b5539..90517d4d770 100644 --- a/src/libsyntax/parse/parser/item.rs +++ b/src/libsyntax/parse/parser/item.rs @@ -1,4 +1,6 @@ use super::{Parser, PResult, PathStyle, SemiColonMode, BlockMode}; +use super::diagnostics::{Error, dummy_arg}; + use crate::maybe_whole; use crate::ptr::P; use crate::ast::{self, DUMMY_NODE_ID, Ident, Attribute, AttrStyle, AnonConst, Item, ItemKind}; @@ -10,7 +12,6 @@ use crate::ast::{Mac, MacDelimiter, Block, BindingMode, FnDecl, MethodSig, SelfK use crate::ext::base::DummyResult; use crate::parse::token; use crate::parse::parser::maybe_append; -use crate::parse::diagnostics::{Error, dummy_arg}; use crate::tokenstream::{TokenTree, TokenStream}; use crate::symbol::{kw, sym}; use crate::source_map::{self, respan, Span}; diff --git a/src/libsyntax/parse/parser/module.rs b/src/libsyntax/parse/parser/module.rs index 2d2fb487d7d..20bd189cf8f 100644 --- a/src/libsyntax/parse/parser/module.rs +++ b/src/libsyntax/parse/parser/module.rs @@ -1,11 +1,11 @@ use super::{Parser, PResult}; use super::item::ItemInfo; +use super::diagnostics::Error; use crate::attr; use crate::ast::{self, Ident, Attribute, ItemKind, Mod, Crate}; use crate::parse::{new_sub_parser_from_file, DirectoryOwnership}; use crate::parse::token::{self, TokenKind}; -use crate::parse::diagnostics::{Error}; use crate::source_map::{SourceMap, Span, DUMMY_SP, FileName}; use crate::symbol::sym; diff --git a/src/libsyntax/parse/parser/stmt.rs b/src/libsyntax/parse/parser/stmt.rs index 855b03ddd6f..c8d6b6ff9dd 100644 --- a/src/libsyntax/parse/parser/stmt.rs +++ b/src/libsyntax/parse/parser/stmt.rs @@ -2,6 +2,7 @@ use super::{Parser, PResult, Restrictions, PrevTokenKind, SemiColonMode, BlockMo use super::expr::LhsExpr; use super::path::PathStyle; use super::pat::GateOr; +use super::diagnostics::Error; use crate::ptr::P; use crate::{maybe_whole, ThinVec}; @@ -9,7 +10,6 @@ use crate::ast::{self, DUMMY_NODE_ID, Stmt, StmtKind, Local, Block, BlockCheckMo use crate::ast::{Attribute, AttrStyle, VisibilityKind, MacStmtStyle, Mac, MacDelimiter}; use crate::ext::base::DummyResult; use crate::parse::{classify, DirectoryOwnership}; -use crate::parse::diagnostics::Error; use crate::parse::token; use crate::source_map::{respan, Span}; use crate::symbol::{kw, sym}; -- cgit 1.4.1-3-g733a5 From c189565edc5c9fc516170885b3a3061b936205fb Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 8 Oct 2019 09:35:34 +0200 Subject: syntax: reduce visibilities --- src/libsyntax/attr/mod.rs | 6 +-- src/libsyntax/ext/expand.rs | 2 +- src/libsyntax/parse/literal.rs | 2 +- src/libsyntax/parse/parser.rs | 60 ++++++++++++------------ src/libsyntax/parse/parser/attr.rs | 11 +++-- src/libsyntax/parse/parser/diagnostics.rs | 77 ++++++++++++++++--------------- src/libsyntax/parse/parser/expr.rs | 8 ++-- src/libsyntax/parse/parser/generics.rs | 2 +- src/libsyntax/parse/parser/item.rs | 6 +-- src/libsyntax/parse/parser/module.rs | 10 ++-- src/libsyntax/parse/parser/pat.rs | 4 +- src/libsyntax/parse/parser/path.rs | 6 +-- src/libsyntax/parse/parser/stmt.rs | 6 +-- src/libsyntax/parse/parser/ty.rs | 2 +- 14 files changed, 101 insertions(+), 101 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/attr/mod.rs b/src/libsyntax/attr/mod.rs index 9c1e0bcaa4a..65257c7e985 100644 --- a/src/libsyntax/attr/mod.rs +++ b/src/libsyntax/attr/mod.rs @@ -280,7 +280,7 @@ impl Attribute { self.item.meta(self.span) } - pub fn parse<'a, T, F>(&self, sess: &'a ParseSess, mut f: F) -> PResult<'a, T> + crate fn parse<'a, T, F>(&self, sess: &'a ParseSess, mut f: F) -> PResult<'a, T> where F: FnMut(&mut Parser<'a>) -> PResult<'a, T>, { let mut parser = Parser::new( @@ -298,14 +298,14 @@ impl Attribute { Ok(result) } - pub fn parse_derive_paths<'a>(&self, sess: &'a ParseSess) -> PResult<'a, Vec> { + crate fn parse_derive_paths<'a>(&self, sess: &'a ParseSess) -> PResult<'a, Vec> { if self.tokens.is_empty() { return Ok(Vec::new()); } self.parse(sess, |p| p.parse_derive_paths()) } - pub fn parse_meta<'a>(&self, sess: &'a ParseSess) -> PResult<'a, MetaItem> { + crate fn parse_meta<'a>(&self, sess: &'a ParseSess) -> PResult<'a, MetaItem> { Ok(MetaItem { path: self.path.clone(), kind: self.parse(sess, |parser| parser.parse_meta_item_kind())?, diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 2559e874762..44a51a01710 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -838,7 +838,7 @@ impl<'a> Parser<'a> { self.this_token_to_string()); // Avoid emitting backtrace info twice. let def_site_span = self.token.span.with_ctxt(SyntaxContext::root()); - let mut err = self.diagnostic().struct_span_err(def_site_span, &msg); + let mut err = self.struct_span_err(def_site_span, &msg); err.span_label(span, "caused by the macro expansion here"); let msg = format!( "the usage of `{}!` is likely invalid in {} context", diff --git a/src/libsyntax/parse/literal.rs b/src/libsyntax/parse/literal.rs index 14e1696610a..54e523430e4 100644 --- a/src/libsyntax/parse/literal.rs +++ b/src/libsyntax/parse/literal.rs @@ -212,7 +212,7 @@ impl Lit { /// Attempts to recover an AST literal from semantic literal. /// This function is used when the original token doesn't exist (e.g. the literal is created /// by an AST-based macro) or unavailable (e.g. from HIR pretty-printing). - pub fn from_lit_kind(kind: LitKind, span: Span) -> Lit { + crate fn from_lit_kind(kind: LitKind, span: Span) -> Lit { Lit { token: kind.to_lit_token(), kind, span } } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 6f55fd23e6e..7914fdbf978 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2,12 +2,10 @@ mod attr; mod expr; mod pat; mod item; -pub use item::AliasKind; mod module; -pub use module::{ModulePath, ModulePathSuccess}; mod ty; mod path; -pub use path::PathStyle; +crate use path::PathStyle; mod stmt; mod generics; mod diagnostics; @@ -46,14 +44,14 @@ bitflags::bitflags! { } #[derive(Clone, Copy, PartialEq, Debug)] -crate enum SemiColonMode { +enum SemiColonMode { Break, Ignore, Comma, } #[derive(Clone, Copy, PartialEq, Debug)] -crate enum BlockMode { +enum BlockMode { Break, Ignore, } @@ -126,33 +124,33 @@ pub struct Parser<'a> { prev_token_kind: PrevTokenKind, restrictions: Restrictions, /// Used to determine the path to externally loaded source files. - crate directory: Directory<'a>, + pub(super) directory: Directory<'a>, /// `true` to parse sub-modules in other files. - pub recurse_into_file_modules: bool, + pub(super) recurse_into_file_modules: bool, /// Name of the root module this parser originated from. If `None`, then the /// name is not known. This does not change while the parser is descending /// into modules, and sub-parsers have new values for this name. - pub root_module_name: Option, - crate expected_tokens: Vec, + crate root_module_name: Option, + expected_tokens: Vec, token_cursor: TokenCursor, desugar_doc_comments: bool, /// `true` we should configure out of line modules as we parse. - pub cfg_mods: bool, + cfg_mods: bool, /// This field is used to keep track of how many left angle brackets we have seen. This is /// required in order to detect extra leading left angle brackets (`<` characters) and error /// appropriately. /// /// See the comments in the `parse_path_segment` function for more details. - crate unmatched_angle_bracket_count: u32, - crate max_angle_bracket_count: u32, + unmatched_angle_bracket_count: u32, + max_angle_bracket_count: u32, /// A list of all unclosed delimiters found by the lexer. If an entry is used for error recovery /// it gets removed from here. Every entry left at the end gets emitted as an independent /// error. - crate unclosed_delims: Vec, - crate last_unexpected_token_span: Option, + pub(super) unclosed_delims: Vec, + last_unexpected_token_span: Option, crate last_type_ascription: Option<(Span, bool /* likely path typo */)>, /// If present, this `Parser` is not parsing Rust code but rather a macro call. - crate subparser_name: Option<&'static str>, + subparser_name: Option<&'static str>, } impl<'a> Drop for Parser<'a> { @@ -196,7 +194,7 @@ struct TokenCursorFrame { /// You can find some more example usage of this in the `collect_tokens` method /// on the parser. #[derive(Clone)] -crate enum LastToken { +enum LastToken { Collecting(Vec), Was(Option), } @@ -299,7 +297,7 @@ impl TokenCursor { } #[derive(Clone, PartialEq)] -crate enum TokenType { +enum TokenType { Token(TokenKind), Keyword(Symbol), Operator, @@ -311,7 +309,7 @@ crate enum TokenType { } impl TokenType { - crate fn to_string(&self) -> String { + fn to_string(&self) -> String { match *self { TokenType::Token(ref t) => format!("`{}`", pprust::token_kind_to_string(t)), TokenType::Keyword(kw) => format!("`{}`", kw), @@ -326,13 +324,13 @@ impl TokenType { } #[derive(Copy, Clone, Debug)] -crate enum TokenExpectType { +enum TokenExpectType { Expect, NoExpect, } impl<'a> Parser<'a> { - pub fn new( + crate fn new( sess: &'a ParseSess, tokens: TokenStream, directory: Option>, @@ -407,7 +405,7 @@ impl<'a> Parser<'a> { pprust::token_to_string(&self.token) } - crate fn token_descr(&self) -> Option<&'static str> { + fn token_descr(&self) -> Option<&'static str> { Some(match &self.token.kind { _ if self.token.is_special_ident() => "reserved identifier", _ if self.token.is_used_keyword() => "keyword", @@ -417,7 +415,7 @@ impl<'a> Parser<'a> { }) } - crate fn this_token_descr(&self) -> String { + pub(super) fn this_token_descr(&self) -> String { if let Some(prefix) = self.token_descr() { format!("{} `{}`", prefix, self.this_token_to_string()) } else { @@ -467,7 +465,7 @@ impl<'a> Parser<'a> { } } - pub fn parse_ident(&mut self) -> PResult<'a, ast::Ident> { + fn parse_ident(&mut self) -> PResult<'a, ast::Ident> { self.parse_ident_common(true) } @@ -500,7 +498,7 @@ impl<'a> Parser<'a> { /// /// This method will automatically add `tok` to `expected_tokens` if `tok` is not /// encountered. - crate fn check(&mut self, tok: &TokenKind) -> bool { + fn check(&mut self, tok: &TokenKind) -> bool { let is_present = self.token == *tok; if !is_present { self.expected_tokens.push(TokenType::Token(tok.clone())); } is_present @@ -522,7 +520,7 @@ impl<'a> Parser<'a> { /// If the next token is the given keyword, eats it and returns `true`. /// Otherwise, returns `false`. An expectation is also added for diagnostics purposes. - pub fn eat_keyword(&mut self, kw: Symbol) -> bool { + fn eat_keyword(&mut self, kw: Symbol) -> bool { if self.check_keyword(kw) { self.bump(); true @@ -560,7 +558,7 @@ impl<'a> Parser<'a> { } } - crate fn check_ident(&mut self) -> bool { + fn check_ident(&mut self) -> bool { self.check_or_expected(self.token.is_ident(), TokenType::Ident) } @@ -725,7 +723,7 @@ impl<'a> Parser<'a> { /// Parses a sequence, including the closing delimiter. The function /// `f` must consume tokens until reaching the next separator or /// closing bracket. - pub fn parse_seq_to_end( + fn parse_seq_to_end( &mut self, ket: &TokenKind, sep: SeqSep, @@ -741,7 +739,7 @@ impl<'a> Parser<'a> { /// Parses a sequence, not including the closing delimiter. The function /// `f` must consume tokens until reaching the next separator or /// closing bracket. - pub fn parse_seq_to_before_end( + fn parse_seq_to_before_end( &mut self, ket: &TokenKind, sep: SeqSep, @@ -759,7 +757,7 @@ impl<'a> Parser<'a> { }) } - crate fn parse_seq_to_before_tokens( + fn parse_seq_to_before_tokens( &mut self, kets: &[&TokenKind], sep: SeqSep, @@ -1101,7 +1099,7 @@ impl<'a> Parser<'a> { /// If the following element can't be a tuple (i.e., it's a function definition), then /// it's not a tuple struct field), and the contents within the parentheses isn't valid, /// so emit a proper diagnostic. - pub fn parse_visibility(&mut self, can_take_tuple: bool) -> PResult<'a, Visibility> { + crate fn parse_visibility(&mut self, can_take_tuple: bool) -> PResult<'a, Visibility> { maybe_whole!(self, NtVis, |x| x); self.expected_tokens.push(TokenType::Keyword(kw::Crate)); @@ -1325,7 +1323,7 @@ impl<'a> Parser<'a> { *t == token::BinOp(token::Star)) } - pub fn parse_optional_str(&mut self) -> Option<(Symbol, ast::StrStyle, Option)> { + fn parse_optional_str(&mut self) -> Option<(Symbol, ast::StrStyle, Option)> { let ret = match self.token.kind { token::Literal(token::Lit { kind: token::Str, symbol, suffix }) => (symbol, ast::StrStyle::Cooked, suffix), diff --git a/src/libsyntax/parse/parser/attr.rs b/src/libsyntax/parse/parser/attr.rs index 07689df389c..cfd10e443e9 100644 --- a/src/libsyntax/parse/parser/attr.rs +++ b/src/libsyntax/parse/parser/attr.rs @@ -20,7 +20,7 @@ const DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG: &str = "an inner attribute is not \ impl<'a> Parser<'a> { /// Parses attributes that appear before an item. - crate fn parse_outer_attributes(&mut self) -> PResult<'a, Vec> { + pub(super) fn parse_outer_attributes(&mut self) -> PResult<'a, Vec> { let mut attrs: Vec = Vec::new(); let mut just_parsed_doc_comment = false; loop { @@ -66,7 +66,7 @@ impl<'a> Parser<'a> { /// /// If `permit_inner` is `true`, then a leading `!` indicates an inner /// attribute. - pub fn parse_attribute(&mut self, permit_inner: bool) -> PResult<'a, ast::Attribute> { + fn parse_attribute(&mut self, permit_inner: bool) -> PResult<'a, ast::Attribute> { debug!("parse_attribute: permit_inner={:?} self.token={:?}", permit_inner, self.token); @@ -84,9 +84,10 @@ impl<'a> Parser<'a> { /// The same as `parse_attribute`, except it takes in an `InnerAttributeParsePolicy` /// that prescribes how to handle inner attributes. - fn parse_attribute_with_inner_parse_policy(&mut self, - inner_parse_policy: InnerAttributeParsePolicy<'_>) - -> PResult<'a, ast::Attribute> { + fn parse_attribute_with_inner_parse_policy( + &mut self, + inner_parse_policy: InnerAttributeParsePolicy<'_> + ) -> PResult<'a, ast::Attribute> { debug!("parse_attribute_with_inner_parse_policy: inner_parse_policy={:?} self.token={:?}", inner_parse_policy, self.token); diff --git a/src/libsyntax/parse/parser/diagnostics.rs b/src/libsyntax/parse/parser/diagnostics.rs index 943838d9dda..a6884ec2c72 100644 --- a/src/libsyntax/parse/parser/diagnostics.rs +++ b/src/libsyntax/parse/parser/diagnostics.rs @@ -17,8 +17,9 @@ use log::{debug, trace}; use std::mem; const TURBOFISH: &'static str = "use `::<...>` instead of `<...>` to specify type arguments"; + /// Creates a placeholder argument. -crate fn dummy_arg(ident: Ident) -> Param { +pub(super) fn dummy_arg(ident: Ident) -> Param { let pat = P(Pat { id: ast::DUMMY_NODE_ID, kind: PatKind::Ident(BindingMode::ByValue(Mutability::Immutable), ident, None), @@ -121,7 +122,7 @@ impl Error { } } -pub trait RecoverQPath: Sized + 'static { +pub(super) trait RecoverQPath: Sized + 'static { const PATH_STYLE: PathStyle = PathStyle::Expr; fn to_ty(&self) -> Option>; fn recovered(qself: Option, path: ast::Path) -> Self; @@ -169,23 +170,23 @@ impl RecoverQPath for Expr { } impl<'a> Parser<'a> { - pub fn fatal(&self, m: &str) -> DiagnosticBuilder<'a> { + crate fn fatal(&self, m: &str) -> DiagnosticBuilder<'a> { self.span_fatal(self.token.span, m) } - pub fn span_fatal>(&self, sp: S, m: &str) -> DiagnosticBuilder<'a> { + crate fn span_fatal>(&self, sp: S, m: &str) -> DiagnosticBuilder<'a> { self.sess.span_diagnostic.struct_span_fatal(sp, m) } - pub fn span_fatal_err>(&self, sp: S, err: Error) -> DiagnosticBuilder<'a> { + pub(super) fn span_fatal_err>(&self, sp: S, err: Error) -> DiagnosticBuilder<'a> { err.span_err(sp, self.diagnostic()) } - pub fn bug(&self, m: &str) -> ! { + pub(super) fn bug(&self, m: &str) -> ! { self.sess.span_diagnostic.span_bug(self.token.span, m) } - pub fn span_err>(&self, sp: S, m: &str) { + pub(super) fn span_err>(&self, sp: S, m: &str) { self.sess.span_diagnostic.span_err(sp, m) } @@ -197,15 +198,15 @@ impl<'a> Parser<'a> { self.sess.span_diagnostic.span_bug(sp, m) } - crate fn diagnostic(&self) -> &'a errors::Handler { + pub(super) fn diagnostic(&self) -> &'a errors::Handler { &self.sess.span_diagnostic } - crate fn span_to_snippet(&self, span: Span) -> Result { + pub(super) fn span_to_snippet(&self, span: Span) -> Result { self.sess.source_map().span_to_snippet(span) } - crate fn expected_ident_found(&self) -> DiagnosticBuilder<'a> { + pub(super) fn expected_ident_found(&self) -> DiagnosticBuilder<'a> { let mut err = self.struct_span_err( self.token.span, &format!("expected identifier, found {}", self.this_token_descr()), @@ -236,7 +237,7 @@ impl<'a> Parser<'a> { err } - pub fn expected_one_of_not_found( + pub(super) fn expected_one_of_not_found( &mut self, edible: &[TokenKind], inedible: &[TokenKind], @@ -423,7 +424,7 @@ impl<'a> Parser<'a> { /// Eats and discards tokens until one of `kets` is encountered. Respects token trees, /// passes through any errors encountered. Used for error recovery. - crate fn eat_to_tokens(&mut self, kets: &[&TokenKind]) { + pub(super) fn eat_to_tokens(&mut self, kets: &[&TokenKind]) { if let Err(ref mut err) = self.parse_seq_to_before_tokens( kets, SeqSep::none(), @@ -441,7 +442,7 @@ impl<'a> Parser<'a> { /// let _ = vec![1, 2, 3].into_iter().collect::>>>(); /// ^^ help: remove extra angle brackets /// ``` - crate fn check_trailing_angle_brackets(&mut self, segment: &PathSegment, end: TokenKind) { + pub(super) fn check_trailing_angle_brackets(&mut self, segment: &PathSegment, end: TokenKind) { // This function is intended to be invoked after parsing a path segment where there are two // cases: // @@ -560,7 +561,7 @@ impl<'a> Parser<'a> { /// inner_op r2 /// / \ /// l1 r1 - crate fn check_no_chained_comparison( + pub(super) fn check_no_chained_comparison( &mut self, lhs: &Expr, outer_op: &AssocOp, @@ -695,7 +696,7 @@ impl<'a> Parser<'a> { } } - crate fn maybe_report_ambiguous_plus( + pub(super) fn maybe_report_ambiguous_plus( &mut self, allow_plus: bool, impl_dyn_multi: bool, @@ -768,7 +769,7 @@ impl<'a> Parser<'a> { /// Tries to recover from associated item paths like `[T]::AssocItem` / `(T, U)::AssocItem`. /// Attempts to convert the base expression/pattern/type into a type, parses the `::AssocItem` /// tail, and combines them into a `::AssocItem` expression/pattern/type. - crate fn maybe_recover_from_bad_qpath( + pub(super) fn maybe_recover_from_bad_qpath( &mut self, base: P, allow_recovery: bool, @@ -784,7 +785,7 @@ impl<'a> Parser<'a> { /// Given an already parsed `Ty`, parses the `::AssocItem` tail and /// combines them into a `::AssocItem` expression/pattern/type. - crate fn maybe_recover_from_bad_qpath_stage_2( + pub(super) fn maybe_recover_from_bad_qpath_stage_2( &mut self, ty_span: Span, ty: P, @@ -823,7 +824,7 @@ impl<'a> Parser<'a> { ))) } - crate fn maybe_consume_incorrect_semicolon(&mut self, items: &[P]) -> bool { + pub(super) fn maybe_consume_incorrect_semicolon(&mut self, items: &[P]) -> bool { if self.eat(&token::Semi) { let mut err = self.struct_span_err(self.prev_span, "expected item, found `;`"); err.span_suggestion_short( @@ -859,7 +860,7 @@ impl<'a> Parser<'a> { /// Creates a `DiagnosticBuilder` for an unexpected token `t` and tries to recover if it is a /// closing delimiter. - pub fn unexpected_try_recover( + pub(super) fn unexpected_try_recover( &mut self, t: &TokenKind, ) -> PResult<'a, bool /* recovered */> { @@ -909,7 +910,7 @@ impl<'a> Parser<'a> { Err(err) } - crate fn parse_semi_or_incorrect_foreign_fn_body( + pub(super) fn parse_semi_or_incorrect_foreign_fn_body( &mut self, ident: &Ident, extern_sp: Span, @@ -947,7 +948,7 @@ impl<'a> Parser<'a> { /// Consumes alternative await syntaxes like `await!()`, `await `, /// `await? `, `await()`, and `await { }`. - crate fn parse_incorrect_await_syntax( + pub(super) fn parse_incorrect_await_syntax( &mut self, lo: Span, await_sp: Span, @@ -999,7 +1000,7 @@ impl<'a> Parser<'a> { } /// If encountering `future.await()`, consumes and emits an error. - crate fn recover_from_await_method_call(&mut self) { + pub(super) fn recover_from_await_method_call(&mut self) { if self.token == token::OpenDelim(token::Paren) && self.look_ahead(1, |t| t == &token::CloseDelim(token::Paren)) { @@ -1022,7 +1023,7 @@ impl<'a> Parser<'a> { /// and suggest writing `for $pat in $expr` instead. /// /// This should be called before parsing the `$block`. - crate fn recover_parens_around_for_head( + pub(super) fn recover_parens_around_for_head( &mut self, pat: P, expr: &Expr, @@ -1060,7 +1061,7 @@ impl<'a> Parser<'a> { } } - crate fn could_ascription_be_path(&self, node: &ast::ExprKind) -> bool { + pub(super) fn could_ascription_be_path(&self, node: &ast::ExprKind) -> bool { self.token.is_ident() && if let ast::ExprKind::Path(..) = node { true } else { false } && !self.token.is_reserved_ident() && // v `foo:bar(baz)` @@ -1074,7 +1075,7 @@ impl<'a> Parser<'a> { self.look_ahead(2, |t| t == &token::Lt)) // `foo:bar::` } - crate fn recover_seq_parse_error( + pub(super) fn recover_seq_parse_error( &mut self, delim: token::DelimToken, lo: Span, @@ -1091,7 +1092,7 @@ impl<'a> Parser<'a> { } } - crate fn recover_closing_delimiter( + pub(super) fn recover_closing_delimiter( &mut self, tokens: &[TokenKind], mut err: DiagnosticBuilder<'a>, @@ -1142,7 +1143,7 @@ impl<'a> Parser<'a> { } /// Recovers from `pub` keyword in places where it seems _reasonable_ but isn't valid. - crate fn eat_bad_pub(&mut self) { + pub(super) fn eat_bad_pub(&mut self) { if self.token.is_keyword(kw::Pub) { match self.parse_visibility(false) { Ok(vis) => { @@ -1160,7 +1161,7 @@ impl<'a> Parser<'a> { /// statement. This is something of a best-effort heuristic. /// /// We terminate when we find an unmatched `}` (without consuming it). - crate fn recover_stmt(&mut self) { + pub(super) fn recover_stmt(&mut self) { self.recover_stmt_(SemiColonMode::Ignore, BlockMode::Ignore) } @@ -1171,7 +1172,7 @@ impl<'a> Parser<'a> { /// /// If `break_on_block` is `Break`, then we will stop consuming tokens /// after finding (and consuming) a brace-delimited block. - crate fn recover_stmt_(&mut self, break_on_semi: SemiColonMode, break_on_block: BlockMode) { + pub(super) fn recover_stmt_(&mut self, break_on_semi: SemiColonMode, break_on_block: BlockMode) { let mut brace_depth = 0; let mut bracket_depth = 0; let mut in_block = false; @@ -1239,7 +1240,7 @@ impl<'a> Parser<'a> { } } - crate fn check_for_for_in_in_typo(&mut self, in_span: Span) { + pub(super) fn check_for_for_in_in_typo(&mut self, in_span: Span) { if self.eat_keyword(kw::In) { // a common typo: `for _ in in bar {}` self.struct_span_err(self.prev_span, "expected iterable, found keyword `in`") @@ -1253,14 +1254,14 @@ impl<'a> Parser<'a> { } } - crate fn expected_semi_or_open_brace(&mut self) -> PResult<'a, T> { + pub(super) fn expected_semi_or_open_brace(&mut self) -> PResult<'a, T> { let token_str = self.this_token_descr(); let mut err = self.fatal(&format!("expected `;` or `{{`, found {}", token_str)); err.span_label(self.token.span, "expected `;` or `{`"); Err(err) } - crate fn eat_incorrect_doc_comment_for_param_type(&mut self) { + pub(super) fn eat_incorrect_doc_comment_for_param_type(&mut self) { if let token::DocComment(_) = self.token.kind { self.struct_span_err( self.token.span, @@ -1288,7 +1289,7 @@ impl<'a> Parser<'a> { } } - crate fn parameter_without_type( + pub(super) fn parameter_without_type( &mut self, err: &mut DiagnosticBuilder<'_>, pat: P, @@ -1351,7 +1352,7 @@ impl<'a> Parser<'a> { None } - crate fn recover_arg_parse(&mut self) -> PResult<'a, (P, P)> { + pub(super) fn recover_arg_parse(&mut self) -> PResult<'a, (P, P)> { let pat = self.parse_pat(Some("argument name"))?; self.expect(&token::Colon)?; let ty = self.parse_ty()?; @@ -1379,7 +1380,7 @@ impl<'a> Parser<'a> { Ok((pat, ty)) } - crate fn recover_bad_self_param( + pub(super) fn recover_bad_self_param( &mut self, mut param: ast::Param, is_trait_item: bool, @@ -1397,7 +1398,7 @@ impl<'a> Parser<'a> { Ok(param) } - crate fn consume_block(&mut self, delim: token::DelimToken) { + pub(super) fn consume_block(&mut self, delim: token::DelimToken) { let mut brace_depth = 0; loop { if self.eat(&token::OpenDelim(delim)) { @@ -1417,7 +1418,7 @@ impl<'a> Parser<'a> { } } - crate fn expected_expression_found(&self) -> DiagnosticBuilder<'a> { + pub(super) fn expected_expression_found(&self) -> DiagnosticBuilder<'a> { let (span, msg) = match (&self.token.kind, self.subparser_name) { (&token::Eof, Some(origin)) => { let sp = self.sess.source_map().next_point(self.token.span); @@ -1462,7 +1463,7 @@ impl<'a> Parser<'a> { /// the parameters are *names* (so we don't emit errors about not being able to find `b` in /// the local scope), but if we find the same name multiple times, like in `fn foo(i8, i8)`, /// we deduplicate them to not complain about duplicated parameter names. - crate fn deduplicate_recovered_params_names(&self, fn_inputs: &mut Vec) { + pub(super) fn deduplicate_recovered_params_names(&self, fn_inputs: &mut Vec) { let mut seen_inputs = FxHashSet::default(); for input in fn_inputs.iter_mut() { let opt_ident = if let (PatKind::Ident(_, ident, _), TyKind::Err) = ( diff --git a/src/libsyntax/parse/parser/expr.rs b/src/libsyntax/parse/parser/expr.rs index 6e52a07c61d..2e6b9de7693 100644 --- a/src/libsyntax/parse/parser/expr.rs +++ b/src/libsyntax/parse/parser/expr.rs @@ -1074,7 +1074,7 @@ impl<'a> Parser<'a> { } /// Matches `lit = true | false | token_lit`. - crate fn parse_lit(&mut self) -> PResult<'a, Lit> { + pub(super) fn parse_lit(&mut self) -> PResult<'a, Lit> { let mut recovered = None; if self.token == token::Dot { // Attempt to recover `.4` as `0.4`. @@ -1253,7 +1253,7 @@ impl<'a> Parser<'a> { } /// Parses a block or unsafe block. - crate fn parse_block_expr( + pub(super) fn parse_block_expr( &mut self, opt_label: Option