]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #106960 - estebank:parse-anon-enums, r=cjgillot
authorMatthias Krüger <matthias.krueger@famsik.de>
Thu, 26 Jan 2023 05:15:24 +0000 (06:15 +0100)
committerGitHub <noreply@github.com>
Thu, 26 Jan 2023 05:15:24 +0000 (06:15 +0100)
Teach parser to understand fake anonymous enum syntax

Parse `Ty | OtherTy` in function argument and return types.
Parse type ascription in top level patterns.

Minimally address #100741.

1  2 
compiler/rustc_parse/src/parser/ty.rs

index 1766b0293de52a33c2eceb3254ecfe0b44e7f0af,43e6eac438ba53b70d3c185991bfd00fdae473cf..25de0a9e75014ae019b680aedaf410e4563bcc5d
@@@ -11,6 -11,7 +11,7 @@@ use rustc_ast::
      self as ast, BareFnTy, FnRetTy, GenericBound, GenericBounds, GenericParam, Generics, Lifetime,
      MacCall, MutTy, Mutability, PolyTraitRef, TraitBoundModifier, TraitObjectSyntax, Ty, TyKind,
  };
+ use rustc_ast_pretty::pprust;
  use rustc_errors::{pluralize, struct_span_err, Applicability, PResult};
  use rustc_span::source_map::Span;
  use rustc_span::symbol::{kw, sym, Ident};
@@@ -43,17 -44,24 +44,24 @@@ pub(super) enum AllowPlus 
      No,
  }
  
- #[derive(PartialEq)]
+ #[derive(PartialEq, Clone, Copy)]
  pub(super) enum RecoverQPath {
      Yes,
      No,
  }
  
+ #[derive(PartialEq, Clone, Copy)]
  pub(super) enum RecoverQuestionMark {
      Yes,
      No,
  }
  
+ #[derive(PartialEq, Clone, Copy)]
+ pub(super) enum RecoverAnonEnum {
+     Yes,
+     No,
+ }
  /// Signals whether parsing a type should recover `->`.
  ///
  /// More specifically, when parsing a function like:
@@@ -86,7 -94,7 +94,7 @@@ impl RecoverReturnSign 
  }
  
  // Is `...` (`CVarArgs`) legal at this level of type parsing?
- #[derive(PartialEq)]
+ #[derive(PartialEq, Clone, Copy)]
  enum AllowCVariadic {
      Yes,
      No,
@@@ -111,6 -119,7 +119,7 @@@ impl<'a> Parser<'a> 
              RecoverReturnSign::Yes,
              None,
              RecoverQuestionMark::Yes,
+             RecoverAnonEnum::No,
          )
      }
  
              RecoverReturnSign::Yes,
              Some(ty_params),
              RecoverQuestionMark::Yes,
+             RecoverAnonEnum::No,
          )
      }
  
              RecoverReturnSign::Yes,
              None,
              RecoverQuestionMark::Yes,
+             RecoverAnonEnum::Yes,
          )
      }
  
              RecoverReturnSign::Yes,
              None,
              RecoverQuestionMark::Yes,
+             RecoverAnonEnum::No,
          )
      }
  
              RecoverReturnSign::Yes,
              None,
              RecoverQuestionMark::No,
+             RecoverAnonEnum::No,
          )
      }
  
              RecoverReturnSign::Yes,
              None,
              RecoverQuestionMark::No,
+             RecoverAnonEnum::No,
          )
      }
  
              RecoverReturnSign::OnlyFatArrow,
              None,
              RecoverQuestionMark::Yes,
+             RecoverAnonEnum::No,
          )
      }
  
                  recover_return_sign,
                  None,
                  RecoverQuestionMark::Yes,
+                 RecoverAnonEnum::Yes,
              )?;
              FnRetTy::Ty(ty)
          } else if recover_return_sign.can_recover(&self.token.kind) {
                  recover_return_sign,
                  None,
                  RecoverQuestionMark::Yes,
+                 RecoverAnonEnum::Yes,
              )?;
              FnRetTy::Ty(ty)
          } else {
          recover_return_sign: RecoverReturnSign,
          ty_generics: Option<&Generics>,
          recover_question_mark: RecoverQuestionMark,
+         recover_anon_enum: RecoverAnonEnum,
      ) -> PResult<'a, P<Ty>> {
          let allow_qpath_recovery = recover_qpath == RecoverQPath::Yes;
          maybe_recover_from_interpolated_ty_qpath!(self, allow_qpath_recovery);
          let mut ty = self.mk_ty(span, kind);
  
          // Try to recover from use of `+` with incorrect priority.
