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};
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:
}
// Is `...` (`CVarArgs`) legal at this level of type parsing?
- #[derive(PartialEq)]
+ #[derive(PartialEq, Clone, Copy)]
enum AllowCVariadic {
Yes,
No,
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)?