rustc_parse/parser/
generics.rs

1use rustc_ast::{
2    self as ast, AttrVec, DUMMY_NODE_ID, GenericBounds, GenericParam, GenericParamKind, TyKind,
3    WhereClause, token,
4};
5use rustc_errors::{Applicability, PResult};
6use rustc_span::{Ident, Span, kw, sym};
7use thin_vec::ThinVec;
8
9use super::{ForceCollect, Parser, Trailing, UsePreAttrPos};
10use crate::errors::{
11    self, MultipleWhereClauses, UnexpectedDefaultValueForLifetimeInGenericParameters,
12    UnexpectedSelfInGenericParameters, WhereClauseBeforeTupleStructBody,
13    WhereClauseBeforeTupleStructBodySugg,
14};
15use crate::exp;
16
17enum PredicateKindOrStructBody {
18    PredicateKind(ast::WherePredicateKind),
19    StructBody(ThinVec<ast::FieldDef>),
20}
21
22impl<'a> Parser<'a> {
23    /// Parses bounds of a lifetime parameter `BOUND + BOUND + BOUND`, possibly with trailing `+`.
24    ///
25    /// ```text
26    /// BOUND = LT_BOUND (e.g., `'a`)
27    /// ```
28    fn parse_lt_param_bounds(&mut self) -> GenericBounds {
29        let mut lifetimes = Vec::new();
30        while self.check_lifetime() {
31            lifetimes.push(ast::GenericBound::Outlives(self.expect_lifetime()));
32
33            if !self.eat_plus() {
34                break;
35            }
36        }
37        lifetimes
38    }
39
40    /// Matches `typaram = IDENT (`?` unbound)? optbounds ( EQ ty )?`.
41    fn parse_ty_param(&mut self, preceding_attrs: AttrVec) -> PResult<'a, GenericParam> {
42        let ident = self.parse_ident()?;
43
44        // We might have a typo'd `Const` that was parsed as a type parameter.
45        if self.may_recover()
46            && ident.name.as_str().to_ascii_lowercase() == kw::Const.as_str()
47            && self.check_ident()
48        // `Const` followed by IDENT
49        {
50            return self.recover_const_param_with_mistyped_const(preceding_attrs, ident);
51        }
52
53        // Parse optional colon and param bounds.
54        let mut colon_span = None;
55        let bounds = if self.eat(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::Colon,
    token_type: crate::parser::token_type::TokenType::Colon,
}exp!(Colon)) {
56            colon_span = Some(self.prev_token.span);
57            // recover from `impl Trait` in type param bound
58            if self.token.is_keyword(kw::Impl) {
59                let impl_span = self.token.span;
60                let snapshot = self.create_snapshot_for_diagnostic();
61                match self.parse_ty() {
62                    Ok(p) => {
63                        if let TyKind::ImplTrait(_, bounds) = &p.kind {
64                            let span = impl_span.to(self.token.span.shrink_to_lo());
65                            let mut err = self.dcx().struct_span_err(
66                                span,
67                                "expected trait bound, found `impl Trait` type",
68                            );
69                            err.span_label(span, "not a trait");
70                            if let [bound, ..] = &bounds[..] {
71                                err.span_suggestion_verbose(
72                                    impl_span.until(bound.span()),
73                                    "use the trait bounds directly",
74                                    String::new(),
75                                    Applicability::MachineApplicable,
76                                );
77                            }
78                            return Err(err);
79                        }
80                    }
81                    Err(err) => {
82                        err.cancel();
83                    }
84                }
85                self.restore_snapshot(snapshot);
86            }
87            self.parse_generic_bounds()?
88        } else {
89            Vec::new()
90        };
91
92        let default = if self.eat(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::Eq,
    token_type: crate::parser::token_type::TokenType::Eq,
}exp!(Eq)) { Some(self.parse_ty()?) } else { None };
93        Ok(GenericParam {
94            ident,
95            id: ast::DUMMY_NODE_ID,
96            attrs: preceding_attrs,
97            bounds,
98            kind: GenericParamKind::Type { default },
99            is_placeholder: false,
100            colon_span,
101        })
102    }
103
104    pub(crate) fn parse_const_param(
105        &mut self,
106        preceding_attrs: AttrVec,
107    ) -> PResult<'a, GenericParam> {
108        let const_span = self.token.span;
109
110        self.expect_keyword(crate::parser::token_type::ExpKeywordPair {
    kw: rustc_span::symbol::kw::Const,
    token_type: crate::parser::token_type::TokenType::KwConst,
}exp!(Const))?;
111        let ident = self.parse_ident()?;
112        if let Err(mut err) = self.expect(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::Colon,
    token_type: crate::parser::token_type::TokenType::Colon,
}exp!(Colon)) {
113            return if self.token.kind == token::Comma || self.token.kind == token::Gt {
114                // Recover parse from `<const N>` where the type is missing.
115                let span = const_span.to(ident.span);
116                err.span_suggestion_verbose(
117                    ident.span.shrink_to_hi(),
118                    "you likely meant to write the type of the const parameter here",
119                    ": /* Type */".to_string(),
120                    Applicability::HasPlaceholders,
121                );
122                let kind = TyKind::Err(err.emit());
123                let ty = self.mk_ty(span, kind);
124                Ok(GenericParam {
125                    ident,
126                    id: ast::DUMMY_NODE_ID,
127                    attrs: preceding_attrs,
128                    bounds: Vec::new(),
129                    kind: GenericParamKind::Const { ty, span, default: None },
130                    is_placeholder: false,
131                    colon_span: None,
132                })
133            } else {
134                Err(err)
135            };
136        }
137        let ty = self.parse_ty()?;
138
139        // Parse optional const generics default value.
140        let default = if self.eat(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::Eq,
    token_type: crate::parser::token_type::TokenType::Eq,
}exp!(Eq)) { Some(self.parse_const_arg()?) } else { None };
141        let span = if let Some(ref default) = default {
142            const_span.to(default.value.span)
143        } else {
144            const_span.to(ty.span)
145        };
146
147        Ok(GenericParam {
148            ident,
149            id: ast::DUMMY_NODE_ID,
150            attrs: preceding_attrs,
151            bounds: Vec::new(),
152            kind: GenericParamKind::Const { ty, span, default },
153            is_placeholder: false,
154            colon_span: None,
155        })
156    }
157
158    pub(crate) fn recover_const_param_with_mistyped_const(
159        &mut self,
160        preceding_attrs: AttrVec,
161        mistyped_const_ident: Ident,
162    ) -> PResult<'a, GenericParam> {
163        let ident = self.parse_ident()?;
164        self.expect(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::Colon,
    token_type: crate::parser::token_type::TokenType::Colon,
}exp!(Colon))?;
165        let ty = self.parse_ty()?;
166
167        // Parse optional const generics default value.
168        let default = if self.eat(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::Eq,
    token_type: crate::parser::token_type::TokenType::Eq,
}exp!(Eq)) { Some(self.parse_const_arg()?) } else { None };
169        let span = if let Some(ref default) = default {
170            mistyped_const_ident.span.to(default.value.span)
171        } else {
172            mistyped_const_ident.span.to(ty.span)
173        };
174
175        self.dcx()
176            .struct_span_err(
177                mistyped_const_ident.span,
178                ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("`const` keyword was mistyped as `{0}`",
                mistyped_const_ident.as_str()))
    })format!("`const` keyword was mistyped as `{}`", mistyped_const_ident.as_str()),