-         if matches!(allow_plus, AllowPlus::Yes) {
+         if allow_plus == AllowPlus::Yes {
              self.maybe_recover_from_bad_type_plus(&ty)?;
          } else {
              self.maybe_report_ambiguous_plus(impl_dyn_multi, &ty);
          }
-         if let RecoverQuestionMark::Yes = recover_question_mark {
+         if RecoverQuestionMark::Yes == recover_question_mark {
              ty = self.maybe_recover_from_question_mark(ty);
          }
+         if recover_anon_enum == RecoverAnonEnum::Yes
+             && self.check_noexpect(&token::BinOp(token::Or))
+             && self.look_ahead(1, |t| t.can_begin_type())
+         {
+             let mut pipes = vec![self.token.span];
+             let mut types = vec![ty];
+             loop {
+                 if !self.eat(&token::BinOp(token::Or)) {
+                     break;
+                 }
+                 pipes.push(self.prev_token.span);
+                 types.push(self.parse_ty_common(
+                     allow_plus,
+                     allow_c_variadic,
+                     recover_qpath,
+                     recover_return_sign,
+                     ty_generics,
+                     recover_question_mark,
+                     RecoverAnonEnum::No,
+                 )?);
+             }
+             let mut err = self.struct_span_err(pipes, "anonymous enums are not supported");
+             for ty in &types {
+                 err.span_label(ty.span, "");
+             }
+             err.help(&format!(
+                 "create a named `enum` and use it here instead:\nenum Name {{\n{}\n}}",
+                 types
+                     .iter()
+                     .enumerate()
+                     .map(|(i, t)| format!(
+                         "    Variant{}({}),",
+                         i + 1, // Lets not confuse people with zero-indexing :)
+                         pprust::to_string(|s| s.print_type(&t)),
+                     ))
+                     .collect::<Vec<_>>()
+                     .join("\n"),
+             ));
+             err.emit();
+             return Ok(self.mk_ty(lo.to(self.prev_token.span), TyKind::Err));
+         }
          if allow_qpath_recovery { self.maybe_recover_from_bad_qpath(ty) } else { Ok(ty) }
      }
  
          let mut bounds = Vec::new();
          let mut negative_bounds = Vec::new();
  
 +        // In addition to looping while we find generic bounds:
 +        // We continue even if we find a keyword. This is necessary for error recovery on,
 +        // for example, `impl fn()`. The only keyword that can go after generic bounds is
 +        // `where`, so stop if it's it.
 +        // We also continue if we find types (not traits), again for error recovery.
          while self.can_begin_bound()
 -            // Continue even if we find a keyword.
 -            // This is necessary for error recover on, for example, `impl fn()`.
 -            //
 -            // The only keyword that can go after generic bounds is `where`, so stop if it's it.
 +            || self.token.can_begin_type()
              || (self.token.is_reserved_ident() && !self.token.is_keyword(kw::Where))
          {
              if self.token.is_keyword(kw::Dyn) {
              && self.look_ahead(1, |tok| tok.kind == TokenKind::OpenDelim(Delimiter::Parenthesis))
              && let Some(path) = self.recover_path_from_fn()
          {
 +            path
 +        } else if !self.token.is_path_start() && self.token.can_begin_type() {
 +            let ty = self.parse_ty_no_plus()?;
 +            // Instead of finding a path (a trait), we found a type.
 +            let mut err = self.struct_span_err(ty.span, "expected a trait, found type");
 +
 +            // If we can recover, try to extract a path from the type. Note
 +            // that we do not use the try operator when parsing the type because
 +            // if it fails then we get a parser error which we don't want (we're trying
 +            // to recover from errors, not make more).
 +            let path = if self.may_recover()
 +                && matches!(ty.kind, TyKind::Ptr(..) | TyKind::Ref(..))
 +                && let TyKind::Path(_, path) = &ty.peel_refs().kind {
 +                // Just get the indirection part of the type.
 +                let span = ty.span.until(path.span);
 +
 +                err.span_suggestion_verbose(
 +                    span,
 +                    "consider removing the indirection",
 +                    "",
 +                    Applicability::MaybeIncorrect,
 +                );
 +
 +                path.clone()
 +            } else {
 +                return Err(err);
 +            };
 +
 +            err.emit();
 +
              path
          } else {
              self.parse_path(PathStyle::Type)?