use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
use rustc_ast::ast::{self, BareFnTy, FnRetTy, GenericParam, Lifetime, MutTy, Ty, TyKind};
-use rustc_ast::ast::{
- GenericBound, GenericBounds, PolyTraitRef, TraitBoundModifier, TraitObjectSyntax,
-};
-use rustc_ast::ast::{Mac, Mutability};
+use rustc_ast::ast::{GenericBound, GenericBounds, MacCall, Mutability};
+use rustc_ast::ast::{PolyTraitRef, TraitBoundModifier, TraitObjectSyntax};
use rustc_ast::ptr::P;
use rustc_ast::token::{self, Token, TokenKind};
use rustc_errors::{pluralize, struct_span_err, Applicability, PResult};
} else if self.eat_keyword(kw::Underscore) {
// A type to be inferred `_`
TyKind::Infer
- } else if self.token_is_bare_fn_keyword() {
+ } else if self.check_fn_front_matter() {
// Function pointer type
- self.parse_ty_bare_fn(Vec::new())?
+ self.parse_ty_bare_fn(lo, Vec::new())?
} else if self.check_keyword(kw::For) {
// Function pointer type or bound list (trait object type) starting with a poly-trait.
// `for<'lt> [unsafe] [extern "ABI"] fn (&'lt S) -> T`
// `for<'lt> Trait1<'lt> + Trait2 + 'a`
let lifetime_defs = self.parse_late_bound_lifetime_defs()?;
- if self.token_is_bare_fn_keyword() {
- self.parse_ty_bare_fn(lifetime_defs)?
+ if self.check_fn_front_matter() {
+ self.parse_ty_bare_fn(lo, lifetime_defs)?
} else {
let path = self.parse_path(PathStyle::Type)?;
let parse_plus = allow_plus == AllowPlus::Yes && self.check_plus();
- self.parse_remaining_bounds(lifetime_defs, path, lo, parse_plus)?
+ self.parse_remaining_bounds_path(lifetime_defs, path, lo, parse_plus)?
}
} else if self.eat_keyword(kw::Impl) {
self.parse_impl_ty(&mut impl_dyn_multi)?
} else if self.is_explicit_dyn_type() {
self.parse_dyn_ty(&mut impl_dyn_multi)?
- } else if self.check(&token::Question)
- || self.check_lifetime() && self.look_ahead(1, |t| t.is_like_plus())
- {
- // Bound list (trait object type)
- let bounds = self.parse_generic_bounds_common(allow_plus, None)?;
- TyKind::TraitObject(bounds, TraitObjectSyntax::None)
} else if self.eat_lt() {
// Qualified path
let (qself, path) = self.parse_qpath(PathStyle::Type)?;
TyKind::Path(Some(qself), path)
- } else if self.token.is_path_start() {
+ } else if self.check_path() {
self.parse_path_start_ty(lo, allow_plus)?
+ } else if self.can_begin_bound() {
+ self.parse_bare_trait_object(lo, allow_plus)?
} else if self.eat(&token::DotDotDot) {
if allow_c_variadic == AllowCVariadic::Yes {
TyKind::CVarArgs
match ty.kind {
// `(TY_BOUND_NOPAREN) + BOUND + ...`.
TyKind::Path(None, path) if maybe_bounds => {
- self.parse_remaining_bounds(Vec::new(), path, lo, true)
+ self.parse_remaining_bounds_path(Vec::new(), path, lo, true)
}
- TyKind::TraitObject(mut bounds, TraitObjectSyntax::None)
+ TyKind::TraitObject(bounds, TraitObjectSyntax::None)
if maybe_bounds && bounds.len() == 1 && !trailing_plus =>
{
- let path = match bounds.remove(0) {
- GenericBound::Trait(pt, ..) => pt.trait_ref.path,
- GenericBound::Outlives(..) => {
- return Err(self.struct_span_err(
- ty.span,
- "expected trait bound, not lifetime bound",
- ));
- }
- };
- self.parse_remaining_bounds(Vec::new(), path, lo, true)
+ self.parse_remaining_bounds(bounds, true)
}
// `(TYPE)`
_ => Ok(TyKind::Paren(P(ty))),
}
}
- fn parse_remaining_bounds(
+ fn parse_bare_trait_object(&mut self, lo: Span, allow_plus: AllowPlus) -> PResult<'a, TyKind> {
+ let lt_no_plus = self.check_lifetime() && !self.look_ahead(1, |t| t.is_like_plus());
+ let bounds = self.parse_generic_bounds_common(allow_plus, None)?;
+ if lt_no_plus {
+ self.struct_span_err(lo, "lifetime in trait object type must be followed by `+`").emit()
+ }
+ Ok(TyKind::TraitObject(bounds, TraitObjectSyntax::None))
+ }
+
+ fn parse_remaining_bounds_path(
&mut self,
generic_params: Vec<GenericParam>,
path: ast::Path,
lo: Span,
parse_plus: bool,
) -> PResult<'a, TyKind> {
- assert_ne!(self.token, token::Question);
-
let poly_trait_ref = PolyTraitRef::new(generic_params, path, lo.to(self.prev_token.span));
- let mut bounds = vec![GenericBound::Trait(poly_trait_ref, TraitBoundModifier::None)];
- if parse_plus {
+ let bounds = vec![GenericBound::Trait(poly_trait_ref, TraitBoundModifier::None)];
+ self.parse_remaining_bounds(bounds, parse_plus)
+ }
+
+ /// Parse the remainder of a bare trait object type given an already parsed list.
+ fn parse_remaining_bounds(
+ &mut self,
+ mut bounds: GenericBounds,
+ plus: bool,
+ ) -> PResult<'a, TyKind> {
+ assert_ne!(self.token, token::Question);
+ if plus {
self.eat_plus(); // `+`, or `+=` gets split and `+` is discarded
bounds.append(&mut self.parse_generic_bounds(Some(self.prev_token.span))?);
}
Ok(TyKind::Typeof(expr))
}
- /// Is the current token one of the keywords that signals a bare function type?
- fn token_is_bare_fn_keyword(&mut self) -> bool {
- self.check_keyword(kw::Fn)
- || self.check_keyword(kw::Unsafe)
- || self.check_keyword(kw::Extern)
- }
-
/// Parses a function pointer type (`TyKind::BareFn`).
/// ```
/// [unsafe] [extern "ABI"] fn (S) -> T
/// | | | Return type
/// Function Style ABI Parameter types
/// ```
- fn parse_ty_bare_fn(&mut self, generic_params: Vec<GenericParam>) -> PResult<'a, TyKind> {
- let unsafety = self.parse_unsafety();
- let ext = self.parse_extern()?;
- self.expect_keyword(kw::Fn)?;
+ /// We actually parse `FnHeader FnDecl`, but we error on `const` and `async` qualifiers.
+ fn parse_ty_bare_fn(&mut self, lo: Span, params: Vec<GenericParam>) -> PResult<'a, TyKind> {
+ let ast::FnHeader { ext, unsafety, constness, asyncness } = self.parse_fn_front_matter()?;
let decl = self.parse_fn_decl(|_| false, AllowPlus::No)?;
- Ok(TyKind::BareFn(P(BareFnTy { ext, unsafety, generic_params, decl })))
+ let whole_span = lo.to(self.prev_token.span);
+ if let ast::Const::Yes(span) = constness {
+ self.error_fn_ptr_bad_qualifier(whole_span, span, "const");
+ }
+ if let ast::Async::Yes { span, .. } = asyncness {
+ self.error_fn_ptr_bad_qualifier(whole_span, span, "async");
+ }
+ Ok(TyKind::BareFn(P(BareFnTy { ext, unsafety, generic_params: params, decl })))
+ }
+
+ /// Emit an error for the given bad function pointer qualifier.
+ fn error_fn_ptr_bad_qualifier(&self, span: Span, qual_span: Span, qual: &str) {
+ self.struct_span_err(span, &format!("an `fn` pointer type cannot be `{}`", qual))
+ .span_label(qual_span, format!("`{}` because of this", qual))
+ .span_suggestion_short(
+ qual_span,
+ &format!("remove the `{}` qualifier", qual),
+ String::new(),
+ Applicability::MaybeIncorrect,
+ )
+ .emit();
}
/// Parses an `impl B0 + ... + Bn` type.
let path = self.parse_path(PathStyle::Type)?;
if self.eat(&token::Not) {
// Macro invocation in type position
- Ok(TyKind::Mac(Mac {
+ Ok(TyKind::MacCall(MacCall {
path,
args: self.parse_mac_args()?,
prior_type_ascription: self.last_type_ascription,
}))
} else if allow_plus == AllowPlus::Yes && self.check_plus() {
// `Trait1 + Trait2 + 'a`
- self.parse_remaining_bounds(Vec::new(), path, lo, true)
+ self.parse_remaining_bounds_path(Vec::new(), path, lo, true)
} else {
// Just a type path.
Ok(TyKind::Path(None, path))