|
1 |
| -use super::{P, Parser, PResult, Restrictions, TokenType}; |
| 1 | +use super::{Parser, PResult, Restrictions, TokenType}; |
2 | 2 |
|
3 | 3 | use crate::{maybe_whole, ThinVec};
|
4 | 4 | use crate::ast::{
|
5 | 5 | self, AngleBracketedArgs, AnonConst, AssocTyConstraint, AssocTyConstraintKind, BlockCheckMode,
|
6 |
| - Expr, GenericArg, Ident, ParenthesizedArgs, Path, PathSegment, QSelf, |
| 6 | + GenericArg, Ident, ParenthesizedArgs, Path, PathSegment, QSelf, |
7 | 7 | };
|
8 | 8 | use crate::parse::token::{self, Token};
|
9 | 9 | use crate::source_map::{Span, BytePos};
|
@@ -323,7 +323,7 @@ impl<'a> Parser<'a> {
|
323 | 323 | };
|
324 | 324 |
|
325 | 325 | debug!("parse_generic_args_with_leading_angle_bracket_recovery: (snapshotting)");
|
326 |
| - match self.parse_generic_args() { |
| 326 | + match self.parse_generic_args(style) { |
327 | 327 | Ok(value) => Ok(value),
|
328 | 328 | Err(ref mut e) if is_first_invocation && self.unmatched_angle_bracket_count > 0 => {
|
329 | 329 | // Cancel error from being unable to find `>`. We know the error
|
@@ -370,15 +370,18 @@ impl<'a> Parser<'a> {
|
370 | 370 | .emit();
|
371 | 371 |
|
372 | 372 | // Try again without unmatched angle bracket characters.
|
373 |
| - self.parse_generic_args() |
| 373 | + self.parse_generic_args(style) |
374 | 374 | },
|
375 | 375 | Err(e) => Err(e),
|
376 | 376 | }
|
377 | 377 | }
|
378 | 378 |
|
379 | 379 | /// Parses (possibly empty) list of lifetime and type arguments and associated type bindings,
|
380 | 380 | /// possibly including trailing comma.
|
381 |
| - fn parse_generic_args(&mut self) -> PResult<'a, (Vec<GenericArg>, Vec<AssocTyConstraint>)> { |
| 381 | + fn parse_generic_args( |
| 382 | + &mut self, |
| 383 | + style: PathStyle, |
| 384 | + ) -> PResult<'a, (Vec<GenericArg>, Vec<AssocTyConstraint>)> { |
382 | 385 | let mut args = Vec::new();
|
383 | 386 | let mut constraints = Vec::new();
|
384 | 387 | let mut misplaced_assoc_ty_constraints: Vec<Span> = Vec::new();
|
@@ -415,59 +418,13 @@ impl<'a> Parser<'a> {
|
415 | 418 | span,
|
416 | 419 | });
|
417 | 420 | assoc_ty_constraints.push(span);
|
418 |
| - } else if [ |
419 |
| - token::Not, |
420 |
| - token::OpenDelim(token::Paren), |
421 |
| - ].contains(&self.token.kind) && self.look_ahead(1, |t| t.is_lit() || t.is_bool_lit()) { |
422 |
| - // Parse bad `const` argument. `!` is only allowed here to go through |
423 |
| - // `recover_bare_const_expr` for better diagnostics when encountering |
424 |
| - // `foo::<!false>()`. `(` is allowed for the case `foo::<(1, 2, 3)>()`. |
425 |
| - |
426 |
| - // This can't possibly be a valid const arg, it is likely missing braces. |
427 |
| - let value = AnonConst { |
428 |
| - id: ast::DUMMY_NODE_ID, |
429 |
| - value: self.recover_bare_const_expr()?, |
430 |
| - }; |
431 |
| - args.push(GenericArg::Const(value)); |
| 421 | + } else if self.check_possible_const_needing_braces(style) { |
| 422 | + args.push(self.parse_const_or_type_arg()?); |
432 | 423 | misplaced_assoc_ty_constraints.append(&mut assoc_ty_constraints);
|
433 | 424 | } else if self.check_const_arg() {
|
434 |
| - // Parse `const` argument. |
435 |
| - |
436 |
| - // `const` arguments that don't require surrunding braces would have a length of |
437 |
| - // one token, so anything that *isn't* surrounded by braces and is not |
438 |
| - // immediately followed by `,` or `>` is not a valid `const` argument. |
439 |
| - let invalid = self.look_ahead(1, |t| t != &token::Lt && t != &token::Comma); |
440 |
| - |
441 |
| - let expr = if let token::OpenDelim(token::Brace) = self.token.kind { |
442 |
| - // Parse `const` argument surrounded by braces. |
443 |
| - self.parse_block_expr( |
444 |
| - None, self.token.span, BlockCheckMode::Default, ThinVec::new() |
445 |
| - )? |
446 |
| - } else if invalid { |
447 |
| - // This can't possibly be a valid const arg, it is likely missing braces. |
448 |
| - self.recover_bare_const_expr()? |
449 |
| - } else if self.token.is_ident() { |
450 |
| - // FIXME(const_generics): to distinguish between idents for types and consts, |
451 |
| - // we should introduce a GenericArg::Ident in the AST and distinguish when |
452 |
| - // lowering to the HIR. For now, idents for const args are not permitted. |
453 |
| - if self.token.is_bool_lit() { |
454 |
| - self.parse_literal_maybe_minus()? |
455 |
| - } else { |
456 |
| - return Err( |
457 |
| - self.fatal("identifiers may currently not be used for const generics") |
458 |
| - ); |
459 |
| - } |
460 |
| - } else { |
461 |
| - self.parse_literal_maybe_minus()? |
462 |
| - }; |
463 |
| - let value = AnonConst { |
464 |
| - id: ast::DUMMY_NODE_ID, |
465 |
| - value: expr, |
466 |
| - }; |
467 |
| - args.push(GenericArg::Const(value)); |
| 425 | + args.push(self.parse_const_arg()?); |
468 | 426 | misplaced_assoc_ty_constraints.append(&mut assoc_ty_constraints);
|
469 | 427 | } else if self.check_type() {
|
470 |
| - // Parse type argument. |
471 | 428 | args.push(GenericArg::Type(self.parse_ty()?));
|
472 | 429 | misplaced_assoc_ty_constraints.append(&mut assoc_ty_constraints);
|
473 | 430 | } else {
|
@@ -499,49 +456,86 @@ impl<'a> Parser<'a> {
|
499 | 456 | Ok((args, constraints))
|
500 | 457 | }
|
501 | 458 |
|
502 |
| - fn recover_bare_const_expr(&mut self) -> PResult<'a, P<Expr>> { |
503 |
| - let snapshot = self.clone(); |
504 |
| - debug!("recover_bare_const_expr {:?}", self.token); |
505 |
| - match self.parse_expr_res(Restrictions::CONST_EXPR_RECOVERY, None) { |
506 |
| - Ok(expr) => { |
507 |
| - debug!("recover_bare_const_expr expr {:?} {:?}", expr, expr.node); |
508 |
| - if let token::Comma | token::Gt = self.token.kind { |
509 |
| - // We parsed the whole const argument successfully without braces. |
510 |
| - debug!("recover_bare_const_expr ok"); |
511 |
| - if !expr.node.is_valid_const_on_its_own() { |
512 |
| - // But it wasn't a literal, so we emit a custom error and |
513 |
| - // suggest the appropriate code. `foo::<-1>()` is valid but gets parsed |
514 |
| - // here, so we need to gate the error only for invalid cases. |
515 |
| - self.span_fatal( |
516 |
| - expr.span, |
517 |
| - "complex const arguments must be surrounded by braces", |
518 |
| - ).multipart_suggestion( |
519 |
| - "surround this const argument in braces", |
520 |
| - vec![ |
521 |
| - (expr.span.shrink_to_lo(), "{ ".to_string()), |
522 |
| - (expr.span.shrink_to_hi(), " }".to_string()), |
523 |
| - ], |
524 |
| - Applicability::MachineApplicable, |
525 |
| - ).emit(); |
| 459 | + fn parse_const_arg(&mut self) -> PResult<'a, GenericArg> { |
| 460 | + let value = if let token::OpenDelim(token::Brace) = self.token.kind { |
| 461 | + // Parse `const` argument surrounded by braces. |
| 462 | + self.parse_block_expr(None, self.token.span, BlockCheckMode::Default, ThinVec::new())? |
| 463 | + } else { |
| 464 | + self.parse_expr_res(Restrictions::CLOSING_ANGLE_BRACKET, None)? |
| 465 | + }; |
| 466 | + let value = AnonConst { id: ast::DUMMY_NODE_ID, value }; |
| 467 | + Ok(GenericArg::Const(value)) |
| 468 | + } |
| 469 | + |
| 470 | + /// Check some ambiguous cases between type and non-block const arguments. |
| 471 | + fn check_possible_const_needing_braces(&mut self, style: PathStyle) -> bool { |
| 472 | + style == PathStyle::Expr && ( |
| 473 | + self.token.kind == token::Not || // `foo::<!const_bool_fn()>()` |
| 474 | + self.token.kind == token::OpenDelim(token::Paren) // `foo::<(1, 2, 3)>()` |
| 475 | + ) |
| 476 | + } |
| 477 | + |
| 478 | + /// There's intent ambiguity for this argument, it could be a const expression missing braces, |
| 479 | + /// or it could be a type argument. We try the later as the grammar expects, and if it fails we |
| 480 | + /// attempt the former and emit a targetted suggestion if valid. |
| 481 | + fn parse_const_or_type_arg(&mut self) -> PResult<'a, GenericArg> { |
| 482 | + let mut snapshot = self.clone(); |
| 483 | + match self.parse_ty() { |
| 484 | + // Nothing to do, this was indeed a type argument. |
| 485 | + Ok(ty) if [ |
| 486 | + token::Comma, |
| 487 | + token::Gt, |
| 488 | + token::BinOp(token::Shr), |
| 489 | + ].contains(&self.token.kind) => Ok(GenericArg::Type(ty)), |
| 490 | + Ok(ty) => { // Could have found `foo::<!false>()`, needs `foo::<{ !false }>()`. |
| 491 | + mem::swap(self, &mut snapshot); |
| 492 | + match self.parse_bad_const_arg() { |
| 493 | + Ok(arg) => Ok(arg), |
| 494 | + Err(mut err) => { |
| 495 | + mem::swap(self, &mut snapshot); |
| 496 | + err.cancel(); |
| 497 | + Ok(GenericArg::Type(ty)) |
| 498 | + } |
| 499 | + } |
| 500 | + } |
| 501 | + Err(mut ty_err) => { |
| 502 | + mem::swap(self, &mut snapshot); |
| 503 | + match self.parse_bad_const_arg() { |
| 504 | + Ok(arg) => { |
| 505 | + ty_err.cancel(); |
| 506 | + Ok(arg) |
| 507 | + } |
| 508 | + Err(mut err) => { |
| 509 | + mem::swap(self, &mut snapshot); |
| 510 | + err.cancel(); |
| 511 | + Err(ty_err) |
526 | 512 | }
|
527 |
| - Ok(expr) |
528 |
| - } else { |
529 |
| - debug!("recover_bare_const_expr not"); |
530 |
| - // We parsed *some* expression, but it isn't the whole argument |
531 |
| - // so we can't ensure it was a const argument with missing braces. |
532 |
| - // Roll-back and emit a regular parser error. |
533 |
| - mem::replace(self, snapshot); |
534 |
| - self.parse_literal_maybe_minus() |
535 | 513 | }
|
536 | 514 | }
|
537 |
| - Err(mut err) => { |
538 |
| - debug!("recover_bare_const_expr err"); |
539 |
| - // We couldn't parse an expression successfully. |
540 |
| - // Roll-back, hide the error and emit a regular parser error. |
541 |
| - err.cancel(); |
542 |
| - mem::replace(self, snapshot); |
543 |
| - self.parse_literal_maybe_minus() |
| 515 | + } |
| 516 | + } |
| 517 | + |
| 518 | + fn parse_bad_const_arg(&mut self) -> PResult<'a, GenericArg> { |
| 519 | + let msg = if self.token.kind == token::OpenDelim(token::Paren) { |
| 520 | + // `foo::<(1, 2, 3)>()` |
| 521 | + "tuples in const arguments must be surrounded by braces" |
| 522 | + } else { |
| 523 | + "complex const arguments must be surrounded by braces" |
| 524 | + }; |
| 525 | + match self.parse_const_arg() { |
| 526 | + Ok(arg) => { |
| 527 | + self.span_fatal(arg.span(), msg) |
| 528 | + .multipart_suggestion( |
| 529 | + "surround this const argument in braces", |
| 530 | + vec![ |
| 531 | + (arg.span().shrink_to_lo(), "{ ".to_string()), |
| 532 | + (arg.span().shrink_to_hi(), " }".to_string()), |
| 533 | + ], |
| 534 | + Applicability::MachineApplicable, |
| 535 | + ).emit(); |
| 536 | + Ok(arg) |
544 | 537 | }
|
| 538 | + Err(err) => Err(err), |
545 | 539 | }
|
546 | 540 | }
|
547 | 541 | }
|
0 commit comments