mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-27 18:57:42 +03:00
Auto merge of #67112 - Centril:expr-polish, r=estebank
Refactor expression parsing thoroughly Based on https://github.com/rust-lang/rust/pull/66994 together with which this has refactored basically the entirety of `expr.rs`. r? @estebank
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
use rustc_errors::PResult;
|
||||
use syntax::ast;
|
||||
use syntax::attr;
|
||||
use syntax::print::pprust;
|
||||
use syntax::token::{self, Nonterminal};
|
||||
use syntax::util::comments;
|
||||
use syntax_pos::{Span, Symbol};
|
||||
@@ -154,7 +155,7 @@ fn parse_attribute_with_inner_parse_policy(
|
||||
(attr_sp, item, style)
|
||||
}
|
||||
_ => {
|
||||
let token_str = self.this_token_to_string();
|
||||
let token_str = pprust::token_to_string(&self.token);
|
||||
return Err(self.fatal(&format!("expected `#`, found `{}`", token_str)));
|
||||
}
|
||||
};
|
||||
@@ -329,7 +330,7 @@ fn parse_meta_item_inner(&mut self) -> PResult<'a, ast::NestedMetaItem> {
|
||||
Err(ref mut err) => err.cancel(),
|
||||
}
|
||||
|
||||
let found = self.this_token_to_string();
|
||||
let found = pprust::token_to_string(&self.token);
|
||||
let msg = format!("expected unsuffixed literal or identifier, found `{}`", found);
|
||||
Err(self.diagnostic().struct_span_err(self.token.span, &msg))
|
||||
}
|
||||
|
||||
@@ -200,7 +200,7 @@ pub(super) fn span_to_snippet(&self, span: Span) -> Result<String, SpanSnippetEr
|
||||
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()),
|
||||
&format!("expected identifier, found {}", super::token_descr(&self.token)),
|
||||
);
|
||||
let valid_follow = &[
|
||||
TokenKind::Eq,
|
||||
@@ -225,7 +225,7 @@ pub(super) fn expected_ident_found(&self) -> DiagnosticBuilder<'a> {
|
||||
);
|
||||
}
|
||||
}
|
||||
if let Some(token_descr) = self.token_descr() {
|
||||
if let Some(token_descr) = super::token_descr_opt(&self.token) {
|
||||
err.span_label(self.token.span, format!("expected identifier, found {}", token_descr));
|
||||
} else {
|
||||
err.span_label(self.token.span, "expected identifier");
|
||||
@@ -272,7 +272,7 @@ fn tokens_to_string(tokens: &[TokenType]) -> String {
|
||||
expected.sort_by_cached_key(|x| x.to_string());
|
||||
expected.dedup();
|
||||
let expect = tokens_to_string(&expected[..]);
|
||||
let actual = self.this_token_descr();
|
||||
let actual = super::token_descr(&self.token);
|
||||
let (msg_exp, (label_sp, label_exp)) = if expected.len() > 1 {
|
||||
let short_expect = if expected.len() > 6 {
|
||||
format!("{} possible tokens", expected.len())
|
||||
@@ -815,7 +815,7 @@ pub(super) fn unexpected_try_recover(
|
||||
t: &TokenKind,
|
||||
) -> PResult<'a, bool /* recovered */> {
|
||||
let token_str = pprust::token_kind_to_string(t);
|
||||
let this_token_str = self.this_token_descr();
|
||||
let this_token_str = super::token_descr(&self.token);
|
||||
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(_)) => {
|
||||
@@ -862,7 +862,7 @@ pub(super) fn expect_semi(&mut self) -> PResult<'a, ()> {
|
||||
return Ok(());
|
||||
}
|
||||
let sm = self.sess.source_map();
|
||||
let msg = format!("expected `;`, found `{}`", self.this_token_descr());
|
||||
let msg = format!("expected `;`, found `{}`", super::token_descr(&self.token));
|
||||
let appl = Applicability::MachineApplicable;
|
||||
if self.token.span == DUMMY_SP || self.prev_span == DUMMY_SP {
|
||||
// Likely inside a macro, can't provide meaninful suggestions.
|
||||
@@ -1270,7 +1270,7 @@ pub(super) fn check_for_for_in_in_typo(&mut self, in_span: Span) {
|
||||
}
|
||||
|
||||
pub(super) fn expected_semi_or_open_brace<T>(&mut self) -> PResult<'a, T> {
|
||||
let token_str = self.this_token_descr();
|
||||
let token_str = super::token_descr(&self.token);
|
||||
let mut err = self.fatal(&format!("expected `;` or `{{`, found {}", token_str));
|
||||
err.span_label(self.token.span, "expected `;` or `{`");
|
||||
Err(err)
|
||||
@@ -1447,7 +1447,7 @@ pub(super) fn expected_expression_found(&self) -> DiagnosticBuilder<'a> {
|
||||
}
|
||||
_ => (
|
||||
self.token.span,
|
||||
format!("expected expression, found {}", self.this_token_descr(),),
|
||||
format!("expected expression, found {}", super::token_descr(&self.token),),
|
||||
),
|
||||
};
|
||||
let mut err = self.struct_span_err(span, &msg);
|
||||
|
||||
+457
-441
@@ -210,30 +210,12 @@ pub(super) fn parse_assoc_expr_with(
|
||||
lhs = self.parse_assoc_op_cast(lhs, lhs_span, ExprKind::Cast)?;
|
||||
continue;
|
||||
} else if op == AssocOp::Colon {
|
||||
let maybe_path = self.could_ascription_be_path(&lhs.kind);
|
||||
self.last_type_ascription = Some((self.prev_span, maybe_path));
|
||||
|
||||
lhs = self.parse_assoc_op_cast(lhs, lhs_span, ExprKind::Type)?;
|
||||
self.sess.gated_spans.gate(sym::type_ascription, lhs.span);
|
||||
lhs = self.parse_assoc_op_ascribe(lhs, lhs_span)?;
|
||||
continue;
|
||||
} else if op == AssocOp::DotDot || op == AssocOp::DotDotEq {
|
||||
// If we didn’t have to handle `x..`/`x..=`, it would be pretty easy to
|
||||
// generalise it to the Fixity::None code.
|
||||
//
|
||||
// We have 2 alternatives here: `x..y`/`x..=y` and `x..`/`x..=` The other
|
||||
// two variants are handled with `parse_prefix_range_expr` call above.
|
||||
let rhs = if self.is_at_start_of_range_notation_rhs() {
|
||||
Some(self.parse_assoc_expr_with(prec + 1, LhsExpr::NotYetParsed)?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let (lhs_span, rhs_span) =
|
||||
(lhs.span, if let Some(ref x) = rhs { x.span } else { cur_op_span });
|
||||
let limits =
|
||||
if op == AssocOp::DotDot { RangeLimits::HalfOpen } else { RangeLimits::Closed };
|
||||
|
||||
let r = self.mk_range(Some(lhs), rhs, limits)?;
|
||||
lhs = self.mk_expr(lhs_span.to(rhs_span), r, AttrVec::new());
|
||||
lhs = self.parse_range_expr(prec, lhs, op, cur_op_span)?;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -395,6 +377,27 @@ fn expr_is_complete(&self, e: &Expr) -> bool {
|
||||
&& !classify::expr_requires_semi_to_be_stmt(e)
|
||||
}
|
||||
|
||||
/// Parses `x..y`, `x..=y`, and `x..`/`x..=`.
|
||||
/// The other two variants are handled in `parse_prefix_range_expr` below.
|
||||
fn parse_range_expr(
|
||||
&mut self,
|
||||
prec: usize,
|
||||
lhs: P<Expr>,
|
||||
op: AssocOp,
|
||||
cur_op_span: Span,
|
||||
) -> PResult<'a, P<Expr>> {
|
||||
let rhs = if self.is_at_start_of_range_notation_rhs() {
|
||||
Some(self.parse_assoc_expr_with(prec + 1, LhsExpr::NotYetParsed)?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let rhs_span = rhs.as_ref().map_or(cur_op_span, |x| x.span);
|
||||
let span = lhs.span.to(rhs_span);
|
||||
let limits =
|
||||
if op == AssocOp::DotDot { RangeLimits::HalfOpen } else { RangeLimits::Closed };
|
||||
Ok(self.mk_expr(span, self.mk_range(Some(lhs), rhs, limits)?, AttrVec::new()))
|
||||
}
|
||||
|
||||
fn is_at_start_of_range_notation_rhs(&self) -> bool {
|
||||
if self.token.can_begin_expr() {
|
||||
// Parse `for i in 1.. { }` as infinite loop, not as `for i in (1..{})`.
|
||||
@@ -408,10 +411,7 @@ fn is_at_start_of_range_notation_rhs(&self) -> bool {
|
||||
}
|
||||
|
||||
/// Parses prefix-forms of range notation: `..expr`, `..`, `..=expr`.
|
||||
fn parse_prefix_range_expr(
|
||||
&mut self,
|
||||
already_parsed_attrs: Option<AttrVec>,
|
||||
) -> PResult<'a, P<Expr>> {
|
||||
fn parse_prefix_range_expr(&mut self, attrs: Option<AttrVec>) -> PResult<'a, P<Expr>> {
|
||||
// Check for deprecated `...` syntax.
|
||||
if self.token == token::DotDotDot {
|
||||
self.err_dotdotdot_syntax(self.token.span);
|
||||
@@ -422,118 +422,107 @@ fn parse_prefix_range_expr(
|
||||
"parse_prefix_range_expr: token {:?} is not DotDot/DotDotEq",
|
||||
self.token
|
||||
);
|
||||
let tok = self.token.clone();
|
||||
let attrs = self.parse_or_use_outer_attributes(already_parsed_attrs)?;
|
||||
let lo = self.token.span;
|
||||
let mut hi = self.token.span;
|
||||
self.bump();
|
||||
let opt_end = if self.is_at_start_of_range_notation_rhs() {
|
||||
// RHS must be parsed with more associativity than the dots.
|
||||
let next_prec = AssocOp::from_token(&tok).unwrap().precedence() + 1;
|
||||
Some(self.parse_assoc_expr_with(next_prec, LhsExpr::NotYetParsed).map(|x| {
|
||||
hi = x.span;
|
||||
x
|
||||
})?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let limits = if tok == token::DotDot { RangeLimits::HalfOpen } else { RangeLimits::Closed };
|
||||
|
||||
let r = self.mk_range(None, opt_end, limits)?;
|
||||
Ok(self.mk_expr(lo.to(hi), r, attrs))
|
||||
let limits = match self.token.kind {
|
||||
token::DotDot => RangeLimits::HalfOpen,
|
||||
_ => RangeLimits::Closed,
|
||||
};
|
||||
let op = AssocOp::from_token(&self.token);
|
||||
let attrs = self.parse_or_use_outer_attributes(attrs)?;
|
||||
let lo = self.token.span;
|
||||
self.bump();
|
||||
let (span, opt_end) = if self.is_at_start_of_range_notation_rhs() {
|
||||
// RHS must be parsed with more associativity than the dots.
|
||||
self.parse_assoc_expr_with(op.unwrap().precedence() + 1, LhsExpr::NotYetParsed)
|
||||
.map(|x| (lo.to(x.span), Some(x)))?
|
||||
} else {
|
||||
(lo, None)
|
||||
};
|
||||
Ok(self.mk_expr(span, self.mk_range(None, opt_end, limits)?, attrs))
|
||||
}
|
||||
|
||||
/// Parses a prefix-unary-operator expr.
|
||||
fn parse_prefix_expr(&mut self, already_parsed_attrs: Option<AttrVec>) -> PResult<'a, P<Expr>> {
|
||||
let attrs = self.parse_or_use_outer_attributes(already_parsed_attrs)?;
|
||||
fn parse_prefix_expr(&mut self, attrs: Option<AttrVec>) -> PResult<'a, P<Expr>> {
|
||||
let attrs = self.parse_or_use_outer_attributes(attrs)?;
|
||||
let lo = self.token.span;
|
||||
// Note: when adding new unary operators, don't forget to adjust TokenKind::can_begin_expr()
|
||||
let (hi, ex) = match self.token.kind {
|
||||
token::Not => {
|
||||
self.bump();
|
||||
let e = self.parse_prefix_expr(None);
|
||||
let (span, e) = self.interpolated_or_expr_span(e)?;
|
||||
(lo.to(span), self.mk_unary(UnOp::Not, e))
|
||||
}
|
||||
// Suggest `!` for bitwise negation when encountering a `~`
|
||||
token::Tilde => {
|
||||
self.bump();
|
||||
let e = self.parse_prefix_expr(None);
|
||||
let (span, e) = self.interpolated_or_expr_span(e)?;
|
||||
let span_of_tilde = lo;
|
||||
self.struct_span_err(span_of_tilde, "`~` cannot be used as a unary operator")
|
||||
.span_suggestion_short(
|
||||
span_of_tilde,
|
||||
"use `!` to perform bitwise not",
|
||||
"!".to_owned(),
|
||||
Applicability::MachineApplicable,
|
||||
)
|
||||
.emit();
|
||||
(lo.to(span), self.mk_unary(UnOp::Not, e))
|
||||
}
|
||||
token::BinOp(token::Minus) => {
|
||||
self.bump();
|
||||
let e = self.parse_prefix_expr(None);
|
||||
let (span, e) = self.interpolated_or_expr_span(e)?;
|
||||
(lo.to(span), self.mk_unary(UnOp::Neg, e))
|
||||
}
|
||||
token::BinOp(token::Star) => {
|
||||
self.bump();
|
||||
let e = self.parse_prefix_expr(None);
|
||||
let (span, e) = self.interpolated_or_expr_span(e)?;
|
||||
(lo.to(span), self.mk_unary(UnOp::Deref, e))
|
||||
}
|
||||
token::BinOp(token::And) | token::AndAnd => self.parse_address_of(lo)?,
|
||||
token::Ident(..) if self.token.is_keyword(kw::Box) => {
|
||||
self.bump();
|
||||
let e = self.parse_prefix_expr(None);
|
||||
let (span, e) = self.interpolated_or_expr_span(e)?;
|
||||
let span = lo.to(span);
|
||||
self.sess.gated_spans.gate(sym::box_syntax, span);
|
||||
(span, ExprKind::Box(e))
|
||||
}
|
||||
token::Ident(..) if self.token.is_ident_named(sym::not) => {
|
||||
// `not` is just an ordinary identifier in Rust-the-language,
|
||||
// but as `rustc`-the-compiler, we can issue clever diagnostics
|
||||
// for confused users who really want to say `!`
|
||||
let token_cannot_continue_expr = |t: &Token| match t.kind {
|
||||
// These tokens can start an expression after `!`, but
|
||||
// can't continue an expression after an ident
|
||||
token::Ident(name, is_raw) => token::ident_can_begin_expr(name, t.span, is_raw),
|
||||
token::Literal(..) | token::Pound => true,
|
||||
_ => t.is_whole_expr(),
|
||||
};
|
||||
let cannot_continue_expr = self.look_ahead(1, token_cannot_continue_expr);
|
||||
if cannot_continue_expr {
|
||||
self.bump();
|
||||
// Emit the error ...
|
||||
self.struct_span_err(
|
||||
self.token.span,
|
||||
&format!("unexpected {} after identifier", self.this_token_descr()),
|
||||
)
|
||||
.span_suggestion_short(
|
||||
// Span the `not` plus trailing whitespace to avoid
|
||||
// trailing whitespace after the `!` in our suggestion
|
||||
self.sess.source_map().span_until_non_whitespace(lo.to(self.token.span)),
|
||||
"use `!` to perform logical negation",
|
||||
"!".to_owned(),
|
||||
Applicability::MachineApplicable,
|
||||
)
|
||||
.emit();
|
||||
// —and recover! (just as if we were in the block
|
||||
// for the `token::Not` arm)
|
||||
let e = self.parse_prefix_expr(None);
|
||||
let (span, e) = self.interpolated_or_expr_span(e)?;
|
||||
(lo.to(span), self.mk_unary(UnOp::Not, e))
|
||||
} else {
|
||||
return self.parse_dot_or_call_expr(Some(attrs));
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
return self.parse_dot_or_call_expr(Some(attrs));
|
||||
}
|
||||
token::Not => self.parse_unary_expr(lo, UnOp::Not), // `!expr`
|
||||
token::Tilde => self.recover_tilde_expr(lo), // `~expr`
|
||||
token::BinOp(token::Minus) => self.parse_unary_expr(lo, UnOp::Neg), // `-expr`
|
||||
token::BinOp(token::Star) => self.parse_unary_expr(lo, UnOp::Deref), // `*expr`
|
||||
token::BinOp(token::And) | token::AndAnd => self.parse_borrow_expr(lo),
|
||||
token::Ident(..) if self.token.is_keyword(kw::Box) => self.parse_box_expr(lo),
|
||||
token::Ident(..) if self.is_mistaken_not_ident_negation() => self.recover_not_expr(lo),
|
||||
_ => return self.parse_dot_or_call_expr(Some(attrs)),
|
||||
}?;
|
||||
Ok(self.mk_expr(lo.to(hi), ex, attrs))
|
||||
}
|
||||
|
||||
fn parse_prefix_expr_common(&mut self, lo: Span) -> PResult<'a, (Span, P<Expr>)> {
|
||||
self.bump();
|
||||
let expr = self.parse_prefix_expr(None);
|
||||
let (span, expr) = self.interpolated_or_expr_span(expr)?;
|
||||
Ok((lo.to(span), expr))
|
||||
}
|
||||
|
||||
fn parse_unary_expr(&mut self, lo: Span, op: UnOp) -> PResult<'a, (Span, ExprKind)> {
|
||||
let (span, expr) = self.parse_prefix_expr_common(lo)?;
|
||||
Ok((span, self.mk_unary(op, expr)))
|
||||
}
|
||||
|
||||
// Recover on `!` suggesting for bitwise negation instead.
|
||||
fn recover_tilde_expr(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> {
|
||||
self.struct_span_err(lo, "`~` cannot be used as a unary operator")
|
||||
.span_suggestion_short(
|
||||
lo,
|
||||
"use `!` to perform bitwise not",
|
||||
"!".to_owned(),
|
||||
Applicability::MachineApplicable,
|
||||
)
|
||||
.emit();
|
||||
|
||||
self.parse_unary_expr(lo, UnOp::Not)
|
||||
}
|
||||
|
||||
/// Parse `box expr`.
|
||||
fn parse_box_expr(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> {
|
||||
let (span, expr) = self.parse_prefix_expr_common(lo)?;
|
||||
self.sess.gated_spans.gate(sym::box_syntax, span);
|
||||
Ok((span, ExprKind::Box(expr)))
|
||||
}
|
||||
|
||||
fn is_mistaken_not_ident_negation(&self) -> bool {
|
||||
let token_cannot_continue_expr = |t: &Token| match t.kind {
|
||||
// These tokens can start an expression after `!`, but
|
||||
// can't continue an expression after an ident
|
||||
token::Ident(name, is_raw) => token::ident_can_begin_expr(name, t.span, is_raw),
|
||||
token::Literal(..) | token::Pound => true,
|
||||
_ => t.is_whole_expr(),
|
||||
};
|
||||
return Ok(self.mk_expr(lo.to(hi), ex, attrs));
|
||||
self.token.is_ident_named(sym::not) && self.look_ahead(1, token_cannot_continue_expr)
|
||||
}
|
||||
|
||||
/// Recover on `not expr` in favor of `!expr`.
|
||||
fn recover_not_expr(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> {
|
||||
// Emit the error...
|
||||
let not_token = self.look_ahead(1, |t| t.clone());
|
||||
self.struct_span_err(
|
||||
not_token.span,
|
||||
&format!("unexpected {} after identifier", super::token_descr(¬_token)),
|
||||
)
|
||||
.span_suggestion_short(
|
||||
// Span the `not` plus trailing whitespace to avoid
|
||||
// trailing whitespace after the `!` in our suggestion
|
||||
self.sess.source_map().span_until_non_whitespace(lo.to(not_token.span)),
|
||||
"use `!` to perform logical negation",
|
||||
"!".to_owned(),
|
||||
Applicability::MachineApplicable,
|
||||
)
|
||||
.emit();
|
||||
|
||||
// ...and recover!
|
||||
self.parse_unary_expr(lo, UnOp::Not)
|
||||
}
|
||||
|
||||
/// Returns the span of expr, if it was not interpolated or the span of the interpolated token.
|
||||
@@ -598,14 +587,7 @@ fn parse_assoc_op_cast(
|
||||
op_noun,
|
||||
);
|
||||
let span_after_type = parser_snapshot_after_type.token.span;
|
||||
let expr = mk_expr(
|
||||
self,
|
||||
P(Ty {
|
||||
span: path.span,
|
||||
kind: TyKind::Path(None, path),
|
||||
id: DUMMY_NODE_ID,
|
||||
}),
|
||||
);
|
||||
let expr = mk_expr(self, self.mk_ty(path.span, TyKind::Path(None, path)));
|
||||
|
||||
let expr_str = self
|
||||
.span_to_snippet(expr.span)
|
||||
@@ -638,33 +620,44 @@ fn parse_assoc_op_cast(
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_assoc_op_ascribe(&mut self, lhs: P<Expr>, lhs_span: Span) -> PResult<'a, P<Expr>> {
|
||||
let maybe_path = self.could_ascription_be_path(&lhs.kind);
|
||||
self.last_type_ascription = Some((self.prev_span, maybe_path));
|
||||
let lhs = self.parse_assoc_op_cast(lhs, lhs_span, ExprKind::Type)?;
|
||||
self.sess.gated_spans.gate(sym::type_ascription, lhs.span);
|
||||
Ok(lhs)
|
||||
}
|
||||
|
||||
/// Parse `& mut? <expr>` or `& raw [ const | mut ] <expr>`.
|
||||
fn parse_address_of(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> {
|
||||
fn parse_borrow_expr(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> {
|
||||
self.expect_and()?;
|
||||
let (k, m) = if self.check_keyword(kw::Raw) && self.look_ahead(1, Token::is_mutability) {
|
||||
let (borrow_kind, mutbl) = self.parse_borrow_modifiers(lo);
|
||||
let expr = self.parse_prefix_expr(None);
|
||||
let (span, expr) = self.interpolated_or_expr_span(expr)?;
|
||||
Ok((lo.to(span), ExprKind::AddrOf(borrow_kind, mutbl, expr)))
|
||||
}
|
||||
|
||||
/// Parse `mut?` or `raw [ const | mut ]`.
|
||||
fn parse_borrow_modifiers(&mut self, lo: Span) -> (ast::BorrowKind, ast::Mutability) {
|
||||
if self.check_keyword(kw::Raw) && self.look_ahead(1, Token::is_mutability) {
|
||||
// `raw [ const | mut ]`.
|
||||
let found_raw = self.eat_keyword(kw::Raw);
|
||||
assert!(found_raw);
|
||||
let mutability = self.parse_const_or_mut().unwrap();
|
||||
self.sess.gated_spans.gate(sym::raw_ref_op, lo.to(self.prev_span));
|
||||
(ast::BorrowKind::Raw, mutability)
|
||||
} else {
|
||||
// `mut?`
|
||||
(ast::BorrowKind::Ref, self.parse_mutability())
|
||||
};
|
||||
let e = self.parse_prefix_expr(None);
|
||||
let (span, e) = self.interpolated_or_expr_span(e)?;
|
||||
Ok((lo.to(span), ExprKind::AddrOf(k, m, e)))
|
||||
}
|
||||
}
|
||||
|
||||
/// Parses `a.b` or `a(13)` or `a[4]` or just `a`.
|
||||
fn parse_dot_or_call_expr(
|
||||
&mut self,
|
||||
already_parsed_attrs: Option<AttrVec>,
|
||||
) -> PResult<'a, P<Expr>> {
|
||||
let attrs = self.parse_or_use_outer_attributes(already_parsed_attrs)?;
|
||||
|
||||
let b = self.parse_bottom_expr();
|
||||
let (span, b) = self.interpolated_or_expr_span(b)?;
|
||||
self.parse_dot_or_call_expr_with(b, span, attrs)
|
||||
fn parse_dot_or_call_expr(&mut self, attrs: Option<AttrVec>) -> PResult<'a, P<Expr>> {
|
||||
let attrs = self.parse_or_use_outer_attributes(attrs)?;
|
||||
let base = self.parse_bottom_expr();
|
||||
let (span, base) = self.interpolated_or_expr_span(base)?;
|
||||
self.parse_dot_or_call_expr_with(base, span, attrs)
|
||||
}
|
||||
|
||||
pub(super) fn parse_dot_or_call_expr_with(
|
||||
@@ -694,95 +687,120 @@ fn error_attr_on_if_expr(&self, expr: &Expr) {
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_dot_or_call_expr_with_(&mut self, e0: P<Expr>, lo: Span) -> PResult<'a, P<Expr>> {
|
||||
let mut e = e0;
|
||||
let mut hi;
|
||||
fn parse_dot_or_call_expr_with_(&mut self, mut e: P<Expr>, lo: Span) -> PResult<'a, P<Expr>> {
|
||||
loop {
|
||||
// expr?
|
||||
while self.eat(&token::Question) {
|
||||
let hi = self.prev_span;
|
||||
e = self.mk_expr(lo.to(hi), ExprKind::Try(e), AttrVec::new());
|
||||
if self.eat(&token::Question) {
|
||||
// `expr?`
|
||||
e = self.mk_expr(lo.to(self.prev_span), ExprKind::Try(e), AttrVec::new());
|
||||
continue;
|
||||
}
|
||||
|
||||
// expr.f
|
||||
if self.eat(&token::Dot) {
|
||||
match self.token.kind {
|
||||
token::Ident(..) => {
|
||||
e = self.parse_dot_suffix(e, lo)?;
|
||||
}
|
||||
token::Literal(token::Lit { kind: token::Integer, symbol, suffix }) => {
|
||||
let span = self.token.span;
|
||||
self.bump();
|
||||
let field = ExprKind::Field(e, Ident::new(symbol, span));
|
||||
e = self.mk_expr(lo.to(span), field, AttrVec::new());
|
||||
|
||||
self.expect_no_suffix(span, "a tuple index", suffix);
|
||||
}
|
||||
token::Literal(token::Lit { kind: token::Float, symbol, .. }) => {
|
||||
self.bump();
|
||||
let fstr = symbol.as_str();
|
||||
let msg = format!("unexpected token: `{}`", symbol);
|
||||
let mut err = self.diagnostic().struct_span_err(self.prev_span, &msg);
|
||||
err.span_label(self.prev_span, "unexpected token");
|
||||
if fstr.chars().all(|x| "0123456789.".contains(x)) {
|
||||
let float = match fstr.parse::<f64>().ok() {
|
||||
Some(f) => f,
|
||||
None => continue,
|
||||
};
|
||||
let sugg = pprust::to_string(|s| {
|
||||
s.popen();
|
||||
s.print_expr(&e);
|
||||
s.s.word(".");
|
||||
s.print_usize(float.trunc() as usize);
|
||||
s.pclose();
|
||||
s.s.word(".");
|
||||
s.s.word(fstr.splitn(2, ".").last().unwrap().to_string())
|
||||
});
|
||||
err.span_suggestion(
|
||||
lo.to(self.prev_span),
|
||||
"try parenthesizing the first index",
|
||||
sugg,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
return Err(err);
|
||||
}
|
||||
_ => {
|
||||
// FIXME Could factor this out into non_fatal_unexpected or something.
|
||||
let actual = self.this_token_to_string();
|
||||
self.span_err(self.token.span, &format!("unexpected token: `{}`", actual));
|
||||
}
|
||||
}
|
||||
// expr.f
|
||||
e = self.parse_dot_suffix_expr(lo, e)?;
|
||||
continue;
|
||||
}
|
||||
if self.expr_is_complete(&e) {
|
||||
break;
|
||||
return Ok(e);
|
||||
}
|
||||
match self.token.kind {
|
||||
// expr(...)
|
||||
token::OpenDelim(token::Paren) => {
|
||||
let seq = self.parse_paren_expr_seq().map(|es| {
|
||||
let nd = self.mk_call(e, es);
|
||||
let hi = self.prev_span;
|
||||
self.mk_expr(lo.to(hi), nd, AttrVec::new())
|
||||
});
|
||||
e = self.recover_seq_parse_error(token::Paren, lo, seq);
|
||||
}
|
||||
|
||||
// expr[...]
|
||||
// Could be either an index expression or a slicing expression.
|
||||
token::OpenDelim(token::Bracket) => {
|
||||
self.bump();
|
||||
let ix = self.parse_expr()?;
|
||||
hi = self.token.span;
|
||||
self.expect(&token::CloseDelim(token::Bracket))?;
|
||||
let index = self.mk_index(e, ix);
|
||||
e = self.mk_expr(lo.to(hi), index, AttrVec::new())
|
||||
}
|
||||
e = match self.token.kind {
|
||||
token::OpenDelim(token::Paren) => self.parse_fn_call_expr(lo, e),
|
||||
token::OpenDelim(token::Bracket) => self.parse_index_expr(lo, e)?,
|
||||
_ => return Ok(e),
|
||||
}
|
||||
}
|
||||
return Ok(e);
|
||||
}
|
||||
|
||||
fn parse_dot_suffix_expr(&mut self, lo: Span, base: P<Expr>) -> PResult<'a, P<Expr>> {
|
||||
match self.token.kind {
|
||||
token::Ident(..) => self.parse_dot_suffix(base, lo),
|
||||
token::Literal(token::Lit { kind: token::Integer, symbol, suffix }) => {
|
||||
Ok(self.parse_tuple_field_access_expr(lo, base, symbol, suffix))
|
||||
}
|
||||
token::Literal(token::Lit { kind: token::Float, symbol, .. }) => {
|
||||
self.recover_field_access_by_float_lit(lo, base, symbol)
|
||||
}
|
||||
_ => {
|
||||
self.error_unexpected_after_dot();
|
||||
Ok(base)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn error_unexpected_after_dot(&self) {
|
||||
// FIXME Could factor this out into non_fatal_unexpected or something.
|
||||
let actual = pprust::token_to_string(&self.token);
|
||||
self.struct_span_err(self.token.span, &format!("unexpected token: `{}`", actual)).emit();
|
||||
}
|
||||
|
||||
fn recover_field_access_by_float_lit(
|
||||
&mut self,
|
||||
lo: Span,
|
||||
base: P<Expr>,
|
||||
sym: Symbol,
|
||||
) -> PResult<'a, P<Expr>> {
|
||||
self.bump();
|
||||
|
||||
let fstr = sym.as_str();
|
||||
let msg = format!("unexpected token: `{}`", sym);
|
||||
|
||||
let mut err = self.struct_span_err(self.prev_span, &msg);
|
||||
err.span_label(self.prev_span, "unexpected token");
|
||||
|
||||
if fstr.chars().all(|x| "0123456789.".contains(x)) {
|
||||
let float = match fstr.parse::<f64>() {
|
||||
Ok(f) => f,
|
||||
Err(_) => {
|
||||
err.emit();
|
||||
return Ok(base);
|
||||
}
|
||||
};
|
||||
let sugg = pprust::to_string(|s| {
|
||||
s.popen();
|
||||
s.print_expr(&base);
|
||||
s.s.word(".");
|
||||
s.print_usize(float.trunc() as usize);
|
||||
s.pclose();
|
||||
s.s.word(".");
|
||||
s.s.word(fstr.splitn(2, ".").last().unwrap().to_string())
|
||||
});
|
||||
err.span_suggestion(
|
||||
lo.to(self.prev_span),
|
||||
"try parenthesizing the first index",
|
||||
sugg,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
Err(err)
|
||||
}
|
||||
|
||||
fn parse_tuple_field_access_expr(
|
||||
&mut self,
|
||||
lo: Span,
|
||||
base: P<Expr>,
|
||||
field: Symbol,
|
||||
suffix: Option<Symbol>,
|
||||
) -> P<Expr> {
|
||||
let span = self.token.span;
|
||||
self.bump();
|
||||
let field = ExprKind::Field(base, Ident::new(field, span));
|
||||
self.expect_no_suffix(span, "a tuple index", suffix);
|
||||
self.mk_expr(lo.to(span), field, AttrVec::new())
|
||||
}
|
||||
|
||||
/// Parse a function call expression, `expr(...)`.
|
||||
fn parse_fn_call_expr(&mut self, lo: Span, fun: P<Expr>) -> P<Expr> {
|
||||
let seq = self.parse_paren_expr_seq().map(|args| {
|
||||
self.mk_expr(lo.to(self.prev_span), self.mk_call(fun, args), AttrVec::new())
|
||||
});
|
||||
self.recover_seq_parse_error(token::Paren, lo, seq)
|
||||
}
|
||||
|
||||
/// Parse an indexing expression `expr[...]`.
|
||||
fn parse_index_expr(&mut self, lo: Span, base: P<Expr>) -> PResult<'a, P<Expr>> {
|
||||
self.bump(); // `[`
|
||||
let index = self.parse_expr()?;
|
||||
self.expect(&token::CloseDelim(token::Bracket))?;
|
||||
Ok(self.mk_expr(lo.to(self.prev_span), self.mk_index(base, index), AttrVec::new()))
|
||||
}
|
||||
|
||||
/// Assuming we have just parsed `.`, continue parsing into an expression.
|
||||
@@ -794,25 +812,22 @@ fn parse_dot_suffix(&mut self, self_arg: P<Expr>, lo: Span) -> PResult<'a, P<Exp
|
||||
let segment = self.parse_path_segment(PathStyle::Expr)?;
|
||||
self.check_trailing_angle_brackets(&segment, token::OpenDelim(token::Paren));
|
||||
|
||||
Ok(match self.token.kind {
|
||||
token::OpenDelim(token::Paren) => {
|
||||
// Method call `expr.f()`
|
||||
let mut args = self.parse_paren_expr_seq()?;
|
||||
args.insert(0, self_arg);
|
||||
if self.check(&token::OpenDelim(token::Paren)) {
|
||||
// Method call `expr.f()`
|
||||
let mut args = self.parse_paren_expr_seq()?;
|
||||
args.insert(0, self_arg);
|
||||
|
||||
let span = lo.to(self.prev_span);
|
||||
self.mk_expr(span, ExprKind::MethodCall(segment, args), AttrVec::new())
|
||||
let span = lo.to(self.prev_span);
|
||||
Ok(self.mk_expr(span, ExprKind::MethodCall(segment, args), AttrVec::new()))
|
||||
} else {
|
||||
// Field access `expr.f`
|
||||
if let Some(args) = segment.args {
|
||||
self.span_err(args.span(), "field expressions may not have generic arguments");
|
||||
}
|
||||
_ => {
|
||||
// Field access `expr.f`
|
||||
if let Some(args) = segment.args {
|
||||
self.span_err(args.span(), "field expressions may not have generic arguments");
|
||||
}
|
||||
|
||||
let span = lo.to(self.prev_span);
|
||||
self.mk_expr(span, ExprKind::Field(self_arg, segment.ident), AttrVec::new())
|
||||
}
|
||||
})
|
||||
let span = lo.to(self.prev_span);
|
||||
Ok(self.mk_expr(span, ExprKind::Field(self_arg, segment.ident), AttrVec::new()))
|
||||
}
|
||||
}
|
||||
|
||||
/// At the bottom (top?) of the precedence hierarchy,
|
||||
@@ -1117,7 +1132,7 @@ pub fn parse_str_lit(&mut self) -> Result<ast::StrLit, Option<Lit>> {
|
||||
|
||||
pub(super) fn parse_lit(&mut self) -> PResult<'a, Lit> {
|
||||
self.parse_opt_lit().ok_or_else(|| {
|
||||
let msg = format!("unexpected token: {}", self.this_token_descr());
|
||||
let msg = format!("unexpected token: {}", super::token_descr(&self.token));
|
||||
self.span_fatal(self.token.span, &msg)
|
||||
})
|
||||
}
|
||||
@@ -1143,14 +1158,7 @@ pub(super) fn parse_opt_lit(&mut self) -> Option<Lit> {
|
||||
});
|
||||
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();
|
||||
self.error_float_lits_must_have_int_part(&token);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1179,6 +1187,17 @@ pub(super) fn parse_opt_lit(&mut self) -> Option<Lit> {
|
||||
}
|
||||
}
|
||||
|
||||
fn error_float_lits_must_have_int_part(&self, token: &Token) {
|
||||
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();
|
||||
}
|
||||
|
||||
fn report_lit_error(&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 {
|
||||
@@ -1282,17 +1301,13 @@ pub(super) fn expect_no_suffix(&self, sp: Span, kind: &str, suffix: Option<Symbo
|
||||
pub fn parse_literal_maybe_minus(&mut self) -> PResult<'a, P<Expr>> {
|
||||
maybe_whole_expr!(self);
|
||||
|
||||
let minus_lo = self.token.span;
|
||||
let minus_present = self.eat(&token::BinOp(token::Minus));
|
||||
let lo = self.token.span;
|
||||
let literal = self.parse_lit()?;
|
||||
let hi = self.prev_span;
|
||||
let expr = self.mk_expr(lo.to(hi), ExprKind::Lit(literal), AttrVec::new());
|
||||
let minus_present = self.eat(&token::BinOp(token::Minus));
|
||||
let lit = self.parse_lit()?;
|
||||
let expr = self.mk_expr(lit.span, ExprKind::Lit(lit), AttrVec::new());
|
||||
|
||||
if minus_present {
|
||||
let minus_hi = self.prev_span;
|
||||
let unary = self.mk_unary(UnOp::Neg, expr);
|
||||
Ok(self.mk_expr(minus_lo.to(minus_hi), unary, AttrVec::new()))
|
||||
Ok(self.mk_expr(lo.to(self.prev_span), self.mk_unary(UnOp::Neg, expr), AttrVec::new()))
|
||||
} else {
|
||||
Ok(expr)
|
||||
}
|
||||
@@ -1362,26 +1377,24 @@ fn parse_capture_clause(&mut self) -> CaptureBy {
|
||||
|
||||
/// Parses the `|arg, arg|` header of a closure.
|
||||
fn parse_fn_block_decl(&mut self) -> PResult<'a, P<FnDecl>> {
|
||||
let inputs_captures = {
|
||||
if self.eat(&token::OrOr) {
|
||||
Vec::new()
|
||||
} else {
|
||||
self.expect(&token::BinOp(token::Or))?;
|
||||
let args = self
|
||||
.parse_seq_to_before_tokens(
|
||||
&[&token::BinOp(token::Or), &token::OrOr],
|
||||
SeqSep::trailing_allowed(token::Comma),
|
||||
TokenExpectType::NoExpect,
|
||||
|p| p.parse_fn_block_param(),
|
||||
)?
|
||||
.0;
|
||||
self.expect_or()?;
|
||||
args
|
||||
}
|
||||
let inputs = if self.eat(&token::OrOr) {
|
||||
Vec::new()
|
||||
} else {
|
||||
self.expect(&token::BinOp(token::Or))?;
|
||||
let args = self
|
||||
.parse_seq_to_before_tokens(
|
||||
&[&token::BinOp(token::Or), &token::OrOr],
|
||||
SeqSep::trailing_allowed(token::Comma),
|
||||
TokenExpectType::NoExpect,
|
||||
|p| p.parse_fn_block_param(),
|
||||
)?
|
||||
.0;
|
||||
self.expect_or()?;
|
||||
args
|
||||
};
|
||||
let output = self.parse_ret_ty(true, true)?;
|
||||
|
||||
Ok(P(FnDecl { inputs: inputs_captures, output }))
|
||||
Ok(P(FnDecl { inputs, output }))
|
||||
}
|
||||
|
||||
/// Parses a parameter in a closure header (e.g., `|arg, arg|`).
|
||||
@@ -1389,17 +1402,16 @@ fn parse_fn_block_param(&mut self) -> PResult<'a, Param> {
|
||||
let lo = self.token.span;
|
||||
let attrs = self.parse_outer_attributes()?;
|
||||
let pat = self.parse_pat(PARAM_EXPECTED)?;
|
||||
let t = if self.eat(&token::Colon) {
|
||||
let ty = if self.eat(&token::Colon) {
|
||||
self.parse_ty()?
|
||||
} else {
|
||||
P(Ty { id: DUMMY_NODE_ID, kind: TyKind::Infer, span: self.prev_span })
|
||||
self.mk_ty(self.prev_span, TyKind::Infer)
|
||||
};
|
||||
let span = lo.to(self.token.span);
|
||||
Ok(Param {
|
||||
attrs: attrs.into(),
|
||||
ty: t,
|
||||
ty,
|
||||
pat,
|
||||
span,
|
||||
span: lo.to(self.token.span),
|
||||
id: DUMMY_NODE_ID,
|
||||
is_placeholder: false,
|
||||
})
|
||||
@@ -1414,28 +1426,29 @@ fn parse_if_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
|
||||
// verify that the last statement is either an implicit return (no `;`) or an explicit
|
||||
// return. This won't catch blocks with an explicit `return`, but that would be caught by
|
||||
// the dead code lint.
|
||||
if self.eat_keyword(kw::Else) || !cond.returns() {
|
||||
let sp = self.sess.source_map().next_point(lo);
|
||||
let mut err =
|
||||
self.diagnostic().struct_span_err(sp, "missing condition for `if` expression");
|
||||
err.span_label(sp, "expected if condition here");
|
||||
return Err(err);
|
||||
}
|
||||
let not_block = self.token != token::OpenDelim(token::Brace);
|
||||
let thn = self.parse_block().map_err(|mut err| {
|
||||
if not_block {
|
||||
err.span_label(lo, "this `if` statement has a condition, but no block");
|
||||
}
|
||||
err
|
||||
})?;
|
||||
let mut els: Option<P<Expr>> = None;
|
||||
let mut hi = thn.span;
|
||||
if self.eat_keyword(kw::Else) {
|
||||
let elexpr = self.parse_else_expr()?;
|
||||
hi = elexpr.span;
|
||||
els = Some(elexpr);
|
||||
}
|
||||
Ok(self.mk_expr(lo.to(hi), ExprKind::If(cond, thn, els), attrs))
|
||||
let thn = if self.eat_keyword(kw::Else) || !cond.returns() {
|
||||
self.error_missing_if_cond(lo, cond.span)
|
||||
} else {
|
||||
let not_block = self.token != token::OpenDelim(token::Brace);
|
||||
self.parse_block().map_err(|mut err| {
|
||||
if not_block {
|
||||
err.span_label(lo, "this `if` expression has a condition, but no block");
|
||||
}
|
||||
err
|
||||
})?
|
||||
};
|
||||
let els = if self.eat_keyword(kw::Else) { Some(self.parse_else_expr()?) } else { None };
|
||||
Ok(self.mk_expr(lo.to(self.prev_span), ExprKind::If(cond, thn, els), attrs))
|
||||
}
|
||||
|
||||
fn error_missing_if_cond(&self, lo: Span, span: Span) -> P<ast::Block> {
|
||||
let sp = self.sess.source_map().next_point(lo);
|
||||
self.struct_span_err(sp, "missing condition for `if` expression")
|
||||
.span_label(sp, "expected if condition here")
|
||||
.emit();
|
||||
let expr = self.mk_expr_err(span);
|
||||
let stmt = self.mk_stmt(span, ast::StmtKind::Expr(expr));
|
||||
self.mk_block(vec![stmt], BlockCheckMode::Default, span)
|
||||
}
|
||||
|
||||
/// Parses the condition of a `if` or `while` expression.
|
||||
@@ -1467,22 +1480,20 @@ fn parse_let_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
|
||||
/// Parses an `else { ... }` expression (`else` token already eaten).
|
||||
fn parse_else_expr(&mut self) -> PResult<'a, P<Expr>> {
|
||||
if self.eat_keyword(kw::If) {
|
||||
return self.parse_if_expr(AttrVec::new());
|
||||
self.parse_if_expr(AttrVec::new())
|
||||
} else {
|
||||
let blk = self.parse_block()?;
|
||||
return Ok(self.mk_expr(blk.span, ExprKind::Block(blk, None), AttrVec::new()));
|
||||
Ok(self.mk_expr(blk.span, ExprKind::Block(blk, None), AttrVec::new()))
|
||||
}
|
||||
}
|
||||
|
||||
/// Parses a `for ... in` expression (`for` token already eaten).
|
||||
/// Parses `for <src_pat> in <src_expr> <src_loop_block>` (`for` token already eaten).
|
||||
fn parse_for_expr(
|
||||
&mut self,
|
||||
opt_label: Option<Label>,
|
||||
span_lo: Span,
|
||||
lo: Span,
|
||||
mut attrs: AttrVec,
|
||||
) -> PResult<'a, P<Expr>> {
|
||||
// Parse: `for <src_pat> in <src_expr> <src_loop_block>`
|
||||
|
||||
// Record whether we are about to parse `for (`.
|
||||
// This is used below for recovery in case of `for ( $stuff ) $block`
|
||||
// in which case we will suggest `for $stuff $block`.
|
||||
@@ -1493,19 +1504,9 @@ fn parse_for_expr(
|
||||
|
||||
let pat = self.parse_top_pat(GateOr::Yes)?;
|
||||
if !self.eat_keyword(kw::In) {
|
||||
let in_span = self.prev_span.between(self.token.span);
|
||||
self.struct_span_err(in_span, "missing `in` in `for` loop")
|
||||
.span_suggestion_short(
|
||||
in_span,
|
||||
"try adding `in` here",
|
||||
" in ".into(),
|
||||
// has been misleading, at least in the past (closed Issue #48492)
|
||||
Applicability::MaybeIncorrect,
|
||||
)
|
||||
.emit();
|
||||
self.error_missing_in_for_loop();
|
||||
}
|
||||
let in_span = self.prev_span;
|
||||
self.check_for_for_in_in_typo(in_span);
|
||||
self.check_for_for_in_in_typo(self.prev_span);
|
||||
let expr = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
|
||||
|
||||
let pat = self.recover_parens_around_for_head(pat, &expr, begin_paren);
|
||||
@@ -1513,52 +1514,61 @@ fn parse_for_expr(
|
||||
let (iattrs, loop_block) = self.parse_inner_attrs_and_block()?;
|
||||
attrs.extend(iattrs);
|
||||
|
||||
let hi = self.prev_span;
|
||||
Ok(self.mk_expr(span_lo.to(hi), ExprKind::ForLoop(pat, expr, loop_block, opt_label), attrs))
|
||||
let kind = ExprKind::ForLoop(pat, expr, loop_block, opt_label);
|
||||
Ok(self.mk_expr(lo.to(self.prev_span), kind, attrs))
|
||||
}
|
||||
|
||||
fn error_missing_in_for_loop(&self) {
|
||||
let in_span = self.prev_span.between(self.token.span);
|
||||
self.struct_span_err(in_span, "missing `in` in `for` loop")
|
||||
.span_suggestion_short(
|
||||
in_span,
|
||||
"try adding `in` here",
|
||||
" in ".into(),
|
||||
// Has been misleading, at least in the past (closed Issue #48492).
|
||||
Applicability::MaybeIncorrect,
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
|
||||
/// Parses a `while` or `while let` expression (`while` token already eaten).
|
||||
fn parse_while_expr(
|
||||
&mut self,
|
||||
opt_label: Option<Label>,
|
||||
span_lo: Span,
|
||||
lo: Span,
|
||||
mut attrs: AttrVec,
|
||||
) -> PResult<'a, P<Expr>> {
|
||||
let cond = self.parse_cond_expr()?;
|
||||
let (iattrs, body) = self.parse_inner_attrs_and_block()?;
|
||||
attrs.extend(iattrs);
|
||||
let span = span_lo.to(body.span);
|
||||
Ok(self.mk_expr(span, ExprKind::While(cond, body, opt_label), attrs))
|
||||
Ok(self.mk_expr(lo.to(self.prev_span), ExprKind::While(cond, body, opt_label), attrs))
|
||||
}
|
||||
|
||||
/// Parses `loop { ... }` (`loop` token already eaten).
|
||||
fn parse_loop_expr(
|
||||
&mut self,
|
||||
opt_label: Option<Label>,
|
||||
span_lo: Span,
|
||||
lo: Span,
|
||||
mut attrs: AttrVec,
|
||||
) -> PResult<'a, P<Expr>> {
|
||||
let (iattrs, body) = self.parse_inner_attrs_and_block()?;
|
||||
attrs.extend(iattrs);
|
||||
let span = span_lo.to(body.span);
|
||||
Ok(self.mk_expr(span, ExprKind::Loop(body, opt_label), attrs))
|
||||
Ok(self.mk_expr(lo.to(self.prev_span), ExprKind::Loop(body, opt_label), attrs))
|
||||
}
|
||||
|
||||
fn eat_label(&mut self) -> Option<Label> {
|
||||
if let Some(ident) = self.token.lifetime() {
|
||||
self.token.lifetime().map(|ident| {
|
||||
let span = self.token.span;
|
||||
self.bump();
|
||||
Some(Label { ident: Ident::new(ident.name, span) })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
Label { ident: Ident::new(ident.name, span) }
|
||||
})
|
||||
}
|
||||
|
||||
/// Parses a `match ... { ... }` expression (`match` token already eaten).
|
||||
fn parse_match_expr(&mut self, mut attrs: AttrVec) -> PResult<'a, P<Expr>> {
|
||||
let match_span = self.prev_span;
|
||||
let lo = self.prev_span;
|
||||
let discriminant = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
|
||||
let scrutinee = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
|
||||
if let Err(mut e) = self.expect(&token::OpenDelim(token::Brace)) {
|
||||
if self.token == token::Semi {
|
||||
e.span_suggestion_short(
|
||||
@@ -1584,13 +1594,13 @@ fn parse_match_expr(&mut self, mut attrs: AttrVec) -> PResult<'a, P<Expr>> {
|
||||
if self.token == token::CloseDelim(token::Brace) {
|
||||
self.bump();
|
||||
}
|
||||
return Ok(self.mk_expr(span, ExprKind::Match(discriminant, arms), attrs));
|
||||
return Ok(self.mk_expr(span, ExprKind::Match(scrutinee, arms), attrs));
|
||||
}
|
||||
}
|
||||
}
|
||||
let hi = self.token.span;
|
||||
self.bump();
|
||||
return Ok(self.mk_expr(lo.to(hi), ExprKind::Match(discriminant, arms), attrs));
|
||||
return Ok(self.mk_expr(lo.to(hi), ExprKind::Match(scrutinee, arms), attrs));
|
||||
}
|
||||
|
||||
pub(super) fn parse_arm(&mut self) -> PResult<'a, Arm> {
|
||||
@@ -1699,16 +1709,13 @@ fn is_try_block(&self) -> bool {
|
||||
|
||||
/// Parses an `async move? {...}` expression.
|
||||
fn parse_async_block(&mut self, mut attrs: AttrVec) -> PResult<'a, P<Expr>> {
|
||||
let span_lo = self.token.span;
|
||||
let lo = self.token.span;
|
||||
self.expect_keyword(kw::Async)?;
|
||||
let capture_clause = self.parse_capture_clause();
|
||||
let (iattrs, body) = self.parse_inner_attrs_and_block()?;
|
||||
attrs.extend(iattrs);
|
||||
Ok(self.mk_expr(
|
||||
span_lo.to(body.span),
|
||||
ExprKind::Async(capture_clause, DUMMY_NODE_ID, body),
|
||||
attrs,
|
||||
))
|
||||
let kind = ExprKind::Async(capture_clause, DUMMY_NODE_ID, body);
|
||||
Ok(self.mk_expr(lo.to(self.prev_span), kind, attrs))
|
||||
}
|
||||
|
||||
fn is_async_block(&self) -> bool {
|
||||
@@ -1723,6 +1730,21 @@ fn is_async_block(&self) -> bool {
|
||||
))
|
||||
}
|
||||
|
||||
fn is_certainly_not_a_block(&self) -> bool {
|
||||
self.look_ahead(1, |t| t.is_ident())
|
||||
&& (
|
||||
// `{ ident, ` cannot start a block.
|
||||
self.look_ahead(2, |t| t == &token::Comma)
|
||||
|| self.look_ahead(2, |t| t == &token::Colon)
|
||||
&& (
|
||||
// `{ ident: token, ` cannot start a block.
|
||||
self.look_ahead(4, |t| t == &token::Comma) ||
|
||||
// `{ ident: ` cannot start a block unless it's a type ascription `ident: Type`.
|
||||
self.look_ahead(3, |t| !t.can_begin_type())
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
fn maybe_parse_struct_expr(
|
||||
&mut self,
|
||||
lo: Span,
|
||||
@@ -1730,41 +1752,27 @@ fn maybe_parse_struct_expr(
|
||||
attrs: &AttrVec,
|
||||
) -> Option<PResult<'a, P<Expr>>> {
|
||||
let struct_allowed = !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL);
|
||||
let certainly_not_a_block = || {
|
||||
self.look_ahead(1, |t| t.is_ident())
|
||||
&& (
|
||||
// `{ ident, ` cannot start a block.
|
||||
self.look_ahead(2, |t| t == &token::Comma)
|
||||
|| self.look_ahead(2, |t| t == &token::Colon)
|
||||
&& (
|
||||
// `{ ident: token, ` cannot start a block.
|
||||
self.look_ahead(4, |t| t == &token::Comma) ||
|
||||
// `{ ident: ` cannot start a block unless it's a type ascription `ident: Type`.
|
||||
self.look_ahead(3, |t| !t.can_begin_type())
|
||||
)
|
||||
)
|
||||
};
|
||||
|
||||
if struct_allowed || certainly_not_a_block() {
|
||||
if struct_allowed || self.is_certainly_not_a_block() {
|
||||
// This is a struct literal, but we don't can't accept them here.
|
||||
let expr = self.parse_struct_expr(lo, path.clone(), attrs.clone());
|
||||
if let (Ok(expr), false) = (&expr, struct_allowed) {
|
||||
self.struct_span_err(expr.span, "struct literals are not allowed here")
|
||||
.multipart_suggestion(
|
||||
"surround the struct literal with parentheses",
|
||||
vec![
|
||||
(lo.shrink_to_lo(), "(".to_string()),
|
||||
(expr.span.shrink_to_hi(), ")".to_string()),
|
||||
],
|
||||
Applicability::MachineApplicable,
|
||||
)
|
||||
.emit();
|
||||
self.error_struct_lit_not_allowed_here(lo, expr.span);
|
||||
}
|
||||
return Some(expr);
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn error_struct_lit_not_allowed_here(&self, lo: Span, sp: Span) {
|
||||
self.struct_span_err(sp, "struct literals are not allowed here")
|
||||
.multipart_suggestion(
|
||||
"surround the struct literal with parentheses",
|
||||
vec![(lo.shrink_to_lo(), "(".to_string()), (sp.shrink_to_hi(), ")".to_string())],
|
||||
Applicability::MachineApplicable,
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
|
||||
pub(super) fn parse_struct_expr(
|
||||
&mut self,
|
||||
lo: Span,
|
||||
@@ -1782,50 +1790,19 @@ pub(super) fn parse_struct_expr(
|
||||
if self.eat(&token::DotDot) {
|
||||
let exp_span = self.prev_span;
|
||||
match self.parse_expr() {
|
||||
Ok(e) => {
|
||||
base = Some(e);
|
||||
}
|
||||
Ok(e) => base = Some(e),
|
||||
Err(mut e) => {
|
||||
e.emit();
|
||||
self.recover_stmt();
|
||||
}
|
||||
}
|
||||
if self.token == token::Comma {
|
||||
self.struct_span_err(
|
||||
exp_span.to(self.prev_span),
|
||||
"cannot use a comma after the base struct",
|
||||
)
|
||||
.span_suggestion_short(
|
||||
self.token.span,
|
||||
"remove this comma",
|
||||
String::new(),
|
||||
Applicability::MachineApplicable,
|
||||
)
|
||||
.note("the base struct must always be the last field")
|
||||
.emit();
|
||||
self.recover_stmt();
|
||||
}
|
||||
self.recover_struct_comma_after_dotdot(exp_span);
|
||||
break;
|
||||
}
|
||||
|
||||
let mut recovery_field = None;
|
||||
if let token::Ident(name, _) = self.token.kind {
|
||||
if !self.token.is_reserved_ident() && self.look_ahead(1, |t| *t == token::Colon) {
|
||||
// Use in case of error after field-looking code: `S { foo: () with a }`.
|
||||
recovery_field = Some(ast::Field {
|
||||
ident: Ident::new(name, self.token.span),
|
||||
span: self.token.span,
|
||||
expr: self.mk_expr(self.token.span, ExprKind::Err, AttrVec::new()),
|
||||
is_shorthand: false,
|
||||
attrs: AttrVec::new(),
|
||||
id: DUMMY_NODE_ID,
|
||||
is_placeholder: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
let mut parsed_field = None;
|
||||
match self.parse_field() {
|
||||
Ok(f) => parsed_field = Some(f),
|
||||
let recovery_field = self.find_struct_error_after_field_looking_code();
|
||||
let parsed_field = match self.parse_field() {
|
||||
Ok(f) => Some(f),
|
||||
Err(mut e) => {
|
||||
e.span_label(struct_sp, "while parsing this struct");
|
||||
e.emit();
|
||||
@@ -1839,8 +1816,9 @@ pub(super) fn parse_struct_expr(
|
||||
break;
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
match self.expect_one_of(&[token::Comma], &[token::CloseDelim(token::Brace)]) {
|
||||
Ok(_) => {
|
||||
@@ -1863,53 +1841,91 @@ pub(super) fn parse_struct_expr(
|
||||
|
||||
let span = lo.to(self.token.span);
|
||||
self.expect(&token::CloseDelim(token::Brace))?;
|
||||
return Ok(self.mk_expr(span, ExprKind::Struct(pth, fields, base), attrs));
|
||||
Ok(self.mk_expr(span, ExprKind::Struct(pth, fields, base), attrs))
|
||||
}
|
||||
|
||||
/// Use in case of error after field-looking code: `S { foo: () with a }`.
|
||||
fn find_struct_error_after_field_looking_code(&self) -> Option<Field> {
|
||||
if let token::Ident(name, _) = self.token.kind {
|
||||
if !self.token.is_reserved_ident() && self.look_ahead(1, |t| *t == token::Colon) {
|
||||
let span = self.token.span;
|
||||
return Some(ast::Field {
|
||||
ident: Ident::new(name, span),
|
||||
span,
|
||||
expr: self.mk_expr_err(span),
|
||||
is_shorthand: false,
|
||||
attrs: AttrVec::new(),
|
||||
id: DUMMY_NODE_ID,
|
||||
is_placeholder: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn recover_struct_comma_after_dotdot(&mut self, span: Span) {
|
||||
if self.token != token::Comma {
|
||||
return;
|
||||
}
|
||||
self.struct_span_err(span.to(self.prev_span), "cannot use a comma after the base struct")
|
||||
.span_suggestion_short(
|
||||
self.token.span,
|
||||
"remove this comma",
|
||||
String::new(),
|
||||
Applicability::MachineApplicable,
|
||||
)
|
||||
.note("the base struct must always be the last field")
|
||||
.emit();
|
||||
self.recover_stmt();
|
||||
}
|
||||
|
||||
/// Parses `ident (COLON expr)?`.
|
||||
fn parse_field(&mut self) -> PResult<'a, Field> {
|
||||
let attrs = self.parse_outer_attributes()?;
|
||||
let attrs = self.parse_outer_attributes()?.into();
|
||||
let lo = self.token.span;
|
||||
|
||||
// Check if a colon exists one ahead. This means we're parsing a fieldname.
|
||||
let (fieldname, expr, is_shorthand) =
|
||||
if self.look_ahead(1, |t| t == &token::Colon || t == &token::Eq) {
|
||||
let fieldname = self.parse_field_name()?;
|
||||
|
||||
// Check for an equals token. This means the source incorrectly attempts to
|
||||
// initialize a field with an eq rather than a colon.
|
||||
if self.token == token::Eq {
|
||||
self.diagnostic()
|
||||
.struct_span_err(self.token.span, "expected `:`, found `=`")
|
||||
.span_suggestion(
|
||||
fieldname.span.shrink_to_hi().to(self.token.span),
|
||||
"replace equals symbol with a colon",
|
||||
":".to_string(),
|
||||
Applicability::MachineApplicable,
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
self.bump(); // `:`
|
||||
(fieldname, self.parse_expr()?, false)
|
||||
} else {
|
||||
let fieldname = self.parse_ident_common(false)?;
|
||||
|
||||
// Mimic `x: x` for the `x` field shorthand.
|
||||
let path = ast::Path::from_ident(fieldname);
|
||||
let expr = self.mk_expr(fieldname.span, ExprKind::Path(None, path), AttrVec::new());
|
||||
(fieldname, expr, true)
|
||||
};
|
||||
let is_shorthand = !self.look_ahead(1, |t| t == &token::Colon || t == &token::Eq);
|
||||
let (ident, expr) = if is_shorthand {
|
||||
// Mimic `x: x` for the `x` field shorthand.
|
||||
let ident = self.parse_ident_common(false)?;
|
||||
let path = ast::Path::from_ident(ident);
|
||||
(ident, self.mk_expr(ident.span, ExprKind::Path(None, path), AttrVec::new()))
|
||||
} else {
|
||||
let ident = self.parse_field_name()?;
|
||||
self.error_on_eq_field_init(ident);
|
||||
self.bump(); // `:`
|
||||
(ident, self.parse_expr()?)
|
||||
};
|
||||
Ok(ast::Field {
|
||||
ident: fieldname,
|
||||
ident,
|
||||
span: lo.to(expr.span),
|
||||
expr,
|
||||
is_shorthand,
|
||||
attrs: attrs.into(),
|
||||
attrs,
|
||||
id: DUMMY_NODE_ID,
|
||||
is_placeholder: false,
|
||||
})
|
||||
}
|
||||
|
||||
/// Check for `=`. This means the source incorrectly attempts to
|
||||
/// initialize a field with an eq rather than a colon.
|
||||
fn error_on_eq_field_init(&self, field_name: Ident) {
|
||||
if self.token != token::Eq {
|
||||
return;
|
||||
}
|
||||
|
||||
self.diagnostic()
|
||||
.struct_span_err(self.token.span, "expected `:`, found `=`")
|
||||
.span_suggestion(
|
||||
field_name.span.shrink_to_hi().to(self.token.span),
|
||||
"replace equals symbol with a colon",
|
||||
":".to_string(),
|
||||
Applicability::MachineApplicable,
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
|
||||
fn err_dotdotdot_syntax(&self, span: Span) {
|
||||
self.struct_span_err(span, "unexpected token: `...`")
|
||||
.span_suggestion(
|
||||
|
||||
@@ -1348,7 +1348,7 @@ fn parse_item_struct(&mut self) -> PResult<'a, ItemInfo> {
|
||||
self.expect_semi()?;
|
||||
body
|
||||
} else {
|
||||
let token_str = self.this_token_descr();
|
||||
let token_str = super::token_descr(&self.token);
|
||||
let mut err = self.fatal(&format!(
|
||||
"expected `where`, `{{`, `(`, or `;` after struct name, found {}",
|
||||
token_str
|
||||
@@ -1374,7 +1374,7 @@ fn parse_item_union(&mut self) -> PResult<'a, ItemInfo> {
|
||||
let (fields, recovered) = self.parse_record_struct_body()?;
|
||||
VariantData::Struct(fields, recovered)
|
||||
} else {
|
||||
let token_str = self.this_token_descr();
|
||||
let token_str = super::token_descr(&self.token);
|
||||
let mut err = self
|
||||
.fatal(&format!("expected `where` or `{{` after union name, found {}", token_str));
|
||||
err.span_label(self.token.span, "expected `where` or `{` after union name");
|
||||
@@ -1411,7 +1411,7 @@ fn parse_record_struct_body(
|
||||
}
|
||||
self.eat(&token::CloseDelim(token::Brace));
|
||||
} else {
|
||||
let token_str = self.this_token_descr();
|
||||
let token_str = super::token_descr(&self.token);
|
||||
let mut err = self.fatal(&format!(
|
||||
"expected `where`, or `{{` after struct name, found {}",
|
||||
token_str
|
||||
@@ -1498,7 +1498,7 @@ fn parse_single_struct_field(
|
||||
let sp = self.sess.source_map().next_point(self.prev_span);
|
||||
let mut err = self.struct_span_err(
|
||||
sp,
|
||||
&format!("expected `,`, or `}}`, found {}", self.this_token_descr()),
|
||||
&format!("expected `,`, or `}}`, found {}", super::token_descr(&self.token)),
|
||||
);
|
||||
if self.token.is_ident() {
|
||||
// This is likely another field; emit the diagnostic and keep going
|
||||
|
||||
@@ -354,6 +354,24 @@ pub enum FollowedByType {
|
||||
No,
|
||||
}
|
||||
|
||||
fn token_descr_opt(token: &Token) -> Option<&'static str> {
|
||||
Some(match token.kind {
|
||||
_ if token.is_special_ident() => "reserved identifier",
|
||||
_ if token.is_used_keyword() => "keyword",
|
||||
_ if token.is_unused_keyword() => "reserved keyword",
|
||||
token::DocComment(..) => "doc comment",
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
|
||||
pub(super) fn token_descr(token: &Token) -> String {
|
||||
let token_str = pprust::token_to_string(token);
|
||||
match token_descr_opt(token) {
|
||||
Some(prefix) => format!("{} `{}`", prefix, token_str),
|
||||
_ => format!("`{}`", token_str),
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Parser<'a> {
|
||||
pub fn new(
|
||||
sess: &'a ParseSess,
|
||||
@@ -422,29 +440,6 @@ fn next_tok(&mut self) -> Token {
|
||||
next
|
||||
}
|
||||
|
||||
/// Converts the current token to a string using `self`'s reader.
|
||||
pub fn this_token_to_string(&self) -> String {
|
||||
pprust::token_to_string(&self.token)
|
||||
}
|
||||
|
||||
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",
|
||||
_ if self.token.is_unused_keyword() => "reserved keyword",
|
||||
token::DocComment(..) => "doc comment",
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
|
||||
pub(super) fn this_token_descr(&self) -> String {
|
||||
if let Some(prefix) = self.token_descr() {
|
||||
format!("{} `{}`", prefix, self.this_token_to_string())
|
||||
} else {
|
||||
format!("`{}`", self.this_token_to_string())
|
||||
}
|
||||
}
|
||||
|
||||
crate fn unexpected<T>(&mut self) -> PResult<'a, T> {
|
||||
match self.expect_one_of(&[], &[]) {
|
||||
Err(e) => Err(e),
|
||||
|
||||
@@ -79,7 +79,7 @@ fn parse_mod_items(&mut self, term: &TokenKind, inner_lo: Span) -> PResult<'a, M
|
||||
}
|
||||
|
||||
if !self.eat(term) {
|
||||
let token_str = self.this_token_descr();
|
||||
let token_str = super::token_descr(&self.token);
|
||||
if !self.maybe_consume_incorrect_semicolon(&items) {
|
||||
let mut err = self.fatal(&format!("expected item, found {}", token_str));
|
||||
err.span_label(self.token.span, "expected item");
|
||||
|
||||
@@ -671,7 +671,7 @@ fn fatal_unexpected_non_pat(
|
||||
err.cancel();
|
||||
|
||||
let expected = expected.unwrap_or("pattern");
|
||||
let msg = format!("expected {}, found {}", expected, self.this_token_descr());
|
||||
let msg = format!("expected {}, found {}", expected, super::token_descr(&self.token));
|
||||
|
||||
let mut err = self.fatal(&msg);
|
||||
err.span_label(self.token.span, format!("expected {}", expected));
|
||||
@@ -876,7 +876,7 @@ fn parse_pat_fields(&mut self) -> PResult<'a, (Vec<FieldPat>, bool)> {
|
||||
etc_span = Some(etc_sp);
|
||||
break;
|
||||
}
|
||||
let token_str = self.this_token_descr();
|
||||
let token_str = super::token_descr(&self.token);
|
||||
let mut err = self.fatal(&format!("expected `}}`, found {}", token_str));
|
||||
|
||||
err.span_label(self.token.span, "expected `}`");
|
||||
|
||||
@@ -323,7 +323,7 @@ pub fn parse_block(&mut self) -> PResult<'a, P<Block>> {
|
||||
|
||||
fn error_block_no_opening_brace<T>(&mut self) -> PResult<'a, T> {
|
||||
let sp = self.token.span;
|
||||
let tok = self.this_token_descr();
|
||||
let tok = super::token_descr(&self.token);
|
||||
let mut e = self.span_fatal(sp, &format!("expected `{{`, found {}", tok));
|
||||
let do_not_suggest_help = self.token.is_keyword(kw::In) || self.token == token::Colon;
|
||||
|
||||
@@ -411,7 +411,7 @@ pub(super) fn parse_block_tail(
|
||||
continue;
|
||||
};
|
||||
}
|
||||
Ok(P(ast::Block { stmts, id: DUMMY_NODE_ID, rules: s, span: lo.to(self.prev_span) }))
|
||||
Ok(self.mk_block(stmts, s, lo.to(self.prev_span)))
|
||||
}
|
||||
|
||||
/// Parses a statement, including the trailing semicolon.
|
||||
@@ -463,7 +463,7 @@ pub fn parse_full_stmt(&mut self, macro_legacy_warnings: bool) -> PResult<'a, Op
|
||||
fn warn_missing_semicolon(&self) {
|
||||
self.diagnostic()
|
||||
.struct_span_warn(self.token.span, {
|
||||
&format!("expected `;`, found {}", self.this_token_descr())
|
||||
&format!("expected `;`, found {}", super::token_descr(&self.token))
|
||||
})
|
||||
.note({
|
||||
"this was erroneously allowed and will become a hard error in a future release"
|
||||
@@ -471,7 +471,11 @@ fn warn_missing_semicolon(&self) {
|
||||
.emit();
|
||||
}
|
||||
|
||||
fn mk_stmt(&self, span: Span, kind: StmtKind) -> Stmt {
|
||||
pub(super) fn mk_block(&self, stmts: Vec<Stmt>, rules: BlockCheckMode, span: Span) -> P<Block> {
|
||||
P(Block { stmts, id: DUMMY_NODE_ID, rules, span })
|
||||
}
|
||||
|
||||
pub(super) fn mk_stmt(&self, span: Span, kind: StmtKind) -> Stmt {
|
||||
Stmt { id: DUMMY_NODE_ID, kind, span }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,7 +135,7 @@ fn parse_ty_common(
|
||||
TyKind::Err
|
||||
}
|
||||
} else {
|
||||
let msg = format!("expected type, found {}", self.this_token_descr());
|
||||
let msg = format!("expected type, found {}", super::token_descr(&self.token));
|
||||
let mut err = self.struct_span_err(self.token.span, &msg);
|
||||
err.span_label(self.token.span, "expected type");
|
||||
self.maybe_annotate_with_ascription(&mut err, true);
|
||||
|
||||
@@ -904,10 +904,8 @@ pub fn ensure_complete_parse<'a>(
|
||||
span: Span,
|
||||
) {
|
||||
if this.token != token::Eof {
|
||||
let msg = format!(
|
||||
"macro expansion ignores token `{}` and any following",
|
||||
this.this_token_to_string()
|
||||
);
|
||||
let token = pprust::token_to_string(&this.token);
|
||||
let msg = format!("macro expansion ignores token `{}` and any following", token);
|
||||
// Avoid emitting backtrace info twice.
|
||||
let def_site_span = this.token.span.with_ctxt(SyntaxContext::root());
|
||||
let mut err = this.struct_span_err(def_site_span, &msg);
|
||||
|
||||
@@ -133,15 +133,17 @@ fn make_expr(mut self: Box<ExpandResult<'a>>) -> Option<P<ast::Expr>> {
|
||||
while self.p.token != token::Eof {
|
||||
match panictry!(self.p.parse_item()) {
|
||||
Some(item) => ret.push(item),
|
||||
None => self
|
||||
.p
|
||||
.sess
|
||||
.span_diagnostic
|
||||
.span_fatal(
|
||||
self.p.token.span,
|
||||
&format!("expected item, found `{}`", self.p.this_token_to_string()),
|
||||
)
|
||||
.raise(),
|
||||
None => {
|
||||
let token = pprust::token_to_string(&self.p.token);
|
||||
self.p
|
||||
.sess
|
||||
.span_diagnostic
|
||||
.span_fatal(
|
||||
self.p.token.span,
|
||||
&format!("expected item, found `{}`", token),
|
||||
)
|
||||
.raise();
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(ret)
|
||||
|
||||
@@ -26,7 +26,7 @@ error: expected `{`, found `;`
|
||||
--> $DIR/issue-46836-identifier-not-instead-of-negation.rs:20:31
|
||||
|
|
||||
LL | if not // lack of braces is [sic]
|
||||
| -- this `if` statement has a condition, but no block
|
||||
| -- this `if` expression has a condition, but no block
|
||||
LL | println!("Then when?");
|
||||
| ^
|
||||
| |
|
||||
|
||||
@@ -2,7 +2,7 @@ warning: irrefutable if-let pattern
|
||||
--> $DIR/if-let.rs:6:13
|
||||
|
|
||||
LL | if let $p = $e $b
|
||||
| ^^
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
...
|
||||
LL | / foo!(a, 1, {
|
||||
LL | | println!("irrefutable pattern");
|
||||
@@ -15,7 +15,7 @@ warning: irrefutable if-let pattern
|
||||
--> $DIR/if-let.rs:6:13
|
||||
|
|
||||
LL | if let $p = $e $b
|
||||
| ^^
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
...
|
||||
LL | / bar!(a, 1, {
|
||||
LL | | println!("irrefutable pattern");
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
fn main() {
|
||||
let n = 1;
|
||||
if 5 == {
|
||||
//~^ NOTE this `if` statement has a condition, but no block
|
||||
//~^ NOTE this `if` expression has a condition, but no block
|
||||
println!("five");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ error: expected `{`, found `}`
|
||||
--> $DIR/if-without-block.rs:7:1
|
||||
|
|
||||
LL | if 5 == {
|
||||
| -- this `if` statement has a condition, but no block
|
||||
| -- this `if` expression has a condition, but no block
|
||||
...
|
||||
LL | }
|
||||
| ^ expected `{`
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
fn main() {
|
||||
if true {
|
||||
} else if { //~ ERROR missing condition
|
||||
//~^ ERROR mismatched types
|
||||
} else {
|
||||
}
|
||||
}
|
||||
@@ -8,6 +9,7 @@ fn main() {
|
||||
fn foo() {
|
||||
if true {
|
||||
} else if { //~ ERROR missing condition
|
||||
//~^ ERROR mismatched types
|
||||
}
|
||||
bar();
|
||||
}
|
||||
|
||||
@@ -5,10 +5,29 @@ LL | } else if {
|
||||
| ^ expected if condition here
|
||||
|
||||
error: missing condition for `if` expression
|
||||
--> $DIR/issue-13483.rs:10:14
|
||||
--> $DIR/issue-13483.rs:11:14
|
||||
|
|
||||
LL | } else if {
|
||||
| ^ expected if condition here
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/issue-13483.rs:3:15
|
||||
|
|
||||
LL | } else if {
|
||||
| _______________^
|
||||
LL | |
|
||||
LL | | } else {
|
||||
| |_____^ expected `bool`, found `()`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/issue-13483.rs:11:15
|
||||
|
|
||||
LL | } else if {
|
||||
| _______________^
|
||||
LL | |
|
||||
LL | | }
|
||||
| |_____^ expected `bool`, found `()`
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
||||
|
||||
@@ -4,7 +4,7 @@ error: expected `{`, found `foo`
|
||||
LL | if $tgt.has_$field() {}
|
||||
| -- -- help: try placing this code inside a block: `{ () }`
|
||||
| |
|
||||
| this `if` statement has a condition, but no block
|
||||
| this `if` expression has a condition, but no block
|
||||
...
|
||||
LL | get_opt!(bar, foo);
|
||||
| ^^^ expected `{`
|
||||
|
||||
@@ -4,7 +4,7 @@ error: expected `{`, found keyword `in`
|
||||
LL | if i in 1..10 {
|
||||
| -- ^^ expected `{`
|
||||
| |
|
||||
| this `if` statement has a condition, but no block
|
||||
| this `if` expression has a condition, but no block
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ error: expected `{`, found `)`
|
||||
LL | (if foobar)
|
||||
| -- ^ expected `{`
|
||||
| |
|
||||
| this `if` statement has a condition, but no block
|
||||
| this `if` expression has a condition, but no block
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ error: expected `{`, found `macro_rules`
|
||||
LL | fn foo(u: u8) { if u8 macro_rules! u8 { (u6) => { fn uuuuuuuuuuu() { use s loo mod u8 {
|
||||
| -- ^^^^^^^^^^^ expected `{`
|
||||
| |
|
||||
| this `if` statement has a condition, but no block
|
||||
| this `if` expression has a condition, but no block
|
||||
|
|
||||
help: try placing this code inside a block
|
||||
|
|
||||
|
||||
@@ -12,7 +12,7 @@ LL | if true 'b: {}
|
||||
| | |
|
||||
| | expected `{`
|
||||
| | help: try placing this code inside a block: `{ 'b: {} }`
|
||||
| this `if` statement has a condition, but no block
|
||||
| this `if` expression has a condition, but no block
|
||||
|
||||
error: expected `{`, found `'b`
|
||||
--> $DIR/label_break_value_illegal_uses.rs:14:21
|
||||
|
||||
@@ -4,13 +4,13 @@ error: expected `{`, found `=>`
|
||||
LL | if (foo) => {}
|
||||
| -- ^^ expected `{`
|
||||
| |
|
||||
| this `if` statement has a condition, but no block
|
||||
| this `if` expression has a condition, but no block
|
||||
|
||||
error: expected `{`, found `bar`
|
||||
--> $DIR/missing-block-hint.rs:7:13
|
||||
|
|
||||
LL | if (foo)
|
||||
| -- this `if` statement has a condition, but no block
|
||||
| -- this `if` expression has a condition, but no block
|
||||
LL | bar;
|
||||
| ^^^-
|
||||
| |
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
#[cfg(FALSE)] fn e() { let _ = x.#![attr]foo(); }
|
||||
//~^ ERROR unexpected token: `#`
|
||||
@@ -1,8 +0,0 @@
|
||||
error: unexpected token: `#`
|
||||
--> $DIR/attr-stmt-expr-attr-bad-2.rs:1:34
|
||||
|
|
||||
LL | #[cfg(FALSE)] fn e() { let _ = x.#![attr]foo(); }
|
||||
| ^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
#[cfg(FALSE)] fn e() { let _ = x.#[attr]foo(); }
|
||||
//~^ ERROR unexpected token: `#`
|
||||
@@ -1,8 +0,0 @@
|
||||
error: unexpected token: `#`
|
||||
--> $DIR/attr-stmt-expr-attr-bad-3.rs:1:34
|
||||
|
|
||||
LL | #[cfg(FALSE)] fn e() { let _ = x.#[attr]foo(); }
|
||||
| ^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
@@ -101,6 +101,13 @@ fn main() {}
|
||||
//~^ ERROR `X..=` range patterns are not supported
|
||||
//~| ERROR expected one of `=>`, `if`, or `|`, found `#`
|
||||
|
||||
#[cfg(FALSE)] fn e() { let _ = x.#![attr]foo(); }
|
||||
//~^ ERROR unexpected token: `#`
|
||||
//~| ERROR expected one of `.`
|
||||
#[cfg(FALSE)] fn e() { let _ = x.#[attr]foo(); }
|
||||
//~^ ERROR unexpected token: `#`
|
||||
//~| ERROR expected one of `.`
|
||||
|
||||
// make sure we don't catch this bug again...
|
||||
#[cfg(FALSE)] fn e() { { fn foo() { #[attr]; } } }
|
||||
//~^ ERROR expected statement after outer attribute
|
||||
|
||||
@@ -149,7 +149,7 @@ LL | #[cfg(FALSE)] fn e() { let _ = if 0 #[attr] {}; }
|
||||
| -- ^ --- help: try placing this code inside a block: `{ {}; }`
|
||||
| | |
|
||||
| | expected `{`
|
||||
| this `if` statement has a condition, but no block
|
||||
| this `if` expression has a condition, but no block
|
||||
|
||||
error: an inner attribute is not permitted in this context
|
||||
--> $DIR/attr-stmt-expr-attr-bad.rs:43:38
|
||||
@@ -202,7 +202,7 @@ LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else if 0 #[attr] {}; }
|
||||
| -- ^ --- help: try placing this code inside a block: `{ {}; }`
|
||||
| | |
|
||||
| | expected `{`
|
||||
| this `if` statement has a condition, but no block
|
||||
| this `if` expression has a condition, but no block
|
||||
|
||||
error: an inner attribute is not permitted in this context
|
||||
--> $DIR/attr-stmt-expr-attr-bad.rs:56:51
|
||||
@@ -225,7 +225,7 @@ LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 #[attr] {}; }
|
||||
| -- ^ --- help: try placing this code inside a block: `{ {}; }`
|
||||
| | |
|
||||
| | expected `{`
|
||||
| this `if` statement has a condition, but no block
|
||||
| this `if` expression has a condition, but no block
|
||||
|
||||
error: an inner attribute is not permitted in this context
|
||||
--> $DIR/attr-stmt-expr-attr-bad.rs:62:46
|
||||
@@ -278,7 +278,7 @@ LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 #[attr] {}
|
||||
| -- ^ --- help: try placing this code inside a block: `{ {}; }`
|
||||
| | |
|
||||
| | expected `{`
|
||||
| this `if` statement has a condition, but no block
|
||||
| this `if` expression has a condition, but no block
|
||||
|
||||
error: an inner attribute is not permitted in this context
|
||||
--> $DIR/attr-stmt-expr-attr-bad.rs:75:67
|
||||
@@ -380,11 +380,35 @@ error: expected one of `=>`, `if`, or `|`, found `#`
|
||||
LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] FOO => () } }
|
||||
| ^ expected one of `=>`, `if`, or `|`
|
||||
|
||||
error: unexpected token: `#`
|
||||
--> $DIR/attr-stmt-expr-attr-bad.rs:104:34
|
||||
|
|
||||
LL | #[cfg(FALSE)] fn e() { let _ = x.#![attr]foo(); }
|
||||
| ^
|
||||
|
||||
error: expected one of `.`, `;`, `?`, or an operator, found `#`
|
||||
--> $DIR/attr-stmt-expr-attr-bad.rs:104:34
|
||||
|
|
||||
LL | #[cfg(FALSE)] fn e() { let _ = x.#![attr]foo(); }
|
||||
| ^ expected one of `.`, `;`, `?`, or an operator
|
||||
|
||||
error: unexpected token: `#`
|
||||
--> $DIR/attr-stmt-expr-attr-bad.rs:107:34
|
||||
|
|
||||
LL | #[cfg(FALSE)] fn e() { let _ = x.#[attr]foo(); }
|
||||
| ^
|
||||
|
||||
error: expected one of `.`, `;`, `?`, or an operator, found `#`
|
||||
--> $DIR/attr-stmt-expr-attr-bad.rs:107:34
|
||||
|
|
||||
LL | #[cfg(FALSE)] fn e() { let _ = x.#[attr]foo(); }
|
||||
| ^ expected one of `.`, `;`, `?`, or an operator
|
||||
|
||||
error: expected statement after outer attribute
|
||||
--> $DIR/attr-stmt-expr-attr-bad.rs:105:44
|
||||
--> $DIR/attr-stmt-expr-attr-bad.rs:112:44
|
||||
|
|
||||
LL | #[cfg(FALSE)] fn e() { { fn foo() { #[attr]; } } }
|
||||
| ^
|
||||
|
||||
error: aborting due to 52 previous errors
|
||||
error: aborting due to 56 previous errors
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ error: expected `{`, found doc comment `/*!*/`
|
||||
LL | if true /*!*/ {}
|
||||
| -- ^^^^^ expected `{`
|
||||
| |
|
||||
| this `if` statement has a condition, but no block
|
||||
| this `if` expression has a condition, but no block
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ warning: irrefutable while-let pattern
|
||||
--> $DIR/while-let.rs:7:13
|
||||
|
|
||||
LL | while let $p = $e $b
|
||||
| ^^^^^
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
...
|
||||
LL | / foo!(_a, 1, {
|
||||
LL | | println!("irrefutable pattern");
|
||||
@@ -15,7 +15,7 @@ warning: irrefutable while-let pattern
|
||||
--> $DIR/while-let.rs:7:13
|
||||
|
|
||||
LL | while let $p = $e $b
|
||||
| ^^^^^
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
...
|
||||
LL | / bar!(_a, 1, {
|
||||
LL | | println!("irrefutable pattern");
|
||||
|
||||
Reference in New Issue
Block a user