use rustc_ast::token::{self, IdentIsRaw, MetaVarKind, Token, TokenKind}; use rustc_ast::util::case::Case; use rustc_ast::{ self as ast, BoundAsyncness, BoundConstness, BoundPolarity, DUMMY_NODE_ID, FnPtrTy, FnRetTy, GenericBound, GenericBounds, GenericParam, Generics, Lifetime, MacCall, MutTy, Mutability, Pinnedness, PolyTraitRef, PreciseCapturingArg, TraitBoundModifiers, TraitObjectSyntax, Ty, TyKind, UnsafeBinderTy, }; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{Applicability, Diag, PResult}; use rustc_span::{ErrorGuaranteed, Ident, Span, kw, sym}; use thin_vec::{ThinVec, thin_vec}; use super::{Parser, PathStyle, SeqSep, TokenType, Trailing}; use crate::errors::{ self, AttributeOnEmptyType, AttributeOnType, DynAfterMut, ExpectedFnPathFoundFnKeyword, ExpectedMutOrConstInRawPointerType, FnPtrWithGenerics, FnPtrWithGenericsSugg, HelpUseLatestEdition, InvalidDynKeyword, LifetimeAfterMut, NeedPlusAfterTraitObjectLifetime, NestedCVariadicType, ReturnTypesUseThinArrow, }; use crate::parser::item::FrontMatterParsingMode; use crate::parser::{FnContext, FnParseMode}; use crate::{exp, maybe_recover_from_interpolated_ty_qpath}; /// Signals whether parsing a type should allow `+`. /// /// For example, let T be the type `impl Default + 'static` /// With `AllowPlus::Yes`, T will be parsed successfully /// With `AllowPlus::No`, parsing T will return a parse error #[derive(Copy, Clone, PartialEq)] pub(super) enum AllowPlus { Yes, No, } #[derive(PartialEq)] pub(super) enum RecoverQPath { Yes, No, } pub(super) enum RecoverQuestionMark { Yes, No, } /// Signals whether parsing a type should recover `->`. /// /// More specifically, when parsing a function like: /// ```compile_fail /// fn foo() => u8 { 0 } /// fn bar(): u8 { 0 } /// ``` /// The compiler will try to recover interpreting `foo() => u8` as `foo() -> u8` when calling /// `parse_ty` with anything except `RecoverReturnSign::No`, and it will try to recover `bar(): u8` /// as `bar() -> u8` when passing `RecoverReturnSign::Yes` to `parse_ty` #[derive(Copy, Clone, PartialEq)] pub(super) enum RecoverReturnSign { Yes, OnlyFatArrow, No, } impl RecoverReturnSign { /// [RecoverReturnSign::Yes] allows for recovering `fn foo() => u8` and `fn foo(): u8`, /// [RecoverReturnSign::OnlyFatArrow] allows for recovering only `fn foo() => u8` (recovering /// colons can cause problems when parsing where clauses), and /// [RecoverReturnSign::No] doesn't allow for any recovery of the return type arrow fn can_recover(self, token: &TokenKind) -> bool { match self { Self::Yes => matches!(token, token::FatArrow | token::Colon), Self::OnlyFatArrow => matches!(token, token::FatArrow), Self::No => false, } } } // Is `...` (`CVarArgs`) legal at this level of type parsing? #[derive(PartialEq)] enum AllowCVariadic { Yes, No, } /// Returns `true` if `IDENT t` can start a type -- `IDENT::a::b`, `IDENT`, /// `IDENT<::AssocTy>`. /// /// Types can also be of the form `IDENT(u8, u8) -> u8`, however this assumes /// that `IDENT` is not the ident of a fn trait. fn can_continue_type_after_non_fn_ident(t: &Token) -> bool { t == &token::PathSep || t == &token::Lt || t == &token::Shl } fn can_begin_dyn_bound_in_edition_2015(t: &Token) -> bool { // `Not`, `Tilde` & `Const` are deliberately not part of this list to // contain the number of potential regressions esp. in MBE code. // `Const` would regress `rfc-2632-const-trait-impl/mbe-dyn-const-2015.rs`. // `Not` would regress `dyn!(...)` macro calls in Rust 2015. t.is_path_start() || t.is_lifetime() || t == &TokenKind::Question || t.is_keyword(kw::For) || t == &TokenKind::OpenParen } impl<'a> Parser<'a> { /// Parses a type. pub fn parse_ty(&mut self) -> PResult<'a, Box> { // Make sure deeply nested types don't overflow the stack. ensure_sufficient_stack(|| { self.parse_ty_common( AllowPlus::Yes, AllowCVariadic::No, RecoverQPath::Yes, RecoverReturnSign::Yes, None, RecoverQuestionMark::Yes, ) }) } pub(super) fn parse_ty_with_generics_recovery( &mut self, ty_params: &Generics, ) -> PResult<'a, Box> { self.parse_ty_common( AllowPlus::Yes, AllowCVariadic::No, RecoverQPath::Yes, RecoverReturnSign::Yes, Some(ty_params), RecoverQuestionMark::Yes, ) } /// Parse a type suitable for a function or function pointer parameter. /// The difference from `parse_ty` is that this version allows `...` /// (`CVarArgs`) at the top level of the type. pub(super) fn parse_ty_for_param(&mut self) -> PResult<'a, Box> { let ty = self.parse_ty_common( AllowPlus::Yes, AllowCVariadic::Yes, RecoverQPath::Yes, RecoverReturnSign::Yes, None, RecoverQuestionMark::Yes, )?; // Recover a trailing `= EXPR` if present. if self.may_recover() && self.check_noexpect(&token::Eq) && self.look_ahead(1, |tok| tok.can_begin_expr()) { let snapshot = self.create_snapshot_for_diagnostic(); self.bump(); let eq_span = self.prev_token.span; match self.parse_expr() { Ok(e) => { self.dcx() .struct_span_err(eq_span.to(e.span), "parameter defaults are not supported") .emit(); } Err(diag) => { diag.cancel(); self.restore_snapshot(snapshot); } } } Ok(ty) } /// Parses a type in restricted contexts where `+` is not permitted. /// /// Example 1: `&'a TYPE` /// `+` is prohibited to maintain operator priority (P(+) < P(&)). /// Example 2: `value1 as TYPE + value2` /// `+` is prohibited to avoid interactions with expression grammar. pub(super) fn parse_ty_no_plus(&mut self) -> PResult<'a, Box> { self.parse_ty_common( AllowPlus::No, AllowCVariadic::No, RecoverQPath::Yes, RecoverReturnSign::Yes, None, RecoverQuestionMark::Yes, ) } /// Parses a type following an `as` cast. Similar to `parse_ty_no_plus`, but signaling origin /// for better diagnostics involving `?`. pub(super) fn parse_as_cast_ty(&mut self) -> PResult<'a, Box> { self.parse_ty_common( AllowPlus::No, AllowCVariadic::No, RecoverQPath::Yes, RecoverReturnSign::Yes, None, RecoverQuestionMark::No, ) } pub(super) fn parse_ty_no_question_mark_recover(&mut self) -> PResult<'a, Box> { self.parse_ty_common( AllowPlus::Yes, AllowCVariadic::No, RecoverQPath::Yes, RecoverReturnSign::Yes, None, RecoverQuestionMark::No, ) } /// Parse a type without recovering `:` as `->` to avoid breaking code such /// as `where fn() : for<'a>`. pub(super) fn parse_ty_for_where_clause(&mut self) -> PResult<'a, Box> { self.parse_ty_common( AllowPlus::Yes, AllowCVariadic::No, RecoverQPath::Yes, RecoverReturnSign::OnlyFatArrow, None, RecoverQuestionMark::Yes, ) } /// Parses an optional return type `[ -> TY ]` in a function declaration. pub(super) fn parse_ret_ty( &mut self, allow_plus: AllowPlus, recover_qpath: RecoverQPath, recover_return_sign: RecoverReturnSign, ) -> PResult<'a, FnRetTy> { let lo = self.prev_token.span; Ok(if self.eat(exp!(RArrow)) { // FIXME(Centril): Can we unconditionally `allow_plus`? let ty = self.parse_ty_common( allow_plus, AllowCVariadic::No, recover_qpath, recover_return_sign, None, RecoverQuestionMark::Yes, )?; FnRetTy::Ty(ty) } else if recover_return_sign.can_recover(&self.token.kind) { // Don't `eat` to prevent `=>` from being added as an expected token which isn't // actually expected and could only confuse users self.bump(); self.dcx().emit_err(ReturnTypesUseThinArrow { span: self.prev_token.span, suggestion: lo.between(self.token.span), }); let ty = self.parse_ty_common( allow_plus, AllowCVariadic::No, recover_qpath, recover_return_sign, None, RecoverQuestionMark::Yes, )?; FnRetTy::Ty(ty) } else { FnRetTy::Default(self.prev_token.span.shrink_to_hi()) }) } fn parse_ty_common( &mut self, allow_plus: AllowPlus, allow_c_variadic: AllowCVariadic, recover_qpath: RecoverQPath, recover_return_sign: RecoverReturnSign, ty_generics: Option<&Generics>, recover_question_mark: RecoverQuestionMark, ) -> PResult<'a, Box> { let allow_qpath_recovery = recover_qpath == RecoverQPath::Yes; maybe_recover_from_interpolated_ty_qpath!(self, allow_qpath_recovery); if self.token == token::Pound && self.look_ahead(1, |t| *t == token::OpenBracket) { let attrs_wrapper = self.parse_outer_attributes()?; let raw_attrs = attrs_wrapper.take_for_recovery(self.psess); let attr_span = raw_attrs[0].span.to(raw_attrs.last().unwrap().span); let (full_span, guar) = match self.parse_ty() { Ok(ty) => { let full_span = attr_span.until(ty.span); let guar = self .dcx() .emit_err(AttributeOnType { span: attr_span, fix_span: full_span }); (attr_span, guar) } Err(err) => { err.cancel(); let guar = self.dcx().emit_err(AttributeOnEmptyType { span: attr_span }); (attr_span, guar) } }; return Ok(self.mk_ty(full_span, TyKind::Err(guar))); } if let Some(ty) = self.eat_metavar_seq_with_matcher( |mv_kind| matches!(mv_kind, MetaVarKind::Ty { .. }), |this| this.parse_ty_no_question_mark_recover(), ) { return Ok(ty); } let lo = self.token.span; let mut impl_dyn_multi = false; let kind = if self.check(exp!(OpenParen)) { self.parse_ty_tuple_or_parens(lo, allow_plus)? } else if self.eat(exp!(Bang)) { // Never type `!` TyKind::Never } else if self.eat(exp!(Star)) { self.parse_ty_ptr()? } else if self.eat(exp!(OpenBracket)) { self.parse_array_or_slice_ty()? } else if self.check(exp!(And)) || self.check(exp!(AndAnd)) { // Reference self.expect_and()?; self.parse_borrowed_pointee()? } else if self.eat_keyword_noexpect(kw::Typeof) { self.parse_typeof_ty()? } else if self.eat_keyword(exp!(Underscore)) { // A type to be inferred `_` TyKind::Infer } else if self.check_fn_front_matter(false, Case::Sensitive) { // Function pointer type self.parse_ty_fn_ptr(lo, ThinVec::new(), None, recover_return_sign)? } else if self.check_keyword(exp!(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 (bound_vars, _) = self.parse_higher_ranked_binder()?; if self.check_fn_front_matter(false, Case::Sensitive) { self.parse_ty_fn_ptr( lo, bound_vars, Some(self.prev_token.span.shrink_to_lo()), recover_return_sign, )? } else { // Try to recover `for<'a> dyn Trait` or `for<'a> impl Trait`. if self.may_recover() && (self.eat_keyword_noexpect(kw::Impl) || self.eat_keyword_noexpect(kw::Dyn)) { let kw = self.prev_token.ident().unwrap().0; let removal_span = kw.span.with_hi(self.token.span.lo()); let path = self.parse_path(PathStyle::Type)?; let parse_plus = allow_plus == AllowPlus::Yes && self.check_plus(); let kind = self.parse_remaining_bounds_path( bound_vars, path, lo, parse_plus, ast::Parens::No, )?; let err = self.dcx().create_err(errors::TransposeDynOrImpl { span: kw.span, kw: kw.name.as_str(), sugg: errors::TransposeDynOrImplSugg { removal_span, insertion_span: lo.shrink_to_lo(), kw: kw.name.as_str(), }, }); // Take the parsed bare trait object and turn it either // into a `dyn` object or an `impl Trait`. let kind = match (kind, kw.name) { (TyKind::TraitObject(bounds, _), kw::Dyn) => { TyKind::TraitObject(bounds, TraitObjectSyntax::Dyn) } (TyKind::TraitObject(bounds, _), kw::Impl) => { TyKind::ImplTrait(ast::DUMMY_NODE_ID, bounds) } _ => return Err(err), }; err.emit(); kind } else { let path = self.parse_path(PathStyle::Type)?; let parse_plus = allow_plus == AllowPlus::Yes && self.check_plus(); self.parse_remaining_bounds_path( bound_vars, path, lo, parse_plus, ast::Parens::No, )? } } } else if self.eat_keyword(exp!(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.eat_lt() { // Qualified path let (qself, path) = self.parse_qpath(PathStyle::Type)?; TyKind::Path(Some(qself), path) } else if self.check_path() { self.parse_path_start_ty(lo, allow_plus, ty_generics)? } else if self.can_begin_bound() { self.parse_bare_trait_object(lo, allow_plus)? } else if self.eat(exp!(DotDotDot)) { match allow_c_variadic { AllowCVariadic::Yes => TyKind::CVarArgs, AllowCVariadic::No => { // FIXME(c_variadic): Should we just allow `...` syntactically // anywhere in a type and use semantic restrictions instead? // NOTE: This may regress certain MBE calls if done incorrectly. let guar = self.dcx().emit_err(NestedCVariadicType { span: lo }); TyKind::Err(guar) } } } else if self.check_keyword(exp!(Unsafe)) && self.look_ahead(1, |tok| tok.kind == token::Lt) { self.parse_unsafe_binder_ty()? } else { let msg = format!("expected type, found {}", super::token_descr(&self.token)); let mut err = self.dcx().struct_span_err(lo, msg); err.span_label(lo, "expected type"); return Err(err); }; let span = lo.to(self.prev_token.span); let mut ty = self.mk_ty(span, kind); // Try to recover from use of `+` with incorrect priority. match allow_plus { AllowPlus::Yes => self.maybe_recover_from_bad_type_plus(&ty)?, AllowPlus::No => self.maybe_report_ambiguous_plus(impl_dyn_multi, &ty), } if let RecoverQuestionMark::Yes = recover_question_mark { ty = self.maybe_recover_from_question_mark(ty); } if allow_qpath_recovery { self.maybe_recover_from_bad_qpath(ty) } else { Ok(ty) } } fn parse_unsafe_binder_ty(&mut self) -> PResult<'a, TyKind> { let lo = self.token.span; assert!(self.eat_keyword(exp!(Unsafe))); self.expect_lt()?; let generic_params = self.parse_generic_params()?; self.expect_gt()?; let inner_ty = self.parse_ty()?; let span = lo.to(self.prev_token.span); self.psess.gated_spans.gate(sym::unsafe_binders, span); Ok(TyKind::UnsafeBinder(Box::new(UnsafeBinderTy { generic_params, inner_ty }))) } /// Parses either: /// - `(TYPE)`, a parenthesized type. /// - `(TYPE,)`, a tuple with a single field of type TYPE. fn parse_ty_tuple_or_parens(&mut self, lo: Span, allow_plus: AllowPlus) -> PResult<'a, TyKind> { let mut trailing_plus = false; let (ts, trailing) = self.parse_paren_comma_seq(|p| { let ty = p.parse_ty()?; trailing_plus = p.prev_token == TokenKind::Plus; Ok(ty) })?; if ts.len() == 1 && matches!(trailing, Trailing::No) { let ty = ts.into_iter().next().unwrap(); let maybe_bounds = allow_plus == AllowPlus::Yes && self.token.is_like_plus(); match ty.kind { // `"(" BareTraitBound ")" "+" Bound "+" ...`. TyKind::Path(None, path) if maybe_bounds => self.parse_remaining_bounds_path( ThinVec::new(), path, lo, true, ast::Parens::Yes, ), // For `('a) + …`, we know that `'a` in type position already lead to an error being // emitted. To reduce output, let's indirectly suppress E0178 (bad `+` in type) and // other irrelevant consequential errors. TyKind::TraitObject(bounds, TraitObjectSyntax::None) if maybe_bounds && bounds.len() == 1 && !trailing_plus => { self.parse_remaining_bounds(bounds, true) } // `(TYPE)` _ => Ok(TyKind::Paren(ty)), } } else { Ok(TyKind::Tup(ts)) } } fn parse_bare_trait_object(&mut self, lo: Span, allow_plus: AllowPlus) -> PResult<'a, TyKind> { // A lifetime only begins a bare trait object type if it is followed by `+`! if self.token.is_lifetime() && !self.look_ahead(1, |t| t.is_like_plus()) { // In Rust 2021 and beyond, we assume that the user didn't intend to write a bare trait // object type with a leading lifetime bound since that seems very unlikely given the // fact that `dyn`-less trait objects are *semantically* invalid. if self.psess.edition.at_least_rust_2021() { let lt = self.expect_lifetime(); let mut err = self.dcx().struct_span_err(lo, "expected type, found lifetime"); err.span_label(lo, "expected type"); return Ok(match self.maybe_recover_ref_ty_no_leading_ampersand(lt, lo, err) { Ok(ref_ty) => ref_ty, Err(err) => TyKind::Err(err.emit()), }); } self.dcx().emit_err(NeedPlusAfterTraitObjectLifetime { span: lo, suggestion: lo.shrink_to_hi(), }); } Ok(TyKind::TraitObject( self.parse_generic_bounds_common(allow_plus)?, TraitObjectSyntax::None, )) } fn maybe_recover_ref_ty_no_leading_ampersand<'cx>( &mut self, lt: Lifetime, lo: Span, mut err: Diag<'cx>, ) -> Result> { if !self.may_recover() { return Err(err); } let snapshot = self.create_snapshot_for_diagnostic(); let mutbl = self.parse_mutability(); match self.parse_ty_no_plus() { Ok(ty) => { err.span_suggestion_verbose( lo.shrink_to_lo(), "you might have meant to write a reference type here", "&", Applicability::MaybeIncorrect, ); err.emit(); Ok(TyKind::Ref(Some(lt), MutTy { ty, mutbl })) } Err(diag) => { diag.cancel(); self.restore_snapshot(snapshot); Err(err) } } } fn parse_remaining_bounds_path( &mut self, generic_params: ThinVec, path: ast::Path, lo: Span, parse_plus: bool, parens: ast::Parens, ) -> PResult<'a, TyKind> { let poly_trait_ref = PolyTraitRef::new( generic_params, path, TraitBoundModifiers::NONE, lo.to(self.prev_token.span), parens, ); let bounds = vec![GenericBound::Trait(poly_trait_ref)]; 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> { if plus { self.eat_plus(); // `+`, or `+=` gets split and `+` is discarded bounds.append(&mut self.parse_generic_bounds()?); } Ok(TyKind::TraitObject(bounds, TraitObjectSyntax::None)) } /// Parses a raw pointer type: `*[const | mut] $type`. fn parse_ty_ptr(&mut self) -> PResult<'a, TyKind> { let mutbl = self.parse_const_or_mut().unwrap_or_else(|| { let span = self.prev_token.span; self.dcx().emit_err(ExpectedMutOrConstInRawPointerType { span, after_asterisk: span.shrink_to_hi(), }); Mutability::Not }); let ty = self.parse_ty_no_plus()?; Ok(TyKind::Ptr(MutTy { ty, mutbl })) } /// Parses an array (`[TYPE; EXPR]`) or slice (`[TYPE]`) type. /// The opening `[` bracket is already eaten. fn parse_array_or_slice_ty(&mut self) -> PResult<'a, TyKind> { let elt_ty = match self.parse_ty() { Ok(ty) => ty, Err(err) if self.look_ahead(1, |t| *t == token::CloseBracket) | self.look_ahead(1, |t| *t == token::Semi) => { // Recover from `[LIT; EXPR]` and `[LIT]` self.bump(); let guar = err.emit(); self.mk_ty(self.prev_token.span, TyKind::Err(guar)) } Err(err) => return Err(err), }; let ty = if self.eat(exp!(Semi)) { let mut length = self.parse_expr_anon_const()?; if let Err(e) = self.expect(exp!(CloseBracket)) { // Try to recover from `X` when `X::` works self.check_mistyped_turbofish_with_multiple_type_params(e, &mut length.value)?; self.expect(exp!(CloseBracket))?; } TyKind::Array(elt_ty, length) } else if self.eat(exp!(CloseBracket)) { TyKind::Slice(elt_ty) } else { self.maybe_recover_array_ty_without_semi(elt_ty)? }; Ok(ty) } /// Recover from malformed array type syntax. /// /// This method attempts to recover from cases like: /// - `[u8, 5]` → suggests using `;`, return a Array type /// - `[u8 5]` → suggests using `;`, return a Array type /// Consider to add more cases in the future. fn maybe_recover_array_ty_without_semi(&mut self, elt_ty: Box) -> PResult<'a, TyKind> { let span = self.token.span; let token_descr = super::token_descr(&self.token); let mut err = self.dcx().struct_span_err(span, format!("expected `;` or `]`, found {}", token_descr)); err.span_label(span, "expected `;` or `]`"); err.note("you might have meant to write a slice or array type"); // If we cannot recover, return the error immediately. if !self.may_recover() { return Err(err); } let snapshot = self.create_snapshot_for_diagnostic(); let suggestion_span = if self.eat(exp!(Comma)) || self.eat(exp!(Star)) { // Consume common erroneous separators. self.prev_token.span } else { self.token.span.shrink_to_lo() }; // we first try to parse pattern like `[u8 5]` let length = match self.parse_expr_anon_const() { Ok(length) => length, Err(e) => { e.cancel(); self.restore_snapshot(snapshot); return Err(err); } }; if let Err(e) = self.expect(exp!(CloseBracket)) { e.cancel(); self.restore_snapshot(snapshot); return Err(err); } err.span_suggestion_verbose( suggestion_span, "you might have meant to use `;` as the separator", ";", Applicability::MaybeIncorrect, ); err.emit(); Ok(TyKind::Array(elt_ty, length)) } fn parse_borrowed_pointee(&mut self) -> PResult<'a, TyKind> { let and_span = self.prev_token.span; let mut opt_lifetime = self.check_lifetime().then(|| self.expect_lifetime()); let (pinned, mut mutbl) = match self.parse_pin_and_mut() { Some(pin_mut) => pin_mut, None => (Pinnedness::Not, self.parse_mutability()), }; if self.token.is_lifetime() && mutbl == Mutability::Mut && opt_lifetime.is_none() { // A lifetime is invalid here: it would be part of a bare trait bound, which requires // it to be followed by a plus, but we disallow plus in the pointee type. // So we can handle this case as an error here, and suggest `'a mut`. // If there *is* a plus next though, handling the error later provides better suggestions // (like adding parentheses) if !self.look_ahead(1, |t| t.is_like_plus()) { let lifetime_span = self.token.span; let span = and_span.to(lifetime_span); let (suggest_lifetime, snippet) = if let Ok(lifetime_src) = self.span_to_snippet(lifetime_span) { (Some(span), lifetime_src) } else { (None, String::new()) }; self.dcx().emit_err(LifetimeAfterMut { span, suggest_lifetime, snippet }); opt_lifetime = Some(self.expect_lifetime()); } } else if self.token.is_keyword(kw::Dyn) && mutbl == Mutability::Not && self.look_ahead(1, |t| t.is_keyword(kw::Mut)) { // We have `&dyn mut ...`, which is invalid and should be `&mut dyn ...`. let span = and_span.to(self.look_ahead(1, |t| t.span)); self.dcx().emit_err(DynAfterMut { span }); // Recovery mutbl = Mutability::Mut; let (dyn_tok, dyn_tok_sp) = (self.token, self.token_spacing); self.bump(); self.bump_with((dyn_tok, dyn_tok_sp)); } let ty = self.parse_ty_no_plus()?; Ok(match pinned { Pinnedness::Not => TyKind::Ref(opt_lifetime, MutTy { ty, mutbl }), Pinnedness::Pinned => TyKind::PinnedRef(opt_lifetime, MutTy { ty, mutbl }), }) } /// Parses `pin` and `mut` annotations on references. /// /// It must be either `pin const` or `pin mut`. pub(crate) fn parse_pin_and_mut(&mut self) -> Option<(Pinnedness, Mutability)> { if self.token.is_ident_named(sym::pin) { let result = self.look_ahead(1, |token| { if token.is_keyword(kw::Const) { Some((Pinnedness::Pinned, Mutability::Not)) } else if token.is_keyword(kw::Mut) { Some((Pinnedness::Pinned, Mutability::Mut)) } else { None } }); if result.is_some() { self.psess.gated_spans.gate(sym::pin_ergonomics, self.token.span); self.bump(); self.bump(); } result } else { None } } // Parses the `typeof(EXPR)`. // To avoid ambiguity, the type is surrounded by parentheses. fn parse_typeof_ty(&mut self) -> PResult<'a, TyKind> { self.expect(exp!(OpenParen))?; let expr = self.parse_expr_anon_const()?; self.expect(exp!(CloseParen))?; Ok(TyKind::Typeof(expr)) } /// Parses a function pointer type (`TyKind::FnPtr`). /// ```ignore (illustrative) /// [unsafe] [extern "ABI"] fn (S) -> T /// // ^~~~~^ ^~~~^ ^~^ ^ /// // | | | | /// // | | | Return type /// // Function Style ABI Parameter types /// ``` /// We actually parse `FnHeader FnDecl`, but we error on `const` and `async` qualifiers. fn parse_ty_fn_ptr( &mut self, lo: Span, mut params: ThinVec, param_insertion_point: Option, recover_return_sign: RecoverReturnSign, ) -> PResult<'a, TyKind> { let inherited_vis = rustc_ast::Visibility { span: rustc_span::DUMMY_SP, kind: rustc_ast::VisibilityKind::Inherited, tokens: None, }; let span_start = self.token.span; let ast::FnHeader { ext, safety, .. } = self.parse_fn_front_matter( &inherited_vis, Case::Sensitive, FrontMatterParsingMode::FunctionPtrType, )?; if self.may_recover() && self.token == TokenKind::Lt { self.recover_fn_ptr_with_generics(lo, &mut params, param_insertion_point)?; } let mode = crate::parser::item::FnParseMode { req_name: |_| false, context: FnContext::Free, req_body: false, }; let decl = self.parse_fn_decl(&mode, AllowPlus::No, recover_return_sign)?; let decl_span = span_start.to(self.prev_token.span); Ok(TyKind::FnPtr(Box::new(FnPtrTy { ext, safety, generic_params: params, decl, decl_span, }))) } /// Recover from function pointer types with a generic parameter list (e.g. `fn<'a>(&'a str)`). fn recover_fn_ptr_with_generics( &mut self, lo: Span, params: &mut ThinVec, param_insertion_point: Option, ) -> PResult<'a, ()> { let generics = self.parse_generics()?; let arity = generics.params.len(); let mut lifetimes: ThinVec<_> = generics .params .into_iter() .filter(|param| matches!(param.kind, ast::GenericParamKind::Lifetime)) .collect(); let sugg = if !lifetimes.is_empty() { let snippet = lifetimes.iter().map(|param| param.ident.as_str()).intersperse(", ").collect(); let (left, snippet) = if let Some(span) = param_insertion_point { (span, if params.is_empty() { snippet } else { format!(", {snippet}") }) } else { (lo.shrink_to_lo(), format!("for<{snippet}> ")) }; Some(FnPtrWithGenericsSugg { left, snippet, right: generics.span, arity, for_param_list_exists: param_insertion_point.is_some(), }) } else { None }; self.dcx().emit_err(FnPtrWithGenerics { span: generics.span, sugg }); params.append(&mut lifetimes); Ok(()) } /// Parses an `impl B0 + ... + Bn` type. fn parse_impl_ty(&mut self, impl_dyn_multi: &mut bool) -> PResult<'a, TyKind> { if self.token.is_lifetime() { self.look_ahead(1, |t| { if let token::Ident(sym, _) = t.kind { // parse pattern with "'a Sized" we're supposed to give suggestion like // "'a + Sized" self.dcx().emit_err(errors::MissingPlusBounds { span: self.token.span, hi: self.token.span.shrink_to_hi(), sym, }); } }) } // Always parse bounds greedily for better error recovery. let bounds = self.parse_generic_bounds()?; *impl_dyn_multi = bounds.len() > 1 || self.prev_token == TokenKind::Plus; Ok(TyKind::ImplTrait(ast::DUMMY_NODE_ID, bounds)) } /// Parse a use-bound aka precise capturing list. /// /// ```ebnf /// UseBound = "use" "<" (PreciseCapture ("," PreciseCapture)* ","?)? ">" /// PreciseCapture = "Self" | Ident | Lifetime /// ``` fn parse_use_bound(&mut self, lo: Span, parens: ast::Parens) -> PResult<'a, GenericBound> { self.expect_lt()?; let (args, _, _) = self.parse_seq_to_before_tokens( &[exp!(Gt)], &[&TokenKind::Ge, &TokenKind::Shr, &TokenKind::Shr], SeqSep::trailing_allowed(exp!(Comma)), |self_| { if self_.check_keyword(exp!(SelfUpper)) { self_.bump(); Ok(PreciseCapturingArg::Arg( ast::Path::from_ident(self_.prev_token.ident().unwrap().0), DUMMY_NODE_ID, )) } else if self_.check_ident() { Ok(PreciseCapturingArg::Arg( ast::Path::from_ident(self_.parse_ident()?), DUMMY_NODE_ID, )) } else if self_.check_lifetime() { Ok(PreciseCapturingArg::Lifetime(self_.expect_lifetime())) } else { self_.unexpected_any() } }, )?; self.expect_gt()?; if let ast::Parens::Yes = parens { self.expect(exp!(CloseParen))?; self.report_parenthesized_bound(lo, self.prev_token.span, "precise capturing lists"); } Ok(GenericBound::Use(args, lo.to(self.prev_token.span))) } /// Is a `dyn B0 + ... + Bn` type allowed here? fn is_explicit_dyn_type(&mut self) -> bool { self.check_keyword(exp!(Dyn)) && (self.token_uninterpolated_span().at_least_rust_2018() || self.look_ahead(1, |t| { (can_begin_dyn_bound_in_edition_2015(t) || *t == TokenKind::Star) && !can_continue_type_after_non_fn_ident(t) })) } /// Parses a `dyn B0 + ... + Bn` type. /// /// Note that this does *not* parse bare trait objects. fn parse_dyn_ty(&mut self, impl_dyn_multi: &mut bool) -> PResult<'a, TyKind> { self.bump(); // `dyn` // We used to parse `*` for `dyn*` here. let syntax = TraitObjectSyntax::Dyn; // Always parse bounds greedily for better error recovery. let bounds = self.parse_generic_bounds()?; *impl_dyn_multi = bounds.len() > 1 || self.prev_token == TokenKind::Plus; Ok(TyKind::TraitObject(bounds, syntax)) } /// Parses a type starting with a path. /// /// This can be: /// 1. a type macro, `mac!(...)`, /// 2. a bare trait object, `B0 + ... + Bn`, /// 3. or a path, `path::to::MyType`. fn parse_path_start_ty( &mut self, lo: Span, allow_plus: AllowPlus, ty_generics: Option<&Generics>, ) -> PResult<'a, TyKind> { // Simple path let path = self.parse_path_inner(PathStyle::Type, ty_generics)?; if self.eat(exp!(Bang)) { // Macro invocation in type position Ok(TyKind::MacCall(Box::new(MacCall { path, args: self.parse_delim_args()? }))) } else if allow_plus == AllowPlus::Yes && self.check_plus() { // `Trait1 + Trait2 + 'a` self.parse_remaining_bounds_path(ThinVec::new(), path, lo, true, ast::Parens::No) } else { // Just a type path. Ok(TyKind::Path(None, path)) } } pub(super) fn parse_generic_bounds(&mut self) -> PResult<'a, GenericBounds> { self.parse_generic_bounds_common(AllowPlus::Yes) } /// Parse generic bounds. /// /// Only if `allow_plus` this parses a `+`-separated list of bounds (trailing `+` is admitted). /// Otherwise, this only parses a single bound or none. fn parse_generic_bounds_common(&mut self, allow_plus: AllowPlus) -> PResult<'a, GenericBounds> { let mut 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() || (self.may_recover() && (self.token.can_begin_type() || (self.token.is_reserved_ident() && !self.token.is_keyword(kw::Where)))) { if self.token.is_keyword(kw::Dyn) { // Account for `&dyn Trait + dyn Other`. self.bump(); self.dcx().emit_err(InvalidDynKeyword { span: self.prev_token.span, suggestion: self.prev_token.span.until(self.token.span), }); } bounds.push(self.parse_generic_bound()?); if allow_plus == AllowPlus::No || !self.eat_plus() { break; } } Ok(bounds) } /// Can the current token begin a bound? fn can_begin_bound(&mut self) -> bool { self.check_path() || self.check_lifetime() || self.check(exp!(Bang)) || self.check(exp!(Question)) || self.check(exp!(Tilde)) || self.check_keyword(exp!(For)) || self.check(exp!(OpenParen)) || self.check(exp!(OpenBracket)) || self.check_keyword(exp!(Const)) || self.check_keyword(exp!(Async)) || self.check_keyword(exp!(Use)) } /// Parse a bound. /// /// ```ebnf /// Bound = LifetimeBound | UseBound | TraitBound /// ``` fn parse_generic_bound(&mut self) -> PResult<'a, GenericBound> { let leading_token = self.prev_token; let lo = self.token.span; // We only admit parenthesized *trait* bounds. However, we want to gracefully recover from // other kinds of parenthesized bounds, so parse the opening parenthesis *here*. // // In the future we might want to lift this syntactic restriction and // introduce "`GenericBound::Paren(Box)`". let parens = if self.eat(exp!(OpenParen)) { ast::Parens::Yes } else { ast::Parens::No }; if self.token.is_lifetime() { self.parse_lifetime_bound(lo, parens) } else if self.eat_keyword(exp!(Use)) { self.parse_use_bound(lo, parens) } else { self.parse_trait_bound(lo, parens, &leading_token) } } /// Parse a lifetime-bound aka outlives-bound. /// /// ```ebnf /// LifetimeBound = Lifetime /// ``` fn parse_lifetime_bound(&mut self, lo: Span, parens: ast::Parens) -> PResult<'a, GenericBound> { let lt = self.expect_lifetime(); if let ast::Parens::Yes = parens { self.expect(exp!(CloseParen))?; self.report_parenthesized_bound(lo, self.prev_token.span, "lifetime bounds"); } Ok(GenericBound::Outlives(lt)) } fn report_parenthesized_bound(&self, lo: Span, hi: Span, kind: &str) -> ErrorGuaranteed { let mut diag = self.dcx().struct_span_err(lo.to(hi), format!("{kind} may not be parenthesized")); diag.multipart_suggestion( "remove the parentheses", vec![(lo, String::new()), (hi, String::new())], Applicability::MachineApplicable, ); diag.emit() } /// Emits an error if any trait bound modifiers were present. fn error_lt_bound_with_modifiers( &self, modifiers: TraitBoundModifiers, binder_span: Option, ) -> ErrorGuaranteed { let TraitBoundModifiers { constness, asyncness, polarity } = modifiers; match constness { BoundConstness::Never => {} BoundConstness::Always(span) | BoundConstness::Maybe(span) => { return self .dcx() .emit_err(errors::ModifierLifetime { span, modifier: constness.as_str() }); } } match polarity { BoundPolarity::Positive => {} BoundPolarity::Negative(span) | BoundPolarity::Maybe(span) => { return self .dcx() .emit_err(errors::ModifierLifetime { span, modifier: polarity.as_str() }); } } match asyncness { BoundAsyncness::Normal => {} BoundAsyncness::Async(span) => { return self .dcx() .emit_err(errors::ModifierLifetime { span, modifier: asyncness.as_str() }); } } if let Some(span) = binder_span { return self.dcx().emit_err(errors::ModifierLifetime { span, modifier: "for<...>" }); } unreachable!("lifetime bound intercepted in `parse_generic_ty_bound` but no modifiers?") } /// Parses the modifiers that may precede a trait in a bound, e.g. `?Trait` or `[const] Trait`. /// /// If no modifiers are present, this does not consume any tokens. /// /// ```ebnf /// Constness = ("const" | "[" "const" "]")? /// Asyncness = "async"? /// Polarity = ("?" | "!")? /// ``` /// /// See `parse_trait_bound` for more context. fn parse_trait_bound_modifiers(&mut self) -> PResult<'a, TraitBoundModifiers> { let modifier_lo = self.token.span; let constness = self.parse_bound_constness()?; let asyncness = if self.token_uninterpolated_span().at_least_rust_2018() && self.eat_keyword(exp!(Async)) { self.psess.gated_spans.gate(sym::async_trait_bounds, self.prev_token.span); BoundAsyncness::Async(self.prev_token.span) } else if self.may_recover() && self.token_uninterpolated_span().is_rust_2015() && self.is_kw_followed_by_ident(kw::Async) { self.bump(); // eat `async` self.dcx().emit_err(errors::AsyncBoundModifierIn2015 { span: self.prev_token.span, help: HelpUseLatestEdition::new(), }); self.psess.gated_spans.gate(sym::async_trait_bounds, self.prev_token.span); BoundAsyncness::Async(self.prev_token.span) } else { BoundAsyncness::Normal }; let modifier_hi = self.prev_token.span; let polarity = if self.eat(exp!(Question)) { BoundPolarity::Maybe(self.prev_token.span) } else if self.eat(exp!(Bang)) { self.psess.gated_spans.gate(sym::negative_bounds, self.prev_token.span); BoundPolarity::Negative(self.prev_token.span) } else { BoundPolarity::Positive }; // Enforce the mutual-exclusivity of `const`/`async` and `?`/`!`. match polarity { BoundPolarity::Positive => { // All trait bound modifiers allowed to combine with positive polarity } BoundPolarity::Maybe(polarity_span) | BoundPolarity::Negative(polarity_span) => { match (asyncness, constness) { (BoundAsyncness::Normal, BoundConstness::Never) => { // Ok, no modifiers. } (_, _) => { let constness = constness.as_str(); let asyncness = asyncness.as_str(); let glue = if !constness.is_empty() && !asyncness.is_empty() { " " } else { "" }; let modifiers_concatenated = format!("{constness}{glue}{asyncness}"); self.dcx().emit_err(errors::PolarityAndModifiers { polarity_span, polarity: polarity.as_str(), modifiers_span: modifier_lo.to(modifier_hi), modifiers_concatenated, }); } } } } Ok(TraitBoundModifiers { constness, asyncness, polarity }) } pub fn parse_bound_constness(&mut self) -> PResult<'a, BoundConstness> { // FIXME(const_trait_impl): remove `~const` parser support once bootstrap has the new syntax // in rustfmt Ok(if self.eat(exp!(Tilde)) { let tilde = self.prev_token.span; self.expect_keyword(exp!(Const))?; let span = tilde.to(self.prev_token.span); self.psess.gated_spans.gate(sym::const_trait_impl, span); BoundConstness::Maybe(span) } else if self.check(exp!(OpenBracket)) && self.look_ahead(1, |t| t.is_keyword(kw::Const)) && self.look_ahead(2, |t| *t == token::CloseBracket) { let start = self.token.span; self.bump(); self.expect_keyword(exp!(Const)).unwrap(); self.bump(); let span = start.to(self.prev_token.span); self.psess.gated_spans.gate(sym::const_trait_impl, span); BoundConstness::Maybe(span) } else if self.eat_keyword(exp!(Const)) { self.psess.gated_spans.gate(sym::const_trait_impl, self.prev_token.span); BoundConstness::Always(self.prev_token.span) } else { BoundConstness::Never }) } /// Parse a trait bound. /// /// ```ebnf /// TraitBound = BareTraitBound | "(" BareTraitBound ")" /// BareTraitBound = /// (HigherRankedBinder Constness Asyncness | Polarity) /// TypePath /// ``` fn parse_trait_bound( &mut self, lo: Span, parens: ast::Parens, leading_token: &Token, ) -> PResult<'a, GenericBound> { let (mut bound_vars, binder_span) = self.parse_higher_ranked_binder()?; let modifiers_lo = self.token.span; let modifiers = self.parse_trait_bound_modifiers()?; let modifiers_span = modifiers_lo.to(self.prev_token.span); if let Some(binder_span) = binder_span { match modifiers.polarity { BoundPolarity::Negative(polarity_span) | BoundPolarity::Maybe(polarity_span) => { self.dcx().emit_err(errors::BinderAndPolarity { binder_span, polarity_span, polarity: modifiers.polarity.as_str(), }); } BoundPolarity::Positive => {} } } // Recover erroneous lifetime bound with modifiers or binder. // e.g. `T: for<'a> 'a` or `T: [const] 'a`. if self.token.is_lifetime() { let _: ErrorGuaranteed = self.error_lt_bound_with_modifiers(modifiers, binder_span); return self.parse_lifetime_bound(lo, parens); } if let (more_bound_vars, Some(binder_span)) = self.parse_higher_ranked_binder()? { bound_vars.extend(more_bound_vars); self.dcx().emit_err(errors::BinderBeforeModifiers { binder_span, modifiers_span }); } let mut path = if self.token.is_keyword(kw::Fn) && self.look_ahead(1, |t| *t == TokenKind::OpenParen) && 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.dcx().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() { let (span, message, sugg, path, applicability) = match &ty.kind { TyKind::Ptr(..) | TyKind::Ref(..) if let TyKind::Path(_, path) = &ty.peel_refs().kind => { ( ty.span.until(path.span), "consider removing the indirection", "", path, Applicability::MaybeIncorrect, ) } TyKind::ImplTrait(_, bounds) if let [GenericBound::Trait(tr, ..), ..] = bounds.as_slice() => { ( ty.span.until(tr.span), "use the trait bounds directly", "", &tr.trait_ref.path, Applicability::MachineApplicable, ) } _ => return Err(err), }; err.span_suggestion_verbose(span, message, sugg, applicability); path.clone() } else { return Err(err); }; err.emit(); path } else { self.parse_path(PathStyle::Type)? }; if self.may_recover() && self.token == TokenKind::OpenParen { self.recover_fn_trait_with_lifetime_params(&mut path, &mut bound_vars)?; } if let ast::Parens::Yes = parens { // Someone has written something like `&dyn (Trait + Other)`. The correct code // would be `&(dyn Trait + Other)` if self.token.is_like_plus() && leading_token.is_keyword(kw::Dyn) { let bounds = vec![]; self.parse_remaining_bounds(bounds, true)?; self.expect(exp!(CloseParen))?; self.dcx().emit_err(errors::IncorrectParensTraitBounds { span: vec![lo, self.prev_token.span], sugg: errors::IncorrectParensTraitBoundsSugg { wrong_span: leading_token.span.shrink_to_hi().to(lo), new_span: leading_token.span.shrink_to_lo(), }, }); } else { self.expect(exp!(CloseParen))?; } } let poly_trait = PolyTraitRef::new(bound_vars, path, modifiers, lo.to(self.prev_token.span), parens); Ok(GenericBound::Trait(poly_trait)) } // recovers a `Fn(..)` parenthesized-style path from `fn(..)` fn recover_path_from_fn(&mut self) -> Option { let fn_token_span = self.token.span; self.bump(); let args_lo = self.token.span; let snapshot = self.create_snapshot_for_diagnostic(); let mode = FnParseMode { req_name: |_| false, context: FnContext::Free, req_body: false }; match self.parse_fn_decl(&mode, AllowPlus::No, RecoverReturnSign::OnlyFatArrow) { Ok(decl) => { self.dcx().emit_err(ExpectedFnPathFoundFnKeyword { fn_token_span }); Some(ast::Path { span: fn_token_span.to(self.prev_token.span), segments: thin_vec![ast::PathSegment { ident: Ident::new(sym::Fn, fn_token_span), id: DUMMY_NODE_ID, args: Some(Box::new(ast::GenericArgs::Parenthesized( ast::ParenthesizedArgs { span: args_lo.to(self.prev_token.span), inputs: decl.inputs.iter().map(|a| a.ty.clone()).collect(), inputs_span: args_lo.until(decl.output.span()), output: decl.output.clone(), } ))), }], tokens: None, }) } Err(diag) => { diag.cancel(); self.restore_snapshot(snapshot); None } } } /// Parse an optional higher-ranked binder. /// /// ```ebnf /// HigherRankedBinder = ("for" "<" GenericParams ">")? /// ``` pub(super) fn parse_higher_ranked_binder( &mut self, ) -> PResult<'a, (ThinVec, Option)> { if self.eat_keyword(exp!(For)) { let lo = self.token.span; self.expect_lt()?; let params = self.parse_generic_params()?; self.expect_gt()?; // We rely on AST validation to rule out invalid cases: There must not be // type or const parameters, and parameters must not have bounds. Ok((params, Some(lo.to(self.prev_token.span)))) } else { Ok((ThinVec::new(), None)) } } /// Recover from `Fn`-family traits (Fn, FnMut, FnOnce) with lifetime arguments /// (e.g. `FnOnce<'a>(&'a str) -> bool`). Up to generic arguments have already /// been eaten. fn recover_fn_trait_with_lifetime_params( &mut self, fn_path: &mut ast::Path, lifetime_defs: &mut ThinVec, ) -> PResult<'a, ()> { let fn_path_segment = fn_path.segments.last_mut().unwrap(); let generic_args = if let Some(p_args) = &fn_path_segment.args { *p_args.clone() } else { // Normally it wouldn't come here because the upstream should have parsed // generic parameters (otherwise it's impossible to call this function). return Ok(()); }; let lifetimes = if let ast::GenericArgs::AngleBracketed(ast::AngleBracketedArgs { span: _, args }) = &generic_args { args.into_iter() .filter_map(|arg| { if let ast::AngleBracketedArg::Arg(generic_arg) = arg && let ast::GenericArg::Lifetime(lifetime) = generic_arg { Some(lifetime) } else { None } }) .collect() } else { Vec::new() }; // Only try to recover if the trait has lifetime params. if lifetimes.is_empty() { return Ok(()); } // Parse `(T, U) -> R`. let inputs_lo = self.token.span; let mode = FnParseMode { req_name: |_| false, context: FnContext::Free, req_body: false }; let inputs: ThinVec<_> = self.parse_fn_params(&mode)?.into_iter().map(|input| input.ty).collect(); let inputs_span = inputs_lo.to(self.prev_token.span); let output = self.parse_ret_ty(AllowPlus::No, RecoverQPath::No, RecoverReturnSign::No)?; let args = ast::ParenthesizedArgs { span: fn_path_segment.span().to(self.prev_token.span), inputs, inputs_span, output, } .into(); *fn_path_segment = ast::PathSegment { ident: fn_path_segment.ident, args: Some(args), id: ast::DUMMY_NODE_ID, }; // Convert parsed `<'a>` in `Fn<'a>` into `for<'a>`. let mut generic_params = lifetimes .iter() .map(|lt| GenericParam { id: lt.id, ident: lt.ident, attrs: ast::AttrVec::new(), bounds: Vec::new(), is_placeholder: false, kind: ast::GenericParamKind::Lifetime, colon_span: None, }) .collect::>(); lifetime_defs.append(&mut generic_params); let generic_args_span = generic_args.span(); let snippet = format!( "for<{}> ", lifetimes.iter().map(|lt| lt.ident.as_str()).intersperse(", ").collect::(), ); let before_fn_path = fn_path.span.shrink_to_lo(); self.dcx() .struct_span_err(generic_args_span, "`Fn` traits cannot take lifetime parameters") .with_multipart_suggestion( "consider using a higher-ranked trait bound instead", vec![(generic_args_span, "".to_owned()), (before_fn_path, snippet)], Applicability::MaybeIncorrect, ) .emit(); Ok(()) } pub(super) fn check_lifetime(&mut self) -> bool { self.expected_token_types.insert(TokenType::Lifetime); self.token.is_lifetime() } /// Parses a single lifetime `'a` or panics. pub(super) fn expect_lifetime(&mut self) -> Lifetime { if let Some((ident, is_raw)) = self.token.lifetime() { if matches!(is_raw, IdentIsRaw::No) && ident.without_first_quote().is_reserved_lifetime() { self.dcx().emit_err(errors::KeywordLifetime { span: ident.span }); } self.bump(); Lifetime { ident, id: ast::DUMMY_NODE_ID } } else { self.dcx().span_bug(self.token.span, "not a lifetime") } } pub(super) fn mk_ty(&self, span: Span, kind: TyKind) -> Box { Box::new(Ty { kind, span, id: ast::DUMMY_NODE_ID, tokens: None }) } }