rustc_parse/parser/
generics.rs

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