179            )
180            .with_span_suggestion_verbose(
181                mistyped_const_ident.span,
182                "use the `const` keyword",
183                kw::Const,
184                Applicability::MachineApplicable,
185            )
186            .emit();
187
188        Ok(GenericParam {
189            ident,
190            id: ast::DUMMY_NODE_ID,
191            attrs: preceding_attrs,
192            bounds: Vec::new(),
193            kind: GenericParamKind::Const { ty, span, default },
194            is_placeholder: false,
195            colon_span: None,
196        })
197    }
198
199    /// Parse a (possibly empty) list of generic (lifetime, type, const) parameters.
200    ///
201    /// ```ebnf
202    /// GenericParams = (GenericParam ("," GenericParam)* ","?)?
203    /// ```
204    pub(super) fn parse_generic_params(&mut self) -> PResult<'a, ThinVec<ast::GenericParam>> {
205        let mut params = ThinVec::new();
206        let mut done = false;
207        while !done {
208            let attrs = self.parse_outer_attributes()?;
209            let param = self.collect_tokens(None, attrs, ForceCollect::No, |this, attrs| {
210                if this.eat_keyword_noexpect(kw::SelfUpper) {
211                    // `Self` as a generic param is invalid. Here we emit the diagnostic and continue parsing
212                    // as if `Self` never existed.
213                    this.dcx()
214                        .emit_err(UnexpectedSelfInGenericParameters { span: this.prev_token.span });
215
216                    // Eat a trailing comma, if it exists.
217                    let _ = this.eat(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::Comma,
    token_type: crate::parser::token_type::TokenType::Comma,
}exp!(Comma));
218                }
219
220                let param = if this.check_lifetime() {
221                    let lifetime = this.expect_lifetime();
222                    // Parse lifetime parameter.
223                    let (colon_span, bounds) = if this.eat(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::Colon,
    token_type: crate::parser::token_type::TokenType::Colon,
}exp!(Colon)) {
224                        (Some(this.prev_token.span), this.parse_lt_param_bounds())
225                    } else {
226                        (None, Vec::new())
227                    };
228
229                    if this.check_noexpect(&token::Eq) && this.look_ahead(1, |t| t.is_lifetime()) {
230                        let lo = this.token.span;
231                        // Parse `= 'lifetime`.
232                        this.bump(); // `=`
233                        this.bump(); // `'lifetime`
234                        let span = lo.to(this.prev_token.span);
235                        this.dcx().emit_err(UnexpectedDefaultValueForLifetimeInGenericParameters {
236                            span,
237                        });
238                    }
239
240                    Some(ast::GenericParam {
241                        ident: lifetime.ident,
242                        id: lifetime.id,
243                        attrs,
244                        bounds,
245                        kind: ast::GenericParamKind::Lifetime,
246                        is_placeholder: false,
247                        colon_span,
248                    })
249                } else if this.check_keyword(crate::parser::token_type::ExpKeywordPair {
    kw: rustc_span::symbol::kw::Const,
    token_type: crate::parser::token_type::TokenType::KwConst,
}exp!(Const)) {
250                    // Parse const parameter.
251                    Some(this.parse_const_param(attrs)?)
252                } else if this.check_ident() {
253                    // Parse type parameter.
254                    Some(this.parse_ty_param(attrs)?)
255                } else if this.token.can_begin_type() {
256                    // Trying to write an associated type bound? (#26271)
257                    let snapshot = this.create_snapshot_for_diagnostic();
258                    let lo = this.token.span;
259                    match this.parse_ty_where_predicate_kind() {
260                        Ok(_) => {
261                            this.dcx().emit_err(errors::BadAssocTypeBounds {
262                                span: lo.to(this.prev_token.span),
263                            });
264                            // FIXME - try to continue parsing other generics?
265                        }
266                        Err(err) => {
267                            err.cancel();
268                            // FIXME - maybe we should overwrite 'self' outside of `collect_tokens`?
269                            this.restore_snapshot(snapshot);
270                        }
271                    }
272                    return Ok((None, Trailing::No, UsePreAttrPos::No));
273                } else {
274                    // Check for trailing attributes and stop parsing.
275                    if !attrs.is_empty() {
276                        if !params.is_empty() {
277                            this.dcx().emit_err(errors::AttrAfterGeneric { span: attrs[0].span });
278                        } else {
279                            this.dcx()
280                                .emit_err(errors::AttrWithoutGenerics { span: attrs[0].span });
281                        }
282                    }
283                    return Ok((None, Trailing::No, UsePreAttrPos::No));
284                };
285
286                if !this.eat(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::Comma,
    token_type: crate::parser::token_type::TokenType::Comma,
}exp!(Comma)) {
287                    done = true;
288                }
289                // We just ate the comma, so no need to capture the trailing token.
290                Ok((param, Trailing::No, UsePreAttrPos::No))
291            })?;
292
293            if let Some(param) = param {
294                params.push(param);
295            } else {
296                break;
297            }
298        }
299        Ok(params)
300    }
301
302    /// Parses a set of optional generic type parameter declarations. Where
303    /// clauses are not parsed here, and must be added later via
304    /// `parse_where_clause()`.
305    ///
306    /// matches generics = ( ) | ( < > ) | ( < typaramseq ( , )? > ) | ( < lifetimes ( , )? > )
307    ///                  | ( < lifetimes , typaramseq ( , )? > )
308    /// where   typaramseq = ( typaram ) | ( typaram , typaramseq )
309    pub(super) fn parse_generics(&mut self) -> PResult<'a, ast::Generics> {
310        // invalid path separator `::` in function definition
311        // for example `fn invalid_path_separator::<T>() {}`
312        if self.eat_noexpect(&token::PathSep) {
313            self.dcx()
314                .emit_err(errors::InvalidPathSepInFnDefinition { span: self.prev_token.span });
315        }
316
317        let span_lo = self.token.span;
318        let (params, span) = if self.eat_lt() {
319            let params = self.parse_generic_params()?;
320            self.expect_gt_or_maybe_suggest_closing_generics(&params)?;
321            (params, span_lo.to(self.prev_token.span))
322        } else {
323            (ThinVec::new(), self.prev_token.span.shrink_to_hi())
324        };
325        Ok(ast::Generics {
326            params,
327            where_clause: WhereClause {
328                has_where_token: false,
329                predicates: ThinVec::new(),
330                span: self.prev_token.span.shrink_to_hi(),
331            },
332            span,
333        })
334    }
335
336    /// Parses an experimental fn contract
337    /// (`contract_requires(WWW) contract_ensures(ZZZ)`)
338    pub(super) fn parse_contract(&mut self) -> PResult<'a, Option<Box<ast::FnContract>>> {
339        let (declarations, requires) = self.parse_contract_requires()?;
340        let ensures = self.parse_contract_ensures()?;
341
342        if requires.is_none() && ensures.is_none() {
343            Ok(None)
344        } else {
345            Ok(Some(Box::new(ast::FnContract { declarations, requires, ensures })))
346        }
347    }
348
349    fn parse_contract_requires(
350        &mut self,
351    ) -> PResult<'a, (ThinVec<rustc_ast::Stmt>, Option<Box<rustc_ast::Expr>>)> {
352        Ok(if self.eat_keyword_noexpect(crate::parser::token_type::ExpKeywordPair {
    kw: rustc_span::symbol::kw::ContractRequires,
    token_type: crate::parser::token_type::TokenType::KwContractRequires,
}exp!(ContractRequires).kw) {
353            self.psess.gated_spans.gate(sym::contracts_internals, self.prev_token.span);
354            let mut decls_and_precond = self.parse_block()?;
355
356            let precond = match decls_and_precond.stmts.pop() {
357                Some(precond) => match precond.kind {
358                    rustc_ast::StmtKind::Expr(expr) => expr,
359                    // Insert dummy node that will be rejected by typechecker to
360                    // avoid reinventing an error
361                    _ => self.mk_unit_expr(decls_and_precond.span),
362                },
363                None => self.mk_unit_expr(decls_and_precond.span),
364            };
365            let precond = self.mk_closure_expr(precond.span, precond);
366            let decls = decls_and_precond.stmts;
367            (decls, Some(precond))
368        } else {
369            (Default::default(), None)
370        })
371    }
372
373    fn parse_contract_ensures(&mut self) -> PResult<'a, Option<Box<rustc_ast::Expr>>> {
374        Ok(if self.eat_keyword_noexpect(crate::parser::token_type::ExpKeywordPair {
    kw: rustc_span::symbol::kw::ContractEnsures,
    token_type: crate::parser::token_type::TokenType::KwContractEnsures,
}exp!(ContractEnsures).kw) {
375            self.psess.gated_spans.gate(sym::contracts_internals, self.prev_token.span);
376            let postcond = self.parse_expr()?;
377            Some(postcond)
378        } else {
379            None
380        })
381    }
382
383    /// Parses an optional where-clause.
384    ///
385    /// ```ignore (only-for-syntax-highlight)
386    /// where T : Trait<U, V> + 'b, 'a : 'b
387    /// ```
388    pub(super) fn parse_where_clause(&mut self) -> PResult<'a, WhereClause> {
389        self.parse_where_clause_common(None).map(|(clause, _)| clause)
390    }
391
392    pub(super) fn parse_struct_where_clause(
393        &mut self,
394        struct_name: Ident,
395        body_insertion_point: Span,
396    ) -> PResult<'a, (WhereClause, Option<ThinVec<ast::FieldDef>>)> {
397        self.parse_where_clause_common(Some((struct_name, body_insertion_point)))
398    }
399
400    fn parse_where_clause_common(
401        &mut self,
402        struct_: Option<(Ident, Span)>,
403    ) -> PResult<'a, (WhereClause, Option<ThinVec<ast::FieldDef>>)> {
404        let mut where_clause = WhereClause {
405            has_where_token: false,
406            predicates: ThinVec::new(),
407            span: self.prev_token.span.shrink_to_hi(),
408        };
409        let mut tuple_struct_body = None;
410
411        if !self.eat_keyword(crate::parser::token_type::ExpKeywordPair {
    kw: rustc_span::symbol::kw::Where,
    token_type: crate::parser::token_type::TokenType::KwWhere,
}exp!(Where)) {
412            return Ok((where_clause, None));
413        }
414
415        if self.eat_noexpect(&token::Colon) {
416            let colon_span = self.prev_token.span;
417            self.dcx()
418                .struct_span_err(colon_span, "unexpected colon after `where`")
419                .with_span_suggestion_short(
420                    colon_span,
421                    "remove the colon",
422                    "",
423                    Applicability::MachineApplicable,
424                )
425                .emit();
426        }
427
428        where_clause.has_where_token = true;
429        let where_lo = self.prev_token.span;
430
431        // We are considering adding generics to the `where` keyword as an alternative higher-rank
432        // parameter syntax (as in `where<'a>` or `where<T>`. To avoid that being a breaking
433        // change we parse those generics now, but report an error.
434        if self.choose_generics_over_qpath(0) {
435            let generics = self.parse_generics()?;
436            self.dcx().emit_err(errors::WhereOnGenerics { span: generics.span });
437        }
438
439        loop {
440            let where_sp = where_lo.to(self.prev_token.span);
441            let attrs = self.parse_outer_attributes()?;
442            let pred_lo = self.token.span;
443            let predicate = self.collect_tokens(None, attrs, ForceCollect::No, |this, attrs| {
444                for attr in &attrs {
445                    self.psess.gated_spans.gate(sym::where_clause_attrs, attr.span);
446                }
447                let kind = if this.check_lifetime() && this.look_ahead(1, |t| !t.is_like_plus()) {
448                    let lifetime = this.expect_lifetime();
449                    // Bounds starting with a colon are mandatory, but possibly empty.
450                    this.expect(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::Colon,
    token_type: crate::parser::token_type::TokenType::Colon,
}exp!(Colon))?;
451                    let bounds = this.parse_lt_param_bounds();
452                    Some(ast::WherePredicateKind::RegionPredicate(ast::WhereRegionPredicate {
453                        lifetime,
454                        bounds,
455                    }))
456                } else if this.check_type() {
457                    match this.parse_ty_where_predicate_kind_or_recover_tuple_struct_body(
458                        struct_, pred_lo, where_sp,
459                    )? {
460                        PredicateKindOrStructBody::PredicateKind(kind) => Some(kind),
461                        PredicateKindOrStructBody::StructBody(body) => {
462                            tuple_struct_body = Some(body);
463                            None
464                        }
465                    }
466                } else {
467                    None
468                };
469                let predicate = kind.map(|kind| ast::WherePredicate {
470                    attrs,
471                    kind,
472                    id: DUMMY_NODE_ID,
473                    span: pred_lo.to(this.prev_token.span),
474                    is_placeholder: false,
475                });
476                Ok((predicate, Trailing::No, UsePreAttrPos::No))
477            })?;
478            match predicate {
479                Some(predicate) => where_clause.predicates.push(predicate),
480                None => break,
481            }
482
483            let prev_token = self.prev_token.span;
484            let ate_comma = self.eat(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::Comma,
    token_type: crate::parser::token_type::TokenType::Comma,
}exp!(Comma));
485
486            if self.eat_keyword_noexpect(kw::Where) {
487                self.dcx().emit_err(MultipleWhereClauses {
488                    span: self.token.span,
489                    previous: pred_lo,
490                    between: prev_token.shrink_to_hi().to(self.prev_token.span),
491                });
492            } else if !ate_comma {
493                break;
494            }
495        }
496
497        where_clause.span = where_lo.to(self.prev_token.span);
498        Ok((where_clause, tuple_struct_body))
499    }
500
501    fn parse_ty_where_predicate_kind_or_recover_tuple_struct_body(
502        &mut self,
503        struct_: Option<(Ident, Span)>,
504        pred_lo: Span,
505        where_sp: Span,
506    ) -> PResult<'a, PredicateKindOrStructBody> {
507        let mut snapshot = None;
508
509        if let Some(struct_) = struct_
510            && self.may_recover()
511            && self.token == token::OpenParen
512        {
513            snapshot = Some((struct_, self.create_snapshot_for_diagnostic()));
514        };
515
516        match self.parse_ty_where_predicate_kind() {
517            Ok(pred) => Ok(PredicateKindOrStructBody::PredicateKind(pred)),
518            Err(type_err) => {
519                let Some(((struct_name, body_insertion_point), mut snapshot)) = snapshot else {
520                    return Err(type_err);
521                };
522
523                // Check if we might have encountered an out of place tuple struct body.
524                match snapshot.parse_tuple_struct_body() {
525                    // Since we don't know the exact reason why we failed to parse the
526                    // predicate (we might have stumbled upon something bogus like `(T): ?`),
527                    // employ a simple heuristic to weed out some pathological cases:
528                    // Look for a semicolon (strong indicator) or anything that might mark
529                    // the end of the item (weak indicator) following the body.
530                    Ok(body)
531                        if #[allow(non_exhaustive_omitted_patterns)] match snapshot.token.kind {
    token::Semi | token::Eof => true,
    _ => false,
}matches!(snapshot.token.kind, token::Semi | token::Eof)
532                            || snapshot.token.can_begin_item() =>
533                    {
534                        type_err.cancel();
535
536                        let body_sp = pred_lo.to(snapshot.prev_token.span);
537                        let map = self.psess.source_map();
538
539                        self.dcx().emit_err(WhereClauseBeforeTupleStructBody {
540                            span: where_sp,
541                            name: struct_name.span,
542                            body: body_sp,
543                            sugg: map.span_to_snippet(body_sp).ok().map(|body| {
544                                WhereClauseBeforeTupleStructBodySugg {
545                                    left: body_insertion_point.shrink_to_hi(),
546                                    snippet: body,
547                                    right: map.end_point(where_sp).to(body_sp),
548                                }
549                            }),
550                        });
551
552                        self.restore_snapshot(snapshot);
553                        Ok(PredicateKindOrStructBody::StructBody(body))
554                    }
555                    Ok(_) => Err(type_err),
556                    Err(body_err) => {
557                        body_err.cancel();
558                        Err(type_err)
559                    }
560                }
561            }
562        }
563    }
564
565    fn parse_ty_where_predicate_kind(&mut self) -> PResult<'a, ast::WherePredicateKind> {
566        // Parse optional `for<'a, 'b>`.
567        // This `for` is parsed greedily and applies to the whole predicate,
568        // the bounded type can have its own `for` applying only to it.
569        // Examples:
570        // * `for<'a> Trait1<'a>: Trait2<'a /* ok */>`
571        // * `(for<'a> Trait1<'a>): Trait2<'a /* not ok */>`
572        // * `for<'a> for<'b> Trait1<'a, 'b>: Trait2<'a /* ok */, 'b /* not ok */>`
573        let (bound_vars, _) = self.parse_higher_ranked_binder()?;
574
575        // Parse type with mandatory colon and (possibly empty) bounds,
576        // or with mandatory equality sign and the second type.
577        let ty = self.parse_ty_for_where_clause()?;
578        if self.eat(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::Colon,
    token_type: crate::parser::token_type::TokenType::Colon,
}exp!(Colon)) {
579            let bounds = self.parse_generic_bounds()?;
580            Ok(ast::WherePredicateKind::BoundPredicate(ast::WhereBoundPredicate {
581                bound_generic_params: bound_vars,
582                bounded_ty: ty,
583                bounds,
584            }))
585        // FIXME: Decide what should be used here, `=` or `==`.
586        // FIXME: We are just dropping the binders in lifetime_defs on the floor here.
587        } else if self.eat(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::Eq,
    token_type: crate::parser::token_type::TokenType::Eq,
}exp!(Eq)) || self.eat(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::EqEq,
    token_type: crate::parser::token_type::TokenType::EqEq,
}exp!(EqEq)) {
588            let rhs_ty = self.parse_ty()?;
589            Ok(ast::WherePredicateKind::EqPredicate(ast::WhereEqPredicate { lhs_ty: ty, rhs_ty }))
590        } else {
591            self.maybe_recover_bounds_doubled_colon(&ty)?;
592            self.unexpected_any()
593        }
594    }
595
596    pub(super) fn choose_generics_over_qpath(&self, start: usize) -> bool {
597        // There's an ambiguity between generic parameters and qualified paths in impls.
598        // If we see `<` it may start both, so we have to inspect some following tokens.
599        // The following combinations can only start generics,
600        // but not qualified paths (with one exception):
601        //     `<` `>` - empty generic parameters
602        //     `<` `#` - generic parameters with attributes
603        //     `<` (LIFETIME|IDENT) `>` - single generic parameter
604        //     `<` (LIFETIME|IDENT) `,` - first generic parameter in a list
605        //     `<` (LIFETIME|IDENT) `:` - generic parameter with bounds
606        //     `<` (LIFETIME|IDENT) `=` - generic parameter with a default
607        //     `<` const                - generic const parameter
608        //     `<` IDENT `?`            - RECOVERY for `impl<T ?Bound` missing a `:`, meant to
609        //                                avoid the `T?` to `Option<T>` recovery for types.
610        // The only truly ambiguous case is
611        //     `<` IDENT `>` `::` IDENT ...
612        // we disambiguate it in favor of generics (`impl<T> ::absolute::Path<T> { ... }`)
613        // because this is what almost always expected in practice, qualified paths in impls
614        // (`impl <Type>::AssocTy { ... }`) aren't even allowed by type checker at the moment.
615        self.look_ahead(start, |t| t == &token::Lt)
616            && (self.look_ahead(start + 1, |t| t == &token::Pound || t == &token::Gt)
617                || self.look_ahead(start + 1, |t| t.is_lifetime() || t.is_ident())
618                    && self.look_ahead(start + 2, |t| {
619                        #[allow(non_exhaustive_omitted_patterns)] match t.kind {
    token::Gt | token::Comma | token::Colon | token::Eq => true,
    _ => false,
}matches!(t.kind, token::Gt | token::Comma | token::Colon | token::Eq)
620                        // Recovery-only branch -- this could be removed,
621                        // since it only affects diagnostics currently.
622                            || t.kind == token::Question
623                    })
624                || self.is_keyword_ahead(start + 1, &[kw::Const]))
625    }
626}