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

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy