2 use crate::ast::{BlockCheckMode, Expr, ExprKind, Item, ItemKind, Pat, PatKind, QSelf, Ty, TyKind};
3 use crate::parse::parser::{BlockMode, PathStyle, TokenType, SemiColonMode};
4 use crate::parse::token;
5 use crate::parse::PResult;
6 use crate::parse::Parser;
7 use crate::print::pprust;
11 use errors::{Applicability, DiagnosticBuilder};
15 pub trait RecoverQPath: Sized + 'static {
16 const PATH_STYLE: PathStyle = PathStyle::Expr;
17 fn to_ty(&self) -> Option<P<Ty>>;
18 fn recovered(qself: Option<QSelf>, path: ast::Path) -> Self;
21 impl RecoverQPath for Ty {
22 const PATH_STYLE: PathStyle = PathStyle::Type;
23 fn to_ty(&self) -> Option<P<Ty>> {
26 fn recovered(qself: Option<QSelf>, path: ast::Path) -> Self {
29 node: TyKind::Path(qself, path),
30 id: ast::DUMMY_NODE_ID,
35 impl RecoverQPath for Pat {
36 fn to_ty(&self) -> Option<P<Ty>> {
39 fn recovered(qself: Option<QSelf>, path: ast::Path) -> Self {
42 node: PatKind::Path(qself, path),
43 id: ast::DUMMY_NODE_ID,
48 impl RecoverQPath for Expr {
49 fn to_ty(&self) -> Option<P<Ty>> {
52 fn recovered(qself: Option<QSelf>, path: ast::Path) -> Self {
55 node: ExprKind::Path(qself, path),
56 attrs: ThinVec::new(),
57 id: ast::DUMMY_NODE_ID,
63 crate fn maybe_report_ambiguous_plus(
69 if !allow_plus && impl_dyn_multi {
70 let sum_with_parens = format!("({})", pprust::ty_to_string(&ty));
71 self.struct_span_err(ty.span, "ambiguous `+` in a type")
74 "use parentheses to disambiguate",
76 Applicability::MachineApplicable,
82 crate fn maybe_recover_from_bad_type_plus(
86 ) -> PResult<'a, ()> {
87 // Do not add `+` to expected tokens.
88 if !allow_plus || !self.token.is_like_plus() {
93 let bounds = self.parse_generic_bounds(None)?;
94 let sum_span = ty.span.to(self.prev_span);
96 let mut err = struct_span_err!(
97 self.sess.span_diagnostic,
100 "expected a path on the left-hand side of `+`, not `{}`",
101 pprust::ty_to_string(ty)
105 TyKind::Rptr(ref lifetime, ref mut_ty) => {
106 let sum_with_parens = pprust::to_string(|s| {
107 use crate::print::pprust::PrintState;
110 s.print_opt_lifetime(lifetime)?;
111 s.print_mutability(mut_ty.mutbl)?;
113 s.print_type(&mut_ty.ty)?;
114 s.print_type_bounds(" +", &bounds)?;
119 "try adding parentheses",
121 Applicability::MachineApplicable,
124 TyKind::Ptr(..) | TyKind::BareFn(..) => {
125 err.span_label(sum_span, "perhaps you forgot parentheses?");
128 err.span_label(sum_span, "expected a path");
135 /// Try to recover from associated item paths like `[T]::AssocItem`/`(T, U)::AssocItem`.
136 /// Attempt to convert the base expression/pattern/type into a type, parse the `::AssocItem`
137 /// tail, and combine them into a `<Ty>::AssocItem` expression/pattern/type.
138 crate fn maybe_recover_from_bad_qpath<T: RecoverQPath>(
141 allow_recovery: bool,
142 ) -> PResult<'a, P<T>> {
143 // Do not add `::` to expected tokens.
144 if allow_recovery && self.token == token::ModSep {
145 if let Some(ty) = base.to_ty() {
146 return self.maybe_recover_from_bad_qpath_stage_2(ty.span, ty);
152 /// Given an already parsed `Ty` parse the `::AssocItem` tail and
153 /// combine them into a `<Ty>::AssocItem` expression/pattern/type.
154 crate fn maybe_recover_from_bad_qpath_stage_2<T: RecoverQPath>(
158 ) -> PResult<'a, P<T>> {
159 self.expect(&token::ModSep)?;
161 let mut path = ast::Path {
162 segments: Vec::new(),
163 span: syntax_pos::DUMMY_SP,
165 self.parse_path_segments(&mut path.segments, T::PATH_STYLE)?;
166 path.span = ty_span.to(self.prev_span);
171 .span_to_snippet(ty_span)
172 .unwrap_or_else(|_| pprust::ty_to_string(&ty));
174 .struct_span_err(path.span, "missing angle brackets in associated item path")
176 // this is a best-effort recovery
179 format!("<{}>::{}", ty_str, path),
180 Applicability::MaybeIncorrect,
184 let path_span = ty_span.shrink_to_hi(); // use an empty path since `position` == 0
195 crate fn maybe_consume_incorrect_semicolon(&mut self, items: &[P<Item>]) -> bool {
196 if self.eat(&token::Semi) {
197 let mut err = self.struct_span_err(self.prev_span, "expected item, found `;`");
198 err.span_suggestion_short(
200 "remove this semicolon",
202 Applicability::MachineApplicable,
204 if !items.is_empty() {
205 let previous_item = &items[items.len() - 1];
206 let previous_item_kind_name = match previous_item.node {
207 // say "braced struct" because tuple-structs and
208 // braceless-empty-struct declarations do take a semicolon
209 ItemKind::Struct(..) => Some("braced struct"),
210 ItemKind::Enum(..) => Some("enum"),
211 ItemKind::Trait(..) => Some("trait"),
212 ItemKind::Union(..) => Some("union"),
215 if let Some(name) = previous_item_kind_name {
217 "{} declarations are not followed by a semicolon",
229 /// Consume alternative await syntaxes like `await <expr>`, `await? <expr>`, `await(<expr>)`
230 /// and `await { <expr> }`.
231 crate fn parse_incorrect_await_syntax(
235 ) -> PResult<'a, (Span, ExprKind)> {
236 let is_question = self.eat(&token::Question); // Handle `await? <expr>`.
237 let expr = if self.token == token::OpenDelim(token::Brace) {
238 // Handle `await { <expr> }`.
239 // This needs to be handled separatedly from the next arm to avoid
240 // interpreting `await { <expr> }?` as `<expr>?.await`.
241 self.parse_block_expr(
244 BlockCheckMode::Default,
249 }.map_err(|mut err| {
250 err.span_label(await_sp, "while parsing this incorrect await expression");
253 let expr_str = self.sess.source_map().span_to_snippet(expr.span)
254 .unwrap_or_else(|_| pprust::expr_to_string(&expr));
255 let suggestion = format!("{}.await{}", expr_str, if is_question { "?" } else { "" });
256 let sp = lo.to(expr.span);
257 let app = match expr.node {
258 ExprKind::Try(_) => Applicability::MaybeIncorrect, // `await <expr>?`
259 _ => Applicability::MachineApplicable,
261 self.struct_span_err(sp, "incorrect use of `await`")
262 .span_suggestion(sp, "`await` is a postfix operation", suggestion, app)
264 Ok((sp, ExprKind::Await(ast::AwaitOrigin::FieldLike, expr)))
267 /// If encountering `future.await()`, consume and emit error.
268 crate fn recover_from_await_method_call(&mut self) {
269 if self.token == token::OpenDelim(token::Paren) &&
270 self.look_ahead(1, |t| t == &token::CloseDelim(token::Paren))
275 let sp = lo.to(self.span);
277 self.struct_span_err(sp, "incorrect use of `await`")
280 "`await` is not a method call, remove the parentheses",
282 Applicability::MachineApplicable,
287 crate fn could_ascription_be_path(&self, node: &ast::ExprKind) -> bool {
288 self.token.is_ident() &&
289 if let ast::ExprKind::Path(..) = node { true } else { false } &&
290 !self.token.is_reserved_ident() && // v `foo:bar(baz)`
291 self.look_ahead(1, |t| t == &token::OpenDelim(token::Paren)) ||
292 self.look_ahead(1, |t| t == &token::Lt) && // `foo:bar<baz`
293 self.look_ahead(2, |t| t.is_ident()) ||
294 self.look_ahead(1, |t| t == &token::Colon) && // `foo:bar:baz`
295 self.look_ahead(2, |t| t.is_ident()) ||
296 self.look_ahead(1, |t| t == &token::ModSep) && // `foo:bar::baz`
297 self.look_ahead(2, |t| t.is_ident())
300 crate fn bad_type_ascription(
302 err: &mut DiagnosticBuilder<'a>,
308 err.span_label(self.span, "expecting a type here because of type ascription");
309 let cm = self.sess.source_map();
310 let next_pos = cm.lookup_char_pos(next_sp.lo());
311 let op_pos = cm.lookup_char_pos(cur_op_span.hi());
312 if op_pos.line != next_pos.line {
315 "try using a semicolon",
317 Applicability::MaybeIncorrect,
323 "maybe you meant to write a path separator here",
325 Applicability::MaybeIncorrect,
328 err.note("type ascription is a nightly-only feature that lets \
329 you annotate an expression with a type: `<expr>: <type>`")
332 "this expression expects an ascribed type after the colon",
334 .help("this might be indicative of a syntax error elsewhere");
339 crate fn recover_seq_parse_error(
341 delim: token::DelimToken,
343 result: PResult<'a, P<Expr>>,
349 // recover from parse error
350 self.consume_block(delim);
351 self.mk_expr(lo.to(self.prev_span), ExprKind::Err, ThinVec::new())
356 crate fn recover_closing_delimiter(
358 tokens: &[token::Token],
359 mut err: DiagnosticBuilder<'a>,
360 ) -> PResult<'a, bool> {
362 // we want to use the last closing delim that would apply
363 for (i, unmatched) in self.unclosed_delims.iter().enumerate().rev() {
364 if tokens.contains(&token::CloseDelim(unmatched.expected_delim))
365 && Some(self.span) > unmatched.unclosed_span
372 // Recover and assume that the detected unclosed delimiter was meant for
373 // this location. Emit the diagnostic and act as if the delimiter was
374 // present for the parser's sake.
376 // Don't attempt to recover from this unclosed delimiter more than once.
377 let unmatched = self.unclosed_delims.remove(pos);
378 let delim = TokenType::Token(token::CloseDelim(unmatched.expected_delim));
380 // We want to suggest the inclusion of the closing delimiter where it makes
381 // the most sense, which is immediately after the last token:
386 // | help: `)` may belong here (FIXME: #58270)
388 // unclosed delimiter
389 if let Some(sp) = unmatched.unclosed_span {
390 err.span_label(sp, "unclosed delimiter");
392 err.span_suggestion_short(
393 self.sess.source_map().next_point(self.prev_span),
394 &format!("{} may belong here", delim.to_string()),
396 Applicability::MaybeIncorrect,
399 self.expected_tokens.clear(); // reduce errors
406 /// Recover from `pub` keyword in places where it seems _reasonable_ but isn't valid.
407 crate fn eat_bad_pub(&mut self) {
408 if self.token.is_keyword(kw::Pub) {
409 match self.parse_visibility(false) {
412 .struct_span_err(vis.span, "unnecessary visibility qualifier")
413 .span_label(vis.span, "`pub` not permitted here")
416 Err(mut err) => err.emit(),
421 // Eat tokens until we can be relatively sure we reached the end of the
422 // statement. This is something of a best-effort heuristic.
424 // We terminate when we find an unmatched `}` (without consuming it).
425 crate fn recover_stmt(&mut self) {
426 self.recover_stmt_(SemiColonMode::Ignore, BlockMode::Ignore)
429 // If `break_on_semi` is `Break`, then we will stop consuming tokens after
430 // finding (and consuming) a `;` outside of `{}` or `[]` (note that this is
431 // approximate - it can mean we break too early due to macros, but that
432 // should only lead to sub-optimal recovery, not inaccurate parsing).
434 // If `break_on_block` is `Break`, then we will stop consuming tokens
435 // after finding (and consuming) a brace-delimited block.
436 crate fn recover_stmt_(&mut self, break_on_semi: SemiColonMode, break_on_block: BlockMode) {
437 let mut brace_depth = 0;
438 let mut bracket_depth = 0;
439 let mut in_block = false;
440 debug!("recover_stmt_ enter loop (semi={:?}, block={:?})",
441 break_on_semi, break_on_block);
443 debug!("recover_stmt_ loop {:?}", self.token);
445 token::OpenDelim(token::DelimToken::Brace) => {
448 if break_on_block == BlockMode::Break &&
454 token::OpenDelim(token::DelimToken::Bracket) => {
458 token::CloseDelim(token::DelimToken::Brace) => {
459 if brace_depth == 0 {
460 debug!("recover_stmt_ return - close delim {:?}", self.token);
465 if in_block && bracket_depth == 0 && brace_depth == 0 {
466 debug!("recover_stmt_ return - block end {:?}", self.token);
470 token::CloseDelim(token::DelimToken::Bracket) => {
472 if bracket_depth < 0 {
478 debug!("recover_stmt_ return - Eof");
483 if break_on_semi == SemiColonMode::Break &&
486 debug!("recover_stmt_ return - Semi");
490 token::Comma if break_on_semi == SemiColonMode::Comma &&
492 bracket_depth == 0 =>
494 debug!("recover_stmt_ return - Semi");
504 crate fn consume_block(&mut self, delim: token::DelimToken) {
505 let mut brace_depth = 0;
507 if self.eat(&token::OpenDelim(delim)) {
509 } else if self.eat(&token::CloseDelim(delim)) {
510 if brace_depth == 0 {
516 } else if self.token == token::Eof || self.eat(&token::CloseDelim(token::NoDelim)) {