Move some parser recovery methods to diagnostics
This commit is contained in:
parent
27a2881402
commit
4117c6d33c
@ -1,14 +1,16 @@
|
|||||||
use crate::ast;
|
use crate::ast;
|
||||||
use crate::ast::{BlockCheckMode, Expr, ExprKind, Item, ItemKind, Pat, PatKind, QSelf, Ty, TyKind};
|
use crate::ast::{BlockCheckMode, Expr, ExprKind, Item, ItemKind, Pat, PatKind, QSelf, Ty, TyKind};
|
||||||
use crate::parse::parser::PathStyle;
|
use crate::parse::parser::{BlockMode, PathStyle, TokenType, SemiColonMode};
|
||||||
use crate::parse::token;
|
use crate::parse::token;
|
||||||
use crate::parse::PResult;
|
use crate::parse::PResult;
|
||||||
use crate::parse::Parser;
|
use crate::parse::Parser;
|
||||||
use crate::print::pprust;
|
use crate::print::pprust;
|
||||||
use crate::ptr::P;
|
use crate::ptr::P;
|
||||||
|
use crate::symbol::keywords;
|
||||||
use crate::ThinVec;
|
use crate::ThinVec;
|
||||||
use errors::Applicability;
|
use errors::{Applicability, DiagnosticBuilder};
|
||||||
use syntax_pos::Span;
|
use syntax_pos::Span;
|
||||||
|
use log::debug;
|
||||||
|
|
||||||
pub trait RecoverQPath: Sized + 'static {
|
pub trait RecoverQPath: Sized + 'static {
|
||||||
const PATH_STYLE: PathStyle = PathStyle::Expr;
|
const PATH_STYLE: PathStyle = PathStyle::Expr;
|
||||||
@ -261,4 +263,266 @@ impl<'a> Parser<'a> {
|
|||||||
.emit();
|
.emit();
|
||||||
Ok((sp, ExprKind::Await(ast::AwaitOrigin::FieldLike, expr)))
|
Ok((sp, ExprKind::Await(ast::AwaitOrigin::FieldLike, expr)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// If encountering `future.await()`, consume and emit 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.span;
|
||||||
|
self.bump(); // (
|
||||||
|
let sp = lo.to(self.span);
|
||||||
|
self.bump(); // )
|
||||||
|
let mut err = self.struct_span_err(sp, "incorrect use of `await`");
|
||||||
|
err.span_suggestion(
|
||||||
|
sp,
|
||||||
|
"`await` is not a method call, remove the parentheses",
|
||||||
|
String::new(),
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
);
|
||||||
|
err.emit()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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<baz`
|
||||||
|
self.look_ahead(2, |t| t.is_ident()) ||
|
||||||
|
self.look_ahead(1, |t| t == &token::Colon) && // `foo:bar:baz`
|
||||||
|
self.look_ahead(2, |t| t.is_ident()) ||
|
||||||
|
self.look_ahead(1, |t| t == &token::ModSep) && // `foo:bar::baz`
|
||||||
|
self.look_ahead(2, |t| t.is_ident())
|
||||||
|
}
|
||||||
|
|
||||||
|
crate fn bad_type_ascription(
|
||||||
|
&self,
|
||||||
|
err: &mut DiagnosticBuilder<'a>,
|
||||||
|
lhs_span: Span,
|
||||||
|
cur_op_span: Span,
|
||||||
|
next_sp: Span,
|
||||||
|
maybe_path: bool,
|
||||||
|
) {
|
||||||
|
err.span_label(self.span, "expecting a type here because of type ascription");
|
||||||
|
let cm = self.sess.source_map();
|
||||||
|
let next_pos = cm.lookup_char_pos(next_sp.lo());
|
||||||
|
let op_pos = cm.lookup_char_pos(cur_op_span.hi());
|
||||||
|
if op_pos.line != next_pos.line {
|
||||||
|
err.span_suggestion(
|
||||||
|
cur_op_span,
|
||||||
|
"try using a semicolon",
|
||||||
|
";".to_string(),
|
||||||
|
Applicability::MaybeIncorrect,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
if maybe_path {
|
||||||
|
err.span_suggestion(
|
||||||
|
cur_op_span,
|
||||||
|
"maybe you meant to write a path separator here",
|
||||||
|
"::".to_string(),
|
||||||
|
Applicability::MaybeIncorrect,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
err.note("type ascription is a nightly-only feature that lets \
|
||||||
|
you annotate an expression with a type: `<expr>: <type>`");
|
||||||
|
err.span_note(
|
||||||
|
lhs_span,
|
||||||
|
"this expression expects an ascribed type after the colon",
|
||||||
|
);
|
||||||
|
err.help("this might be indicative of a syntax error elsewhere");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
crate fn recover_seq_parse_error(
|
||||||
|
&mut self,
|
||||||
|
delim: token::DelimToken,
|
||||||
|
lo: Span,
|
||||||
|
result: PResult<'a, P<Expr>>,
|
||||||
|
) -> P<Expr> {
|
||||||
|
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: &[token::Token],
|
||||||
|
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.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 (FIXME: #58270)
|
||||||
|
// |
|
||||||
|
// 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),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Recover 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(keywords::Pub) {
|
||||||
|
match self.parse_visibility(false) {
|
||||||
|
Ok(vis) => {
|
||||||
|
let mut err = self.diagnostic()
|
||||||
|
.struct_span_err(vis.span, "unnecessary visibility qualifier");
|
||||||
|
err.span_label(vis.span, "`pub` not permitted here");
|
||||||
|
err.emit();
|
||||||
|
}
|
||||||
|
Err(mut err) => err.emit(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Eat 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 {
|
||||||
|
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;
|
||||||
|
} else {
|
||||||
|
self.bump();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
self.bump()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -104,14 +104,14 @@ pub enum PathStyle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Debug)]
|
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||||
enum SemiColonMode {
|
crate enum SemiColonMode {
|
||||||
Break,
|
Break,
|
||||||
Ignore,
|
Ignore,
|
||||||
Comma,
|
Comma,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Debug)]
|
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||||
enum BlockMode {
|
crate enum BlockMode {
|
||||||
Break,
|
Break,
|
||||||
Ignore,
|
Ignore,
|
||||||
}
|
}
|
||||||
@ -389,7 +389,7 @@ crate enum TokenType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl TokenType {
|
impl TokenType {
|
||||||
fn to_string(&self) -> String {
|
crate fn to_string(&self) -> String {
|
||||||
match *self {
|
match *self {
|
||||||
TokenType::Token(ref t) => format!("`{}`", pprust::token_to_string(t)),
|
TokenType::Token(ref t) => format!("`{}`", pprust::token_to_string(t)),
|
||||||
TokenType::Keyword(kw) => format!("`{}`", kw.name()),
|
TokenType::Keyword(kw) => format!("`{}`", kw.name()),
|
||||||
@ -673,56 +673,6 @@ impl<'a> Parser<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn recover_closing_delimiter(
|
|
||||||
&mut self,
|
|
||||||
tokens: &[token::Token],
|
|
||||||
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.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 (FIXME: #58270)
|
|
||||||
// |
|
|
||||||
// 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),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Expect next token to be edible or inedible token. If edible,
|
/// Expect next token to be edible or inedible token. If edible,
|
||||||
/// then consume it; if inedible, then return without consuming
|
/// then consume it; if inedible, then return without consuming
|
||||||
/// anything. Signal a fatal error if next token is unexpected.
|
/// anything. Signal a fatal error if next token is unexpected.
|
||||||
@ -2343,7 +2293,7 @@ impl<'a> Parser<'a> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mk_expr(&self, span: Span, node: ExprKind, attrs: ThinVec<Attribute>) -> P<Expr> {
|
crate fn mk_expr(&self, span: Span, node: ExprKind, attrs: ThinVec<Attribute>) -> P<Expr> {
|
||||||
P(Expr { node, span, attrs, id: ast::DUMMY_NODE_ID })
|
P(Expr { node, span, attrs, id: ast::DUMMY_NODE_ID })
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2936,23 +2886,7 @@ impl<'a> Parser<'a> {
|
|||||||
ExprKind::Await(ast::AwaitOrigin::FieldLike, self_arg),
|
ExprKind::Await(ast::AwaitOrigin::FieldLike, self_arg),
|
||||||
ThinVec::new(),
|
ThinVec::new(),
|
||||||
);
|
);
|
||||||
if self.token == token::OpenDelim(token::Paren) &&
|
self.recover_from_await_method_call();
|
||||||
self.look_ahead(1, |t| t == &token::CloseDelim(token::Paren))
|
|
||||||
{
|
|
||||||
// future.await()
|
|
||||||
let lo = self.span;
|
|
||||||
self.bump(); // (
|
|
||||||
let sp = lo.to(self.span);
|
|
||||||
self.bump(); // )
|
|
||||||
let mut err = self.struct_span_err(sp, "incorrect use of `await`");
|
|
||||||
err.span_suggestion(
|
|
||||||
sp,
|
|
||||||
"`await` is not a method call, remove the parentheses",
|
|
||||||
String::new(),
|
|
||||||
Applicability::MachineApplicable,
|
|
||||||
);
|
|
||||||
err.emit()
|
|
||||||
}
|
|
||||||
return Ok(await_expr);
|
return Ok(await_expr);
|
||||||
}
|
}
|
||||||
let segment = self.parse_path_segment(PathStyle::Expr)?;
|
let segment = self.parse_path_segment(PathStyle::Expr)?;
|
||||||
@ -3191,23 +3125,6 @@ impl<'a> Parser<'a> {
|
|||||||
return Ok(e);
|
return Ok(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn recover_seq_parse_error(
|
|
||||||
&mut self,
|
|
||||||
delim: token::DelimToken,
|
|
||||||
lo: Span,
|
|
||||||
result: PResult<'a, P<Expr>>,
|
|
||||||
) -> P<Expr> {
|
|
||||||
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 process_potential_macro_variable(&mut self) {
|
crate fn process_potential_macro_variable(&mut self) {
|
||||||
let (token, span) = match self.token {
|
let (token, span) = match self.token {
|
||||||
token::Dollar if self.span.ctxt() != syntax_pos::hygiene::SyntaxContext::empty() &&
|
token::Dollar if self.span.ctxt() != syntax_pos::hygiene::SyntaxContext::empty() &&
|
||||||
@ -3610,58 +3527,6 @@ impl<'a> Parser<'a> {
|
|||||||
Ok(lhs)
|
Ok(lhs)
|
||||||
}
|
}
|
||||||
|
|
||||||
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<baz`
|
|
||||||
self.look_ahead(2, |t| t.is_ident()) ||
|
|
||||||
self.look_ahead(1, |t| t == &token::Colon) && // `foo:bar:baz`
|
|
||||||
self.look_ahead(2, |t| t.is_ident()) ||
|
|
||||||
self.look_ahead(1, |t| t == &token::ModSep) && // `foo:bar::baz`
|
|
||||||
self.look_ahead(2, |t| t.is_ident())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn bad_type_ascription(
|
|
||||||
&self,
|
|
||||||
err: &mut DiagnosticBuilder<'a>,
|
|
||||||
lhs_span: Span,
|
|
||||||
cur_op_span: Span,
|
|
||||||
next_sp: Span,
|
|
||||||
maybe_path: bool,
|
|
||||||
) {
|
|
||||||
err.span_label(self.span, "expecting a type here because of type ascription");
|
|
||||||
let cm = self.sess.source_map();
|
|
||||||
let next_pos = cm.lookup_char_pos(next_sp.lo());
|
|
||||||
let op_pos = cm.lookup_char_pos(cur_op_span.hi());
|
|
||||||
if op_pos.line != next_pos.line {
|
|
||||||
err.span_suggestion(
|
|
||||||
cur_op_span,
|
|
||||||
"try using a semicolon",
|
|
||||||
";".to_string(),
|
|
||||||
Applicability::MaybeIncorrect,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
if maybe_path {
|
|
||||||
err.span_suggestion(
|
|
||||||
cur_op_span,
|
|
||||||
"maybe you meant to write a path separator here",
|
|
||||||
"::".to_string(),
|
|
||||||
Applicability::MaybeIncorrect,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
err.note("type ascription is a nightly-only feature that lets \
|
|
||||||
you annotate an expression with a type: `<expr>: <type>`");
|
|
||||||
err.span_note(
|
|
||||||
lhs_span,
|
|
||||||
"this expression expects an ascribed type after the colon",
|
|
||||||
);
|
|
||||||
err.help("this might be indicative of a syntax error elsewhere");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_assoc_op_cast(&mut self, lhs: P<Expr>, lhs_span: Span,
|
fn parse_assoc_op_cast(&mut self, lhs: P<Expr>, lhs_span: Span,
|
||||||
expr_kind: fn(P<Expr>, P<Ty>) -> ExprKind)
|
expr_kind: fn(P<Expr>, P<Ty>) -> ExprKind)
|
||||||
-> PResult<'a, P<Expr>> {
|
-> PResult<'a, P<Expr>> {
|
||||||
@ -4943,92 +4808,6 @@ impl<'a> Parser<'a> {
|
|||||||
Ok(self.parse_stmt_(true))
|
Ok(self.parse_stmt_(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Eat 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).
|
|
||||||
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.
|
|
||||||
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 {
|
|
||||||
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;
|
|
||||||
} else {
|
|
||||||
self.bump();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
self.bump()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_stmt_(&mut self, macro_legacy_warnings: bool) -> Option<Stmt> {
|
fn parse_stmt_(&mut self, macro_legacy_warnings: bool) -> Option<Stmt> {
|
||||||
self.parse_stmt_without_recovery(macro_legacy_warnings).unwrap_or_else(|mut e| {
|
self.parse_stmt_without_recovery(macro_legacy_warnings).unwrap_or_else(|mut e| {
|
||||||
e.emit();
|
e.emit();
|
||||||
@ -6932,26 +6711,6 @@ impl<'a> Parser<'a> {
|
|||||||
Ok((class_name, ItemKind::Union(vdata, generics), None))
|
Ok((class_name, ItemKind::Union(vdata, generics), None))
|
||||||
}
|
}
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_record_struct_body(
|
fn parse_record_struct_body(
|
||||||
&mut self,
|
&mut self,
|
||||||
) -> PResult<'a, (Vec<StructField>, /* recovered */ bool)> {
|
) -> PResult<'a, (Vec<StructField>, /* recovered */ bool)> {
|
||||||
@ -8649,21 +8408,6 @@ impl<'a> Parser<'a> {
|
|||||||
).emit();
|
).emit();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Recover from `pub` keyword in places where it seems _reasonable_ but isn't valid.
|
|
||||||
fn eat_bad_pub(&mut self) {
|
|
||||||
if self.token.is_keyword(keywords::Pub) {
|
|
||||||
match self.parse_visibility(false) {
|
|
||||||
Ok(vis) => {
|
|
||||||
let mut err = self.diagnostic()
|
|
||||||
.struct_span_err(vis.span, "unnecessary visibility qualifier");
|
|
||||||
err.span_label(vis.span, "`pub` not permitted here");
|
|
||||||
err.emit();
|
|
||||||
}
|
|
||||||
Err(mut err) => err.emit(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// When lowering a `async fn` to the HIR, we need to move all of the arguments of the function
|
/// When lowering a `async fn` to the HIR, we need to move all of the arguments of the function
|
||||||
/// into the generated closure so that they are dropped when the future is polled and not when
|
/// into the generated closure so that they are dropped when the future is polled and not when
|
||||||
/// it is created.
|
/// it is created.
|
||||||
|
Loading…
Reference in New Issue
Block a user