rustc_parse/parser/
path.rs

1use std::mem;
2
3use ast::token::IdentIsRaw;
4use rustc_ast::ptr::P;
5use rustc_ast::token::{self, MetaVarKind, Token, TokenKind};
6use rustc_ast::{
7    self as ast, AngleBracketedArg, AngleBracketedArgs, AnonConst, AssocItemConstraint,
8    AssocItemConstraintKind, BlockCheckMode, GenericArg, GenericArgs, Generics, ParenthesizedArgs,
9    Path, PathSegment, QSelf,
10};
11use rustc_errors::{Applicability, Diag, PResult};
12use rustc_span::{BytePos, Ident, Span, kw, sym};
13use thin_vec::ThinVec;
14use tracing::debug;
15
16use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
17use super::{Parser, Restrictions, TokenType};
18use crate::ast::{PatKind, TyKind};
19use crate::errors::{
20    self, FnPathFoundNamedParams, PathFoundAttributeInParams, PathFoundCVariadicParams,
21    PathSingleColon, PathTripleColon,
22};
23use crate::exp;
24use crate::parser::{CommaRecoveryMode, RecoverColon, RecoverComma};
25
26/// Specifies how to parse a path.
27#[derive(Copy, Clone, PartialEq)]
28pub(super) enum PathStyle {
29    /// In some contexts, notably in expressions, paths with generic arguments are ambiguous
30    /// with something else. For example, in expressions `segment < ....` can be interpreted
31    /// as a comparison and `segment ( ....` can be interpreted as a function call.
32    /// In all such contexts the non-path interpretation is preferred by default for practical
33    /// reasons, but the path interpretation can be forced by the disambiguator `::`, e.g.
34    /// `x<y>` - comparisons, `x::<y>` - unambiguously a path.
35    ///
36    /// Also, a path may never be followed by a `:`. This means that we can eagerly recover if
37    /// we encounter it.
38    Expr,
39    /// The same as `Expr`, but may be followed by a `:`.
40    /// For example, this code:
41    /// ```rust
42    /// struct S;
43    ///
44    /// let S: S;
45    /// //  ^ Followed by a `:`
46    /// ```
47    Pat,
48    /// In other contexts, notably in types, no ambiguity exists and paths can be written
49    /// without the disambiguator, e.g., `x<y>` - unambiguously a path.
50    /// Paths with disambiguators are still accepted, `x::<Y>` - unambiguously a path too.
51    Type,
52    /// A path with generic arguments disallowed, e.g., `foo::bar::Baz`, used in imports,
53    /// visibilities or attributes.
54    /// Technically, this variant is unnecessary and e.g., `Expr` can be used instead
55    /// (paths in "mod" contexts have to be checked later for absence of generic arguments
56    /// anyway, due to macros), but it is used to avoid weird suggestions about expected
57    /// tokens when something goes wrong.
58    Mod,
59}
60
61impl PathStyle {
62    fn has_generic_ambiguity(&self) -> bool {
63        matches!(self, Self::Expr | Self::Pat)
64    }
65}
66
67impl<'a> Parser<'a> {
68    /// Parses a qualified path.
69    /// Assumes that the leading `<` has been parsed already.
70    ///
71    /// `qualified_path = <type [as trait_ref]>::path`
72    ///
73    /// # Examples
74    /// `<T>::default`
75    /// `<T as U>::a`
76    /// `<T as U>::F::a<S>` (without disambiguator)
77    /// `<T as U>::F::a::<S>` (with disambiguator)
78    pub(super) fn parse_qpath(&mut self, style: PathStyle) -> PResult<'a, (P<QSelf>, Path)> {
79        let lo = self.prev_token.span;
80        let ty = self.parse_ty()?;
81
82        // `path` will contain the prefix of the path up to the `>`,
83        // if any (e.g., `U` in the `<T as U>::*` examples
84        // above). `path_span` has the span of that path, or an empty
85        // span in the case of something like `<T>::Bar`.
86        let (mut path, path_span);
87        if self.eat_keyword(exp!(As)) {
88            let path_lo = self.token.span;
89            path = self.parse_path(PathStyle::Type)?;
90            path_span = path_lo.to(self.prev_token.span);
91        } else {
92            path_span = self.token.span.to(self.token.span);
93            path = ast::Path { segments: ThinVec::new(), span: path_span, tokens: None };
94        }
95
96        // See doc comment for `unmatched_angle_bracket_count`.
97        self.expect(exp!(Gt))?;
98        if self.unmatched_angle_bracket_count > 0 {
99            self.unmatched_angle_bracket_count -= 1;
100            debug!("parse_qpath: (decrement) count={:?}", self.unmatched_angle_bracket_count);
101        }
102
103        let is_import_coupler = self.is_import_coupler();
104        if !is_import_coupler && !self.recover_colon_before_qpath_proj() {
105            self.expect(exp!(PathSep))?;
106        }
107
108        let qself = P(QSelf { ty, path_span, position: path.segments.len() });
109        if !is_import_coupler {
110            self.parse_path_segments(&mut path.segments, style, None)?;
111        }
112
113        Ok((
114            qself,
115            Path { segments: path.segments, span: lo.to(self.prev_token.span), tokens: None },
116        ))
117    }
118
119    /// Recover from an invalid single colon, when the user likely meant a qualified path.
120    /// We avoid emitting this if not followed by an identifier, as our assumption that the user
121    /// intended this to be a qualified path may not be correct.
122    ///
123    /// ```ignore (diagnostics)
124    /// <Bar as Baz<T>>:Qux
125    ///                ^ help: use double colon
126    /// ```
127    fn recover_colon_before_qpath_proj(&mut self) -> bool {
128        if !self.check_noexpect(&TokenKind::Colon)
129            || self.look_ahead(1, |t| !t.is_non_reserved_ident())
130        {
131            return false;
132        }
133
134        self.bump(); // colon
135
136        self.dcx()
137            .struct_span_err(
138                self.prev_token.span,
139                "found single colon before projection in qualified path",
140            )
141            .with_span_suggestion(
142                self.prev_token.span,
143                "use double colon",
144                "::",
145                Applicability::MachineApplicable,
146            )
147            .emit();
148
149        true
150    }
151
152    pub(super) fn parse_path(&mut self, style: PathStyle) -> PResult<'a, Path> {
153        self.parse_path_inner(style, None)
154    }
155
156    /// Parses simple paths.
157    ///
158    /// `path = [::] segment+`
159    /// `segment = ident | ident[::]<args> | ident[::](args) [-> type]`
160    ///
161    /// # Examples
162    /// `a::b::C<D>` (without disambiguator)
163    /// `a::b::C::<D>` (with disambiguator)
164    /// `Fn(Args)` (without disambiguator)
165    /// `Fn::(Args)` (with disambiguator)
166    pub(super) fn parse_path_inner(
167        &mut self,
168        style: PathStyle,
169        ty_generics: Option<&Generics>,
170    ) -> PResult<'a, Path> {
171        let reject_generics_if_mod_style = |parser: &Parser<'_>, path: Path| {
172            // Ensure generic arguments don't end up in attribute paths, such as:
173            //
174            //     macro_rules! m {
175            //         ($p:path) => { #[$p] struct S; }
176            //     }
177            //
178            //     m!(inline<u8>); //~ ERROR: unexpected generic arguments in path
179            //
180            if style == PathStyle::Mod && path.segments.iter().any(|segment| segment.args.is_some())
181            {
182                let span = path
183                    .segments
184                    .iter()
185                    .filter_map(|segment| segment.args.as_ref())
186                    .map(|arg| arg.span())
187                    .collect::<Vec<_>>();
188                parser.dcx().emit_err(errors::GenericsInPath { span });
189                // Ignore these arguments to prevent unexpected behaviors.
190                let segments = path
191                    .segments
192                    .iter()
193                    .map(|segment| PathSegment { ident: segment.ident, id: segment.id, args: None })
194                    .collect();
195                Path { segments, ..path }
196            } else {
197                path
198            }
199        };
200
201        if let Some(path) =
202            self.eat_metavar_seq(MetaVarKind::Path, |this| this.parse_path(PathStyle::Type))
203        {
204            return Ok(reject_generics_if_mod_style(self, path));
205        }
206
207        // If we have a `ty` metavar in the form of a path, reparse it directly as a path, instead
208        // of reparsing it as a `ty` and then extracting the path.
209        if let Some(path) = self.eat_metavar_seq(MetaVarKind::Ty { is_path: true }, |this| {
210            this.parse_path(PathStyle::Type)
211        }) {
212            return Ok(reject_generics_if_mod_style(self, path));
213        }
214
215        let lo = self.token.span;
216        let mut segments = ThinVec::new();
217        let mod_sep_ctxt = self.token.span.ctxt();
218        if self.eat_path_sep() {
219            segments.push(PathSegment::path_root(lo.shrink_to_lo().with_ctxt(mod_sep_ctxt)));
220        }
221        self.parse_path_segments(&mut segments, style, ty_generics)?;
222        Ok(Path { segments, span: lo.to(self.prev_token.span), tokens: None })
223    }
224
225    pub(super) fn parse_path_segments(
226        &mut self,
227        segments: &mut ThinVec<PathSegment>,
228        style: PathStyle,
229        ty_generics: Option<&Generics>,
230    ) -> PResult<'a, ()> {
231        loop {
232            let segment = self.parse_path_segment(style, ty_generics)?;
233            if style.has_generic_ambiguity() {
234                // In order to check for trailing angle brackets, we must have finished
235                // recursing (`parse_path_segment` can indirectly call this function),
236                // that is, the next token must be the highlighted part of the below example:
237                //
238                // `Foo::<Bar as Baz<T>>::Qux`
239                //                      ^ here
240                //
241                // As opposed to the below highlight (if we had only finished the first
242                // recursion):
243                //
244                // `Foo::<Bar as Baz<T>>::Qux`
245                //                     ^ here
246                //
247                // `PathStyle::Expr` is only provided at the root invocation and never in
248                // `parse_path_segment` to recurse and therefore can be checked to maintain
249                // this invariant.
250                self.check_trailing_angle_brackets(&segment, &[exp!(PathSep)]);
251            }
252            segments.push(segment);
253
254            if self.is_import_coupler() || !self.eat_path_sep() {
255                // IMPORTANT: We can *only ever* treat single colons as typo'ed double colons in
256                // expression contexts (!) since only there paths cannot possibly be followed by
257                // a colon and still form a syntactically valid construct. In pattern contexts,
258                // a path may be followed by a type annotation. E.g., `let pat:ty`. In type
259                // contexts, a path may be followed by a list of bounds. E.g., `where ty:bound`.
260                if self.may_recover()
261                    && style == PathStyle::Expr // (!)
262                    && self.token == token::Colon
263                    && self.look_ahead(1, |token| token.is_non_reserved_ident())
264                {
265                    // Emit a special error message for `a::b:c` to help users
266                    // otherwise, `a: c` might have meant to introduce a new binding
267                    if self.token.span.lo() == self.prev_token.span.hi()
268                        && self.look_ahead(1, |token| self.token.span.hi() == token.span.lo())
269                    {
270                        self.bump(); // bump past the colon
271                        self.dcx().emit_err(PathSingleColon {
272                            span: self.prev_token.span,
273                            suggestion: self.prev_token.span.shrink_to_hi(),
274                        });
275                    }
276                    continue;
277                }
278
279                return Ok(());
280            }
281        }
282    }
283
284    /// Eat `::` or, potentially, `:::`.
285    #[must_use]
286    pub(super) fn eat_path_sep(&mut self) -> bool {
287        let result = self.eat(exp!(PathSep));
288        if result && self.may_recover() {
289            if self.eat_noexpect(&token::Colon) {
290                self.dcx().emit_err(PathTripleColon { span: self.prev_token.span });
291            }
292        }
293        result
294    }
295
296    pub(super) fn parse_path_segment(
297        &mut self,
298        style: PathStyle,
299        ty_generics: Option<&Generics>,
300    ) -> PResult<'a, PathSegment> {
301        let ident = self.parse_path_segment_ident()?;
302        let is_args_start = |token: &Token| {
303            matches!(token.kind, token::Lt | token::Shl | token::OpenParen | token::LArrow)
304        };
305        let check_args_start = |this: &mut Self| {
306            this.expected_token_types.insert(TokenType::Lt);
307            this.expected_token_types.insert(TokenType::OpenParen);
308            is_args_start(&this.token)
309        };
310
311        Ok(
312            if style == PathStyle::Type && check_args_start(self)
313                || style != PathStyle::Mod && self.check_path_sep_and_look_ahead(is_args_start)
314            {
315                // We use `style == PathStyle::Expr` to check if this is in a recursion or not. If
316                // it isn't, then we reset the unmatched angle bracket count as we're about to start
317                // parsing a new path.
318                if style == PathStyle::Expr {
319                    self.unmatched_angle_bracket_count = 0;
320                }
321
322                // Generic arguments are found - `<`, `(`, `::<` or `::(`.
323                // First, eat `::` if it exists.
324                let _ = self.eat_path_sep();
325
326                let lo = self.token.span;
327                let args = if self.eat_lt() {
328                    // `<'a, T, A = U>`
329                    let args = self.parse_angle_args_with_leading_angle_bracket_recovery(
330                        style,
331                        lo,
332                        ty_generics,
333                    )?;
334                    self.expect_gt().map_err(|mut err| {
335                        // Try to recover a `:` into a `::`
336                        if self.token == token::Colon
337                            && self.look_ahead(1, |token| token.is_non_reserved_ident())
338                        {
339                            err.cancel();
340                            err = self.dcx().create_err(PathSingleColon {
341                                span: self.token.span,
342                                suggestion: self.prev_token.span.shrink_to_hi(),
343                            });
344                        }
345                        // Attempt to find places where a missing `>` might belong.
346                        else if let Some(arg) = args
347                            .iter()
348                            .rev()
349                            .find(|arg| !matches!(arg, AngleBracketedArg::Constraint(_)))
350                        {
351                            err.span_suggestion_verbose(
352                                arg.span().shrink_to_hi(),
353                                "you might have meant to end the type parameters here",
354                                ">",
355                                Applicability::MaybeIncorrect,
356                            );
357                        }
358                        err
359                    })?;
360                    let span = lo.to(self.prev_token.span);
361                    AngleBracketedArgs { args, span }.into()
362                } else if self.token == token::OpenParen
363                    // FIXME(return_type_notation): Could also recover `...` here.
364                    && self.look_ahead(1, |t| *t == token::DotDot)
365                {
366                    self.bump(); // (
367                    self.bump(); // ..
368                    self.expect(exp!(CloseParen))?;
369                    let span = lo.to(self.prev_token.span);
370
371                    self.psess.gated_spans.gate(sym::return_type_notation, span);
372
373                    let prev_lo = self.prev_token.span.shrink_to_hi();
374                    if self.eat_noexpect(&token::RArrow) {
375                        let lo = self.prev_token.span;
376                        let ty = self.parse_ty()?;
377                        let span = lo.to(ty.span);
378                        let suggestion = prev_lo.to(ty.span);
379                        self.dcx()
380                            .emit_err(errors::BadReturnTypeNotationOutput { span, suggestion });
381                    }
382
383                    P(ast::GenericArgs::ParenthesizedElided(span))
384                } else {
385                    // `(T, U) -> R`
386
387                    let prev_token_before_parsing = self.prev_token;
388                    let token_before_parsing = self.token;
389                    let mut snapshot = None;
390                    if self.may_recover()
391                        && prev_token_before_parsing == token::PathSep
392                        && (style == PathStyle::Expr && self.token.can_begin_expr()
393                            || style == PathStyle::Pat
394                                && self.token.can_begin_pattern(token::NtPatKind::PatParam {
395                                    inferred: false,
396                                }))
397                    {
398                        snapshot = Some(self.create_snapshot_for_diagnostic());
399                    }
400
401                    let dcx = self.dcx();
402                    let parse_params_result = self.parse_paren_comma_seq(|p| {
403                        let param = p.parse_param_general(|_| false, false, false);
404                        param.map(move |param| {
405                            if !matches!(param.pat.kind, PatKind::Missing) {
406                                dcx.emit_err(FnPathFoundNamedParams {
407                                    named_param_span: param.pat.span,
408                                });
409                            }
410                            if matches!(param.ty.kind, TyKind::CVarArgs) {
411                                dcx.emit_err(PathFoundCVariadicParams { span: param.pat.span });
412                            }
413                            if !param.attrs.is_empty() {
414                                dcx.emit_err(PathFoundAttributeInParams {
415                                    span: param.attrs[0].span,
416                                });
417                            }
418                            param.ty
419                        })
420                    });
421
422                    let (inputs, _) = match parse_params_result {
423                        Ok(output) => output,
424                        Err(mut error) if prev_token_before_parsing == token::PathSep => {
425                            error.span_label(
426                                prev_token_before_parsing.span.to(token_before_parsing.span),
427                                "while parsing this parenthesized list of type arguments starting here",
428                            );
429
430                            if let Some(mut snapshot) = snapshot {
431                                snapshot.recover_fn_call_leading_path_sep(
432                                    style,
433                                    prev_token_before_parsing,
434                                    &mut error,
435                                )
436                            }
437
438                            return Err(error);
439                        }
440                        Err(error) => return Err(error),
441                    };
442                    let inputs_span = lo.to(self.prev_token.span);
443                    let output =
444                        self.parse_ret_ty(AllowPlus::No, RecoverQPath::No, RecoverReturnSign::No)?;
445                    let span = ident.span.to(self.prev_token.span);
446                    ParenthesizedArgs { span, inputs, inputs_span, output }.into()
447                };
448
449                PathSegment { ident, args: Some(args), id: ast::DUMMY_NODE_ID }
450            } else {
451                // Generic arguments are not found.
452                PathSegment::from_ident(ident)
453            },
454        )
455    }
456
457    pub(super) fn parse_path_segment_ident(&mut self) -> PResult<'a, Ident> {
458        match self.token.ident() {
459            Some((ident, IdentIsRaw::No)) if ident.is_path_segment_keyword() => {
460                self.bump();
461                Ok(ident)
462            }
463            _ => self.parse_ident(),
464        }
465    }
466
467    /// Recover `$path::(...)` as `$path(...)`.
468    ///
469    /// ```ignore (diagnostics)
470    /// foo::(420, "bar")
471    ///    ^^ remove extra separator to make the function call
472    /// // or
473    /// match x {
474    ///    Foo::(420, "bar") => { ... },
475    ///       ^^ remove extra separator to turn this into tuple struct pattern
476    ///    _ => { ... },
477    /// }
478    /// ```
479    fn recover_fn_call_leading_path_sep(
480        &mut self,
481        style: PathStyle,
482        prev_token_before_parsing: Token,
483        error: &mut Diag<'_>,
484    ) {
485        match style {
486            PathStyle::Expr
487                if let Ok(_) = self
488                    .parse_paren_comma_seq(|p| p.parse_expr())
489                    .map_err(|error| error.cancel()) => {}
490            PathStyle::Pat
491                if let Ok(_) = self
492                    .parse_paren_comma_seq(|p| {
493                        p.parse_pat_allow_top_guard(
494                            None,
495                            RecoverComma::No,
496                            RecoverColon::No,
497                            CommaRecoveryMode::LikelyTuple,
498                        )
499                    })
500                    .map_err(|error| error.cancel()) => {}
501            _ => {
502                return;
503            }
504        }
505
506        if let token::PathSep | token::RArrow = self.token.kind {
507            return;
508        }
509
510        error.span_suggestion_verbose(
511            prev_token_before_parsing.span,
512            format!(
513                "consider removing the `::` here to {}",
514                match style {
515                    PathStyle::Expr => "call the expression",
516                    PathStyle::Pat => "turn this into a tuple struct pattern",
517                    _ => {
518                        return;
519                    }
520                }
521            ),
522            "",
523            Applicability::MaybeIncorrect,
524        );
525    }
526
527    /// Parses generic args (within a path segment) with recovery for extra leading angle brackets.
528    /// For the purposes of understanding the parsing logic of generic arguments, this function
529    /// can be thought of being the same as just calling `self.parse_angle_args()` if the source
530    /// had the correct amount of leading angle brackets.
531    ///
532    /// ```ignore (diagnostics)
533    /// bar::<<<<T as Foo>::Output>();
534    ///      ^^ help: remove extra angle brackets
535    /// ```
536    fn parse_angle_args_with_leading_angle_bracket_recovery(
537        &mut self,
538        style: PathStyle,
539        lo: Span,
540        ty_generics: Option<&Generics>,
541    ) -> PResult<'a, ThinVec<AngleBracketedArg>> {
542        // We need to detect whether there are extra leading left angle brackets and produce an
543        // appropriate error and suggestion. This cannot be implemented by looking ahead at
544        // upcoming tokens for a matching `>` character - if there are unmatched `<` tokens
545        // then there won't be matching `>` tokens to find.
546        //
547        // To explain how this detection works, consider the following example:
548        //
549        // ```ignore (diagnostics)
550        // bar::<<<<T as Foo>::Output>();
551        //      ^^ help: remove extra angle brackets
552        // ```
553        //
554        // Parsing of the left angle brackets starts in this function. We start by parsing the
555        // `<` token (incrementing the counter of unmatched angle brackets on `Parser` via
556        // `eat_lt`):
557        //
558        // *Upcoming tokens:* `<<<<T as Foo>::Output>;`
559        // *Unmatched count:* 1
560        // *`parse_path_segment` calls deep:* 0
561        //
562        // This has the effect of recursing as this function is called if a `<` character
563        // is found within the expected generic arguments:
564        //
565        // *Upcoming tokens:* `<<<T as Foo>::Output>;`
566        // *Unmatched count:* 2
567        // *`parse_path_segment` calls deep:* 1
568        //
569        // Eventually we will have recursed until having consumed all of the `<` tokens and
570        // this will be reflected in the count:
571        //
572        // *Upcoming tokens:* `T as Foo>::Output>;`
573        // *Unmatched count:* 4
574        // `parse_path_segment` calls deep:* 3
575        //
576        // The parser will continue until reaching the first `>` - this will decrement the
577        // unmatched angle bracket count and return to the parent invocation of this function
578        // having succeeded in parsing:
579        //
580        // *Upcoming tokens:* `::Output>;`
581        // *Unmatched count:* 3
582        // *`parse_path_segment` calls deep:* 2
583        //
584        // This will continue until the next `>` character which will also return successfully
585        // to the parent invocation of this function and decrement the count:
586        //
587        // *Upcoming tokens:* `;`
588        // *Unmatched count:* 2
589        // *`parse_path_segment` calls deep:* 1
590        //
591        // At this point, this function will expect to find another matching `>` character but
592        // won't be able to and will return an error. This will continue all the way up the
593        // call stack until the first invocation:
594        //
595        // *Upcoming tokens:* `;`
596        // *Unmatched count:* 2
597        // *`parse_path_segment` calls deep:* 0
598        //
599        // In doing this, we have managed to work out how many unmatched leading left angle
600        // brackets there are, but we cannot recover as the unmatched angle brackets have
601        // already been consumed. To remedy this, we keep a snapshot of the parser state
602        // before we do the above. We can then inspect whether we ended up with a parsing error
603        // and unmatched left angle brackets and if so, restore the parser state before we
604        // consumed any `<` characters to emit an error and consume the erroneous tokens to
605        // recover by attempting to parse again.
606        //
607        // In practice, the recursion of this function is indirect and there will be other
608        // locations that consume some `<` characters - as long as we update the count when
609        // this happens, it isn't an issue.
610
611        let is_first_invocation = style == PathStyle::Expr;
612        // Take a snapshot before attempting to parse - we can restore this later.
613        let snapshot = is_first_invocation.then(|| self.clone());
614
615        self.angle_bracket_nesting += 1;
616        debug!("parse_generic_args_with_leading_angle_bracket_recovery: (snapshotting)");
617        match self.parse_angle_args(ty_generics) {
618            Ok(args) => {
619                self.angle_bracket_nesting -= 1;
620                Ok(args)
621            }
622            Err(e) if self.angle_bracket_nesting > 10 => {
623                self.angle_bracket_nesting -= 1;
624                // When encountering severely malformed code where there are several levels of
625                // nested unclosed angle args (`f::<f::<f::<f::<...`), we avoid severe O(n^2)
626                // behavior by bailing out earlier (#117080).
627                e.emit().raise_fatal();
628            }
629            Err(e) if is_first_invocation && self.unmatched_angle_bracket_count > 0 => {
630                self.angle_bracket_nesting -= 1;
631
632                // Swap `self` with our backup of the parser state before attempting to parse
633                // generic arguments.
634                let snapshot = mem::replace(self, snapshot.unwrap());
635
636                // Eat the unmatched angle brackets.
637                let all_angle_brackets = (0..snapshot.unmatched_angle_bracket_count)
638                    .fold(true, |a, _| a && self.eat_lt());
639
640                if !all_angle_brackets {
641                    // If there are other tokens in between the extraneous `<`s, we cannot simply
642                    // suggest to remove them. This check also prevents us from accidentally ending
643                    // up in the middle of a multibyte character (issue #84104).
644                    let _ = mem::replace(self, snapshot);
645                    Err(e)
646                } else {
647                    // Cancel error from being unable to find `>`. We know the error
648                    // must have been this due to a non-zero unmatched angle bracket
649                    // count.
650                    e.cancel();
651
652                    debug!(
653                        "parse_generic_args_with_leading_angle_bracket_recovery: (snapshot failure) \
654                         snapshot.count={:?}",
655                        snapshot.unmatched_angle_bracket_count,
656                    );
657
658                    // Make a span over ${unmatched angle bracket count} characters.
659                    // This is safe because `all_angle_brackets` ensures that there are only `<`s,
660                    // i.e. no multibyte characters, in this range.
661                    let span = lo
662                        .with_hi(lo.lo() + BytePos(snapshot.unmatched_angle_bracket_count.into()));
663                    self.dcx().emit_err(errors::UnmatchedAngle {
664                        span,
665                        plural: snapshot.unmatched_angle_bracket_count > 1,
666                    });
667
668                    // Try again without unmatched angle bracket characters.
669                    self.parse_angle_args(ty_generics)
670                }
671            }
672            Err(e) => {
673                self.angle_bracket_nesting -= 1;
674                Err(e)
675            }
676        }
677    }
678
679    /// Parses (possibly empty) list of generic arguments / associated item constraints,
680    /// possibly including trailing comma.
681    pub(super) fn parse_angle_args(
682        &mut self,
683        ty_generics: Option<&Generics>,
684    ) -> PResult<'a, ThinVec<AngleBracketedArg>> {
685        let mut args = ThinVec::new();
686        while let Some(arg) = self.parse_angle_arg(ty_generics)? {
687            args.push(arg);
688            if !self.eat(exp!(Comma)) {
689                if self.check_noexpect(&TokenKind::Semi)
690                    && self.look_ahead(1, |t| t.is_ident() || t.is_lifetime())
691                {
692                    // Add `>` to the list of expected tokens.
693                    self.check(exp!(Gt));
694                    // Handle `,` to `;` substitution
695                    let mut err = self.unexpected().unwrap_err();
696                    self.bump();
697                    err.span_suggestion_verbose(
698                        self.prev_token.span.until(self.token.span),
699                        "use a comma to separate type parameters",
700                        ", ",
701                        Applicability::MachineApplicable,
702                    );
703                    err.emit();
704                    continue;
705                }
706                if !self.token.kind.should_end_const_arg()
707                    && self.handle_ambiguous_unbraced_const_arg(&mut args)?
708                {
709                    // We've managed to (partially) recover, so continue trying to parse
710                    // arguments.
711                    continue;
712                }
713                break;
714            }
715        }
716        Ok(args)
717    }
718
719    /// Parses a single argument in the angle arguments `<...>` of a path segment.
720    fn parse_angle_arg(
721        &mut self,
722        ty_generics: Option<&Generics>,
723    ) -> PResult<'a, Option<AngleBracketedArg>> {
724        let lo = self.token.span;
725        let arg = self.parse_generic_arg(ty_generics)?;
726        match arg {
727            Some(arg) => {
728                // we are using noexpect here because we first want to find out if either `=` or `:`
729                // is present and then use that info to push the other token onto the tokens list
730                let separated =
731                    self.check_noexpect(&token::Colon) || self.check_noexpect(&token::Eq);
732                if separated && (self.check(exp!(Colon)) | self.check(exp!(Eq))) {
733                    let arg_span = arg.span();
734                    let (binder, ident, gen_args) = match self.get_ident_from_generic_arg(&arg) {
735                        Ok(ident_gen_args) => ident_gen_args,
736                        Err(()) => return Ok(Some(AngleBracketedArg::Arg(arg))),
737                    };
738                    if binder {
739                        // FIXME(compiler-errors): this could be improved by suggesting lifting
740                        // this up to the trait, at least before this becomes real syntax.
741                        // e.g. `Trait<for<'a> Assoc = Ty>` -> `for<'a> Trait<Assoc = Ty>`
742                        return Err(self.dcx().struct_span_err(
743                            arg_span,
744                            "`for<...>` is not allowed on associated type bounds",
745                        ));
746                    }
747                    let kind = if self.eat(exp!(Colon)) {
748                        AssocItemConstraintKind::Bound { bounds: self.parse_generic_bounds()? }
749                    } else if self.eat(exp!(Eq)) {
750                        self.parse_assoc_equality_term(
751                            ident,
752                            gen_args.as_ref(),
753                            self.prev_token.span,
754                        )?
755                    } else {
756                        unreachable!();
757                    };
758
759                    let span = lo.to(self.prev_token.span);
760
761                    let constraint =
762                        AssocItemConstraint { id: ast::DUMMY_NODE_ID, ident, gen_args, kind, span };
763                    Ok(Some(AngleBracketedArg::Constraint(constraint)))
764                } else {
765                    // we only want to suggest `:` and `=` in contexts where the previous token
766                    // is an ident and the current token or the next token is an ident
767                    if self.prev_token.is_ident()
768                        && (self.token.is_ident() || self.look_ahead(1, |token| token.is_ident()))
769                    {
770                        self.check(exp!(Colon));
771                        self.check(exp!(Eq));
772                    }
773                    Ok(Some(AngleBracketedArg::Arg(arg)))
774                }
775            }
776            _ => Ok(None),
777        }
778    }
779
780    /// Parse the term to the right of an associated item equality constraint.
781    ///
782    /// That is, parse `$term` in `Item = $term` where `$term` is a type or
783    /// a const expression (wrapped in curly braces if complex).
784    fn parse_assoc_equality_term(
785        &mut self,
786        ident: Ident,
787        gen_args: Option<&GenericArgs>,
788        eq: Span,
789    ) -> PResult<'a, AssocItemConstraintKind> {
790        let arg = self.parse_generic_arg(None)?;
791        let span = ident.span.to(self.prev_token.span);
792        let term = match arg {
793            Some(GenericArg::Type(ty)) => ty.into(),
794            Some(GenericArg::Const(c)) => {
795                self.psess.gated_spans.gate(sym::associated_const_equality, span);
796                c.into()
797            }
798            Some(GenericArg::Lifetime(lt)) => {
799                let guar = self.dcx().emit_err(errors::LifetimeInEqConstraint {
800                    span: lt.ident.span,
801                    lifetime: lt.ident,
802                    binding_label: span,
803                    colon_sugg: gen_args
804                        .map_or(ident.span, |args| args.span())
805                        .between(lt.ident.span),
806                });
807                self.mk_ty(lt.ident.span, ast::TyKind::Err(guar)).into()
808            }
809            None => {
810                let after_eq = eq.shrink_to_hi();
811                let before_next = self.token.span.shrink_to_lo();
812                let mut err = self
813                    .dcx()
814                    .struct_span_err(after_eq.to(before_next), "missing type to the right of `=`");
815                if matches!(self.token.kind, token::Comma | token::Gt) {
816                    err.span_suggestion(
817                        self.psess.source_map().next_point(eq).to(before_next),
818                        "to constrain the associated type, add a type after `=`",
819                        " TheType",
820                        Applicability::HasPlaceholders,
821                    );
822                    err.span_suggestion(
823                        eq.to(before_next),
824                        format!("remove the `=` if `{ident}` is a type"),
825                        "",
826                        Applicability::MaybeIncorrect,
827                    )
828                } else {
829                    err.span_label(
830                        self.token.span,
831                        format!("expected type, found {}", super::token_descr(&self.token)),
832                    )
833                };
834                return Err(err);
835            }
836        };
837        Ok(AssocItemConstraintKind::Equality { term })
838    }
839
840    /// We do not permit arbitrary expressions as const arguments. They must be one of:
841    /// - An expression surrounded in `{}`.
842    /// - A literal.
843    /// - A numeric literal prefixed by `-`.
844    /// - A single-segment path.
845    pub(super) fn expr_is_valid_const_arg(&self, expr: &P<rustc_ast::Expr>) -> bool {
846        match &expr.kind {
847            ast::ExprKind::Block(_, _)
848            | ast::ExprKind::Lit(_)
849            | ast::ExprKind::IncludedBytes(..) => true,
850            ast::ExprKind::Unary(ast::UnOp::Neg, expr) => {
851                matches!(expr.kind, ast::ExprKind::Lit(_))
852            }
853            // We can only resolve single-segment paths at the moment, because multi-segment paths
854            // require type-checking: see `visit_generic_arg` in `src/librustc_resolve/late.rs`.
855            ast::ExprKind::Path(None, path)
856                if let [segment] = path.segments.as_slice()
857                    && segment.args.is_none() =>
858            {
859                true
860            }
861            _ => false,
862        }
863    }
864
865    /// Parse a const argument, e.g. `<3>`. It is assumed the angle brackets will be parsed by
866    /// the caller.
867    pub(super) fn parse_const_arg(&mut self) -> PResult<'a, AnonConst> {
868        // Parse const argument.
869        let value = if self.token.kind == token::OpenBrace {
870            self.parse_expr_block(None, self.token.span, BlockCheckMode::Default)?
871        } else {
872            self.handle_unambiguous_unbraced_const_arg()?
873        };
874        Ok(AnonConst { id: ast::DUMMY_NODE_ID, value })
875    }
876
877    /// Parse a generic argument in a path segment.
878    /// This does not include constraints, e.g., `Item = u8`, which is handled in `parse_angle_arg`.
879    pub(super) fn parse_generic_arg(
880        &mut self,
881        ty_generics: Option<&Generics>,
882    ) -> PResult<'a, Option<GenericArg>> {
883        let start = self.token.span;
884        let arg = if self.check_lifetime() && self.look_ahead(1, |t| !t.is_like_plus()) {
885            // Parse lifetime argument.
886            GenericArg::Lifetime(self.expect_lifetime())
887        } else if self.check_const_arg() {
888            // Parse const argument.
889            GenericArg::Const(self.parse_const_arg()?)
890        } else if self.check_type() {
891            // Parse type argument.
892
893            // Proactively create a parser snapshot enabling us to rewind and try to reparse the
894            // input as a const expression in case we fail to parse a type. If we successfully
895            // do so, we will report an error that it needs to be wrapped in braces.
896            let mut snapshot = None;
897            if self.may_recover() && self.token.can_begin_expr() {
898                snapshot = Some(self.create_snapshot_for_diagnostic());
899            }
900
901            match self.parse_ty() {
902                Ok(ty) => {
903                    // Since the type parser recovers from some malformed slice and array types and
904                    // successfully returns a type, we need to look for `TyKind::Err`s in the
905                    // type to determine if error recovery has occurred and if the input is not a
906                    // syntactically valid type after all.
907                    if let ast::TyKind::Slice(inner_ty) | ast::TyKind::Array(inner_ty, _) = &ty.kind
908                        && let ast::TyKind::Err(_) = inner_ty.kind
909                        && let Some(snapshot) = snapshot
910                        && let Some(expr) =
911                            self.recover_unbraced_const_arg_that_can_begin_ty(snapshot)
912                    {
913                        return Ok(Some(
914                            self.dummy_const_arg_needs_braces(
915                                self.dcx()
916                                    .struct_span_err(expr.span, "invalid const generic expression"),
917                                expr.span,
918                            ),
919                        ));
920                    }
921
922                    GenericArg::Type(ty)
923                }
924                Err(err) => {
925                    if let Some(snapshot) = snapshot
926                        && let Some(expr) =
927                            self.recover_unbraced_const_arg_that_can_begin_ty(snapshot)
928                    {
929                        return Ok(Some(self.dummy_const_arg_needs_braces(err, expr.span)));
930                    }
931                    // Try to recover from possible `const` arg without braces.
932                    return self.recover_const_arg(start, err).map(Some);
933                }
934            }
935        } else if self.token.is_keyword(kw::Const) {
936            return self.recover_const_param_declaration(ty_generics);
937        } else {
938            // Fall back by trying to parse a const-expr expression. If we successfully do so,
939            // then we should report an error that it needs to be wrapped in braces.
940            let snapshot = self.create_snapshot_for_diagnostic();
941            let attrs = self.parse_outer_attributes()?;
942            match self.parse_expr_res(Restrictions::CONST_EXPR, attrs) {
943                Ok((expr, _)) => {
944                    return Ok(Some(self.dummy_const_arg_needs_braces(
945                        self.dcx().struct_span_err(expr.span, "invalid const generic expression"),
946                        expr.span,
947                    )));
948                }
949                Err(err) => {
950                    self.restore_snapshot(snapshot);
951                    err.cancel();
952                    return Ok(None);
953                }
954            }
955        };
956        Ok(Some(arg))
957    }
958
959    /// Given a arg inside of generics, we try to destructure it as if it were the LHS in
960    /// `LHS = ...`, i.e. an associated item binding.
961    /// This returns a bool indicating if there are any `for<'a, 'b>` binder args, the
962    /// identifier, and any GAT arguments.
963    fn get_ident_from_generic_arg(
964        &self,
965        gen_arg: &GenericArg,
966    ) -> Result<(bool, Ident, Option<GenericArgs>), ()> {
967        if let GenericArg::Type(ty) = gen_arg {
968            if let ast::TyKind::Path(qself, path) = &ty.kind
969                && qself.is_none()
970                && let [seg] = path.segments.as_slice()
971            {
972                return Ok((false, seg.ident, seg.args.as_deref().cloned()));
973            } else if let ast::TyKind::TraitObject(bounds, ast::TraitObjectSyntax::None) = &ty.kind
974                && let [ast::GenericBound::Trait(trait_ref)] = bounds.as_slice()
975                && trait_ref.modifiers == ast::TraitBoundModifiers::NONE
976                && let [seg] = trait_ref.trait_ref.path.segments.as_slice()
977            {
978                return Ok((true, seg.ident, seg.args.as_deref().cloned()));
979            }
980        }
981        Err(())
982    }
983}
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