|
1 |
| -use super::{Parser, PResult, Restrictions, TokenType}; |
| 1 | +use super::{P, Parser, PResult, Restrictions, TokenType}; |
2 | 2 |
|
3 | 3 | use crate::{maybe_whole, ThinVec};
|
4 |
| -use crate::ast::{self, QSelf, Path, PathSegment, Ident, ParenthesizedArgs, AngleBracketedArgs}; |
5 |
| -use crate::ast::{AnonConst, GenericArg, AssocTyConstraint, AssocTyConstraintKind, BlockCheckMode}; |
| 4 | +use crate::ast::{ |
| 5 | + self, AngleBracketedArgs, AnonConst, AssocTyConstraint, AssocTyConstraintKind, BlockCheckMode, |
| 6 | + Expr, GenericArg, Ident, ParenthesizedArgs, Path, PathSegment, QSelf, |
| 7 | +}; |
6 | 8 | use crate::parse::token::{self, Token};
|
7 | 9 | use crate::source_map::{Span, BytePos};
|
8 | 10 | use crate::symbol::kw;
|
@@ -412,54 +414,37 @@ impl<'a> Parser<'a> {
|
412 | 414 | span,
|
413 | 415 | });
|
414 | 416 | assoc_ty_constraints.push(span);
|
| 417 | + } else if [ |
| 418 | + token::Not, |
| 419 | + token::OpenDelim(token::Paren), |
| 420 | + ].contains(&self.token.kind) && self.look_ahead(1, |t| t.is_lit() || t.is_bool_lit()) { |
| 421 | + // Parse bad `const` argument. `!` is only allowed here to go through |
| 422 | + // `recover_bare_const_expr` for better diagnostics when encountering |
| 423 | + // `foo::<!false>()`. `(` is allowed for the case `foo::<(1, 2, 3)>()`. |
| 424 | + |
| 425 | + // This can't possibly be a valid const arg, it is likely missing braces. |
| 426 | + let value = AnonConst { |
| 427 | + id: ast::DUMMY_NODE_ID, |
| 428 | + value: self.recover_bare_const_expr()?, |
| 429 | + }; |
| 430 | + args.push(GenericArg::Const(value)); |
| 431 | + misplaced_assoc_ty_constraints.append(&mut assoc_ty_constraints); |
415 | 432 | } else if self.check_const_arg() {
|
416 |
| - // Parse const argument. |
| 433 | + // Parse `const` argument. |
| 434 | + |
| 435 | + // `const` arguments that don't require surrunding braces would have a length of |
| 436 | + // one token, so anything that *isn't* surrounded by braces and is not |
| 437 | + // immediately followed by `,` or `>` is not a valid `const` argument. |
417 | 438 | let invalid = self.look_ahead(1, |t| t != &token::Lt && t != &token::Comma);
|
| 439 | + |
418 | 440 | let expr = if let token::OpenDelim(token::Brace) = self.token.kind {
|
| 441 | + // Parse `const` argument surrounded by braces. |
419 | 442 | self.parse_block_expr(
|
420 | 443 | None, self.token.span, BlockCheckMode::Default, ThinVec::new()
|
421 | 444 | )?
|
422 | 445 | } else if invalid {
|
423 | 446 | // This can't possibly be a valid const arg, it is likely missing braces.
|
424 |
| - let snapshot = self.clone(); |
425 |
| - match self.parse_expr_res(Restrictions::CONST_EXPR_RECOVERY, None) { |
426 |
| - Ok(expr) => { |
427 |
| - if self.token == token::Comma || self.token == token::Gt { |
428 |
| - // We parsed the whole const argument successfully without braces. |
429 |
| - if !expr.node.is_valid_const_on_its_own() { |
430 |
| - // But it wasn't a literal, so we emit a custom error and |
431 |
| - // suggest the appropriate code. |
432 |
| - let msg = |
433 |
| - "complex const arguments must be surrounded by braces"; |
434 |
| - let appl = Applicability::MachineApplicable; |
435 |
| - self.span_fatal(expr.span, msg) |
436 |
| - .multipart_suggestion( |
437 |
| - "surround this const argument in braces", |
438 |
| - vec![ |
439 |
| - (expr.span.shrink_to_lo(), "{ ".to_string()), |
440 |
| - (expr.span.shrink_to_hi(), " }".to_string()), |
441 |
| - ], |
442 |
| - appl, |
443 |
| - ) |
444 |
| - .emit(); |
445 |
| - } |
446 |
| - expr |
447 |
| - } else { |
448 |
| - // We parsed *some* expression, but it isn't the whole argument |
449 |
| - // so we can't ensure it was a const argument with missing braces. |
450 |
| - // Roll-back and emit a regular parser error. |
451 |
| - mem::replace(self, snapshot); |
452 |
| - self.parse_literal_maybe_minus()? |
453 |
| - } |
454 |
| - } |
455 |
| - Err(mut err) => { |
456 |
| - // We couldn't parse an expression successfully. |
457 |
| - // Roll-back, hide the error and emit a regular parser error. |
458 |
| - err.cancel(); |
459 |
| - mem::replace(self, snapshot); |
460 |
| - self.parse_literal_maybe_minus()? |
461 |
| - } |
462 |
| - } |
| 447 | + self.recover_bare_const_expr()? |
463 | 448 | } else if self.token.is_ident() {
|
464 | 449 | // FIXME(const_generics): to distinguish between idents for types and consts,
|
465 | 450 | // we should introduce a GenericArg::Ident in the AST and distinguish when
|
@@ -512,4 +497,50 @@ impl<'a> Parser<'a> {
|
512 | 497 |
|
513 | 498 | Ok((args, constraints))
|
514 | 499 | }
|
| 500 | + |
| 501 | + fn recover_bare_const_expr(&mut self) -> PResult<'a, P<Expr>> { |
| 502 | + let snapshot = self.clone(); |
| 503 | + debug!("recover_bare_const_expr {:?}", self.token); |
| 504 | + match self.parse_expr_res(Restrictions::CONST_EXPR_RECOVERY, None) { |
| 505 | + Ok(expr) => { |
| 506 | + debug!("recover_bare_const_expr expr {:?} {:?}", expr, expr.node); |
| 507 | + if let token::Comma | token::Gt = self.token.kind { |
| 508 | + // We parsed the whole const argument successfully without braces. |
| 509 | + debug!("recover_bare_const_expr ok"); |
| 510 | + if !expr.node.is_valid_const_on_its_own() { |
| 511 | + // But it wasn't a literal, so we emit a custom error and |
| 512 | + // suggest the appropriate code. `foo::<-1>()` is valid but gets parsed |
| 513 | + // here, so we need to gate the error only for invalid cases. |
| 514 | + self.span_fatal( |
| 515 | + expr.span, |
| 516 | + "complex const arguments must be surrounded by braces", |
| 517 | + ).multipart_suggestion( |
| 518 | + "surround this const argument in braces", |
| 519 | + vec![ |
| 520 | + (expr.span.shrink_to_lo(), "{ ".to_string()), |
| 521 | + (expr.span.shrink_to_hi(), " }".to_string()), |
| 522 | + ], |
| 523 | + Applicability::MachineApplicable, |
| 524 | + ).emit(); |
| 525 | + } |
| 526 | + Ok(expr) |
| 527 | + } else { |
| 528 | + debug!("recover_bare_const_expr not"); |
| 529 | + // We parsed *some* expression, but it isn't the whole argument |
| 530 | + // so we can't ensure it was a const argument with missing braces. |
| 531 | + // Roll-back and emit a regular parser error. |
| 532 | + mem::replace(self, snapshot); |
| 533 | + self.parse_literal_maybe_minus() |
| 534 | + } |
| 535 | + } |
| 536 | + Err(mut err) => { |
| 537 | + debug!("recover_bare_const_expr err"); |
| 538 | + // We couldn't parse an expression successfully. |
| 539 | + // Roll-back, hide the error and emit a regular parser error. |
| 540 | + err.cancel(); |
| 541 | + mem::replace(self, snapshot); |
| 542 | + self.parse_literal_maybe_minus() |
| 543 | + } |
| 544 | + } |
| 545 | + } |
515 | 546 | }
|
0 commit comments