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 attrs = self.parse_outer_attributes()?;
371            let pred_lo = self.token.span;
372            let predicate = self.collect_tokens(None, attrs, ForceCollect::No, |this, attrs| {
373                for attr in &attrs {
374                    self.psess.gated_spans.gate(sym::where_clause_attrs, attr.span);
375                }
376                let kind = if this.check_lifetime() && this.look_ahead(1, |t| !t.is_like_plus()) {
377                    let lifetime = this.expect_lifetime();
378                    // Bounds starting with a colon are mandatory, but possibly empty.
379                    this.expect(exp!(Colon))?;
380                    let bounds = this.parse_lt_param_bounds();
381                    Some(ast::WherePredicateKind::RegionPredicate(ast::WhereRegionPredicate {
382                        lifetime,
383                        bounds,
384                    }))
385                } else if this.check_type() {
386                    match this.parse_ty_where_predicate_kind_or_recover_tuple_struct_body(
387                        struct_, pred_lo, where_sp,
388                    )? {
389                        PredicateKindOrStructBody::PredicateKind(kind) => Some(kind),
390                        PredicateKindOrStructBody::StructBody(body) => {
391                            tuple_struct_body = Some(body);
392                            None
393                        }
394                    }
395                } else {
396                    None
397                };
398                let predicate = kind.map(|kind| ast::WherePredicate {
399                    attrs,
400                    kind,
401                    id: DUMMY_NODE_ID,
402                    span: pred_lo.to(this.prev_token.span),
403                    is_placeholder: false,
404                });
405                Ok((predicate, Trailing::No, UsePreAttrPos::No))
406            })?;
407            match predicate {
408                Some(predicate) => where_clause.predicates.push(predicate),
409                None => break,
410            }
411
412            let prev_token = self.prev_token.span;
413            let ate_comma = self.eat(exp!(Comma));
414
415            if self.eat_keyword_noexpect(kw::Where) {
416                self.dcx().emit_err(MultipleWhereClauses {
417                    span: self.token.span,
418                    previous: pred_lo,
419                    between: prev_token.shrink_to_hi().to(self.prev_token.span),
420                });
421            } else if !ate_comma {
422                break;
423            }
424        }
425
426        where_clause.span = where_lo.to(self.prev_token.span);
427        Ok((where_clause, tuple_struct_body))
428    }
429
430    fn parse_ty_where_predicate_kind_or_recover_tuple_struct_body(
431        &mut self,
432        struct_: Option<(Ident, Span)>,
433        pred_lo: Span,
434        where_sp: Span,
435    ) -> PResult<'a, PredicateKindOrStructBody> {
436        let mut snapshot = None;
437
438        if let Some(struct_) = struct_
439            && self.may_recover()
440            && self.token == token::OpenDelim(Delimiter::Parenthesis)
441        {
442            snapshot = Some((struct_, self.create_snapshot_for_diagnostic()));
443        };
444
445        match self.parse_ty_where_predicate_kind() {
446            Ok(pred) => Ok(PredicateKindOrStructBody::PredicateKind(pred)),
447            Err(type_err) => {
448                let Some(((struct_name, body_insertion_point), mut snapshot)) = snapshot else {
449                    return Err(type_err);
450                };
451
452                // Check if we might have encountered an out of place tuple struct body.
453                match snapshot.parse_tuple_struct_body() {
454                    // Since we don't know the exact reason why we failed to parse the
455                    // predicate (we might have stumbled upon something bogus like `(T): ?`),
456                    // employ a simple heuristic to weed out some pathological cases:
457                    // Look for a semicolon (strong indicator) or anything that might mark
458                    // the end of the item (weak indicator) following the body.
459                    Ok(body)
460                        if matches!(snapshot.token.kind, token::Semi | token::Eof)
461                            || snapshot.token.can_begin_item() =>
462                    {
463                        type_err.cancel();
464
465                        let body_sp = pred_lo.to(snapshot.prev_token.span);
466                        let map = self.psess.source_map();
467
468                        self.dcx().emit_err(WhereClauseBeforeTupleStructBody {
469                            span: where_sp,
470                            name: struct_name.span,
471                            body: body_sp,
472                            sugg: map.span_to_snippet(body_sp).ok().map(|body| {
473                                WhereClauseBeforeTupleStructBodySugg {
474                                    left: body_insertion_point.shrink_to_hi(),
475                                    snippet: body,
476                                    right: map.end_point(where_sp).to(body_sp),
477                                }
478                            }),
479                        });
480
481                        self.restore_snapshot(snapshot);
482                        Ok(PredicateKindOrStructBody::StructBody(body))
483                    }
484                    Ok(_) => Err(type_err),
485                    Err(body_err) => {
486                        body_err.cancel();
487                        Err(type_err)
488                    }
489                }
490            }
491        }
492    }
493
494    fn parse_ty_where_predicate_kind(&mut self) -> PResult<'a, ast::WherePredicateKind> {
495        // Parse optional `for<'a, 'b>`.
496        // This `for` is parsed greedily and applies to the whole predicate,
497        // the bounded type can have its own `for` applying only to it.
498        // Examples:
499        // * `for<'a> Trait1<'a>: Trait2<'a /* ok */>`
500        // * `(for<'a> Trait1<'a>): Trait2<'a /* not ok */>`
501        // * `for<'a> for<'b> Trait1<'a, 'b>: Trait2<'a /* ok */, 'b /* not ok */>`
502        let (lifetime_defs, _) = self.parse_late_bound_lifetime_defs()?;
503
504        // Parse type with mandatory colon and (possibly empty) bounds,
505        // or with mandatory equality sign and the second type.
506        let ty = self.parse_ty_for_where_clause()?;
507        if self.eat(exp!(Colon)) {
508            let bounds = self.parse_generic_bounds()?;
509            Ok(ast::WherePredicateKind::BoundPredicate(ast::WhereBoundPredicate {
510                bound_generic_params: lifetime_defs,
511                bounded_ty: ty,
512                bounds,
513            }))
514        // FIXME: Decide what should be used here, `=` or `==`.
515        // FIXME: We are just dropping the binders in lifetime_defs on the floor here.
516        } else if self.eat(exp!(Eq)) || self.eat(exp!(EqEq)) {
517            let rhs_ty = self.parse_ty()?;
518            Ok(ast::WherePredicateKind::EqPredicate(ast::WhereEqPredicate { lhs_ty: ty, rhs_ty }))
519        } else {
520            self.maybe_recover_bounds_doubled_colon(&ty)?;
521            self.unexpected_any()
522        }
523    }
524
525    pub(super) fn choose_generics_over_qpath(&self, start: usize) -> bool {
526        // There's an ambiguity between generic parameters and qualified paths in impls.
527        // If we see `<` it may start both, so we have to inspect some following tokens.
528        // The following combinations can only start generics,
529        // but not qualified paths (with one exception):
530        //     `<` `>` - empty generic parameters
531        //     `<` `#` - generic parameters with attributes
532        //     `<` (LIFETIME|IDENT) `>` - single generic parameter
533        //     `<` (LIFETIME|IDENT) `,` - first generic parameter in a list
534        //     `<` (LIFETIME|IDENT) `:` - generic parameter with bounds
535        //     `<` (LIFETIME|IDENT) `=` - generic parameter with a default
536        //     `<` const                - generic const parameter
537        //     `<` IDENT `?`            - RECOVERY for `impl<T ?Bound` missing a `:`, meant to
538        //                                avoid the `T?` to `Option<T>` recovery for types.
539        // The only truly ambiguous case is
540        //     `<` IDENT `>` `::` IDENT ...
541        // we disambiguate it in favor of generics (`impl<T> ::absolute::Path<T> { ... }`)
542        // because this is what almost always expected in practice, qualified paths in impls
543        // (`impl <Type>::AssocTy { ... }`) aren't even allowed by type checker at the moment.
544        self.look_ahead(start, |t| t == &token::Lt)
545            && (self.look_ahead(start + 1, |t| t == &token::Pound || t == &token::Gt)
546                || self.look_ahead(start + 1, |t| t.is_lifetime() || t.is_ident())
547                    && self.look_ahead(start + 2, |t| {
548                        matches!(t.kind, token::Gt | token::Comma | token::Colon | token::Eq)
549                        // Recovery-only branch -- this could be removed,
550                        // since it only affects diagnostics currently.
551                            || matches!(t.kind, token::Question)
552                    })
553                || self.is_keyword_ahead(start + 1, &[kw::Const]))
554    }
555}