Replace some bool params with an enum

This commit is contained in:
Maybe Waffle 2022-09-15 20:27:23 +04:00
parent 38b0865248
commit d86f9cd464
7 changed files with 63 additions and 47 deletions

View File

@ -29,6 +29,7 @@ extern crate rustc_macros;
extern crate tracing; extern crate tracing;
pub mod util { pub mod util {
pub mod case;
pub mod classify; pub mod classify;
pub mod comments; pub mod comments;
pub mod literal; pub mod literal;

View File

@ -5,6 +5,7 @@ pub use TokenKind::*;
use crate::ast; use crate::ast;
use crate::ptr::P; use crate::ptr::P;
use crate::util::case::Case;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::sync::Lrc; use rustc_data_structures::sync::Lrc;
@ -618,10 +619,10 @@ impl Token {
self.is_non_raw_ident_where(|id| id.name == kw) self.is_non_raw_ident_where(|id| id.name == kw)
} }
/// Returns `true` if the token is a given keyword, `kw` or if `case_insensitive` is true and this token is an identifier equal to `kw` ignoring the case. /// Returns `true` if the token is a given keyword, `kw` or if `case` is `Insensitive` and this token is an identifier equal to `kw` ignoring the case.
pub fn is_keyword_case(&self, kw: Symbol, case_insensitive: bool) -> bool { pub fn is_keyword_case(&self, kw: Symbol, case: Case) -> bool {
self.is_keyword(kw) self.is_keyword(kw)
|| (case_insensitive || (case == Case::Insensitive
&& self.is_non_raw_ident_where(|id| { && self.is_non_raw_ident_where(|id| {
id.name.as_str().to_lowercase() == kw.as_str().to_lowercase() id.name.as_str().to_lowercase() == kw.as_str().to_lowercase()
})) }))

View File

@ -0,0 +1,6 @@
/// Whatever to ignore case (`fn` vs `Fn` vs `FN`) or not. Used for recovering.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum Case {
Sensitive,
Insensitive,
}

View File

@ -33,6 +33,7 @@ use core::mem;
use rustc_ast::ptr::P; use rustc_ast::ptr::P;
use rustc_ast::token::{self, Delimiter, Token, TokenKind}; use rustc_ast::token::{self, Delimiter, Token, TokenKind};
use rustc_ast::tokenstream::Spacing; use rustc_ast::tokenstream::Spacing;
use rustc_ast::util::case::Case;
use rustc_ast::util::classify; use rustc_ast::util::classify;
use rustc_ast::util::literal::LitError; use rustc_ast::util::literal::LitError;
use rustc_ast::util::parser::{prec_let_scrutinee_needs_par, AssocOp, Fixity}; use rustc_ast::util::parser::{prec_let_scrutinee_needs_par, AssocOp, Fixity};
@ -2024,7 +2025,7 @@ impl<'a> Parser<'a> {
if self.eat_keyword(kw::Static) { Movability::Static } else { Movability::Movable }; if self.eat_keyword(kw::Static) { Movability::Static } else { Movability::Movable };
let asyncness = if self.token.uninterpolated_span().rust_2018() { let asyncness = if self.token.uninterpolated_span().rust_2018() {
self.parse_asyncness(false) self.parse_asyncness(Case::Sensitive)
} else { } else {
Async::No Async::No
}; };

View File

@ -8,6 +8,7 @@ use rustc_ast::ast::*;
use rustc_ast::ptr::P; use rustc_ast::ptr::P;
use rustc_ast::token::{self, Delimiter, TokenKind}; use rustc_ast::token::{self, Delimiter, TokenKind};
use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree}; use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree};
use rustc_ast::util::case::Case;
use rustc_ast::{self as ast, AttrVec, Attribute, DUMMY_NODE_ID}; use rustc_ast::{self as ast, AttrVec, Attribute, DUMMY_NODE_ID};
use rustc_ast::{Async, Const, Defaultness, IsAuto, Mutability, Unsafe, UseTree, UseTreeKind}; use rustc_ast::{Async, Const, Defaultness, IsAuto, Mutability, Unsafe, UseTree, UseTreeKind};
use rustc_ast::{BindingAnnotation, Block, FnDecl, FnSig, Param, SelfKind}; use rustc_ast::{BindingAnnotation, Block, FnDecl, FnSig, Param, SelfKind};
@ -34,7 +35,7 @@ impl<'a> Parser<'a> {
/// Parses a `mod <foo> { ... }` or `mod <foo>;` item. /// Parses a `mod <foo> { ... }` or `mod <foo>;` item.
fn parse_item_mod(&mut self, attrs: &mut AttrVec) -> PResult<'a, ItemInfo> { fn parse_item_mod(&mut self, attrs: &mut AttrVec) -> PResult<'a, ItemInfo> {
let unsafety = self.parse_unsafety(false); let unsafety = self.parse_unsafety(Case::Sensitive);
self.expect_keyword(kw::Mod)?; self.expect_keyword(kw::Mod)?;
let id = self.parse_ident()?; let id = self.parse_ident()?;
let mod_kind = if self.eat(&token::Semi) { let mod_kind = if self.eat(&token::Semi) {
@ -150,7 +151,7 @@ impl<'a> Parser<'a> {
&vis, &vis,
&mut def, &mut def,
fn_parse_mode, fn_parse_mode,
false, Case::Sensitive,
)?; )?;
if let Some((ident, kind)) = kind { if let Some((ident, kind)) = kind {
self.error_on_unconsumed_default(def, &kind); self.error_on_unconsumed_default(def, &kind);
@ -212,14 +213,14 @@ impl<'a> Parser<'a> {
vis: &Visibility, vis: &Visibility,
def: &mut Defaultness, def: &mut Defaultness,
fn_parse_mode: FnParseMode, fn_parse_mode: FnParseMode,
kw_case_insensitive: bool, case: Case,
) -> PResult<'a, Option<ItemInfo>> { ) -> PResult<'a, Option<ItemInfo>> {
let def_final = def == &Defaultness::Final; let def_final = def == &Defaultness::Final;
let mut def_ = || mem::replace(def, Defaultness::Final); let mut def_ = || mem::replace(def, Defaultness::Final);
let info = if self.eat_keyword_case(kw::Use, kw_case_insensitive) { let info = if self.eat_keyword_case(kw::Use, case) {
self.parse_use_item()? self.parse_use_item()?
} else if self.check_fn_front_matter(def_final, kw_case_insensitive) { } else if self.check_fn_front_matter(def_final, case) {
// FUNCTION ITEM // FUNCTION ITEM
let (ident, sig, generics, body) = self.parse_fn(attrs, fn_parse_mode, lo, vis)?; let (ident, sig, generics, body) = self.parse_fn(attrs, fn_parse_mode, lo, vis)?;
(ident, ItemKind::Fn(Box::new(Fn { defaultness: def_(), sig, generics, body }))) (ident, ItemKind::Fn(Box::new(Fn { defaultness: def_(), sig, generics, body })))
@ -233,7 +234,7 @@ impl<'a> Parser<'a> {
} }
} else if self.is_unsafe_foreign_mod() { } else if self.is_unsafe_foreign_mod() {
// EXTERN BLOCK // EXTERN BLOCK
let unsafety = self.parse_unsafety(false); let unsafety = self.parse_unsafety(Case::Sensitive);
self.expect_keyword(kw::Extern)?; self.expect_keyword(kw::Extern)?;
self.parse_item_foreign_mod(attrs, unsafety)? self.parse_item_foreign_mod(attrs, unsafety)?
} else if self.is_static_global() { } else if self.is_static_global() {
@ -242,7 +243,7 @@ impl<'a> Parser<'a> {
let m = self.parse_mutability(); let m = self.parse_mutability();
let (ident, ty, expr) = self.parse_item_global(Some(m))?; let (ident, ty, expr) = self.parse_item_global(Some(m))?;
(ident, ItemKind::Static(ty, m, expr)) (ident, ItemKind::Static(ty, m, expr))
} else if let Const::Yes(const_span) = self.parse_constness(false) { } else if let Const::Yes(const_span) = self.parse_constness(Case::Sensitive) {
// CONST ITEM // CONST ITEM
if self.token.is_keyword(kw::Impl) { if self.token.is_keyword(kw::Impl) {
// recover from `const impl`, suggest `impl const` // recover from `const impl`, suggest `impl const`
@ -294,11 +295,19 @@ impl<'a> Parser<'a> {
} else if self.isnt_macro_invocation() && vis.kind.is_pub() { } else if self.isnt_macro_invocation() && vis.kind.is_pub() {
self.recover_missing_kw_before_item()?; self.recover_missing_kw_before_item()?;
return Ok(None); return Ok(None);
} else if self.isnt_macro_invocation() && !kw_case_insensitive { } else if self.isnt_macro_invocation() && case == Case::Sensitive {
_ = def_; _ = def_;
// Recover wrong cased keywords // Recover wrong cased keywords
return self.parse_item_kind(attrs, macros_allowed, lo, vis, def, fn_parse_mode, true); return self.parse_item_kind(
attrs,
macros_allowed,
lo,
vis,
def,
fn_parse_mode,
Case::Insensitive,
);
} else if macros_allowed && self.check_path() { } else if macros_allowed && self.check_path() {
// MACRO INVOCATION ITEM // MACRO INVOCATION ITEM
(Ident::empty(), ItemKind::MacCall(P(self.parse_item_macro(vis)?))) (Ident::empty(), ItemKind::MacCall(P(self.parse_item_macro(vis)?)))
@ -551,7 +560,7 @@ impl<'a> Parser<'a> {
attrs: &mut AttrVec, attrs: &mut AttrVec,
defaultness: Defaultness, defaultness: Defaultness,
) -> PResult<'a, ItemInfo> { ) -> PResult<'a, ItemInfo> {
let unsafety = self.parse_unsafety(false); let unsafety = self.parse_unsafety(Case::Sensitive);
self.expect_keyword(kw::Impl)?; self.expect_keyword(kw::Impl)?;
// First, parse generic parameters if necessary. // First, parse generic parameters if necessary.
@ -565,7 +574,7 @@ impl<'a> Parser<'a> {
generics generics
}; };
let constness = self.parse_constness(false); let constness = self.parse_constness(Case::Sensitive);
if let Const::Yes(span) = constness { if let Const::Yes(span) = constness {
self.sess.gated_spans.gate(sym::const_trait_impl, span); self.sess.gated_spans.gate(sym::const_trait_impl, span);
} }
@ -809,7 +818,7 @@ impl<'a> Parser<'a> {
/// Parses `unsafe? auto? trait Foo { ... }` or `trait Foo = Bar;`. /// Parses `unsafe? auto? trait Foo { ... }` or `trait Foo = Bar;`.
fn parse_item_trait(&mut self, attrs: &mut AttrVec, lo: Span) -> PResult<'a, ItemInfo> { fn parse_item_trait(&mut self, attrs: &mut AttrVec, lo: Span) -> PResult<'a, ItemInfo> {
let unsafety = self.parse_unsafety(false); let unsafety = self.parse_unsafety(Case::Sensitive);
// Parse optional `auto` prefix. // Parse optional `auto` prefix.
let is_auto = if self.eat_keyword(kw::Auto) { IsAuto::Yes } else { IsAuto::No }; let is_auto = if self.eat_keyword(kw::Auto) { IsAuto::Yes } else { IsAuto::No };
@ -1758,7 +1767,7 @@ impl<'a> Parser<'a> {
let (ident, is_raw) = self.ident_or_err()?; let (ident, is_raw) = self.ident_or_err()?;
if !is_raw && ident.is_reserved() { if !is_raw && ident.is_reserved() {
let snapshot = self.create_snapshot_for_diagnostic(); let snapshot = self.create_snapshot_for_diagnostic();
let err = if self.check_fn_front_matter(false, false) { let err = if self.check_fn_front_matter(false, Case::Sensitive) {
let inherited_vis = Visibility { let inherited_vis = Visibility {
span: rustc_span::DUMMY_SP, span: rustc_span::DUMMY_SP,
kind: VisibilityKind::Inherited, kind: VisibilityKind::Inherited,
@ -2147,11 +2156,7 @@ impl<'a> Parser<'a> {
/// ///
/// `check_pub` adds additional `pub` to the checks in case users place it /// `check_pub` adds additional `pub` to the checks in case users place it
/// wrongly, can be used to ensure `pub` never comes after `default`. /// wrongly, can be used to ensure `pub` never comes after `default`.
pub(super) fn check_fn_front_matter( pub(super) fn check_fn_front_matter(&mut self, check_pub: bool, case: Case) -> bool {
&mut self,
check_pub: bool,
kw_case_insensitive: bool,
) -> bool {
// We use an over-approximation here. // We use an over-approximation here.
// `const const`, `fn const` won't parse, but we're not stepping over other syntax either. // `const const`, `fn const` won't parse, but we're not stepping over other syntax either.
// `pub` is added in case users got confused with the ordering like `async pub fn`, // `pub` is added in case users got confused with the ordering like `async pub fn`,
@ -2161,12 +2166,12 @@ impl<'a> Parser<'a> {
} else { } else {
&[kw::Const, kw::Async, kw::Unsafe, kw::Extern] &[kw::Const, kw::Async, kw::Unsafe, kw::Extern]
}; };
self.check_keyword_case(kw::Fn, kw_case_insensitive) // Definitely an `fn`. self.check_keyword_case(kw::Fn, case) // Definitely an `fn`.
// `$qual fn` or `$qual $qual`: // `$qual fn` or `$qual $qual`:
|| quals.iter().any(|&kw| self.check_keyword_case(kw, kw_case_insensitive)) || quals.iter().any(|&kw| self.check_keyword_case(kw, case))
&& self.look_ahead(1, |t| { && self.look_ahead(1, |t| {
// `$qual fn`, e.g. `const fn` or `async fn`. // `$qual fn`, e.g. `const fn` or `async fn`.
t.is_keyword_case(kw::Fn, kw_case_insensitive) t.is_keyword_case(kw::Fn, case)
// Two qualifiers `$qual $qual` is enough, e.g. `async unsafe`. // Two qualifiers `$qual $qual` is enough, e.g. `async unsafe`.
|| ( || (
( (
@ -2175,16 +2180,16 @@ impl<'a> Parser<'a> {
// Rule out 2015 `const async: T = val`. // Rule out 2015 `const async: T = val`.
&& i.is_reserved() && i.is_reserved()
) )
|| kw_case_insensitive || case == Case::Insensitive
&& t.is_non_raw_ident_where(|i| quals.iter().any(|qual| qual.as_str() == i.name.as_str().to_lowercase())) && t.is_non_raw_ident_where(|i| quals.iter().any(|qual| qual.as_str() == i.name.as_str().to_lowercase()))
) )
// Rule out unsafe extern block. // Rule out unsafe extern block.
&& !self.is_unsafe_foreign_mod()) && !self.is_unsafe_foreign_mod())
}) })
// `extern ABI fn` // `extern ABI fn`
|| self.check_keyword_case(kw::Extern, kw_case_insensitive) || self.check_keyword_case(kw::Extern, case)
&& self.look_ahead(1, |t| t.can_begin_literal_maybe_minus()) && self.look_ahead(1, |t| t.can_begin_literal_maybe_minus())
&& self.look_ahead(2, |t| t.is_keyword_case(kw::Fn, kw_case_insensitive)) && self.look_ahead(2, |t| t.is_keyword_case(kw::Fn, case))
} }
/// Parses all the "front matter" (or "qualifiers") for a `fn` declaration, /// Parses all the "front matter" (or "qualifiers") for a `fn` declaration,
@ -2200,22 +2205,22 @@ impl<'a> Parser<'a> {
/// `Visibility::Inherited` when no visibility is known. /// `Visibility::Inherited` when no visibility is known.
pub(super) fn parse_fn_front_matter(&mut self, orig_vis: &Visibility) -> PResult<'a, FnHeader> { pub(super) fn parse_fn_front_matter(&mut self, orig_vis: &Visibility) -> PResult<'a, FnHeader> {
let sp_start = self.token.span; let sp_start = self.token.span;
let constness = self.parse_constness(true); let constness = self.parse_constness(Case::Insensitive);
let async_start_sp = self.token.span; let async_start_sp = self.token.span;
let asyncness = self.parse_asyncness(true); let asyncness = self.parse_asyncness(Case::Insensitive);
let unsafe_start_sp = self.token.span; let unsafe_start_sp = self.token.span;
let unsafety = self.parse_unsafety(true); let unsafety = self.parse_unsafety(Case::Insensitive);
let ext_start_sp = self.token.span; let ext_start_sp = self.token.span;
let ext = self.parse_extern(true); let ext = self.parse_extern(Case::Insensitive);
if let Async::Yes { span, .. } = asyncness { if let Async::Yes { span, .. } = asyncness {
self.ban_async_in_2015(span); self.ban_async_in_2015(span);
} }
if !self.eat_keyword_case(kw::Fn, true) { if !self.eat_keyword_case(kw::Fn, Case::Insensitive) {
// It is possible for `expect_one_of` to recover given the contents of // It is possible for `expect_one_of` to recover given the contents of
// `self.expected_tokens`, therefore, do not use `self.unexpected()` which doesn't // `self.expected_tokens`, therefore, do not use `self.unexpected()` which doesn't
// account for this. // account for this.

View File

@ -22,6 +22,7 @@ use rustc_ast::token::{self, Delimiter, Nonterminal, Token, TokenKind};
use rustc_ast::tokenstream::AttributesData; use rustc_ast::tokenstream::AttributesData;
use rustc_ast::tokenstream::{self, DelimSpan, Spacing}; use rustc_ast::tokenstream::{self, DelimSpan, Spacing};
use rustc_ast::tokenstream::{TokenStream, TokenTree}; use rustc_ast::tokenstream::{TokenStream, TokenTree};
use rustc_ast::util::case::Case;
use rustc_ast::AttrId; use rustc_ast::AttrId;
use rustc_ast::DUMMY_NODE_ID; use rustc_ast::DUMMY_NODE_ID;
use rustc_ast::{self as ast, AnonConst, AttrStyle, AttrVec, Const, Extern}; use rustc_ast::{self as ast, AnonConst, AttrStyle, AttrVec, Const, Extern};
@ -604,12 +605,12 @@ impl<'a> Parser<'a> {
self.token.is_keyword(kw) self.token.is_keyword(kw)
} }
fn check_keyword_case(&mut self, kw: Symbol, case_insensitive: bool) -> bool { fn check_keyword_case(&mut self, kw: Symbol, case: Case) -> bool {
if self.check_keyword(kw) { if self.check_keyword(kw) {
return true; return true;
} }
if case_insensitive if case == Case::Insensitive
&& let Some((ident, /* is_raw */ false)) = self.token.ident() && let Some((ident, /* is_raw */ false)) = self.token.ident()
&& ident.as_str().to_lowercase() == kw.as_str().to_lowercase() { && ident.as_str().to_lowercase() == kw.as_str().to_lowercase() {
true true
@ -633,12 +634,12 @@ impl<'a> Parser<'a> {
/// Eats a keyword, optionally ignoring the case. /// Eats a keyword, optionally ignoring the case.
/// If the case differs (and is ignored) an error is issued. /// If the case differs (and is ignored) an error is issued.
/// This is useful for recovery. /// This is useful for recovery.
fn eat_keyword_case(&mut self, kw: Symbol, case_insensitive: bool) -> bool { fn eat_keyword_case(&mut self, kw: Symbol, case: Case) -> bool {
if self.eat_keyword(kw) { if self.eat_keyword(kw) {
return true; return true;
} }
if case_insensitive if case == Case::Insensitive
&& let Some((ident, /* is_raw */ false)) = self.token.ident() && let Some((ident, /* is_raw */ false)) = self.token.ident()
&& ident.as_str().to_lowercase() == kw.as_str().to_lowercase() { && ident.as_str().to_lowercase() == kw.as_str().to_lowercase() {
self self
@ -1136,8 +1137,8 @@ impl<'a> Parser<'a> {
} }
/// Parses asyncness: `async` or nothing. /// Parses asyncness: `async` or nothing.
fn parse_asyncness(&mut self, case_insensitive: bool) -> Async { fn parse_asyncness(&mut self, case: Case) -> Async {
if self.eat_keyword_case(kw::Async, case_insensitive) { if self.eat_keyword_case(kw::Async, case) {
let span = self.prev_token.uninterpolated_span(); let span = self.prev_token.uninterpolated_span();
Async::Yes { span, closure_id: DUMMY_NODE_ID, return_impl_trait_id: DUMMY_NODE_ID } Async::Yes { span, closure_id: DUMMY_NODE_ID, return_impl_trait_id: DUMMY_NODE_ID }
} else { } else {
@ -1146,8 +1147,8 @@ impl<'a> Parser<'a> {
} }
/// Parses unsafety: `unsafe` or nothing. /// Parses unsafety: `unsafe` or nothing.
fn parse_unsafety(&mut self, case_insensitive: bool) -> Unsafe { fn parse_unsafety(&mut self, case: Case) -> Unsafe {
if self.eat_keyword_case(kw::Unsafe, case_insensitive) { if self.eat_keyword_case(kw::Unsafe, case) {
Unsafe::Yes(self.prev_token.uninterpolated_span()) Unsafe::Yes(self.prev_token.uninterpolated_span())
} else { } else {
Unsafe::No Unsafe::No
@ -1155,10 +1156,10 @@ impl<'a> Parser<'a> {
} }
/// Parses constness: `const` or nothing. /// Parses constness: `const` or nothing.
fn parse_constness(&mut self, case_insensitive: bool) -> Const { fn parse_constness(&mut self, case: Case) -> Const {
// Avoid const blocks to be parsed as const items // Avoid const blocks to be parsed as const items
if self.look_ahead(1, |t| t != &token::OpenDelim(Delimiter::Brace)) if self.look_ahead(1, |t| t != &token::OpenDelim(Delimiter::Brace))
&& self.eat_keyword_case(kw::Const, case_insensitive) && self.eat_keyword_case(kw::Const, case)
{ {
Const::Yes(self.prev_token.uninterpolated_span()) Const::Yes(self.prev_token.uninterpolated_span())
} else { } else {
@ -1413,8 +1414,8 @@ impl<'a> Parser<'a> {
} }
/// Parses `extern string_literal?`. /// Parses `extern string_literal?`.
fn parse_extern(&mut self, case_insensitive: bool) -> Extern { fn parse_extern(&mut self, case: Case) -> Extern {
if self.eat_keyword_case(kw::Extern, case_insensitive) { if self.eat_keyword_case(kw::Extern, case) {
let mut extern_span = self.prev_token.span; let mut extern_span = self.prev_token.span;
let abi = self.parse_abi(); let abi = self.parse_abi();
if let Some(abi) = abi { if let Some(abi) = abi {

View File

@ -4,6 +4,7 @@ use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
use rustc_ast::ptr::P; use rustc_ast::ptr::P;
use rustc_ast::token::{self, Delimiter, Token, TokenKind}; use rustc_ast::token::{self, Delimiter, Token, TokenKind};
use rustc_ast::util::case::Case;
use rustc_ast::{ use rustc_ast::{
self as ast, BareFnTy, FnRetTy, GenericBound, GenericBounds, GenericParam, Generics, Lifetime, self as ast, BareFnTy, FnRetTy, GenericBound, GenericBounds, GenericParam, Generics, Lifetime,
MacCall, MutTy, Mutability, PolyTraitRef, TraitBoundModifier, TraitObjectSyntax, Ty, TyKind, MacCall, MutTy, Mutability, PolyTraitRef, TraitBoundModifier, TraitObjectSyntax, Ty, TyKind,
@ -267,7 +268,7 @@ impl<'a> Parser<'a> {
} else if self.eat_keyword(kw::Underscore) { } else if self.eat_keyword(kw::Underscore) {
// A type to be inferred `_` // A type to be inferred `_`
TyKind::Infer TyKind::Infer
} else if self.check_fn_front_matter(false, false) { } else if self.check_fn_front_matter(false, Case::Sensitive) {
// Function pointer type // Function pointer type
self.parse_ty_bare_fn(lo, Vec::new(), recover_return_sign)? self.parse_ty_bare_fn(lo, Vec::new(), recover_return_sign)?
} else if self.check_keyword(kw::For) { } else if self.check_keyword(kw::For) {
@ -275,7 +276,7 @@ impl<'a> Parser<'a> {
// `for<'lt> [unsafe] [extern "ABI"] fn (&'lt S) -> T` // `for<'lt> [unsafe] [extern "ABI"] fn (&'lt S) -> T`
// `for<'lt> Trait1<'lt> + Trait2 + 'a` // `for<'lt> Trait1<'lt> + Trait2 + 'a`
let lifetime_defs = self.parse_late_bound_lifetime_defs()?; let lifetime_defs = self.parse_late_bound_lifetime_defs()?;
if self.check_fn_front_matter(false, false) { if self.check_fn_front_matter(false, Case::Sensitive) {
self.parse_ty_bare_fn(lo, lifetime_defs, recover_return_sign)? self.parse_ty_bare_fn(lo, lifetime_defs, recover_return_sign)?
} else { } else {
let path = self.parse_path(PathStyle::Type)?; let path = self.parse_path(PathStyle::Type)?;