-// ignore-tidy-filelength
-
mod expr;
use expr::LhsExpr;
mod pat;
pub use item::AliasKind;
mod module;
pub use module::{ModulePath, ModulePathSuccess};
+mod ty;
+mod path;
+pub use path::PathStyle;
-use crate::ast::{self, AngleBracketedArgs, ParenthesizedArgs, AttrStyle, BareFnTy};
-use crate::ast::{AnonConst, Arg, Attribute, BindingMode};
+use crate::ast::{self, AttrStyle};
+use crate::ast::{Arg, Attribute, BindingMode};
use crate::ast::{Block, BlockCheckMode, Expr, ExprKind, Stmt, StmtKind};
-use crate::ast::{FnDecl, FunctionRetTy};
+use crate::ast::{FnDecl};
use crate::ast::{Ident, IsAsync, Local, Lifetime};
use crate::ast::{MacStmtStyle, Mac_, MacDelimiter};
-use crate::ast::{MutTy, Mutability};
-use crate::ast::{PolyTraitRef, QSelf, PathSegment};
+use crate::ast::{Mutability};
use crate::ast::StrStyle;
use crate::ast::SelfKind;
-use crate::ast::{GenericBound, TraitBoundModifier, TraitObjectSyntax};
-use crate::ast::{GenericParam, GenericParamKind, GenericArg, WhereClause};
-use crate::ast::{Ty, TyKind, AssocTyConstraint, AssocTyConstraintKind, GenericBounds};
+use crate::ast::{GenericParam, GenericParamKind, WhereClause};
+use crate::ast::{Ty, TyKind, GenericBounds};
use crate::ast::{Visibility, VisibilityKind, Unsafety, CrateSugar};
use crate::ext::base::DummyResult;
use crate::ext::hygiene::SyntaxContext;
}
}
-/// Specifies how to parse a path.
-#[derive(Copy, Clone, PartialEq)]
-pub enum PathStyle {
- /// In some contexts, notably in expressions, paths with generic arguments are ambiguous
- /// with something else. For example, in expressions `segment < ....` can be interpreted
- /// as a comparison and `segment ( ....` can be interpreted as a function call.
- /// In all such contexts the non-path interpretation is preferred by default for practical
- /// reasons, but the path interpretation can be forced by the disambiguator `::`, e.g.
- /// `x<y>` - comparisons, `x::<y>` - unambiguously a path.
- Expr,
- /// In other contexts, notably in types, no ambiguity exists and paths can be written
- /// without the disambiguator, e.g., `x<y>` - unambiguously a path.
- /// Paths with disambiguators are still accepted, `x::<Y>` - unambiguously a path too.
- Type,
- /// A path with generic arguments disallowed, e.g., `foo::bar::Baz`, used in imports,
- /// visibilities or attributes.
- /// Technically, this variant is unnecessary and e.g., `Expr` can be used instead
- /// (paths in "mod" contexts have to be checked later for absence of generic arguments
- /// anyway, due to macros), but it is used to avoid weird suggestions about expected
- /// tokens when something goes wrong.
- Mod,
-}
-
#[derive(Clone, Copy, PartialEq, Debug)]
crate enum SemiColonMode {
Break,
}
}
-/// Returns `true` if `IDENT t` can start a type -- `IDENT::a::b`, `IDENT<u8, u8>`,
-/// `IDENT<<u8 as Trait>::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::ModSep || t == &token::Lt ||
- t == &token::BinOp(token::Shl)
-}
-
#[derive(Copy, Clone, Debug)]
crate enum TokenExpectType {
Expect,
self.look_ahead(dist, |t| kws.iter().any(|&kw| t.is_keyword(kw)))
}
- /// 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 `TyKind::BareFn` type.
- fn parse_ty_bare_fn(&mut self, generic_params: Vec<GenericParam>) -> PResult<'a, TyKind> {
- /*
-
- [unsafe] [extern "ABI"] fn (S) -> T
- ^~~~^ ^~~~^ ^~^ ^
- | | | |
- | | | Return type
- | | Argument types
- | |
- | ABI
- Function Style
- */
-
- let unsafety = self.parse_unsafety();
- let abi = if self.eat_keyword(kw::Extern) {
- self.parse_opt_abi()?.unwrap_or(Abi::C)
- } else {
- Abi::Rust
- };
-
- self.expect_keyword(kw::Fn)?;
- let (inputs, c_variadic) = self.parse_fn_args(false, true)?;
- let ret_ty = self.parse_ret_ty(false)?;
- let decl = P(FnDecl {
- inputs,
- output: ret_ty,
- c_variadic,
- });
- Ok(TyKind::BareFn(P(BareFnTy {
- abi,
- unsafety,
- generic_params,
- decl,
- })))
- }
-
/// Parses asyncness: `async` or nothing.
fn parse_asyncness(&mut self) -> IsAsync {
if self.eat_keyword(kw::Async) {
}
}
- /// Parses an optional return type `[ -> TY ]` in a function declaration.
- fn parse_ret_ty(&mut self, allow_plus: bool) -> PResult<'a, FunctionRetTy> {
- if self.eat(&token::RArrow) {
- Ok(FunctionRetTy::Ty(self.parse_ty_common(allow_plus, true, false)?))
- } else {
- Ok(FunctionRetTy::Default(self.token.span.shrink_to_lo()))
- }
- }
-
- /// Parses a type.
- pub fn parse_ty(&mut self) -> PResult<'a, P<Ty>> {
- self.parse_ty_common(true, true, false)
- }
-
- /// 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.
- fn parse_ty_no_plus(&mut self) -> PResult<'a, P<Ty>> {
- self.parse_ty_common(false, true, false)
- }
-
- fn parse_ty_common(&mut self, allow_plus: bool, allow_qpath_recovery: bool,
- allow_c_variadic: bool) -> PResult<'a, P<Ty>> {
- maybe_recover_from_interpolated_ty_qpath!(self, allow_qpath_recovery);
- maybe_whole!(self, NtTy, |x| x);
-
- let lo = self.token.span;
- let mut impl_dyn_multi = false;
- let node = if self.eat(&token::OpenDelim(token::Paren)) {
- // `(TYPE)` is a parenthesized type.
- // `(TYPE,)` is a tuple with a single field of type TYPE.
- let mut ts = vec![];
- let mut last_comma = false;
- while self.token != token::CloseDelim(token::Paren) {
- ts.push(self.parse_ty()?);
- if self.eat(&token::Comma) {
- last_comma = true;
- } else {
- last_comma = false;
- break;
- }
- }
- let trailing_plus = self.prev_token_kind == PrevTokenKind::Plus;
- self.expect(&token::CloseDelim(token::Paren))?;
-
- if ts.len() == 1 && !last_comma {
- let ty = ts.into_iter().nth(0).unwrap().into_inner();
- let maybe_bounds = allow_plus && self.token.is_like_plus();
- match ty.node {
- // `(TY_BOUND_NOPAREN) + BOUND + ...`.
- TyKind::Path(None, ref path) if maybe_bounds => {
- self.parse_remaining_bounds(Vec::new(), path.clone(), lo, true)?
- }
- TyKind::TraitObject(ref bounds, TraitObjectSyntax::None)
- if maybe_bounds && bounds.len() == 1 && !trailing_plus => {
- let path = match bounds[0] {
- GenericBound::Trait(ref pt, ..) => pt.trait_ref.path.clone(),
- GenericBound::Outlives(..) => self.bug("unexpected lifetime bound"),
- };
- self.parse_remaining_bounds(Vec::new(), path, lo, true)?
- }
- // `(TYPE)`
- _ => TyKind::Paren(P(ty))
- }
- } else {
- TyKind::Tup(ts)
- }
- } else if self.eat(&token::Not) {
- // Never type `!`
- TyKind::Never
- } else if self.eat(&token::BinOp(token::Star)) {
- // Raw pointer
- TyKind::Ptr(self.parse_ptr()?)
- } else if self.eat(&token::OpenDelim(token::Bracket)) {
- // Array or slice
- let t = self.parse_ty()?;
- // Parse optional `; EXPR` in `[TYPE; EXPR]`
- let t = match self.maybe_parse_fixed_length_of_vec()? {
- None => TyKind::Slice(t),
- Some(length) => TyKind::Array(t, AnonConst {
- id: ast::DUMMY_NODE_ID,
- value: length,
- }),
- };
- self.expect(&token::CloseDelim(token::Bracket))?;
- t
- } else if self.check(&token::BinOp(token::And)) || self.check(&token::AndAnd) {
- // Reference
- self.expect_and()?;
- self.parse_borrowed_pointee()?
- } else if self.eat_keyword_noexpect(kw::Typeof) {
- // `typeof(EXPR)`
- // In order to not be ambiguous, the type must be surrounded by parens.
- self.expect(&token::OpenDelim(token::Paren))?;
- let e = AnonConst {
- id: ast::DUMMY_NODE_ID,
- value: self.parse_expr()?,
- };
- self.expect(&token::CloseDelim(token::Paren))?;
- TyKind::Typeof(e)
- } else if self.eat_keyword(kw::Underscore) {
- // A type to be inferred `_`
- TyKind::Infer
- } else if self.token_is_bare_fn_keyword() {
- // Function pointer type
- self.parse_ty_bare_fn(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 lo = self.token.span;
- let lifetime_defs = self.parse_late_bound_lifetime_defs()?;
- if self.token_is_bare_fn_keyword() {
- self.parse_ty_bare_fn(lifetime_defs)?
- } else {
- let path = self.parse_path(PathStyle::Type)?;
- let parse_plus = allow_plus && self.check_plus();
- self.parse_remaining_bounds(lifetime_defs, path, lo, parse_plus)?
- }
- } else if self.eat_keyword(kw::Impl) {
- // Always parse bounds greedily for better error recovery.
- let bounds = self.parse_generic_bounds(None)?;
- impl_dyn_multi = bounds.len() > 1 || self.prev_token_kind == PrevTokenKind::Plus;
- TyKind::ImplTrait(ast::DUMMY_NODE_ID, bounds)
- } else if self.check_keyword(kw::Dyn) &&
- (self.token.span.rust_2018() ||
- self.look_ahead(1, |t| t.can_begin_bound() &&
- !can_continue_type_after_non_fn_ident(t))) {
- self.bump(); // `dyn`
- // Always parse bounds greedily for better error recovery.
- let bounds = self.parse_generic_bounds(None)?;
- impl_dyn_multi = bounds.len() > 1 || self.prev_token_kind == PrevTokenKind::Plus;
- TyKind::TraitObject(bounds, TraitObjectSyntax::Dyn)
- } else if self.check(&token::Question) ||
- self.check_lifetime() && self.look_ahead(1, |t| t.is_like_plus()) {
- // Bound list (trait object type)
- TyKind::TraitObject(self.parse_generic_bounds_common(allow_plus, None)?,
- 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() {
- // Simple path
- let path = self.parse_path(PathStyle::Type)?;
- if self.eat(&token::Not) {
- // Macro invocation in type position
- let (delim, tts) = self.expect_delimited_token_tree()?;
- let node = Mac_ {
- path,
- tts,
- delim,
- prior_type_ascription: self.last_type_ascription,
- };
- TyKind::Mac(respan(lo.to(self.prev_span), node))
- } else {
- // Just a type path or bound list (trait object type) starting with a trait.
- // `Type`
- // `Trait1 + Trait2 + 'a`
- if allow_plus && self.check_plus() {
- self.parse_remaining_bounds(Vec::new(), path, lo, true)?
- } else {
- TyKind::Path(None, path)
- }
- }
- } else if self.check(&token::DotDotDot) {
- if allow_c_variadic {
- self.eat(&token::DotDotDot);
- TyKind::CVarArgs
- } else {
- return Err(self.fatal(
- "only foreign functions are allowed to be C-variadic"
- ));
- }
- } else {
- let msg = format!("expected type, found {}", self.this_token_descr());
- let mut err = self.fatal(&msg);
- err.span_label(self.token.span, "expected type");
- self.maybe_annotate_with_ascription(&mut err, true);
- return Err(err);
- };
-
- let span = lo.to(self.prev_span);
- let ty = P(Ty { node, span, id: ast::DUMMY_NODE_ID });
-
- // Try to recover from use of `+` with incorrect priority.
- self.maybe_report_ambiguous_plus(allow_plus, impl_dyn_multi, &ty);
- self.maybe_recover_from_bad_type_plus(allow_plus, &ty)?;
- self.maybe_recover_from_bad_qpath(ty, allow_qpath_recovery)
- }
-
- fn parse_remaining_bounds(&mut self, generic_params: Vec<GenericParam>, path: ast::Path,
- lo: Span, parse_plus: bool) -> PResult<'a, TyKind> {
- let poly_trait_ref = PolyTraitRef::new(generic_params, path, lo.to(self.prev_span));
- let mut bounds = vec![GenericBound::Trait(poly_trait_ref, TraitBoundModifier::None)];
- if parse_plus {
- self.eat_plus(); // `+`, or `+=` gets split and `+` is discarded
- bounds.append(&mut self.parse_generic_bounds(Some(self.prev_span))?);
- }
- Ok(TyKind::TraitObject(bounds, TraitObjectSyntax::None))
- }
-
- fn parse_borrowed_pointee(&mut self) -> PResult<'a, TyKind> {
- let opt_lifetime = if self.check_lifetime() { Some(self.expect_lifetime()) } else { None };
- let mutbl = self.parse_mutability();
- let ty = self.parse_ty_no_plus()?;
- return Ok(TyKind::Rptr(opt_lifetime, MutTy { ty, mutbl }));
- }
-
- fn parse_ptr(&mut self) -> PResult<'a, MutTy> {
- let mutbl = if self.eat_keyword(kw::Mut) {
- Mutability::Mutable
- } else if self.eat_keyword(kw::Const) {
- Mutability::Immutable
- } else {
- let span = self.prev_span;
- let msg = "expected mut or const in raw pointer type";
- self.struct_span_err(span, msg)
- .span_label(span, msg)
- .help("use `*mut T` or `*const T` as appropriate")
- .emit();
- Mutability::Immutable
- };
- let t = self.parse_ty_no_plus()?;
- Ok(MutTy { ty: t, mutbl })
- }
-
fn is_named_argument(&self) -> bool {
let offset = match self.token.kind {
token::Interpolated(ref nt) => match **nt {
})
}
- fn maybe_parse_fixed_length_of_vec(&mut self) -> PResult<'a, Option<P<ast::Expr>>> {
- if self.eat(&token::Semi) {
- Ok(Some(self.parse_expr()?))
- } else {
- Ok(None)
- }
- }
-
- fn parse_path_segment_ident(&mut self) -> PResult<'a, ast::Ident> {
- match self.token.kind {
- token::Ident(name, _) if name.is_path_segment_keyword() => {
- let span = self.token.span;
- self.bump();
- Ok(Ident::new(name, span))
- }
- _ => self.parse_ident(),
- }
- }
-
fn parse_ident_or_underscore(&mut self) -> PResult<'a, ast::Ident> {
match self.token.kind {
token::Ident(name, false) if name == kw::Underscore => {
}
}
- /// Parses a qualified path.
- /// Assumes that the leading `<` has been parsed already.
- ///
- /// `qualified_path = <type [as trait_ref]>::path`
- ///
- /// # Examples
- /// `<T>::default`
- /// `<T as U>::a`
- /// `<T as U>::F::a<S>` (without disambiguator)
- /// `<T as U>::F::a::<S>` (with disambiguator)
- fn parse_qpath(&mut self, style: PathStyle) -> PResult<'a, (QSelf, ast::Path)> {
- let lo = self.prev_span;
- let ty = self.parse_ty()?;
-
- // `path` will contain the prefix of the path up to the `>`,
- // if any (e.g., `U` in the `<T as U>::*` examples
- // above). `path_span` has the span of that path, or an empty
- // span in the case of something like `<T>::Bar`.
- let (mut path, path_span);
- if self.eat_keyword(kw::As) {
- let path_lo = self.token.span;
- path = self.parse_path(PathStyle::Type)?;
- path_span = path_lo.to(self.prev_span);
- } else {
- path_span = self.token.span.to(self.token.span);
- path = ast::Path { segments: Vec::new(), span: path_span };
- }
-
- // See doc comment for `unmatched_angle_bracket_count`.
- self.expect(&token::Gt)?;
- if self.unmatched_angle_bracket_count > 0 {
- self.unmatched_angle_bracket_count -= 1;
- debug!("parse_qpath: (decrement) count={:?}", self.unmatched_angle_bracket_count);
- }
-
- self.expect(&token::ModSep)?;
-
- let qself = QSelf { ty, path_span, position: path.segments.len() };
- self.parse_path_segments(&mut path.segments, style)?;
-
- Ok((qself, ast::Path { segments: path.segments, span: lo.to(self.prev_span) }))
- }
-
- /// Parses simple paths.
- ///
- /// `path = [::] segment+`
- /// `segment = ident | ident[::]<args> | ident[::](args) [-> type]`
- ///
- /// # Examples
- /// `a::b::C<D>` (without disambiguator)
- /// `a::b::C::<D>` (with disambiguator)
- /// `Fn(Args)` (without disambiguator)
- /// `Fn::(Args)` (with disambiguator)
- pub fn parse_path(&mut self, style: PathStyle) -> PResult<'a, ast::Path> {
- maybe_whole!(self, NtPath, |path| {
- if style == PathStyle::Mod &&
- path.segments.iter().any(|segment| segment.args.is_some()) {
- self.diagnostic().span_err(path.span, "unexpected generic arguments in path");
- }
- path
- });
-
- let lo = self.meta_var_span.unwrap_or(self.token.span);
- let mut segments = Vec::new();
- let mod_sep_ctxt = self.token.span.ctxt();
- if self.eat(&token::ModSep) {
- segments.push(PathSegment::path_root(lo.shrink_to_lo().with_ctxt(mod_sep_ctxt)));
- }
- self.parse_path_segments(&mut segments, style)?;
-
- Ok(ast::Path { segments, span: lo.to(self.prev_span) })
- }
-
- /// Like `parse_path`, but also supports parsing `Word` meta items into paths for
- /// backwards-compatibility. This is used when parsing derive macro paths in `#[derive]`
- /// attributes.
- pub fn parse_path_allowing_meta(&mut self, style: PathStyle) -> PResult<'a, ast::Path> {
- let meta_ident = match self.token.kind {
- token::Interpolated(ref nt) => match **nt {
- token::NtMeta(ref meta) => match meta.node {
- ast::MetaItemKind::Word => Some(meta.path.clone()),
- _ => None,
- },
- _ => None,
- },
- _ => None,
- };
- if let Some(path) = meta_ident {
- self.bump();
- return Ok(path);
- }
- self.parse_path(style)
- }
-
- crate fn parse_path_segments(&mut self,
- segments: &mut Vec<PathSegment>,
- style: PathStyle)
- -> PResult<'a, ()> {
- loop {
- let segment = self.parse_path_segment(style)?;
- if style == PathStyle::Expr {
- // In order to check for trailing angle brackets, we must have finished
- // recursing (`parse_path_segment` can indirectly call this function),
- // that is, the next token must be the highlighted part of the below example:
- //
- // `Foo::<Bar as Baz<T>>::Qux`
- // ^ here
- //
- // As opposed to the below highlight (if we had only finished the first
- // recursion):
- //
- // `Foo::<Bar as Baz<T>>::Qux`
- // ^ here
- //
- // `PathStyle::Expr` is only provided at the root invocation and never in
- // `parse_path_segment` to recurse and therefore can be checked to maintain
- // this invariant.
- self.check_trailing_angle_brackets(&segment, token::ModSep);
- }
- segments.push(segment);
-
- if self.is_import_coupler() || !self.eat(&token::ModSep) {
- return Ok(());
- }
- }
- }
-
- fn parse_path_segment(&mut self, style: PathStyle) -> PResult<'a, PathSegment> {
- let ident = self.parse_path_segment_ident()?;
-
- let is_args_start = |token: &Token| match token.kind {
- token::Lt | token::BinOp(token::Shl) | token::OpenDelim(token::Paren)
- | token::LArrow => true,
- _ => false,
- };
- let check_args_start = |this: &mut Self| {
- this.expected_tokens.extend_from_slice(
- &[TokenType::Token(token::Lt), TokenType::Token(token::OpenDelim(token::Paren))]
- );
- is_args_start(&this.token)
- };
-
- Ok(if style == PathStyle::Type && check_args_start(self) ||
- style != PathStyle::Mod && self.check(&token::ModSep)
- && self.look_ahead(1, |t| is_args_start(t)) {
- // We use `style == PathStyle::Expr` to check if this is in a recursion or not. If
- // it isn't, then we reset the unmatched angle bracket count as we're about to start
- // parsing a new path.
- if style == PathStyle::Expr {
- self.unmatched_angle_bracket_count = 0;
- self.max_angle_bracket_count = 0;
- }
-
- // Generic arguments are found - `<`, `(`, `::<` or `::(`.
- self.eat(&token::ModSep);
- let lo = self.token.span;
- let args = if self.eat_lt() {
- // `<'a, T, A = U>`
- let (args, constraints) =
- self.parse_generic_args_with_leaning_angle_bracket_recovery(style, lo)?;
- self.expect_gt()?;
- let span = lo.to(self.prev_span);
- AngleBracketedArgs { args, constraints, span }.into()
- } else {
- // `(T, U) -> R`
- let (inputs, _) = self.parse_paren_comma_seq(|p| p.parse_ty())?;
- let span = lo.to(self.prev_span);
- let output = if self.eat(&token::RArrow) {
- Some(self.parse_ty_common(false, false, false)?)
- } else {
- None
- };
- ParenthesizedArgs { inputs, output, span }.into()
- };
-
- PathSegment { ident, args, id: ast::DUMMY_NODE_ID }
- } else {
- // Generic arguments are not found.
- PathSegment::from_ident(ident)
- })
- }
-
crate fn check_lifetime(&mut self) -> bool {
self.expected_tokens.push(TokenType::Lifetime);
self.token.is_lifetime()
}).emit();
}
- /// Parses bounds of a type parameter `BOUND + BOUND + ...`, possibly with trailing `+`.
- ///
- /// ```
- /// BOUND = TY_BOUND | LT_BOUND
- /// LT_BOUND = LIFETIME (e.g., `'a`)
- /// TY_BOUND = TY_BOUND_NOPAREN | (TY_BOUND_NOPAREN)
- /// TY_BOUND_NOPAREN = [?] [for<LT_PARAM_DEFS>] SIMPLE_PATH (e.g., `?for<'a: 'b> m::Trait<'a>`)
- /// ```
- fn parse_generic_bounds_common(&mut self,
- allow_plus: bool,
- colon_span: Option<Span>) -> PResult<'a, GenericBounds> {
- let mut bounds = Vec::new();
- let mut negative_bounds = Vec::new();
- let mut last_plus_span = None;
- let mut was_negative = false;
- loop {
- // This needs to be synchronized with `TokenKind::can_begin_bound`.
- let is_bound_start = self.check_path() || self.check_lifetime() ||
- self.check(&token::Not) || // used for error reporting only
- self.check(&token::Question) ||
- self.check_keyword(kw::For) ||
- self.check(&token::OpenDelim(token::Paren));
- if is_bound_start {
- let lo = self.token.span;
- let has_parens = self.eat(&token::OpenDelim(token::Paren));
- let inner_lo = self.token.span;
- let is_negative = self.eat(&token::Not);
- let question = if self.eat(&token::Question) { Some(self.prev_span) } else { None };
- if self.token.is_lifetime() {
- if let Some(question_span) = question {
- self.span_err(question_span,
- "`?` may only modify trait bounds, not lifetime bounds");
- }
- bounds.push(GenericBound::Outlives(self.expect_lifetime()));
- if has_parens {
- let inner_span = inner_lo.to(self.prev_span);
- self.expect(&token::CloseDelim(token::Paren))?;
- let mut err = self.struct_span_err(
- lo.to(self.prev_span),
- "parenthesized lifetime bounds are not supported"
- );
- if let Ok(snippet) = self.span_to_snippet(inner_span) {
- err.span_suggestion_short(
- lo.to(self.prev_span),
- "remove the parentheses",
- snippet.to_owned(),
- Applicability::MachineApplicable
- );
- }
- err.emit();
- }
- } else {
- let lifetime_defs = self.parse_late_bound_lifetime_defs()?;
- let path = self.parse_path(PathStyle::Type)?;
- if has_parens {
- self.expect(&token::CloseDelim(token::Paren))?;
- }
- let poly_span = lo.to(self.prev_span);
- if is_negative {
- was_negative = true;
- if let Some(sp) = last_plus_span.or(colon_span) {
- negative_bounds.push(sp.to(poly_span));
- }
- } else {
- let poly_trait = PolyTraitRef::new(lifetime_defs, path, poly_span);
- let modifier = if question.is_some() {
- TraitBoundModifier::Maybe
- } else {
- TraitBoundModifier::None
- };
- bounds.push(GenericBound::Trait(poly_trait, modifier));
- }
- }
- } else {
- break
- }
-
- if !allow_plus || !self.eat_plus() {
- break
- } else {
- last_plus_span = Some(self.prev_span);
- }
- }
-
- if !negative_bounds.is_empty() || was_negative {
- let plural = negative_bounds.len() > 1;
- let last_span = negative_bounds.last().map(|sp| *sp);
- let mut err = self.struct_span_err(
- negative_bounds,
- "negative trait bounds are not supported",
- );
- if let Some(sp) = last_span {
- err.span_label(sp, "negative trait bounds are not supported");
- }
- if let Some(bound_list) = colon_span {
- let bound_list = bound_list.to(self.prev_span);
- let mut new_bound_list = String::new();
- if !bounds.is_empty() {
- let mut snippets = bounds.iter().map(|bound| bound.span())
- .map(|span| self.span_to_snippet(span));
- while let Some(Ok(snippet)) = snippets.next() {
- new_bound_list.push_str(" + ");
- new_bound_list.push_str(&snippet);
- }
- new_bound_list = new_bound_list.replacen(" +", ":", 1);
- }
- err.span_suggestion_hidden(
- bound_list,
- &format!("remove the trait bound{}", if plural { "s" } else { "" }),
- new_bound_list,
- Applicability::MachineApplicable,
- );
- }
- err.emit();
- }
-
- return Ok(bounds);
- }
-
- crate fn parse_generic_bounds(&mut self,
- colon_span: Option<Span>) -> PResult<'a, GenericBounds> {
- self.parse_generic_bounds_common(true, colon_span)
- }
-
/// Parses bounds of a lifetime parameter `BOUND + BOUND + BOUND`, possibly with trailing `+`.
///
/// ```
})
}
- /// Parses generic args (within a path segment) with recovery for extra leading angle brackets.
- /// For the purposes of understanding the parsing logic of generic arguments, this function
- /// can be thought of being the same as just calling `self.parse_generic_args()` if the source
- /// had the correct amount of leading angle brackets.
- ///
- /// ```ignore (diagnostics)
- /// bar::<<<<T as Foo>::Output>();
- /// ^^ help: remove extra angle brackets
- /// ```
- fn parse_generic_args_with_leaning_angle_bracket_recovery(
- &mut self,
- style: PathStyle,
- lo: Span,
- ) -> PResult<'a, (Vec<GenericArg>, Vec<AssocTyConstraint>)> {
- // We need to detect whether there are extra leading left angle brackets and produce an
- // appropriate error and suggestion. This cannot be implemented by looking ahead at
- // upcoming tokens for a matching `>` character - if there are unmatched `<` tokens
- // then there won't be matching `>` tokens to find.
- //
- // To explain how this detection works, consider the following example:
- //
- // ```ignore (diagnostics)
- // bar::<<<<T as Foo>::Output>();
- // ^^ help: remove extra angle brackets
- // ```
- //
- // Parsing of the left angle brackets starts in this function. We start by parsing the
- // `<` token (incrementing the counter of unmatched angle brackets on `Parser` via
- // `eat_lt`):
- //
- // *Upcoming tokens:* `<<<<T as Foo>::Output>;`
- // *Unmatched count:* 1
- // *`parse_path_segment` calls deep:* 0
- //
- // This has the effect of recursing as this function is called if a `<` character
- // is found within the expected generic arguments:
- //
- // *Upcoming tokens:* `<<<T as Foo>::Output>;`
- // *Unmatched count:* 2
- // *`parse_path_segment` calls deep:* 1
- //
- // Eventually we will have recursed until having consumed all of the `<` tokens and
- // this will be reflected in the count:
- //
- // *Upcoming tokens:* `T as Foo>::Output>;`
- // *Unmatched count:* 4
- // `parse_path_segment` calls deep:* 3
- //
- // The parser will continue until reaching the first `>` - this will decrement the
- // unmatched angle bracket count and return to the parent invocation of this function
- // having succeeded in parsing:
- //
- // *Upcoming tokens:* `::Output>;`
- // *Unmatched count:* 3
- // *`parse_path_segment` calls deep:* 2
- //
- // This will continue until the next `>` character which will also return successfully
- // to the parent invocation of this function and decrement the count:
- //
- // *Upcoming tokens:* `;`
- // *Unmatched count:* 2
- // *`parse_path_segment` calls deep:* 1
- //
- // At this point, this function will expect to find another matching `>` character but
- // won't be able to and will return an error. This will continue all the way up the
- // call stack until the first invocation:
- //
- // *Upcoming tokens:* `;`
- // *Unmatched count:* 2
- // *`parse_path_segment` calls deep:* 0
- //
- // In doing this, we have managed to work out how many unmatched leading left angle
- // brackets there are, but we cannot recover as the unmatched angle brackets have
- // already been consumed. To remedy this, we keep a snapshot of the parser state
- // before we do the above. We can then inspect whether we ended up with a parsing error
- // and unmatched left angle brackets and if so, restore the parser state before we
- // consumed any `<` characters to emit an error and consume the erroneous tokens to
- // recover by attempting to parse again.
- //
- // In practice, the recursion of this function is indirect and there will be other
- // locations that consume some `<` characters - as long as we update the count when
- // this happens, it isn't an issue.
-
- let is_first_invocation = style == PathStyle::Expr;
- // Take a snapshot before attempting to parse - we can restore this later.
- let snapshot = if is_first_invocation {
- Some(self.clone())
- } else {
- None
- };
-
- debug!("parse_generic_args_with_leading_angle_bracket_recovery: (snapshotting)");
- match self.parse_generic_args() {
- Ok(value) => Ok(value),
- Err(ref mut e) if is_first_invocation && self.unmatched_angle_bracket_count > 0 => {
- // Cancel error from being unable to find `>`. We know the error
- // must have been this due to a non-zero unmatched angle bracket
- // count.
- e.cancel();
-
- // Swap `self` with our backup of the parser state before attempting to parse
- // generic arguments.
- let snapshot = mem::replace(self, snapshot.unwrap());
-
- debug!(
- "parse_generic_args_with_leading_angle_bracket_recovery: (snapshot failure) \
- snapshot.count={:?}",
- snapshot.unmatched_angle_bracket_count,
- );
-
- // Eat the unmatched angle brackets.
- for _ in 0..snapshot.unmatched_angle_bracket_count {
- self.eat_lt();
- }
-
- // Make a span over ${unmatched angle bracket count} characters.
- let span = lo.with_hi(
- lo.lo() + BytePos(snapshot.unmatched_angle_bracket_count)
- );
- let plural = snapshot.unmatched_angle_bracket_count > 1;
- self.diagnostic()
- .struct_span_err(
- span,
- &format!(
- "unmatched angle bracket{}",
- if plural { "s" } else { "" }
- ),
- )
- .span_suggestion(
- span,
- &format!(
- "remove extra angle bracket{}",
- if plural { "s" } else { "" }
- ),
- String::new(),
- Applicability::MachineApplicable,
- )
- .emit();
-
- // Try again without unmatched angle bracket characters.
- self.parse_generic_args()
- },
- Err(e) => Err(e),
- }
- }
-
- /// Parses (possibly empty) list of lifetime and type arguments and associated type bindings,
- /// possibly including trailing comma.
- fn parse_generic_args(&mut self) -> PResult<'a, (Vec<GenericArg>, Vec<AssocTyConstraint>)> {
- let mut args = Vec::new();
- let mut constraints = Vec::new();
- let mut misplaced_assoc_ty_constraints: Vec<Span> = Vec::new();
- let mut assoc_ty_constraints: Vec<Span> = Vec::new();
-
- let args_lo = self.token.span;
-
- loop {
- if self.check_lifetime() && self.look_ahead(1, |t| !t.is_like_plus()) {
- // Parse lifetime argument.
- args.push(GenericArg::Lifetime(self.expect_lifetime()));
- misplaced_assoc_ty_constraints.append(&mut assoc_ty_constraints);
- } else if self.check_ident() && self.look_ahead(1,
- |t| t == &token::Eq || t == &token::Colon) {
- // Parse associated type constraint.
- let lo = self.token.span;
- let ident = self.parse_ident()?;
- let kind = if self.eat(&token::Eq) {
- AssocTyConstraintKind::Equality {
- ty: self.parse_ty()?,
- }
- } else if self.eat(&token::Colon) {
- AssocTyConstraintKind::Bound {
- bounds: self.parse_generic_bounds(Some(self.prev_span))?,
- }
- } else {
- unreachable!();
- };
- let span = lo.to(self.prev_span);
- constraints.push(AssocTyConstraint {
- id: ast::DUMMY_NODE_ID,
- ident,
- kind,
- span,
- });
- assoc_ty_constraints.push(span);
- } else if self.check_const_arg() {
- // Parse const argument.
- let expr = if let token::OpenDelim(token::Brace) = self.token.kind {
- self.parse_block_expr(
- None, self.token.span, BlockCheckMode::Default, ThinVec::new()
- )?
- } else if self.token.is_ident() {
- // FIXME(const_generics): to distinguish between idents for types and consts,
- // we should introduce a GenericArg::Ident in the AST and distinguish when
- // lowering to the HIR. For now, idents for const args are not permitted.
- if self.token.is_keyword(kw::True) || self.token.is_keyword(kw::False) {
- self.parse_literal_maybe_minus()?
- } else {
- return Err(
- self.fatal("identifiers may currently not be used for const generics")
- );
- }
- } else {
- self.parse_literal_maybe_minus()?
- };
- let value = AnonConst {
- id: ast::DUMMY_NODE_ID,
- value: expr,
- };
- args.push(GenericArg::Const(value));
- misplaced_assoc_ty_constraints.append(&mut assoc_ty_constraints);
- } else if self.check_type() {
- // Parse type argument.
- args.push(GenericArg::Type(self.parse_ty()?));
- misplaced_assoc_ty_constraints.append(&mut assoc_ty_constraints);
- } else {
- break
- }
-
- if !self.eat(&token::Comma) {
- break
- }
- }
-
- // FIXME: we would like to report this in ast_validation instead, but we currently do not
- // preserve ordering of generic parameters with respect to associated type binding, so we
- // lose that information after parsing.
- if misplaced_assoc_ty_constraints.len() > 0 {
- let mut err = self.struct_span_err(
- args_lo.to(self.prev_span),
- "associated type bindings must be declared after generic parameters",
- );
- for span in misplaced_assoc_ty_constraints {
- err.span_label(
- span,
- "this associated type binding should be moved after the generic parameters",
- );
- }
- err.emit();
- }
-
- Ok((args, constraints))
- }
-
/// Parses an optional where-clause and places it in `generics`.
///
/// ```ignore (only-for-syntax-highlight)
self.is_keyword_ahead(1, &[kw::Const]))
}
- fn parse_late_bound_lifetime_defs(&mut self) -> PResult<'a, Vec<GenericParam>> {
- if self.eat_keyword(kw::For) {
- 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
- // parameters, and the lifetime parameters must not have bounds.
- Ok(params)
- } else {
- Ok(Vec::new())
- }
- }
-
/// Parses `pub`, `pub(crate)` and `pub(in path)` plus shortcuts `crate` for `pub(crate)`,
/// `pub(self)` for `pub(in self)` and `pub(super)` for `pub(in super)`.
/// If the following element can't be a tuple (i.e., it's a function definition), then
--- /dev/null
+use super::{Parser, PResult, TokenType, BlockCheckMode};
+
+use crate::{maybe_whole, ThinVec};
+use crate::ast::{self, QSelf, Path, PathSegment, Ident, ParenthesizedArgs, AngleBracketedArgs};
+use crate::ast::{AnonConst, GenericArg, AssocTyConstraint, AssocTyConstraintKind};
+use crate::parse::token::{self, Token};
+use crate::source_map::{Span, BytePos};
+use crate::symbol::{kw};
+
+use std::mem;
+use log::debug;
+use errors::{Applicability};
+
+/// Specifies how to parse a path.
+#[derive(Copy, Clone, PartialEq)]
+pub enum PathStyle {
+ /// In some contexts, notably in expressions, paths with generic arguments are ambiguous
+ /// with something else. For example, in expressions `segment < ....` can be interpreted
+ /// as a comparison and `segment ( ....` can be interpreted as a function call.
+ /// In all such contexts the non-path interpretation is preferred by default for practical
+ /// reasons, but the path interpretation can be forced by the disambiguator `::`, e.g.
+ /// `x<y>` - comparisons, `x::<y>` - unambiguously a path.
+ Expr,
+ /// In other contexts, notably in types, no ambiguity exists and paths can be written
+ /// without the disambiguator, e.g., `x<y>` - unambiguously a path.
+ /// Paths with disambiguators are still accepted, `x::<Y>` - unambiguously a path too.
+ Type,
+ /// A path with generic arguments disallowed, e.g., `foo::bar::Baz`, used in imports,
+ /// visibilities or attributes.
+ /// Technically, this variant is unnecessary and e.g., `Expr` can be used instead
+ /// (paths in "mod" contexts have to be checked later for absence of generic arguments
+ /// anyway, due to macros), but it is used to avoid weird suggestions about expected
+ /// tokens when something goes wrong.
+ Mod,
+}
+
+impl<'a> Parser<'a> {
+ /// Parses a qualified path.
+ /// Assumes that the leading `<` has been parsed already.
+ ///
+ /// `qualified_path = <type [as trait_ref]>::path`
+ ///
+ /// # Examples
+ /// `<T>::default`
+ /// `<T as U>::a`
+ /// `<T as U>::F::a<S>` (without disambiguator)
+ /// `<T as U>::F::a::<S>` (with disambiguator)
+ pub(super) fn parse_qpath(&mut self, style: PathStyle) -> PResult<'a, (QSelf, Path)> {
+ let lo = self.prev_span;
+ let ty = self.parse_ty()?;
+
+ // `path` will contain the prefix of the path up to the `>`,
+ // if any (e.g., `U` in the `<T as U>::*` examples
+ // above). `path_span` has the span of that path, or an empty
+ // span in the case of something like `<T>::Bar`.
+ let (mut path, path_span);
+ if self.eat_keyword(kw::As) {
+ let path_lo = self.token.span;
+ path = self.parse_path(PathStyle::Type)?;
+ path_span = path_lo.to(self.prev_span);
+ } else {
+ path_span = self.token.span.to(self.token.span);
+ path = ast::Path { segments: Vec::new(), span: path_span };
+ }
+
+ // See doc comment for `unmatched_angle_bracket_count`.
+ self.expect(&token::Gt)?;
+ if self.unmatched_angle_bracket_count > 0 {
+ self.unmatched_angle_bracket_count -= 1;
+ debug!("parse_qpath: (decrement) count={:?}", self.unmatched_angle_bracket_count);
+ }
+
+ self.expect(&token::ModSep)?;
+
+ let qself = QSelf { ty, path_span, position: path.segments.len() };
+ self.parse_path_segments(&mut path.segments, style)?;
+
+ Ok((qself, Path { segments: path.segments, span: lo.to(self.prev_span) }))
+ }
+
+ /// Parses simple paths.
+ ///
+ /// `path = [::] segment+`
+ /// `segment = ident | ident[::]<args> | ident[::](args) [-> type]`
+ ///
+ /// # Examples
+ /// `a::b::C<D>` (without disambiguator)
+ /// `a::b::C::<D>` (with disambiguator)
+ /// `Fn(Args)` (without disambiguator)
+ /// `Fn::(Args)` (with disambiguator)
+ pub fn parse_path(&mut self, style: PathStyle) -> PResult<'a, Path> {
+ maybe_whole!(self, NtPath, |path| {
+ if style == PathStyle::Mod &&
+ path.segments.iter().any(|segment| segment.args.is_some()) {
+ self.diagnostic().span_err(path.span, "unexpected generic arguments in path");
+ }
+ path
+ });
+
+ let lo = self.meta_var_span.unwrap_or(self.token.span);
+ let mut segments = Vec::new();
+ let mod_sep_ctxt = self.token.span.ctxt();
+ if self.eat(&token::ModSep) {
+ segments.push(PathSegment::path_root(lo.shrink_to_lo().with_ctxt(mod_sep_ctxt)));
+ }
+ self.parse_path_segments(&mut segments, style)?;
+
+ Ok(Path { segments, span: lo.to(self.prev_span) })
+ }
+
+ /// Like `parse_path`, but also supports parsing `Word` meta items into paths for
+ /// backwards-compatibility. This is used when parsing derive macro paths in `#[derive]`
+ /// attributes.
+ pub fn parse_path_allowing_meta(&mut self, style: PathStyle) -> PResult<'a, Path> {
+ let meta_ident = match self.token.kind {
+ token::Interpolated(ref nt) => match **nt {
+ token::NtMeta(ref meta) => match meta.node {
+ ast::MetaItemKind::Word => Some(meta.path.clone()),
+ _ => None,
+ },
+ _ => None,
+ },
+ _ => None,
+ };
+ if let Some(path) = meta_ident {
+ self.bump();
+ return Ok(path);
+ }
+ self.parse_path(style)
+ }
+
+ crate fn parse_path_segments(&mut self,
+ segments: &mut Vec<PathSegment>,
+ style: PathStyle)
+ -> PResult<'a, ()> {
+ loop {
+ let segment = self.parse_path_segment(style)?;
+ if style == PathStyle::Expr {
+ // In order to check for trailing angle brackets, we must have finished
+ // recursing (`parse_path_segment` can indirectly call this function),
+ // that is, the next token must be the highlighted part of the below example:
+ //
+ // `Foo::<Bar as Baz<T>>::Qux`
+ // ^ here
+ //
+ // As opposed to the below highlight (if we had only finished the first
+ // recursion):
+ //
+ // `Foo::<Bar as Baz<T>>::Qux`
+ // ^ here
+ //
+ // `PathStyle::Expr` is only provided at the root invocation and never in
+ // `parse_path_segment` to recurse and therefore can be checked to maintain
+ // this invariant.
+ self.check_trailing_angle_brackets(&segment, token::ModSep);
+ }
+ segments.push(segment);
+
+ if self.is_import_coupler() || !self.eat(&token::ModSep) {
+ return Ok(());
+ }
+ }
+ }
+
+ pub(super) fn parse_path_segment(&mut self, style: PathStyle) -> PResult<'a, PathSegment> {
+ let ident = self.parse_path_segment_ident()?;
+
+ let is_args_start = |token: &Token| match token.kind {
+ token::Lt | token::BinOp(token::Shl) | token::OpenDelim(token::Paren)
+ | token::LArrow => true,
+ _ => false,
+ };
+ let check_args_start = |this: &mut Self| {
+ this.expected_tokens.extend_from_slice(
+ &[TokenType::Token(token::Lt), TokenType::Token(token::OpenDelim(token::Paren))]
+ );
+ is_args_start(&this.token)
+ };
+
+ Ok(if style == PathStyle::Type && check_args_start(self) ||
+ style != PathStyle::Mod && self.check(&token::ModSep)
+ && self.look_ahead(1, |t| is_args_start(t)) {
+ // We use `style == PathStyle::Expr` to check if this is in a recursion or not. If
+ // it isn't, then we reset the unmatched angle bracket count as we're about to start
+ // parsing a new path.
+ if style == PathStyle::Expr {
+ self.unmatched_angle_bracket_count = 0;
+ self.max_angle_bracket_count = 0;
+ }
+
+ // Generic arguments are found - `<`, `(`, `::<` or `::(`.
+ self.eat(&token::ModSep);
+ let lo = self.token.span;
+ let args = if self.eat_lt() {
+ // `<'a, T, A = U>`
+ let (args, constraints) =
+ self.parse_generic_args_with_leaning_angle_bracket_recovery(style, lo)?;
+ self.expect_gt()?;
+ let span = lo.to(self.prev_span);
+ AngleBracketedArgs { args, constraints, span }.into()
+ } else {
+ // `(T, U) -> R`
+ let (inputs, _) = self.parse_paren_comma_seq(|p| p.parse_ty())?;
+ let span = lo.to(self.prev_span);
+ let output = if self.eat(&token::RArrow) {
+ Some(self.parse_ty_common(false, false, false)?)
+ } else {
+ None
+ };
+ ParenthesizedArgs { inputs, output, span }.into()
+ };
+
+ PathSegment { ident, args, id: ast::DUMMY_NODE_ID }
+ } else {
+ // Generic arguments are not found.
+ PathSegment::from_ident(ident)
+ })
+ }
+
+ pub(super) fn parse_path_segment_ident(&mut self) -> PResult<'a, Ident> {
+ match self.token.kind {
+ token::Ident(name, _) if name.is_path_segment_keyword() => {
+ let span = self.token.span;
+ self.bump();
+ Ok(Ident::new(name, span))
+ }
+ _ => self.parse_ident(),
+ }
+ }
+
+ /// Parses generic args (within a path segment) with recovery for extra leading angle brackets.
+ /// For the purposes of understanding the parsing logic of generic arguments, this function
+ /// can be thought of being the same as just calling `self.parse_generic_args()` if the source
+ /// had the correct amount of leading angle brackets.
+ ///
+ /// ```ignore (diagnostics)
+ /// bar::<<<<T as Foo>::Output>();
+ /// ^^ help: remove extra angle brackets
+ /// ```
+ fn parse_generic_args_with_leaning_angle_bracket_recovery(
+ &mut self,
+ style: PathStyle,
+ lo: Span,
+ ) -> PResult<'a, (Vec<GenericArg>, Vec<AssocTyConstraint>)> {
+ // We need to detect whether there are extra leading left angle brackets and produce an
+ // appropriate error and suggestion. This cannot be implemented by looking ahead at
+ // upcoming tokens for a matching `>` character - if there are unmatched `<` tokens
+ // then there won't be matching `>` tokens to find.
+ //
+ // To explain how this detection works, consider the following example:
+ //
+ // ```ignore (diagnostics)
+ // bar::<<<<T as Foo>::Output>();
+ // ^^ help: remove extra angle brackets
+ // ```
+ //
+ // Parsing of the left angle brackets starts in this function. We start by parsing the
+ // `<` token (incrementing the counter of unmatched angle brackets on `Parser` via
+ // `eat_lt`):
+ //
+ // *Upcoming tokens:* `<<<<T as Foo>::Output>;`
+ // *Unmatched count:* 1
+ // *`parse_path_segment` calls deep:* 0
+ //
+ // This has the effect of recursing as this function is called if a `<` character
+ // is found within the expected generic arguments:
+ //
+ // *Upcoming tokens:* `<<<T as Foo>::Output>;`
+ // *Unmatched count:* 2
+ // *`parse_path_segment` calls deep:* 1
+ //
+ // Eventually we will have recursed until having consumed all of the `<` tokens and
+ // this will be reflected in the count:
+ //
+ // *Upcoming tokens:* `T as Foo>::Output>;`
+ // *Unmatched count:* 4
+ // `parse_path_segment` calls deep:* 3
+ //
+ // The parser will continue until reaching the first `>` - this will decrement the
+ // unmatched angle bracket count and return to the parent invocation of this function
+ // having succeeded in parsing:
+ //
+ // *Upcoming tokens:* `::Output>;`
+ // *Unmatched count:* 3
+ // *`parse_path_segment` calls deep:* 2
+ //
+ // This will continue until the next `>` character which will also return successfully
+ // to the parent invocation of this function and decrement the count:
+ //
+ // *Upcoming tokens:* `;`
+ // *Unmatched count:* 2
+ // *`parse_path_segment` calls deep:* 1
+ //
+ // At this point, this function will expect to find another matching `>` character but
+ // won't be able to and will return an error. This will continue all the way up the
+ // call stack until the first invocation:
+ //
+ // *Upcoming tokens:* `;`
+ // *Unmatched count:* 2
+ // *`parse_path_segment` calls deep:* 0
+ //
+ // In doing this, we have managed to work out how many unmatched leading left angle
+ // brackets there are, but we cannot recover as the unmatched angle brackets have
+ // already been consumed. To remedy this, we keep a snapshot of the parser state
+ // before we do the above. We can then inspect whether we ended up with a parsing error
+ // and unmatched left angle brackets and if so, restore the parser state before we
+ // consumed any `<` characters to emit an error and consume the erroneous tokens to
+ // recover by attempting to parse again.
+ //
+ // In practice, the recursion of this function is indirect and there will be other
+ // locations that consume some `<` characters - as long as we update the count when
+ // this happens, it isn't an issue.
+
+ let is_first_invocation = style == PathStyle::Expr;
+ // Take a snapshot before attempting to parse - we can restore this later.
+ let snapshot = if is_first_invocation {
+ Some(self.clone())
+ } else {
+ None
+ };
+
+ debug!("parse_generic_args_with_leading_angle_bracket_recovery: (snapshotting)");
+ match self.parse_generic_args() {
+ Ok(value) => Ok(value),
+ Err(ref mut e) if is_first_invocation && self.unmatched_angle_bracket_count > 0 => {
+ // Cancel error from being unable to find `>`. We know the error
+ // must have been this due to a non-zero unmatched angle bracket
+ // count.
+ e.cancel();
+
+ // Swap `self` with our backup of the parser state before attempting to parse
+ // generic arguments.
+ let snapshot = mem::replace(self, snapshot.unwrap());
+
+ debug!(
+ "parse_generic_args_with_leading_angle_bracket_recovery: (snapshot failure) \
+ snapshot.count={:?}",
+ snapshot.unmatched_angle_bracket_count,
+ );
+
+ // Eat the unmatched angle brackets.
+ for _ in 0..snapshot.unmatched_angle_bracket_count {
+ self.eat_lt();
+ }
+
+ // Make a span over ${unmatched angle bracket count} characters.
+ let span = lo.with_hi(
+ lo.lo() + BytePos(snapshot.unmatched_angle_bracket_count)
+ );
+ let plural = snapshot.unmatched_angle_bracket_count > 1;
+ self.diagnostic()
+ .struct_span_err(
+ span,
+ &format!(
+ "unmatched angle bracket{}",
+ if plural { "s" } else { "" }
+ ),
+ )
+ .span_suggestion(
+ span,
+ &format!(
+ "remove extra angle bracket{}",
+ if plural { "s" } else { "" }
+ ),
+ String::new(),
+ Applicability::MachineApplicable,
+ )
+ .emit();
+
+ // Try again without unmatched angle bracket characters.
+ self.parse_generic_args()
+ },
+ Err(e) => Err(e),
+ }
+ }
+
+ /// Parses (possibly empty) list of lifetime and type arguments and associated type bindings,
+ /// possibly including trailing comma.
+ fn parse_generic_args(&mut self) -> PResult<'a, (Vec<GenericArg>, Vec<AssocTyConstraint>)> {
+ let mut args = Vec::new();
+ let mut constraints = Vec::new();
+ let mut misplaced_assoc_ty_constraints: Vec<Span> = Vec::new();
+ let mut assoc_ty_constraints: Vec<Span> = Vec::new();
+
+ let args_lo = self.token.span;
+
+ loop {
+ if self.check_lifetime() && self.look_ahead(1, |t| !t.is_like_plus()) {
+ // Parse lifetime argument.
+ args.push(GenericArg::Lifetime(self.expect_lifetime()));
+ misplaced_assoc_ty_constraints.append(&mut assoc_ty_constraints);
+ } else if self.check_ident() && self.look_ahead(1,
+ |t| t == &token::Eq || t == &token::Colon) {
+ // Parse associated type constraint.
+ let lo = self.token.span;
+ let ident = self.parse_ident()?;
+ let kind = if self.eat(&token::Eq) {
+ AssocTyConstraintKind::Equality {
+ ty: self.parse_ty()?,
+ }
+ } else if self.eat(&token::Colon) {
+ AssocTyConstraintKind::Bound {
+ bounds: self.parse_generic_bounds(Some(self.prev_span))?,
+ }
+ } else {
+ unreachable!();
+ };
+ let span = lo.to(self.prev_span);
+ constraints.push(AssocTyConstraint {
+ id: ast::DUMMY_NODE_ID,
+ ident,
+ kind,
+ span,
+ });
+ assoc_ty_constraints.push(span);
+ } else if self.check_const_arg() {
+ // Parse const argument.
+ let expr = if let token::OpenDelim(token::Brace) = self.token.kind {
+ self.parse_block_expr(
+ None, self.token.span, BlockCheckMode::Default, ThinVec::new()
+ )?
+ } else if self.token.is_ident() {
+ // FIXME(const_generics): to distinguish between idents for types and consts,
+ // we should introduce a GenericArg::Ident in the AST and distinguish when
+ // lowering to the HIR. For now, idents for const args are not permitted.
+ if self.token.is_keyword(kw::True) || self.token.is_keyword(kw::False) {
+ self.parse_literal_maybe_minus()?
+ } else {
+ return Err(
+ self.fatal("identifiers may currently not be used for const generics")
+ );
+ }
+ } else {
+ self.parse_literal_maybe_minus()?
+ };
+ let value = AnonConst {
+ id: ast::DUMMY_NODE_ID,
+ value: expr,
+ };
+ args.push(GenericArg::Const(value));
+ misplaced_assoc_ty_constraints.append(&mut assoc_ty_constraints);
+ } else if self.check_type() {
+ // Parse type argument.
+ args.push(GenericArg::Type(self.parse_ty()?));
+ misplaced_assoc_ty_constraints.append(&mut assoc_ty_constraints);
+ } else {
+ break
+ }
+
+ if !self.eat(&token::Comma) {
+ break
+ }
+ }
+
+ // FIXME: we would like to report this in ast_validation instead, but we currently do not
+ // preserve ordering of generic parameters with respect to associated type binding, so we
+ // lose that information after parsing.
+ if misplaced_assoc_ty_constraints.len() > 0 {
+ let mut err = self.struct_span_err(
+ args_lo.to(self.prev_span),
+ "associated type bindings must be declared after generic parameters",
+ );
+ for span in misplaced_assoc_ty_constraints {
+ err.span_label(
+ span,
+ "this associated type binding should be moved after the generic parameters",
+ );
+ }
+ err.emit();
+ }
+
+ Ok((args, constraints))
+ }
+}
--- /dev/null
+use super::{Parser, PResult, PathStyle, PrevTokenKind};
+
+use crate::{maybe_whole, maybe_recover_from_interpolated_ty_qpath};
+use crate::ptr::P;
+use crate::ast::{self, Ty, TyKind, MutTy, BareFnTy, FunctionRetTy, GenericParam};
+use crate::ast::{TraitBoundModifier, TraitObjectSyntax, GenericBound, GenericBounds, PolyTraitRef};
+use crate::ast::{Mutability, AnonConst, FnDecl, Mac_};
+use crate::parse::token::{self, Token};
+use crate::source_map::{respan, Span};
+use crate::symbol::{kw};
+
+use rustc_target::spec::abi::Abi;
+
+use errors::{Applicability};
+
+/// Returns `true` if `IDENT t` can start a type -- `IDENT::a::b`, `IDENT<u8, u8>`,
+/// `IDENT<<u8 as Trait>::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::ModSep || t == &token::Lt ||
+ t == &token::BinOp(token::Shl)
+}
+
+impl<'a> Parser<'a> {
+ /// Parses a type.
+ pub fn parse_ty(&mut self) -> PResult<'a, P<Ty>> {
+ self.parse_ty_common(true, true, false)
+ }
+
+ /// 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, P<Ty>> {
+ self.parse_ty_common(false, true, false)
+ }
+
+ /// Parses an optional return type `[ -> TY ]` in a function declaration.
+ pub(super) fn parse_ret_ty(&mut self, allow_plus: bool) -> PResult<'a, FunctionRetTy> {
+ if self.eat(&token::RArrow) {
+ Ok(FunctionRetTy::Ty(self.parse_ty_common(allow_plus, true, false)?))
+ } else {
+ Ok(FunctionRetTy::Default(self.token.span.shrink_to_lo()))
+ }
+ }
+
+ pub(super) fn parse_ty_common(&mut self, allow_plus: bool, allow_qpath_recovery: bool,
+ allow_c_variadic: bool) -> PResult<'a, P<Ty>> {
+ maybe_recover_from_interpolated_ty_qpath!(self, allow_qpath_recovery);
+ maybe_whole!(self, NtTy, |x| x);
+
+ let lo = self.token.span;
+ let mut impl_dyn_multi = false;
+ let node = if self.eat(&token::OpenDelim(token::Paren)) {
+ // `(TYPE)` is a parenthesized type.
+ // `(TYPE,)` is a tuple with a single field of type TYPE.
+ let mut ts = vec![];
+ let mut last_comma = false;
+ while self.token != token::CloseDelim(token::Paren) {
+ ts.push(self.parse_ty()?);
+ if self.eat(&token::Comma) {
+ last_comma = true;
+ } else {
+ last_comma = false;
+ break;
+ }
+ }
+ let trailing_plus = self.prev_token_kind == PrevTokenKind::Plus;
+ self.expect(&token::CloseDelim(token::Paren))?;
+
+ if ts.len() == 1 && !last_comma {
+ let ty = ts.into_iter().nth(0).unwrap().into_inner();
+ let maybe_bounds = allow_plus && self.token.is_like_plus();
+ match ty.node {
+ // `(TY_BOUND_NOPAREN) + BOUND + ...`.
+ TyKind::Path(None, ref path) if maybe_bounds => {
+ self.parse_remaining_bounds(Vec::new(), path.clone(), lo, true)?
+ }
+ TyKind::TraitObject(ref bounds, TraitObjectSyntax::None)
+ if maybe_bounds && bounds.len() == 1 && !trailing_plus => {
+ let path = match bounds[0] {
+ GenericBound::Trait(ref pt, ..) => pt.trait_ref.path.clone(),
+ GenericBound::Outlives(..) => self.bug("unexpected lifetime bound"),
+ };
+ self.parse_remaining_bounds(Vec::new(), path, lo, true)?
+ }
+ // `(TYPE)`
+ _ => TyKind::Paren(P(ty))
+ }
+ } else {
+ TyKind::Tup(ts)
+ }
+ } else if self.eat(&token::Not) {
+ // Never type `!`
+ TyKind::Never
+ } else if self.eat(&token::BinOp(token::Star)) {
+ // Raw pointer
+ TyKind::Ptr(self.parse_ptr()?)
+ } else if self.eat(&token::OpenDelim(token::Bracket)) {
+ // Array or slice
+ let t = self.parse_ty()?;
+ // Parse optional `; EXPR` in `[TYPE; EXPR]`
+ let t = match self.maybe_parse_fixed_length_of_vec()? {
+ None => TyKind::Slice(t),
+ Some(length) => TyKind::Array(t, AnonConst {
+ id: ast::DUMMY_NODE_ID,
+ value: length,
+ }),
+ };
+ self.expect(&token::CloseDelim(token::Bracket))?;
+ t
+ } else if self.check(&token::BinOp(token::And)) || self.check(&token::AndAnd) {
+ // Reference
+ self.expect_and()?;
+ self.parse_borrowed_pointee()?
+ } else if self.eat_keyword_noexpect(kw::Typeof) {
+ // `typeof(EXPR)`
+ // In order to not be ambiguous, the type must be surrounded by parens.
+ self.expect(&token::OpenDelim(token::Paren))?;
+ let e = AnonConst {
+ id: ast::DUMMY_NODE_ID,
+ value: self.parse_expr()?,
+ };
+ self.expect(&token::CloseDelim(token::Paren))?;
+ TyKind::Typeof(e)
+ } else if self.eat_keyword(kw::Underscore) {
+ // A type to be inferred `_`
+ TyKind::Infer
+ } else if self.token_is_bare_fn_keyword() {
+ // Function pointer type
+ self.parse_ty_bare_fn(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 lo = self.token.span;
+ let lifetime_defs = self.parse_late_bound_lifetime_defs()?;
+ if self.token_is_bare_fn_keyword() {
+ self.parse_ty_bare_fn(lifetime_defs)?
+ } else {
+ let path = self.parse_path(PathStyle::Type)?;
+ let parse_plus = allow_plus && self.check_plus();
+ self.parse_remaining_bounds(lifetime_defs, path, lo, parse_plus)?
+ }
+ } else if self.eat_keyword(kw::Impl) {
+ // Always parse bounds greedily for better error recovery.
+ let bounds = self.parse_generic_bounds(None)?;
+ impl_dyn_multi = bounds.len() > 1 || self.prev_token_kind == PrevTokenKind::Plus;
+ TyKind::ImplTrait(ast::DUMMY_NODE_ID, bounds)
+ } else if self.check_keyword(kw::Dyn) &&
+ (self.token.span.rust_2018() ||
+ self.look_ahead(1, |t| t.can_begin_bound() &&
+ !can_continue_type_after_non_fn_ident(t))) {
+ self.bump(); // `dyn`
+ // Always parse bounds greedily for better error recovery.
+ let bounds = self.parse_generic_bounds(None)?;
+ impl_dyn_multi = bounds.len() > 1 || self.prev_token_kind == PrevTokenKind::Plus;
+ TyKind::TraitObject(bounds, TraitObjectSyntax::Dyn)
+ } else if self.check(&token::Question) ||
+ self.check_lifetime() && self.look_ahead(1, |t| t.is_like_plus()) {
+ // Bound list (trait object type)
+ TyKind::TraitObject(self.parse_generic_bounds_common(allow_plus, None)?,
+ 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() {
+ // Simple path
+ let path = self.parse_path(PathStyle::Type)?;
+ if self.eat(&token::Not) {
+ // Macro invocation in type position
+ let (delim, tts) = self.expect_delimited_token_tree()?;
+ let node = Mac_ {
+ path,
+ tts,
+ delim,
+ prior_type_ascription: self.last_type_ascription,
+ };
+ TyKind::Mac(respan(lo.to(self.prev_span), node))
+ } else {
+ // Just a type path or bound list (trait object type) starting with a trait.
+ // `Type`
+ // `Trait1 + Trait2 + 'a`
+ if allow_plus && self.check_plus() {
+ self.parse_remaining_bounds(Vec::new(), path, lo, true)?
+ } else {
+ TyKind::Path(None, path)
+ }
+ }
+ } else if self.check(&token::DotDotDot) {
+ if allow_c_variadic {
+ self.eat(&token::DotDotDot);
+ TyKind::CVarArgs
+ } else {
+ return Err(self.fatal(
+ "only foreign functions are allowed to be C-variadic"
+ ));
+ }
+ } else {
+ let msg = format!("expected type, found {}", self.this_token_descr());
+ let mut err = self.fatal(&msg);
+ err.span_label(self.token.span, "expected type");
+ self.maybe_annotate_with_ascription(&mut err, true);
+ return Err(err);
+ };
+
+ let span = lo.to(self.prev_span);
+ let ty = P(Ty { node, span, id: ast::DUMMY_NODE_ID });
+
+ // Try to recover from use of `+` with incorrect priority.
+ self.maybe_report_ambiguous_plus(allow_plus, impl_dyn_multi, &ty);
+ self.maybe_recover_from_bad_type_plus(allow_plus, &ty)?;
+ self.maybe_recover_from_bad_qpath(ty, allow_qpath_recovery)
+ }
+
+ fn parse_remaining_bounds(&mut self, generic_params: Vec<GenericParam>, path: ast::Path,
+ lo: Span, parse_plus: bool) -> PResult<'a, TyKind> {
+ let poly_trait_ref = PolyTraitRef::new(generic_params, path, lo.to(self.prev_span));
+ let mut bounds = vec![GenericBound::Trait(poly_trait_ref, TraitBoundModifier::None)];
+ if parse_plus {
+ self.eat_plus(); // `+`, or `+=` gets split and `+` is discarded
+ bounds.append(&mut self.parse_generic_bounds(Some(self.prev_span))?);
+ }
+ Ok(TyKind::TraitObject(bounds, TraitObjectSyntax::None))
+ }
+
+ fn parse_ptr(&mut self) -> PResult<'a, MutTy> {
+ let mutbl = if self.eat_keyword(kw::Mut) {
+ Mutability::Mutable
+ } else if self.eat_keyword(kw::Const) {
+ Mutability::Immutable
+ } else {
+ let span = self.prev_span;
+ let msg = "expected mut or const in raw pointer type";
+ self.struct_span_err(span, msg)
+ .span_label(span, msg)
+ .help("use `*mut T` or `*const T` as appropriate")
+ .emit();
+ Mutability::Immutable
+ };
+ let t = self.parse_ty_no_plus()?;
+ Ok(MutTy { ty: t, mutbl })
+ }
+
+ fn maybe_parse_fixed_length_of_vec(&mut self) -> PResult<'a, Option<P<ast::Expr>>> {
+ if self.eat(&token::Semi) {
+ Ok(Some(self.parse_expr()?))
+ } else {
+ Ok(None)
+ }
+ }
+
+ fn parse_borrowed_pointee(&mut self) -> PResult<'a, TyKind> {
+ let opt_lifetime = if self.check_lifetime() { Some(self.expect_lifetime()) } else { None };
+ let mutbl = self.parse_mutability();
+ let ty = self.parse_ty_no_plus()?;
+ return Ok(TyKind::Rptr(opt_lifetime, MutTy { ty, mutbl }));
+ }
+
+ /// 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 `TyKind::BareFn` type.
+ fn parse_ty_bare_fn(&mut self, generic_params: Vec<GenericParam>) -> PResult<'a, TyKind> {
+ /*
+
+ [unsafe] [extern "ABI"] fn (S) -> T
+ ^~~~^ ^~~~^ ^~^ ^
+ | | | |
+ | | | Return type
+ | | Argument types
+ | |
+ | ABI
+ Function Style
+ */
+
+ let unsafety = self.parse_unsafety();
+ let abi = if self.eat_keyword(kw::Extern) {
+ self.parse_opt_abi()?.unwrap_or(Abi::C)
+ } else {
+ Abi::Rust
+ };
+
+ self.expect_keyword(kw::Fn)?;
+ let (inputs, c_variadic) = self.parse_fn_args(false, true)?;
+ let ret_ty = self.parse_ret_ty(false)?;
+ let decl = P(FnDecl {
+ inputs,
+ output: ret_ty,
+ c_variadic,
+ });
+ Ok(TyKind::BareFn(P(BareFnTy {
+ abi,
+ unsafety,
+ generic_params,
+ decl,
+ })))
+ }
+
+ crate fn parse_generic_bounds(&mut self,
+ colon_span: Option<Span>) -> PResult<'a, GenericBounds> {
+ self.parse_generic_bounds_common(true, colon_span)
+ }
+
+ /// Parses bounds of a type parameter `BOUND + BOUND + ...`, possibly with trailing `+`.
+ ///
+ /// ```
+ /// BOUND = TY_BOUND | LT_BOUND
+ /// LT_BOUND = LIFETIME (e.g., `'a`)
+ /// TY_BOUND = TY_BOUND_NOPAREN | (TY_BOUND_NOPAREN)
+ /// TY_BOUND_NOPAREN = [?] [for<LT_PARAM_DEFS>] SIMPLE_PATH (e.g., `?for<'a: 'b> m::Trait<'a>`)
+ /// ```
+ fn parse_generic_bounds_common(&mut self,
+ allow_plus: bool,
+ colon_span: Option<Span>) -> PResult<'a, GenericBounds> {
+ let mut bounds = Vec::new();
+ let mut negative_bounds = Vec::new();
+ let mut last_plus_span = None;
+ let mut was_negative = false;
+ loop {
+ // This needs to be synchronized with `TokenKind::can_begin_bound`.
+ let is_bound_start = self.check_path() || self.check_lifetime() ||
+ self.check(&token::Not) || // used for error reporting only
+ self.check(&token::Question) ||
+ self.check_keyword(kw::For) ||
+ self.check(&token::OpenDelim(token::Paren));
+ if is_bound_start {
+ let lo = self.token.span;
+ let has_parens = self.eat(&token::OpenDelim(token::Paren));
+ let inner_lo = self.token.span;
+ let is_negative = self.eat(&token::Not);
+ let question = if self.eat(&token::Question) { Some(self.prev_span) } else { None };
+ if self.token.is_lifetime() {
+ if let Some(question_span) = question {
+ self.span_err(question_span,
+ "`?` may only modify trait bounds, not lifetime bounds");
+ }
+ bounds.push(GenericBound::Outlives(self.expect_lifetime()));
+ if has_parens {
+ let inner_span = inner_lo.to(self.prev_span);
+ self.expect(&token::CloseDelim(token::Paren))?;
+ let mut err = self.struct_span_err(
+ lo.to(self.prev_span),
+ "parenthesized lifetime bounds are not supported"
+ );
+ if let Ok(snippet) = self.span_to_snippet(inner_span) {
+ err.span_suggestion_short(
+ lo.to(self.prev_span),
+ "remove the parentheses",
+ snippet.to_owned(),
+ Applicability::MachineApplicable
+ );
+ }
+ err.emit();
+ }
+ } else {
+ let lifetime_defs = self.parse_late_bound_lifetime_defs()?;
+ let path = self.parse_path(PathStyle::Type)?;
+ if has_parens {
+ self.expect(&token::CloseDelim(token::Paren))?;
+ }
+ let poly_span = lo.to(self.prev_span);
+ if is_negative {
+ was_negative = true;
+ if let Some(sp) = last_plus_span.or(colon_span) {
+ negative_bounds.push(sp.to(poly_span));
+ }
+ } else {
+ let poly_trait = PolyTraitRef::new(lifetime_defs, path, poly_span);
+ let modifier = if question.is_some() {
+ TraitBoundModifier::Maybe
+ } else {
+ TraitBoundModifier::None
+ };
+ bounds.push(GenericBound::Trait(poly_trait, modifier));
+ }
+ }
+ } else {
+ break
+ }
+
+ if !allow_plus || !self.eat_plus() {
+ break
+ } else {
+ last_plus_span = Some(self.prev_span);
+ }
+ }
+
+ if !negative_bounds.is_empty() || was_negative {
+ let plural = negative_bounds.len() > 1;
+ let last_span = negative_bounds.last().map(|sp| *sp);
+ let mut err = self.struct_span_err(
+ negative_bounds,
+ "negative trait bounds are not supported",
+ );
+ if let Some(sp) = last_span {
+ err.span_label(sp, "negative trait bounds are not supported");
+ }
+ if let Some(bound_list) = colon_span {
+ let bound_list = bound_list.to(self.prev_span);
+ let mut new_bound_list = String::new();
+ if !bounds.is_empty() {
+ let mut snippets = bounds.iter().map(|bound| bound.span())
+ .map(|span| self.span_to_snippet(span));
+ while let Some(Ok(snippet)) = snippets.next() {
+ new_bound_list.push_str(" + ");
+ new_bound_list.push_str(&snippet);
+ }
+ new_bound_list = new_bound_list.replacen(" +", ":", 1);
+ }
+ err.span_suggestion_hidden(
+ bound_list,
+ &format!("remove the trait bound{}", if plural { "s" } else { "" }),
+ new_bound_list,
+ Applicability::MachineApplicable,
+ );
+ }
+ err.emit();
+ }
+
+ return Ok(bounds);
+ }
+
+ // TODO remove super below.
+
+ pub(super) fn parse_late_bound_lifetime_defs(&mut self) -> PResult<'a, Vec<GenericParam>> {
+ if self.eat_keyword(kw::For) {
+ 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
+ // parameters, and the lifetime parameters must not have bounds.
+ Ok(params)
+ } else {
+ Ok(Vec::new())
+ }
+ }
+}