3 BlockCheckMode, Expr, ExprKind, Item, ItemKind, Pat, PatKind, QSelf, Ty, TyKind, VariantData,
5 use crate::parse::parser::{BlockMode, PathStyle, SemiColonMode, TokenType};
6 use crate::parse::token;
7 use crate::parse::PResult;
8 use crate::parse::Parser;
9 use crate::print::pprust;
11 use crate::source_map::Spanned;
12 use crate::symbol::kw;
14 use errors::{Applicability, DiagnosticBuilder};
16 use syntax_pos::{Span, DUMMY_SP};
18 pub trait RecoverQPath: Sized + 'static {
19 const PATH_STYLE: PathStyle = PathStyle::Expr;
20 fn to_ty(&self) -> Option<P<Ty>>;
21 fn recovered(qself: Option<QSelf>, path: ast::Path) -> Self;
24 impl RecoverQPath for Ty {
25 const PATH_STYLE: PathStyle = PathStyle::Type;
26 fn to_ty(&self) -> Option<P<Ty>> {
29 fn recovered(qself: Option<QSelf>, path: ast::Path) -> Self {
32 node: TyKind::Path(qself, path),
33 id: ast::DUMMY_NODE_ID,
38 impl RecoverQPath for Pat {
39 fn to_ty(&self) -> Option<P<Ty>> {
42 fn recovered(qself: Option<QSelf>, path: ast::Path) -> Self {
45 node: PatKind::Path(qself, path),
46 id: ast::DUMMY_NODE_ID,
51 impl RecoverQPath for Expr {
52 fn to_ty(&self) -> Option<P<Ty>> {
55 fn recovered(qself: Option<QSelf>, path: ast::Path) -> Self {
58 node: ExprKind::Path(qself, path),
59 attrs: ThinVec::new(),
60 id: ast::DUMMY_NODE_ID,
66 crate fn maybe_report_ambiguous_plus(
72 if !allow_plus && impl_dyn_multi {
73 let sum_with_parens = format!("({})", pprust::ty_to_string(&ty));
74 self.struct_span_err(ty.span, "ambiguous `+` in a type")
77 "use parentheses to disambiguate",
79 Applicability::MachineApplicable,
85 crate fn maybe_report_invalid_custom_discriminants(
87 discriminant_spans: Vec<Span>,
88 variants: &[Spanned<ast::Variant_>],
90 let has_fields = variants.iter().any(|variant| match variant.node.data {
91 VariantData::Tuple(..) | VariantData::Struct(..) => true,
92 VariantData::Unit(..) => false,
95 if !discriminant_spans.is_empty() && has_fields {
96 let mut err = self.struct_span_err(
97 discriminant_spans.clone(),
98 "custom discriminant values are not allowed in enums with fields",
100 for sp in discriminant_spans {
101 err.span_label(sp, "invalid custom discriminant");
103 for variant in variants.iter() {
104 if let VariantData::Struct(fields, ..) | VariantData::Tuple(fields, ..) =
107 let fields = if fields.len() > 1 {
114 &format!("variant with {fields} defined here", fields = fields),
123 crate fn maybe_recover_from_bad_type_plus(
127 ) -> PResult<'a, ()> {
128 // Do not add `+` to expected tokens.
129 if !allow_plus || !self.token.is_like_plus() {
134 let bounds = self.parse_generic_bounds(None)?;
135 let sum_span = ty.span.to(self.prev_span);
137 let mut err = struct_span_err!(
138 self.sess.span_diagnostic,
141 "expected a path on the left-hand side of `+`, not `{}`",
142 pprust::ty_to_string(ty)
146 TyKind::Rptr(ref lifetime, ref mut_ty) => {
147 let sum_with_parens = pprust::to_string(|s| {
148 use crate::print::pprust::PrintState;
151 s.print_opt_lifetime(lifetime)?;
152 s.print_mutability(mut_ty.mutbl)?;
154 s.print_type(&mut_ty.ty)?;
155 s.print_type_bounds(" +", &bounds)?;
160 "try adding parentheses",
162 Applicability::MachineApplicable,
165 TyKind::Ptr(..) | TyKind::BareFn(..) => {
166 err.span_label(sum_span, "perhaps you forgot parentheses?");
169 err.span_label(sum_span, "expected a path");
176 /// Try to recover from associated item paths like `[T]::AssocItem`/`(T, U)::AssocItem`.
177 /// Attempt to convert the base expression/pattern/type into a type, parse the `::AssocItem`
178 /// tail, and combine them into a `<Ty>::AssocItem` expression/pattern/type.
179 crate fn maybe_recover_from_bad_qpath<T: RecoverQPath>(
182 allow_recovery: bool,
183 ) -> PResult<'a, P<T>> {
184 // Do not add `::` to expected tokens.
185 if allow_recovery && self.token == token::ModSep {
186 if let Some(ty) = base.to_ty() {
187 return self.maybe_recover_from_bad_qpath_stage_2(ty.span, ty);
193 /// Given an already parsed `Ty` parse the `::AssocItem` tail and
194 /// combine them into a `<Ty>::AssocItem` expression/pattern/type.
195 crate fn maybe_recover_from_bad_qpath_stage_2<T: RecoverQPath>(
199 ) -> PResult<'a, P<T>> {
200 self.expect(&token::ModSep)?;
202 let mut path = ast::Path {
203 segments: Vec::new(),
206 self.parse_path_segments(&mut path.segments, T::PATH_STYLE)?;
207 path.span = ty_span.to(self.prev_span);
212 .span_to_snippet(ty_span)
213 .unwrap_or_else(|_| pprust::ty_to_string(&ty));
215 .struct_span_err(path.span, "missing angle brackets in associated item path")
217 // this is a best-effort recovery
220 format!("<{}>::{}", ty_str, path),
221 Applicability::MaybeIncorrect,
225 let path_span = ty_span.shrink_to_hi(); // use an empty path since `position` == 0
236 crate fn maybe_consume_incorrect_semicolon(&mut self, items: &[P<Item>]) -> bool {
237 if self.eat(&token::Semi) {
238 let mut err = self.struct_span_err(self.prev_span, "expected item, found `;`");
239 err.span_suggestion_short(
241 "remove this semicolon",
243 Applicability::MachineApplicable,
245 if !items.is_empty() {
246 let previous_item = &items[items.len() - 1];
247 let previous_item_kind_name = match previous_item.node {
248 // say "braced struct" because tuple-structs and
249 // braceless-empty-struct declarations do take a semicolon
250 ItemKind::Struct(..) => Some("braced struct"),
251 ItemKind::Enum(..) => Some("enum"),
252 ItemKind::Trait(..) => Some("trait"),
253 ItemKind::Union(..) => Some("union"),
256 if let Some(name) = previous_item_kind_name {
258 "{} declarations are not followed by a semicolon",
270 /// Create a `DiagnosticBuilder` for an unexpected token `t` and try to recover if it is a
271 /// closing delimiter.
272 pub fn unexpected_try_recover(
275 ) -> PResult<'a, bool /* recovered */> {
276 let token_str = pprust::token_to_string(t);
277 let this_token_str = self.this_token_descr();
278 let (prev_sp, sp) = match (&self.token, self.subparser_name) {
279 // Point at the end of the macro call when reaching end of macro arguments.
280 (token::Token::Eof, Some(_)) => {
281 let sp = self.sess.source_map().next_point(self.span);
284 // We don't want to point at the following span after DUMMY_SP.
285 // This happens when the parser finds an empty TokenStream.
286 _ if self.prev_span == DUMMY_SP => (self.span, self.span),
287 // EOF, don't want to point at the following char, but rather the last token.
288 (token::Token::Eof, None) => (self.prev_span, self.span),
289 _ => (self.sess.source_map().next_point(self.prev_span), self.span),
292 "expected `{}`, found {}",
294 match (&self.token, self.subparser_name) {
295 (token::Token::Eof, Some(origin)) => format!("end of {}", origin),
299 let mut err = self.struct_span_err(sp, &msg);
300 let label_exp = format!("expected `{}`", token_str);
301 match self.recover_closing_delimiter(&[t.clone()], err) {
304 return Ok(recovered);
307 let cm = self.sess.source_map();
308 match (cm.lookup_line(prev_sp.lo()), cm.lookup_line(sp.lo())) {
309 (Ok(ref a), Ok(ref b)) if a.line == b.line => {
310 // When the spans are in the same line, it means that the only content
311 // between them is whitespace, point only at the found token.
312 err.span_label(sp, label_exp);
315 err.span_label(prev_sp, label_exp);
316 err.span_label(sp, "unexpected token");
322 /// Consume alternative await syntaxes like `await <expr>`, `await? <expr>`, `await(<expr>)`
323 /// and `await { <expr> }`.
324 crate fn parse_incorrect_await_syntax(
328 ) -> PResult<'a, (Span, ExprKind)> {
329 let is_question = self.eat(&token::Question); // Handle `await? <expr>`.
330 let expr = if self.token == token::OpenDelim(token::Brace) {
331 // Handle `await { <expr> }`.
332 // This needs to be handled separatedly from the next arm to avoid
333 // interpreting `await { <expr> }?` as `<expr>?.await`.
334 self.parse_block_expr(
337 BlockCheckMode::Default,
342 }.map_err(|mut err| {
343 err.span_label(await_sp, "while parsing this incorrect await expression");
346 let expr_str = self.sess.source_map().span_to_snippet(expr.span)
347 .unwrap_or_else(|_| pprust::expr_to_string(&expr));
348 let suggestion = format!("{}.await{}", expr_str, if is_question { "?" } else { "" });
349 let sp = lo.to(expr.span);
350 let app = match expr.node {
351 ExprKind::Try(_) => Applicability::MaybeIncorrect, // `await <expr>?`
352 _ => Applicability::MachineApplicable,
354 self.struct_span_err(sp, "incorrect use of `await`")
355 .span_suggestion(sp, "`await` is a postfix operation", suggestion, app)
357 Ok((sp, ExprKind::Await(ast::AwaitOrigin::FieldLike, expr)))
360 /// If encountering `future.await()`, consume and emit error.
361 crate fn recover_from_await_method_call(&mut self) {
362 if self.token == token::OpenDelim(token::Paren) &&
363 self.look_ahead(1, |t| t == &token::CloseDelim(token::Paren))
368 let sp = lo.to(self.span);
370 self.struct_span_err(sp, "incorrect use of `await`")
373 "`await` is not a method call, remove the parentheses",
375 Applicability::MachineApplicable,
380 crate fn could_ascription_be_path(&self, node: &ast::ExprKind) -> bool {
381 self.token.is_ident() &&
382 if let ast::ExprKind::Path(..) = node { true } else { false } &&
383 !self.token.is_reserved_ident() && // v `foo:bar(baz)`
384 self.look_ahead(1, |t| t == &token::OpenDelim(token::Paren)) ||
385 self.look_ahead(1, |t| t == &token::Lt) && // `foo:bar<baz`
386 self.look_ahead(2, |t| t.is_ident()) ||
387 self.look_ahead(1, |t| t == &token::Colon) && // `foo:bar:baz`
388 self.look_ahead(2, |t| t.is_ident()) ||
389 self.look_ahead(1, |t| t == &token::ModSep) && // `foo:bar::baz`
390 self.look_ahead(2, |t| t.is_ident())
393 crate fn bad_type_ascription(
395 err: &mut DiagnosticBuilder<'a>,
401 err.span_label(self.span, "expecting a type here because of type ascription");
402 let cm = self.sess.source_map();
403 let next_pos = cm.lookup_char_pos(next_sp.lo());
404 let op_pos = cm.lookup_char_pos(cur_op_span.hi());
405 if op_pos.line != next_pos.line {
408 "try using a semicolon",
410 Applicability::MaybeIncorrect,
416 "maybe you meant to write a path separator here",
418 Applicability::MaybeIncorrect,
421 err.note("type ascription is a nightly-only feature that lets \
422 you annotate an expression with a type: `<expr>: <type>`")
425 "this expression expects an ascribed type after the colon",
427 .help("this might be indicative of a syntax error elsewhere");
432 crate fn recover_seq_parse_error(
434 delim: token::DelimToken,
436 result: PResult<'a, P<Expr>>,
442 // recover from parse error
443 self.consume_block(delim);
444 self.mk_expr(lo.to(self.prev_span), ExprKind::Err, ThinVec::new())
449 crate fn recover_closing_delimiter(
451 tokens: &[token::Token],
452 mut err: DiagnosticBuilder<'a>,
453 ) -> PResult<'a, bool> {
455 // we want to use the last closing delim that would apply
456 for (i, unmatched) in self.unclosed_delims.iter().enumerate().rev() {
457 if tokens.contains(&token::CloseDelim(unmatched.expected_delim))
458 && Some(self.span) > unmatched.unclosed_span
465 // Recover and assume that the detected unclosed delimiter was meant for
466 // this location. Emit the diagnostic and act as if the delimiter was
467 // present for the parser's sake.
469 // Don't attempt to recover from this unclosed delimiter more than once.
470 let unmatched = self.unclosed_delims.remove(pos);
471 let delim = TokenType::Token(token::CloseDelim(unmatched.expected_delim));
473 // We want to suggest the inclusion of the closing delimiter where it makes
474 // the most sense, which is immediately after the last token:
479 // | help: `)` may belong here (FIXME: #58270)
481 // unclosed delimiter
482 if let Some(sp) = unmatched.unclosed_span {
483 err.span_label(sp, "unclosed delimiter");
485 err.span_suggestion_short(
486 self.sess.source_map().next_point(self.prev_span),
487 &format!("{} may belong here", delim.to_string()),
489 Applicability::MaybeIncorrect,
492 self.expected_tokens.clear(); // reduce errors
499 /// Recover from `pub` keyword in places where it seems _reasonable_ but isn't valid.
500 crate fn eat_bad_pub(&mut self) {
501 if self.token.is_keyword(kw::Pub) {
502 match self.parse_visibility(false) {
505 .struct_span_err(vis.span, "unnecessary visibility qualifier")
506 .span_label(vis.span, "`pub` not permitted here")
509 Err(mut err) => err.emit(),
514 // Eat tokens until we can be relatively sure we reached the end of the
515 // statement. This is something of a best-effort heuristic.
517 // We terminate when we find an unmatched `}` (without consuming it).
518 crate fn recover_stmt(&mut self) {
519 self.recover_stmt_(SemiColonMode::Ignore, BlockMode::Ignore)
522 // If `break_on_semi` is `Break`, then we will stop consuming tokens after
523 // finding (and consuming) a `;` outside of `{}` or `[]` (note that this is
524 // approximate - it can mean we break too early due to macros, but that
525 // should only lead to sub-optimal recovery, not inaccurate parsing).
527 // If `break_on_block` is `Break`, then we will stop consuming tokens
528 // after finding (and consuming) a brace-delimited block.
529 crate fn recover_stmt_(&mut self, break_on_semi: SemiColonMode, break_on_block: BlockMode) {
530 let mut brace_depth = 0;
531 let mut bracket_depth = 0;
532 let mut in_block = false;
533 debug!("recover_stmt_ enter loop (semi={:?}, block={:?})",
534 break_on_semi, break_on_block);
536 debug!("recover_stmt_ loop {:?}", self.token);
538 token::OpenDelim(token::DelimToken::Brace) => {
541 if break_on_block == BlockMode::Break &&
547 token::OpenDelim(token::DelimToken::Bracket) => {
551 token::CloseDelim(token::DelimToken::Brace) => {
552 if brace_depth == 0 {
553 debug!("recover_stmt_ return - close delim {:?}", self.token);
558 if in_block && bracket_depth == 0 && brace_depth == 0 {
559 debug!("recover_stmt_ return - block end {:?}", self.token);
563 token::CloseDelim(token::DelimToken::Bracket) => {
565 if bracket_depth < 0 {
571 debug!("recover_stmt_ return - Eof");
576 if break_on_semi == SemiColonMode::Break &&
579 debug!("recover_stmt_ return - Semi");
583 token::Comma if break_on_semi == SemiColonMode::Comma &&
585 bracket_depth == 0 =>
587 debug!("recover_stmt_ return - Semi");
597 crate fn consume_block(&mut self, delim: token::DelimToken) {
598 let mut brace_depth = 0;
600 if self.eat(&token::OpenDelim(delim)) {
602 } else if self.eat(&token::CloseDelim(delim)) {
603 if brace_depth == 0 {
609 } else if self.token == token::Eof || self.eat(&token::CloseDelim(token::NoDelim)) {
617 crate fn expected_expression_found(&self) -> DiagnosticBuilder<'a> {
618 let (span, msg) = match (&self.token, self.subparser_name) {
619 (&token::Token::Eof, Some(origin)) => {
620 let sp = self.sess.source_map().next_point(self.span);
621 (sp, format!("expected expression, found end of {}", origin))
623 _ => (self.span, format!(
624 "expected expression, found {}",
625 self.this_token_descr(),
628 let mut err = self.struct_span_err(span, &msg);
629 let sp = self.sess.source_map().start_point(self.span);
630 if let Some(sp) = self.sess.ambiguous_block_expr_parse.borrow().get(&sp) {
631 self.sess.expr_parentheses_needed(&mut err, *sp, None);
633 err.span_label(span, "expected expression");