use super::pat::{GateOr, PARAM_EXPECTED}; use super::ty::{AllowPlus, RecoverQPath}; use super::{BlockMode, Parser, PathStyle, Restrictions, TokenType}; use super::{SemiColonMode, SeqSep, TokenExpectType}; use crate::maybe_recover_from_interpolated_ty_qpath; use rustc_ast::ast::{self, AttrStyle, AttrVec, CaptureBy, Field, Ident, Lit, DUMMY_NODE_ID}; use rustc_ast::ast::{AnonConst, BinOp, BinOpKind, FnDecl, FnRetTy, Mac, Param, Ty, TyKind, UnOp}; use rustc_ast::ast::{Arm, Async, BlockCheckMode, Expr, ExprKind, Label, Movability, RangeLimits}; use rustc_ast::ptr::P; use rustc_ast::token::{self, Token, TokenKind}; use rustc_ast::util::classify; use rustc_ast::util::literal::LitError; use rustc_ast::util::parser::{prec_let_scrutinee_needs_par, AssocOp, Fixity}; use rustc_ast_pretty::pprust; use rustc_errors::{Applicability, PResult}; use rustc_span::source_map::{self, Span, Spanned}; use rustc_span::symbol::{kw, sym, Symbol}; use std::mem; /// Possibly accepts an `token::Interpolated` expression (a pre-parsed expression /// dropped into the token stream, which happens while parsing the result of /// macro expansion). Placement of these is not as complex as I feared it would /// be. The important thing is to make sure that lookahead doesn't balk at /// `token::Interpolated` tokens. macro_rules! maybe_whole_expr { ($p:expr) => { if let token::Interpolated(nt) = &$p.token.kind { match &**nt { token::NtExpr(e) | token::NtLiteral(e) => { let e = e.clone(); $p.bump(); return Ok(e); } token::NtPath(path) => { let path = path.clone(); $p.bump(); return Ok($p.mk_expr( $p.token.span, ExprKind::Path(None, path), AttrVec::new(), )); } token::NtBlock(block) => { let block = block.clone(); $p.bump(); return Ok($p.mk_expr( $p.token.span, ExprKind::Block(block, None), AttrVec::new(), )); } _ => {} }; } }; } #[derive(Debug)] pub(super) enum LhsExpr { NotYetParsed, AttributesParsed(AttrVec), AlreadyParsed(P), } impl From> for LhsExpr { /// Converts `Some(attrs)` into `LhsExpr::AttributesParsed(attrs)` /// and `None` into `LhsExpr::NotYetParsed`. /// /// This conversion does not allocate. fn from(o: Option) -> Self { if let Some(attrs) = o { LhsExpr::AttributesParsed(attrs) } else { LhsExpr::NotYetParsed } } } impl From> for LhsExpr { /// Converts the `expr: P` into `LhsExpr::AlreadyParsed(expr)`. /// /// This conversion does not allocate. fn from(expr: P) -> Self { LhsExpr::AlreadyParsed(expr) } } impl<'a> Parser<'a> { /// Parses an expression. #[inline] pub fn parse_expr(&mut self) -> PResult<'a, P> { self.parse_expr_res(Restrictions::empty(), None) } pub(super) fn parse_anon_const_expr(&mut self) -> PResult<'a, AnonConst> { self.parse_expr().map(|value| AnonConst { id: DUMMY_NODE_ID, value }) } fn parse_expr_catch_underscore(&mut self) -> PResult<'a, P> { match self.parse_expr() { Ok(expr) => Ok(expr), Err(mut err) => match self.token.ident() { Some((Ident { name: kw::Underscore, .. }, false)) if self.look_ahead(1, |t| t == &token::Comma) => { // Special-case handling of `foo(_, _, _)` err.emit(); self.bump(); Ok(self.mk_expr(self.prev_token.span, ExprKind::Err, AttrVec::new())) } _ => Err(err), }, } } /// Parses a sequence of expressions delimited by parentheses. fn parse_paren_expr_seq(&mut self) -> PResult<'a, Vec>> { self.parse_paren_comma_seq(|p| p.parse_expr_catch_underscore()).map(|(r, _)| r) } /// Parses an expression, subject to the given restrictions. #[inline] pub(super) fn parse_expr_res( &mut self, r: Restrictions, already_parsed_attrs: Option, ) -> PResult<'a, P> { self.with_res(r, |this| this.parse_assoc_expr(already_parsed_attrs)) } /// Parses an associative expression. /// /// This parses an expression accounting for associativity and precedence of the operators in /// the expression. #[inline] fn parse_assoc_expr(&mut self, already_parsed_attrs: Option) -> PResult<'a, P> { self.parse_assoc_expr_with(0, already_parsed_attrs.into()) } /// Parses an associative expression with operators of at least `min_prec` precedence. pub(super) fn parse_assoc_expr_with( &mut self, min_prec: usize, lhs: LhsExpr, ) -> PResult<'a, P> { let mut lhs = if let LhsExpr::AlreadyParsed(expr) = lhs { expr } else { let attrs = match lhs { LhsExpr::AttributesParsed(attrs) => Some(attrs), _ => None, }; if [token::DotDot, token::DotDotDot, token::DotDotEq].contains(&self.token.kind) { return self.parse_prefix_range_expr(attrs); } else { self.parse_prefix_expr(attrs)? } }; let last_type_ascription_set = self.last_type_ascription.is_some(); if !self.should_continue_as_assoc_expr(&lhs) { self.last_type_ascription = None; return Ok(lhs); } self.expected_tokens.push(TokenType::Operator); while let Some(op) = self.check_assoc_op() { // Adjust the span for interpolated LHS to point to the `$lhs` token // and not to what it refers to. let lhs_span = match self.prev_token.kind { TokenKind::Interpolated(..) => self.prev_token.span, _ => lhs.span, }; let cur_op_span = self.token.span; let restrictions = if op.node.is_assign_like() { self.restrictions & Restrictions::NO_STRUCT_LITERAL } else { self.restrictions }; let prec = op.node.precedence(); if prec < min_prec { break; } // Check for deprecated `...` syntax if self.token == token::DotDotDot && op.node == AssocOp::DotDotEq { self.err_dotdotdot_syntax(self.token.span); } if self.token == token::LArrow { self.err_larrow_operator(self.token.span); } self.bump(); if op.node.is_comparison() { if let Some(expr) = self.check_no_chained_comparison(&lhs, &op)? { return Ok(expr); } } let op = op.node; // Special cases: if op == AssocOp::As { lhs = self.parse_assoc_op_cast(lhs, lhs_span, ExprKind::Cast)?; continue; } else if op == AssocOp::Colon { 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. lhs = self.parse_range_expr(prec, lhs, op, cur_op_span)?; break; } let fixity = op.fixity(); let prec_adjustment = match fixity { Fixity::Right => 0, Fixity::Left => 1, // We currently have no non-associative operators that are not handled above by // the special cases. The code is here only for future convenience. Fixity::None => 1, }; let rhs = self.with_res(restrictions - Restrictions::STMT_EXPR, |this| { this.parse_assoc_expr_with(prec + prec_adjustment, LhsExpr::NotYetParsed) })?; // Make sure that the span of the parent node is larger than the span of lhs and rhs, // including the attributes. let lhs_span = lhs.attrs.iter().find(|a| a.style == AttrStyle::Outer).map_or(lhs_span, |a| a.span); let span = lhs_span.to(rhs.span); lhs = match op { AssocOp::Add | AssocOp::Subtract | AssocOp::Multiply | AssocOp::Divide | AssocOp::Modulus | AssocOp::LAnd | AssocOp::LOr | AssocOp::BitXor | AssocOp::BitAnd | AssocOp::BitOr | AssocOp::ShiftLeft | AssocOp::ShiftRight | AssocOp::Equal | AssocOp::Less | AssocOp::LessEqual | AssocOp::NotEqual | AssocOp::Greater | AssocOp::GreaterEqual => { let ast_op = op.to_ast_binop().unwrap(); let binary = self.mk_binary(source_map::respan(cur_op_span, ast_op), lhs, rhs); self.mk_expr(span, binary, AttrVec::new()) } AssocOp::Assign => { self.mk_expr(span, ExprKind::Assign(lhs, rhs, cur_op_span), AttrVec::new()) } AssocOp::AssignOp(k) => { let aop = match k { token::Plus => BinOpKind::Add, token::Minus => BinOpKind::Sub, token::Star => BinOpKind::Mul, token::Slash => BinOpKind::Div, token::Percent => BinOpKind::Rem, token::Caret => BinOpKind::BitXor, token::And => BinOpKind::BitAnd, token::Or => BinOpKind::BitOr, token::Shl => BinOpKind::Shl, token::Shr => BinOpKind::Shr, }; let aopexpr = self.mk_assign_op(source_map::respan(cur_op_span, aop), lhs, rhs); self.mk_expr(span, aopexpr, AttrVec::new()) } AssocOp::As | AssocOp::Colon | AssocOp::DotDot | AssocOp::DotDotEq => { self.span_bug(span, "AssocOp should have been handled by special case") } }; if let Fixity::None = fixity { break; } } if last_type_ascription_set { self.last_type_ascription = None; } Ok(lhs) } fn should_continue_as_assoc_expr(&mut self, lhs: &Expr) -> bool { match (self.expr_is_complete(lhs), self.check_assoc_op().map(|op| op.node)) { // Semi-statement forms are odd: // See https://github.com/rust-lang/rust/issues/29071 (true, None) => false, (false, _) => true, // Continue parsing the expression. // An exhaustive check is done in the following block, but these are checked first // because they *are* ambiguous but also reasonable looking incorrect syntax, so we // want to keep their span info to improve diagnostics in these cases in a later stage. (true, Some(AssocOp::Multiply)) | // `{ 42 } *foo = bar;` or `{ 42 } * 3` (true, Some(AssocOp::Subtract)) | // `{ 42 } -5` (true, Some(AssocOp::LAnd)) | // `{ 42 } &&x` (#61475) (true, Some(AssocOp::Add)) // `{ 42 } + 42 // If the next token is a keyword, then the tokens above *are* unambiguously incorrect: // `if x { a } else { b } && if y { c } else { d }` if !self.look_ahead(1, |t| t.is_reserved_ident()) => { // These cases are ambiguous and can't be identified in the parser alone. let sp = self.sess.source_map().start_point(self.token.span); self.sess.ambiguous_block_expr_parse.borrow_mut().insert(sp, lhs.span); false } (true, Some(ref op)) if !op.can_continue_expr_unambiguously() => false, (true, Some(_)) => { self.error_found_expr_would_be_stmt(lhs); true } } } /// We've found an expression that would be parsed as a statement, /// but the next token implies this should be parsed as an expression. /// For example: `if let Some(x) = x { x } else { 0 } / 2`. fn error_found_expr_would_be_stmt(&self, lhs: &Expr) { let mut err = self.struct_span_err( self.token.span, &format!("expected expression, found `{}`", pprust::token_to_string(&self.token),), ); err.span_label(self.token.span, "expected expression"); self.sess.expr_parentheses_needed(&mut err, lhs.span, Some(pprust::expr_to_string(&lhs))); err.emit(); } /// Possibly translate the current token to an associative operator. /// The method does not advance the current token. /// /// Also performs recovery for `and` / `or` which are mistaken for `&&` and `||` respectively. fn check_assoc_op(&self) -> Option> { let (op, span) = match (AssocOp::from_token(&self.token), self.token.ident()) { (Some(op), _) => (op, self.token.span), (None, Some((Ident { name: sym::and, span }, false))) => { self.error_bad_logical_op("and", "&&", "conjunction"); (AssocOp::LAnd, span) } (None, Some((Ident { name: sym::or, span }, false))) => { self.error_bad_logical_op("or", "||", "disjunction"); (AssocOp::LOr, span) } _ => return None, }; Some(source_map::respan(span, op)) } /// Error on `and` and `or` suggesting `&&` and `||` respectively. fn error_bad_logical_op(&self, bad: &str, good: &str, english: &str) { self.struct_span_err(self.token.span, &format!("`{}` is not a logical operator", bad)) .span_suggestion_short( self.token.span, &format!("use `{}` to perform logical {}", good, english), good.to_string(), Applicability::MachineApplicable, ) .note("unlike in e.g., python and PHP, `&&` and `||` are used for logical operators") .emit(); } /// Checks if this expression is a successfully parsed statement. fn expr_is_complete(&self, e: &Expr) -> bool { self.restrictions.contains(Restrictions::STMT_EXPR) && !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, op: AssocOp, cur_op_span: Span, ) -> PResult<'a, P> { 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..{})`. if self.token == token::OpenDelim(token::Brace) { return !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL); } true } else { false } } /// Parses prefix-forms of range notation: `..expr`, `..`, `..=expr`. fn parse_prefix_range_expr(&mut self, attrs: Option) -> PResult<'a, P> { // Check for deprecated `...` syntax. if self.token == token::DotDotDot { self.err_dotdotdot_syntax(self.token.span); } debug_assert!( [token::DotDot, token::DotDotDot, token::DotDotEq].contains(&self.token.kind), "parse_prefix_range_expr: token {:?} is not DotDot/DotDotEq", self.token ); 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, attrs: Option) -> PResult<'a, P> { 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.uninterpolate().kind { 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)> { 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.uninterpolate().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(), }; 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. fn interpolated_or_expr_span( &self, expr: PResult<'a, P>, ) -> PResult<'a, (Span, P)> { expr.map(|e| { ( match self.prev_token.kind { TokenKind::Interpolated(..) => self.prev_token.span, _ => e.span, }, e, ) }) } fn parse_assoc_op_cast( &mut self, lhs: P, lhs_span: Span, expr_kind: fn(P, P) -> ExprKind, ) -> PResult<'a, P> { let mk_expr = |this: &mut Self, rhs: P| { this.mk_expr(lhs_span.to(rhs.span), expr_kind(lhs, rhs), AttrVec::new()) }; // Save the state of the parser before parsing type normally, in case there is a // LessThan comparison after this cast. let parser_snapshot_before_type = self.clone(); let cast_expr = match self.parse_ty_no_plus() { Ok(rhs) => mk_expr(self, rhs), Err(mut type_err) => { // Rewind to before attempting to parse the type with generics, to recover // from situations like `x as usize < y` in which we first tried to parse // `usize < y` as a type with generic arguments. let parser_snapshot_after_type = self.clone(); mem::replace(self, parser_snapshot_before_type); match self.parse_path(PathStyle::Expr) { Ok(path) => { let (op_noun, op_verb) = match self.token.kind { token::Lt => ("comparison", "comparing"), token::BinOp(token::Shl) => ("shift", "shifting"), _ => { // We can end up here even without `<` being the next token, for // example because `parse_ty_no_plus` returns `Err` on keywords, // but `parse_path` returns `Ok` on them due to error recovery. // Return original error and parser state. mem::replace(self, parser_snapshot_after_type); return Err(type_err); } }; // Successfully parsed the type path leaving a `<` yet to parse. type_err.cancel(); // Report non-fatal diagnostics, keep `x as usize` as an expression // in AST and continue parsing. let msg = format!( "`<` is interpreted as a start of generic arguments for `{}`, not a {}", pprust::path_to_string(&path), op_noun, ); let span_after_type = parser_snapshot_after_type.token.span; let expr = mk_expr(self, self.mk_ty(path.span, TyKind::Path(None, path))); let expr_str = self .span_to_snippet(expr.span) .unwrap_or_else(|_| pprust::expr_to_string(&expr)); self.struct_span_err(self.token.span, &msg) .span_label( self.look_ahead(1, |t| t.span).to(span_after_type), "interpreted as generic arguments", ) .span_label(self.token.span, format!("not interpreted as {}", op_noun)) .span_suggestion( expr.span, &format!("try {} the cast value", op_verb), format!("({})", expr_str), Applicability::MachineApplicable, ) .emit(); expr } Err(mut path_err) => { // Couldn't parse as a path, return original error and parser state. path_err.cancel(); mem::replace(self, parser_snapshot_after_type); return Err(type_err); } } } }; self.parse_and_disallow_postfix_after_cast(cast_expr) } /// Parses a postfix operators such as `.`, `?`, or index (`[]`) after a cast, /// then emits an error and returns the newly parsed tree. /// The resulting parse tree for `&x as T[0]` has a precedence of `((&x) as T)[0]`. fn parse_and_disallow_postfix_after_cast( &mut self, cast_expr: P, ) -> PResult<'a, P> { // Save the memory location of expr before parsing any following postfix operators. // This will be compared with the memory location of the output expression. // If they different we can assume we parsed another expression because the existing expression is not reallocated. let addr_before = &*cast_expr as *const _ as usize; let span = cast_expr.span; let with_postfix = self.parse_dot_or_call_expr_with_(cast_expr, span)?; let changed = addr_before != &*with_postfix as *const _ as usize; // Check if an illegal postfix operator has been added after the cast. // If the resulting expression is not a cast, or has a different memory location, it is an illegal postfix operator. if !matches!(with_postfix.kind, ExprKind::Cast(_, _) | ExprKind::Type(_, _)) || changed { let msg = format!( "casts cannot be followed by {}", match with_postfix.kind { ExprKind::Index(_, _) => "indexing", ExprKind::Try(_) => "?", ExprKind::Field(_, _) => "a field access", ExprKind::MethodCall(_, _) => "a method call", ExprKind::Call(_, _) => "a function call", ExprKind::Await(_) => "`.await`", _ => unreachable!("parse_dot_or_call_expr_with_ shouldn't produce this"), } ); let mut err = self.struct_span_err(span, &msg); // If type ascription is "likely an error", the user will already be getting a useful // help message, and doesn't need a second. if self.last_type_ascription.map_or(false, |last_ascription| last_ascription.1) { self.maybe_annotate_with_ascription(&mut err, false); } else { let suggestions = vec![ (span.shrink_to_lo(), "(".to_string()), (span.shrink_to_hi(), ")".to_string()), ]; err.multipart_suggestion( "try surrounding the expression in parentheses", suggestions, Applicability::MachineApplicable, ); } err.emit(); }; Ok(with_postfix) } fn parse_assoc_op_ascribe(&mut self, lhs: P, lhs_span: Span) -> PResult<'a, P> { let maybe_path = self.could_ascription_be_path(&lhs.kind); self.last_type_ascription = Some((self.prev_token.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? ` or `& raw [ const | mut ] `. fn parse_borrow_expr(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> { self.expect_and()?; 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_token.span)); (ast::BorrowKind::Raw, mutability) } else { // `mut?` (ast::BorrowKind::Ref, self.parse_mutability()) } } /// Parses `a.b` or `a(13)` or `a[4]` or just `a`. fn parse_dot_or_call_expr(&mut self, attrs: Option) -> PResult<'a, P> { 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( &mut self, e0: P, lo: Span, mut attrs: AttrVec, ) -> PResult<'a, P> { // Stitch the list of outer attributes onto the return value. // A little bit ugly, but the best way given the current code // structure self.parse_dot_or_call_expr_with_(e0, lo).map(|expr| { expr.map(|mut expr| { attrs.extend::>(expr.attrs.into()); expr.attrs = attrs; expr }) }) } fn parse_dot_or_call_expr_with_(&mut self, mut e: P, lo: Span) -> PResult<'a, P> { loop { if self.eat(&token::Question) { // `expr?` e = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Try(e), AttrVec::new()); continue; } if self.eat(&token::Dot) { // expr.f e = self.parse_dot_suffix_expr(lo, e)?; continue; } if self.expr_is_complete(&e) { return Ok(e); } 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), } } } fn parse_dot_suffix_expr(&mut self, lo: Span, base: P) -> PResult<'a, P> { match self.token.uninterpolate().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, sym: Symbol, ) -> PResult<'a, P> { self.bump(); let fstr = sym.as_str(); let msg = format!("unexpected token: `{}`", sym); let mut err = self.struct_span_err(self.prev_token.span, &msg); err.span_label(self.prev_token.span, "unexpected token"); if fstr.chars().all(|x| "0123456789.".contains(x)) { let float = match fstr.parse::() { 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_token.span), "try parenthesizing the first index", sugg, Applicability::MachineApplicable, ); } Err(err) } fn parse_tuple_field_access_expr( &mut self, lo: Span, base: P, field: Symbol, suffix: Option, ) -> P { self.bump(); let span = self.prev_token.span; 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) -> P { let seq = self.parse_paren_expr_seq().map(|args| { self.mk_expr(lo.to(self.prev_token.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) -> PResult<'a, P> { self.bump(); // `[` let index = self.parse_expr()?; self.expect(&token::CloseDelim(token::Bracket))?; Ok(self.mk_expr(lo.to(self.prev_token.span), self.mk_index(base, index), AttrVec::new())) } /// Assuming we have just parsed `.`, continue parsing into an expression. fn parse_dot_suffix(&mut self, self_arg: P, lo: Span) -> PResult<'a, P> { if self.token.uninterpolated_span().rust_2018() && self.eat_keyword(kw::Await) { return self.mk_await_expr(self_arg, lo); } let segment = self.parse_path_segment(PathStyle::Expr)?; self.check_trailing_angle_brackets(&segment, token::OpenDelim(token::Paren)); 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_token.span); Ok(self.mk_expr(span, ExprKind::MethodCall(segment, args), AttrVec::new())) } else { // Field access `expr.f` if let Some(args) = segment.args { self.struct_span_err( args.span(), "field expressions cannot have generic arguments", ) .emit(); } let span = lo.to(self.prev_token.span); Ok(self.mk_expr(span, ExprKind::Field(self_arg, segment.ident), AttrVec::new())) } } /// At the bottom (top?) of the precedence hierarchy, /// Parses things like parenthesized exprs, macros, `return`, etc. /// /// N.B., this does not parse outer attributes, and is private because it only works /// correctly if called from `parse_dot_or_call_expr()`. fn parse_bottom_expr(&mut self) -> PResult<'a, P> { maybe_recover_from_interpolated_ty_qpath!(self, true); maybe_whole_expr!(self); // Outer attributes are already parsed and will be // added to the return value after the fact. // // Therefore, prevent sub-parser from parsing // attributes by giving them a empty "already-parsed" list. let attrs = AttrVec::new(); // Note: when adding new syntax here, don't forget to adjust `TokenKind::can_begin_expr()`. let lo = self.token.span; if let token::Literal(_) = self.token.kind { // This match arm is a special-case of the `_` match arm below and // could be removed without changing functionality, but it's faster // to have it here, especially for programs with large constants. self.parse_lit_expr(attrs) } else if self.check(&token::OpenDelim(token::Paren)) { self.parse_tuple_parens_expr(attrs) } else if self.check(&token::OpenDelim(token::Brace)) { self.parse_block_expr(None, lo, BlockCheckMode::Default, attrs) } else if self.check(&token::BinOp(token::Or)) || self.check(&token::OrOr) { self.parse_closure_expr(attrs) } else if self.check(&token::OpenDelim(token::Bracket)) { self.parse_array_or_repeat_expr(attrs) } else if self.eat_lt() { let (qself, path) = self.parse_qpath(PathStyle::Expr)?; Ok(self.mk_expr(lo.to(path.span), ExprKind::Path(Some(qself), path), attrs)) } else if self.token.is_path_start() { self.parse_path_start_expr(attrs) } else if self.check_keyword(kw::Move) || self.check_keyword(kw::Static) { self.parse_closure_expr(attrs) } else if self.eat_keyword(kw::If) { self.parse_if_expr(attrs) } else if self.eat_keyword(kw::For) { self.parse_for_expr(None, self.prev_token.span, attrs) } else if self.eat_keyword(kw::While) { self.parse_while_expr(None, self.prev_token.span, attrs) } else if let Some(label) = self.eat_label() { self.parse_labeled_expr(label, attrs) } else if self.eat_keyword(kw::Loop) { self.parse_loop_expr(None, self.prev_token.span, attrs) } else if self.eat_keyword(kw::Continue) { let kind = ExprKind::Continue(self.eat_label()); Ok(self.mk_expr(lo.to(self.prev_token.span), kind, attrs)) } else if self.eat_keyword(kw::Match) { let match_sp = self.prev_token.span; self.parse_match_expr(attrs).map_err(|mut err| { err.span_label(match_sp, "while parsing this match expression"); err }) } else if self.eat_keyword(kw::Unsafe) { self.parse_block_expr(None, lo, BlockCheckMode::Unsafe(ast::UserProvided), attrs) } else if self.is_do_catch_block() { self.recover_do_catch(attrs) } else if self.is_try_block() { self.expect_keyword(kw::Try)?; self.parse_try_block(lo, attrs) } else if self.eat_keyword(kw::Return) { self.parse_return_expr(attrs) } else if self.eat_keyword(kw::Break) { self.parse_break_expr(attrs) } else if self.eat_keyword(kw::Yield) { self.parse_yield_expr(attrs) } else if self.eat_keyword(kw::Let) { self.parse_let_expr(attrs) } else if !self.unclosed_delims.is_empty() && self.check(&token::Semi) { // Don't complain about bare semicolons after unclosed braces // recovery in order to keep the error count down. Fixing the // delimiters will possibly also fix the bare semicolon found in // expression context. For example, silence the following error: // // error: expected expression, found `;` // --> file.rs:2:13 // | // 2 | foo(bar(; // | ^ expected expression self.bump(); Ok(self.mk_expr_err(self.token.span)) } else if self.token.uninterpolated_span().rust_2018() { // `Span::rust_2018()` is somewhat expensive; don't get it repeatedly. if self.check_keyword(kw::Async) { if self.is_async_block() { // Check for `async {` and `async move {`. self.parse_async_block(attrs) } else { self.parse_closure_expr(attrs) } } else if self.eat_keyword(kw::Await) { self.recover_incorrect_await_syntax(lo, self.prev_token.span, attrs) } else { self.parse_lit_expr(attrs) } } else { self.parse_lit_expr(attrs) } } fn parse_lit_expr(&mut self, attrs: AttrVec) -> PResult<'a, P> { let lo = self.token.span; match self.parse_opt_lit() { Some(literal) => { let expr = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Lit(literal), attrs); self.maybe_recover_from_bad_qpath(expr, true) } None => return Err(self.expected_expression_found()), } } fn parse_tuple_parens_expr(&mut self, mut attrs: AttrVec) -> PResult<'a, P> { let lo = self.token.span; self.expect(&token::OpenDelim(token::Paren))?; attrs.extend(self.parse_inner_attributes()?); // `(#![foo] a, b, ...)` is OK. let (es, trailing_comma) = match self.parse_seq_to_end( &token::CloseDelim(token::Paren), SeqSep::trailing_allowed(token::Comma), |p| p.parse_expr_catch_underscore(), ) { Ok(x) => x, Err(err) => return Ok(self.recover_seq_parse_error(token::Paren, lo, Err(err))), }; let kind = if es.len() == 1 && !trailing_comma { // `(e)` is parenthesized `e`. ExprKind::Paren(es.into_iter().next().unwrap()) } else { // `(e,)` is a tuple with only one field, `e`. ExprKind::Tup(es) }; let expr = self.mk_expr(lo.to(self.prev_token.span), kind, attrs); self.maybe_recover_from_bad_qpath(expr, true) } fn parse_array_or_repeat_expr(&mut self, mut attrs: AttrVec) -> PResult<'a, P> { let lo = self.token.span; self.bump(); // `[` attrs.extend(self.parse_inner_attributes()?); let close = &token::CloseDelim(token::Bracket); let kind = if self.eat(close) { // Empty vector ExprKind::Array(Vec::new()) } else { // Non-empty vector let first_expr = self.parse_expr()?; if self.eat(&token::Semi) { // Repeating array syntax: `[ 0; 512 ]` let count = self.parse_anon_const_expr()?; self.expect(close)?; ExprKind::Repeat(first_expr, count) } else if self.eat(&token::Comma) { // Vector with two or more elements. let sep = SeqSep::trailing_allowed(token::Comma); let (remaining_exprs, _) = self.parse_seq_to_end(close, sep, |p| p.parse_expr())?; let mut exprs = vec![first_expr]; exprs.extend(remaining_exprs); ExprKind::Array(exprs) } else { // Vector with one element self.expect(close)?; ExprKind::Array(vec![first_expr]) } }; let expr = self.mk_expr(lo.to(self.prev_token.span), kind, attrs); self.maybe_recover_from_bad_qpath(expr, true) } fn parse_path_start_expr(&mut self, attrs: AttrVec) -> PResult<'a, P> { let lo = self.token.span; let path = self.parse_path(PathStyle::Expr)?; // `!`, as an operator, is prefix, so we know this isn't that. let (hi, kind) = if self.eat(&token::Not) { // MACRO INVOCATION expression let mac = Mac { path, args: self.parse_mac_args()?, prior_type_ascription: self.last_type_ascription, }; (self.prev_token.span, ExprKind::Mac(mac)) } else if self.check(&token::OpenDelim(token::Brace)) { if let Some(expr) = self.maybe_parse_struct_expr(lo, &path, &attrs) { return expr; } else { (path.span, ExprKind::Path(None, path)) } } else { (path.span, ExprKind::Path(None, path)) }; let expr = self.mk_expr(lo.to(hi), kind, attrs); self.maybe_recover_from_bad_qpath(expr, true) } fn parse_labeled_expr(&mut self, label: Label, attrs: AttrVec) -> PResult<'a, P> { let lo = label.ident.span; self.expect(&token::Colon)?; if self.eat_keyword(kw::While) { return self.parse_while_expr(Some(label), lo, attrs); } if self.eat_keyword(kw::For) { return self.parse_for_expr(Some(label), lo, attrs); } if self.eat_keyword(kw::Loop) { return self.parse_loop_expr(Some(label), lo, attrs); } if self.token == token::OpenDelim(token::Brace) { return self.parse_block_expr(Some(label), lo, BlockCheckMode::Default, attrs); } let msg = "expected `while`, `for`, `loop` or `{` after a label"; self.struct_span_err(self.token.span, msg).span_label(self.token.span, msg).emit(); // Continue as an expression in an effort to recover on `'label: non_block_expr`. self.parse_expr() } /// Recover on the syntax `do catch { ... }` suggesting `try { ... }` instead. fn recover_do_catch(&mut self, attrs: AttrVec) -> PResult<'a, P> { let lo = self.token.span; self.bump(); // `do` self.bump(); // `catch` let span_dc = lo.to(self.prev_token.span); self.struct_span_err(span_dc, "found removed `do catch` syntax") .span_suggestion( span_dc, "replace with the new syntax", "try".to_string(), Applicability::MachineApplicable, ) .note("following RFC #2388, the new non-placeholder syntax is `try`") .emit(); self.parse_try_block(lo, attrs) } /// Parse an expression if the token can begin one. fn parse_expr_opt(&mut self) -> PResult<'a, Option>> { Ok(if self.token.can_begin_expr() { Some(self.parse_expr()?) } else { None }) } /// Parse `"return" expr?`. fn parse_return_expr(&mut self, attrs: AttrVec) -> PResult<'a, P> { let lo = self.prev_token.span; let kind = ExprKind::Ret(self.parse_expr_opt()?); let expr = self.mk_expr(lo.to(self.prev_token.span), kind, attrs); self.maybe_recover_from_bad_qpath(expr, true) } /// Parse `"('label ":")? break expr?`. fn parse_break_expr(&mut self, attrs: AttrVec) -> PResult<'a, P> { let lo = self.prev_token.span; let label = self.eat_label(); let kind = if self.token != token::OpenDelim(token::Brace) || !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL) { self.parse_expr_opt()? } else { None }; let expr = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Break(label, kind), attrs); self.maybe_recover_from_bad_qpath(expr, true) } /// Parse `"yield" expr?`. fn parse_yield_expr(&mut self, attrs: AttrVec) -> PResult<'a, P> { let lo = self.prev_token.span; let kind = ExprKind::Yield(self.parse_expr_opt()?); let span = lo.to(self.prev_token.span); self.sess.gated_spans.gate(sym::generators, span); let expr = self.mk_expr(span, kind, attrs); self.maybe_recover_from_bad_qpath(expr, true) } /// Returns a string literal if the next token is a string literal. /// In case of error returns `Some(lit)` if the next token is a literal with a wrong kind, /// and returns `None` if the next token is not literal at all. pub fn parse_str_lit(&mut self) -> Result> { match self.parse_opt_lit() { Some(lit) => match lit.kind { ast::LitKind::Str(symbol_unescaped, style) => Ok(ast::StrLit { style, symbol: lit.token.symbol, suffix: lit.token.suffix, span: lit.span, symbol_unescaped, }), _ => Err(Some(lit)), }, None => Err(None), } } pub(super) fn parse_lit(&mut self) -> PResult<'a, Lit> { self.parse_opt_lit().ok_or_else(|| { let msg = format!("unexpected token: {}", super::token_descr(&self.token)); self.struct_span_err(self.token.span, &msg) }) } /// Matches `lit = true | false | token_lit`. /// Returns `None` if the next token is not a literal. pub(super) fn parse_opt_lit(&mut self) -> Option { let mut recovered = None; if self.token == token::Dot { // Attempt to recover `.4` as `0.4`. We don't currently have any syntax where // dot would follow an optional literal, so we do this unconditionally. recovered = self.look_ahead(1, |next_token| { if let token::Literal(token::Lit { kind: token::Integer, symbol, suffix }) = next_token.kind { if self.token.span.hi() == next_token.span.lo() { let s = String::from("0.") + &symbol.as_str(); let kind = TokenKind::lit(token::Float, Symbol::intern(&s), suffix); return Some(Token::new(kind, self.token.span.to(next_token.span))); } } None }); if let Some(token) = &recovered { self.bump(); self.error_float_lits_must_have_int_part(&token); } } let token = recovered.as_ref().unwrap_or(&self.token); match Lit::from_token(token) { Ok(lit) => { self.bump(); Some(lit) } Err(LitError::NotLiteral) => None, Err(err) => { let span = token.span; let lit = match token.kind { token::Literal(lit) => lit, _ => unreachable!(), }; self.bump(); self.report_lit_error(err, lit, span); // Pack possible quotes and prefixes from the original literal into // the error literal's symbol so they can be pretty-printed faithfully. let suffixless_lit = token::Lit::new(lit.kind, lit.symbol, None); let symbol = Symbol::intern(&suffixless_lit.to_string()); let lit = token::Lit::new(token::Err, symbol, lit.suffix); Some(Lit::from_lit_token(lit, span).unwrap_or_else(|_| unreachable!())) } } } 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 { s.len() > 1 && s.starts_with(first_chars) && s[1..].chars().all(|c| c.is_ascii_digit()) } let token::Lit { kind, suffix, .. } = lit; match err { // `NotLiteral` is not an error by itself, so we don't report // it and give the parser opportunity to try something else. LitError::NotLiteral => {} // `LexerError` *is* an error, but it was already reported // by lexer, so here we don't report it the second time. LitError::LexerError => {} LitError::InvalidSuffix => { self.expect_no_suffix( span, &format!("{} {} literal", kind.article(), kind.descr()), suffix, ); } LitError::InvalidIntSuffix => { let suf = suffix.expect("suffix error with no suffix").as_str(); if looks_like_width_suffix(&['i', 'u'], &suf) { // If it looks like a width, try to be helpful. let msg = format!("invalid width `{}` for integer literal", &suf[1..]); self.struct_span_err(span, &msg) .help("valid widths are 8, 16, 32, 64 and 128") .emit(); } else { let msg = format!("invalid suffix `{}` for integer literal", suf); self.struct_span_err(span, &msg) .span_label(span, format!("invalid suffix `{}`", suf)) .help("the suffix must be one of the integral types (`u32`, `isize`, etc)") .emit(); } } LitError::InvalidFloatSuffix => { let suf = suffix.expect("suffix error with no suffix").as_str(); if looks_like_width_suffix(&['f'], &suf) { // If it looks like a width, try to be helpful. let msg = format!("invalid width `{}` for float literal", &suf[1..]); self.struct_span_err(span, &msg).help("valid widths are 32 and 64").emit(); } else { let msg = format!("invalid suffix `{}` for float literal", suf); self.struct_span_err(span, &msg) .span_label(span, format!("invalid suffix `{}`", suf)) .help("valid suffixes are `f32` and `f64`") .emit(); } } LitError::NonDecimalFloat(base) => { let descr = match base { 16 => "hexadecimal", 8 => "octal", 2 => "binary", _ => unreachable!(), }; self.struct_span_err(span, &format!("{} float literal is not supported", descr)) .span_label(span, "not supported") .emit(); } LitError::IntTooLarge => { self.struct_span_err(span, "integer literal is too large").emit(); } } } pub(super) fn expect_no_suffix(&self, sp: Span, kind: &str, suffix: Option) { if let Some(suf) = suffix { let mut err = if kind == "a tuple index" && [sym::i32, sym::u32, sym::isize, sym::usize].contains(&suf) { // #59553: warn instead of reject out of hand to allow the fix to percolate // through the ecosystem when people fix their macros let mut err = self .sess .span_diagnostic .struct_span_warn(sp, &format!("suffixes on {} are invalid", kind)); err.note(&format!( "`{}` is *temporarily* accepted on tuple index fields as it was \ incorrectly accepted on stable for a few releases", suf, )); err.help( "on proc macros, you'll want to use `syn::Index::from` or \ `proc_macro::Literal::*_unsuffixed` for code that will desugar \ to tuple field access", ); err.note( "see issue #60210 \ for more information", ); err } else { self.struct_span_err(sp, &format!("suffixes on {} are invalid", kind)) }; err.span_label(sp, format!("invalid suffix `{}`", suf)); err.emit(); } } /// Matches `'-' lit | lit` (cf. `ast_validation::AstValidator::check_expr_within_pat`). pub fn parse_literal_maybe_minus(&mut self) -> PResult<'a, P> { maybe_whole_expr!(self); let lo = self.token.span; 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 { Ok(self.mk_expr( lo.to(self.prev_token.span), self.mk_unary(UnOp::Neg, expr), AttrVec::new(), )) } else { Ok(expr) } } /// Parses a block or unsafe block. pub(super) fn parse_block_expr( &mut self, opt_label: Option