1 use super::ty
::{AllowPlus, RecoverQPath, RecoverReturnSign}
;
2 use super::{Parser, Restrictions, TokenType}
;
3 use crate::maybe_whole
;
5 use rustc_ast
::token
::{self, Delimiter, Token, TokenKind}
;
7 self as ast
, AngleBracketedArg
, AngleBracketedArgs
, AnonConst
, AssocConstraint
,
8 AssocConstraintKind
, BlockCheckMode
, GenericArg
, GenericArgs
, Generics
, ParenthesizedArgs
,
9 Path
, PathSegment
, QSelf
,
11 use rustc_errors
::{pluralize, Applicability, PResult}
;
12 use rustc_span
::source_map
::{BytePos, Span}
;
13 use rustc_span
::symbol
::{kw, sym, Ident}
;
17 /// Specifies how to parse a path.
18 #[derive(Copy, Clone, PartialEq)]
20 /// In some contexts, notably in expressions, paths with generic arguments are ambiguous
21 /// with something else. For example, in expressions `segment < ....` can be interpreted
22 /// as a comparison and `segment ( ....` can be interpreted as a function call.
23 /// In all such contexts the non-path interpretation is preferred by default for practical
24 /// reasons, but the path interpretation can be forced by the disambiguator `::`, e.g.
25 /// `x<y>` - comparisons, `x::<y>` - unambiguously a path.
27 /// In other contexts, notably in types, no ambiguity exists and paths can be written
28 /// without the disambiguator, e.g., `x<y>` - unambiguously a path.
29 /// Paths with disambiguators are still accepted, `x::<Y>` - unambiguously a path too.
31 /// A path with generic arguments disallowed, e.g., `foo::bar::Baz`, used in imports,
32 /// visibilities or attributes.
33 /// Technically, this variant is unnecessary and e.g., `Expr` can be used instead
34 /// (paths in "mod" contexts have to be checked later for absence of generic arguments
35 /// anyway, due to macros), but it is used to avoid weird suggestions about expected
36 /// tokens when something goes wrong.
41 /// Parses a qualified path.
42 /// Assumes that the leading `<` has been parsed already.
44 /// `qualified_path = <type [as trait_ref]>::path`
49 /// `<T as U>::F::a<S>` (without disambiguator)
50 /// `<T as U>::F::a::<S>` (with disambiguator)
51 pub(super) fn parse_qpath(&mut self, style
: PathStyle
) -> PResult
<'a
, (QSelf
, Path
)> {
52 let lo
= self.prev_token
.span
;
53 let ty
= self.parse_ty()?
;
55 // `path` will contain the prefix of the path up to the `>`,
56 // if any (e.g., `U` in the `<T as U>::*` examples
57 // above). `path_span` has the span of that path, or an empty
58 // span in the case of something like `<T>::Bar`.
59 let (mut path
, path_span
);
60 if self.eat_keyword(kw
::As
) {
61 let path_lo
= self.token
.span
;
62 path
= self.parse_path(PathStyle
::Type
)?
;
63 path_span
= path_lo
.to(self.prev_token
.span
);
65 path_span
= self.token
.span
.to(self.token
.span
);
66 path
= ast
::Path { segments: Vec::new(), span: path_span, tokens: None }
;
69 // See doc comment for `unmatched_angle_bracket_count`.
70 self.expect(&token
::Gt
)?
;
71 if self.unmatched_angle_bracket_count
> 0 {
72 self.unmatched_angle_bracket_count
-= 1;
73 debug
!("parse_qpath: (decrement) count={:?}", self.unmatched_angle_bracket_count
);
76 if !self.recover_colon_before_qpath_proj() {
77 self.expect(&token
::ModSep
)?
;
80 let qself
= QSelf { ty, path_span, position: path.segments.len() }
;
81 self.parse_path_segments(&mut path
.segments
, style
, None
)?
;
85 Path { segments: path.segments, span: lo.to(self.prev_token.span), tokens: None }
,
89 /// Recover from an invalid single colon, when the user likely meant a qualified path.
90 /// We avoid emitting this if not followed by an identifier, as our assumption that the user
91 /// intended this to be a qualified path may not be correct.
93 /// ```ignore (diagnostics)
94 /// <Bar as Baz<T>>:Qux
95 /// ^ help: use double colon
97 fn recover_colon_before_qpath_proj(&mut self) -> bool
{
98 if !self.check_noexpect(&TokenKind
::Colon
)
99 || self.look_ahead(1, |t
| !t
.is_ident() || t
.is_reserved_ident())
104 self.bump(); // colon
108 self.prev_token
.span
,
109 "found single colon before projection in qualified path",
112 self.prev_token
.span
,
115 Applicability
::MachineApplicable
,
122 pub(super) fn parse_path(&mut self, style
: PathStyle
) -> PResult
<'a
, Path
> {
123 self.parse_path_inner(style
, None
)
126 /// Parses simple paths.
128 /// `path = [::] segment+`
129 /// `segment = ident | ident[::]<args> | ident[::](args) [-> type]`
132 /// `a::b::C<D>` (without disambiguator)
133 /// `a::b::C::<D>` (with disambiguator)
134 /// `Fn(Args)` (without disambiguator)
135 /// `Fn::(Args)` (with disambiguator)
136 pub(super) fn parse_path_inner(
139 ty_generics
: Option
<&Generics
>,
140 ) -> PResult
<'a
, Path
> {
141 let reject_generics_if_mod_style
= |parser
: &Parser
<'_
>, path
: &Path
| {
142 // Ensure generic arguments don't end up in attribute paths, such as:
145 // ($p:path) => { #[$p] struct S; }
148 // m!(inline<u8>); //~ ERROR: unexpected generic arguments in path
150 if style
== PathStyle
::Mod
&& path
.segments
.iter().any(|segment
| segment
.args
.is_some())
156 .filter_map(|segment
| segment
.args
.as_ref())
157 .map(|arg
| arg
.span())
158 .collect
::<Vec
<_
>>(),
159 "unexpected generic arguments in path",
165 maybe_whole
!(self, NtPath
, |path
| {
166 reject_generics_if_mod_style(self, &path
);
170 if let token
::Interpolated(nt
) = &self.token
.kind
{
171 if let token
::NtTy(ty
) = &**nt
{
172 if let ast
::TyKind
::Path(None
, path
) = &ty
.kind
{
173 let path
= path
.clone();
175 reject_generics_if_mod_style(self, &path
);
181 let lo
= self.token
.span
;
182 let mut segments
= Vec
::new();
183 let mod_sep_ctxt
= self.token
.span
.ctxt();
184 if self.eat(&token
::ModSep
) {
185 segments
.push(PathSegment
::path_root(lo
.shrink_to_lo().with_ctxt(mod_sep_ctxt
)));
187 self.parse_path_segments(&mut segments
, style
, ty_generics
)?
;
189 Ok(Path { segments, span: lo.to(self.prev_token.span), tokens: None }
)
192 pub(super) fn parse_path_segments(
194 segments
: &mut Vec
<PathSegment
>,
196 ty_generics
: Option
<&Generics
>,
197 ) -> PResult
<'a
, ()> {
199 let segment
= self.parse_path_segment(style
, ty_generics
)?
;
200 if style
== PathStyle
::Expr
{
201 // In order to check for trailing angle brackets, we must have finished
202 // recursing (`parse_path_segment` can indirectly call this function),
203 // that is, the next token must be the highlighted part of the below example:
205 // `Foo::<Bar as Baz<T>>::Qux`
208 // As opposed to the below highlight (if we had only finished the first
211 // `Foo::<Bar as Baz<T>>::Qux`
214 // `PathStyle::Expr` is only provided at the root invocation and never in
215 // `parse_path_segment` to recurse and therefore can be checked to maintain
217 self.check_trailing_angle_brackets(&segment
, &[&token
::ModSep
]);
219 segments
.push(segment
);
221 if self.is_import_coupler() || !self.eat(&token
::ModSep
) {
227 pub(super) fn parse_path_segment(
230 ty_generics
: Option
<&Generics
>,
231 ) -> PResult
<'a
, PathSegment
> {
232 let ident
= self.parse_path_segment_ident()?
;
233 let is_args_start
= |token
: &Token
| {
237 | token
::BinOp(token
::Shl
)
238 | token
::OpenDelim(Delimiter
::Parenthesis
)
242 let check_args_start
= |this
: &mut Self| {
243 this
.expected_tokens
.extend_from_slice(&[
244 TokenType
::Token(token
::Lt
),
245 TokenType
::Token(token
::OpenDelim(Delimiter
::Parenthesis
)),
247 is_args_start(&this
.token
)
251 if style
== PathStyle
::Type
&& check_args_start(self)
252 || style
!= PathStyle
::Mod
253 && self.check(&token
::ModSep
)
254 && self.look_ahead(1, |t
| is_args_start(t
))
256 // We use `style == PathStyle::Expr` to check if this is in a recursion or not. If
257 // it isn't, then we reset the unmatched angle bracket count as we're about to start
258 // parsing a new path.
259 if style
== PathStyle
::Expr
{
260 self.unmatched_angle_bracket_count
= 0;
261 self.max_angle_bracket_count
= 0;
264 // Generic arguments are found - `<`, `(`, `::<` or `::(`.
265 self.eat(&token
::ModSep
);
266 let lo
= self.token
.span
;
267 let args
= if self.eat_lt() {
269 let args
= self.parse_angle_args_with_leading_angle_bracket_recovery(
274 self.expect_gt().map_err(|mut err
| {
275 // Attempt to find places where a missing `>` might belong.
276 if let Some(arg
) = args
279 .skip_while(|arg
| matches
!(arg
, AngleBracketedArg
::Constraint(_
)))
282 err
.span_suggestion_verbose(
283 arg
.span().shrink_to_hi(),
284 "you might have meant to end the type parameters here",
286 Applicability
::MaybeIncorrect
,
291 let span
= lo
.to(self.prev_token
.span
);
292 AngleBracketedArgs { args, span }
.into()
295 let (inputs
, _
) = self.parse_paren_comma_seq(|p
| p
.parse_ty())?
;
296 let inputs_span
= lo
.to(self.prev_token
.span
);
298 self.parse_ret_ty(AllowPlus
::No
, RecoverQPath
::No
, RecoverReturnSign
::No
)?
;
299 let span
= ident
.span
.to(self.prev_token
.span
);
300 ParenthesizedArgs { span, inputs, inputs_span, output }
.into()
303 PathSegment { ident, args, id: ast::DUMMY_NODE_ID }
305 // Generic arguments are not found.
306 PathSegment
::from_ident(ident
)
311 pub(super) fn parse_path_segment_ident(&mut self) -> PResult
<'a
, Ident
> {
312 match self.token
.ident() {
313 Some((ident
, false)) if ident
.is_path_segment_keyword() => {
317 _
=> self.parse_ident(),
321 /// Parses generic args (within a path segment) with recovery for extra leading angle brackets.
322 /// For the purposes of understanding the parsing logic of generic arguments, this function
323 /// can be thought of being the same as just calling `self.parse_angle_args()` if the source
324 /// had the correct amount of leading angle brackets.
326 /// ```ignore (diagnostics)
327 /// bar::<<<<T as Foo>::Output>();
328 /// ^^ help: remove extra angle brackets
330 fn parse_angle_args_with_leading_angle_bracket_recovery(
334 ty_generics
: Option
<&Generics
>,
335 ) -> PResult
<'a
, Vec
<AngleBracketedArg
>> {
336 // We need to detect whether there are extra leading left angle brackets and produce an
337 // appropriate error and suggestion. This cannot be implemented by looking ahead at
338 // upcoming tokens for a matching `>` character - if there are unmatched `<` tokens
339 // then there won't be matching `>` tokens to find.
341 // To explain how this detection works, consider the following example:
343 // ```ignore (diagnostics)
344 // bar::<<<<T as Foo>::Output>();
345 // ^^ help: remove extra angle brackets
348 // Parsing of the left angle brackets starts in this function. We start by parsing the
349 // `<` token (incrementing the counter of unmatched angle brackets on `Parser` via
352 // *Upcoming tokens:* `<<<<T as Foo>::Output>;`
353 // *Unmatched count:* 1
354 // *`parse_path_segment` calls deep:* 0
356 // This has the effect of recursing as this function is called if a `<` character
357 // is found within the expected generic arguments:
359 // *Upcoming tokens:* `<<<T as Foo>::Output>;`
360 // *Unmatched count:* 2
361 // *`parse_path_segment` calls deep:* 1
363 // Eventually we will have recursed until having consumed all of the `<` tokens and
364 // this will be reflected in the count:
366 // *Upcoming tokens:* `T as Foo>::Output>;`
367 // *Unmatched count:* 4
368 // `parse_path_segment` calls deep:* 3
370 // The parser will continue until reaching the first `>` - this will decrement the
371 // unmatched angle bracket count and return to the parent invocation of this function
372 // having succeeded in parsing:
374 // *Upcoming tokens:* `::Output>;`
375 // *Unmatched count:* 3
376 // *`parse_path_segment` calls deep:* 2
378 // This will continue until the next `>` character which will also return successfully
379 // to the parent invocation of this function and decrement the count:
381 // *Upcoming tokens:* `;`
382 // *Unmatched count:* 2
383 // *`parse_path_segment` calls deep:* 1
385 // At this point, this function will expect to find another matching `>` character but
386 // won't be able to and will return an error. This will continue all the way up the
387 // call stack until the first invocation:
389 // *Upcoming tokens:* `;`
390 // *Unmatched count:* 2
391 // *`parse_path_segment` calls deep:* 0
393 // In doing this, we have managed to work out how many unmatched leading left angle
394 // brackets there are, but we cannot recover as the unmatched angle brackets have
395 // already been consumed. To remedy this, we keep a snapshot of the parser state
396 // before we do the above. We can then inspect whether we ended up with a parsing error
397 // and unmatched left angle brackets and if so, restore the parser state before we
398 // consumed any `<` characters to emit an error and consume the erroneous tokens to
399 // recover by attempting to parse again.
401 // In practice, the recursion of this function is indirect and there will be other
402 // locations that consume some `<` characters - as long as we update the count when
403 // this happens, it isn't an issue.
405 let is_first_invocation
= style
== PathStyle
::Expr
;
406 // Take a snapshot before attempting to parse - we can restore this later.
407 let snapshot
= if is_first_invocation { Some(self.clone()) }
else { None }
;
409 debug
!("parse_generic_args_with_leading_angle_bracket_recovery: (snapshotting)");
410 match self.parse_angle_args(ty_generics
) {
411 Ok(args
) => Ok(args
),
412 Err(e
) if is_first_invocation
&& self.unmatched_angle_bracket_count
> 0 => {
413 // Swap `self` with our backup of the parser state before attempting to parse
414 // generic arguments.
415 let snapshot
= mem
::replace(self, snapshot
.unwrap());
417 // Eat the unmatched angle brackets.
418 let all_angle_brackets
= (0..snapshot
.unmatched_angle_bracket_count
)
419 .fold(true, |a
, _
| a
&& self.eat_lt());
421 if !all_angle_brackets
{
422 // If there are other tokens in between the extraneous `<`s, we cannot simply
423 // suggest to remove them. This check also prevents us from accidentally ending
424 // up in the middle of a multibyte character (issue #84104).
425 let _
= mem
::replace(self, snapshot
);
428 // Cancel error from being unable to find `>`. We know the error
429 // must have been this due to a non-zero unmatched angle bracket
434 "parse_generic_args_with_leading_angle_bracket_recovery: (snapshot failure) \
435 snapshot.count={:?}",
436 snapshot
.unmatched_angle_bracket_count
,
439 // Make a span over ${unmatched angle bracket count} characters.
440 // This is safe because `all_angle_brackets` ensures that there are only `<`s,
441 // i.e. no multibyte characters, in this range.
443 lo
.with_hi(lo
.lo() + BytePos(snapshot
.unmatched_angle_bracket_count
));
444 self.struct_span_err(
447 "unmatched angle bracket{}",
448 pluralize
!(snapshot
.unmatched_angle_bracket_count
)
454 "remove extra angle bracket{}",
455 pluralize
!(snapshot
.unmatched_angle_bracket_count
)
458 Applicability
::MachineApplicable
,
462 // Try again without unmatched angle bracket characters.
463 self.parse_angle_args(ty_generics
)
470 /// Parses (possibly empty) list of generic arguments / associated item constraints,
471 /// possibly including trailing comma.
472 pub(super) fn parse_angle_args(
474 ty_generics
: Option
<&Generics
>,
475 ) -> PResult
<'a
, Vec
<AngleBracketedArg
>> {
476 let mut args
= Vec
::new();
477 while let Some(arg
) = self.parse_angle_arg(ty_generics
)?
{
479 if !self.eat(&token
::Comma
) {
480 if self.check_noexpect(&TokenKind
::Semi
)
481 && self.look_ahead(1, |t
| t
.is_ident() || t
.is_lifetime())
483 // Add `>` to the list of expected tokens.
484 self.check(&token
::Gt
);
485 // Handle `,` to `;` substitution
486 let mut err
= self.unexpected
::<()>().unwrap_err();
488 err
.span_suggestion_verbose(
489 self.prev_token
.span
.until(self.token
.span
),
490 "use a comma to separate type parameters",
492 Applicability
::MachineApplicable
,
497 if !self.token
.kind
.should_end_const_arg() {
498 if self.handle_ambiguous_unbraced_const_arg(&mut args
)?
{
499 // We've managed to (partially) recover, so continue trying to parse
510 /// Parses a single argument in the angle arguments `<...>` of a path segment.
513 ty_generics
: Option
<&Generics
>,
514 ) -> PResult
<'a
, Option
<AngleBracketedArg
>> {
515 let lo
= self.token
.span
;
516 let arg
= self.parse_generic_arg(ty_generics
)?
;
519 // we are using noexpect here because we first want to find out if either `=` or `:`
520 // is present and then use that info to push the other token onto the tokens list
522 self.check_noexpect(&token
::Colon
) || self.check_noexpect(&token
::Eq
);
523 if separated
&& (self.check(&token
::Colon
) | self.check(&token
::Eq
)) {
524 let arg_span
= arg
.span();
525 let (binder
, ident
, gen_args
) = match self.get_ident_from_generic_arg(&arg
) {
526 Ok(ident_gen_args
) => ident_gen_args
,
527 Err(()) => return Ok(Some(AngleBracketedArg
::Arg(arg
))),
530 // FIXME(compiler-errors): this could be improved by suggesting lifting
531 // this up to the trait, at least before this becomes real syntax.
532 // e.g. `Trait<for<'a> Assoc = Ty>` -> `for<'a> Trait<Assoc = Ty>`
533 return Err(self.struct_span_err(
535 "`for<...>` is not allowed on associated type bounds",
538 let kind
= if self.eat(&token
::Colon
) {
539 // Parse associated type constraint bound.
541 let bounds
= self.parse_generic_bounds(Some(self.prev_token
.span
))?
;
542 AssocConstraintKind
::Bound { bounds }
543 } else if self.eat(&token
::Eq
) {
544 self.parse_assoc_equality_term(ident
, self.prev_token
.span
)?
549 let span
= lo
.to(self.prev_token
.span
);
551 // Gate associated type bounds, e.g., `Iterator<Item: Ord>`.
552 if let AssocConstraintKind
::Bound { .. }
= kind
{
553 self.sess
.gated_spans
.gate(sym
::associated_type_bounds
, span
);
556 AssocConstraint { id: ast::DUMMY_NODE_ID, ident, gen_args, kind, span }
;
557 Ok(Some(AngleBracketedArg
::Constraint(constraint
)))
559 // we only want to suggest `:` and `=` in contexts where the previous token
560 // is an ident and the current token or the next token is an ident
561 if self.prev_token
.is_ident()
562 && (self.token
.is_ident() || self.look_ahead(1, |token
| token
.is_ident()))
564 self.check(&token
::Colon
);
565 self.check(&token
::Eq
);
567 Ok(Some(AngleBracketedArg
::Arg(arg
)))
574 /// Parse the term to the right of an associated item equality constraint.
575 /// That is, parse `<term>` in `Item = <term>`.
576 /// Right now, this only admits types in `<term>`.
577 fn parse_assoc_equality_term(
581 ) -> PResult
<'a
, AssocConstraintKind
> {
582 let arg
= self.parse_generic_arg(None
)?
;
583 let span
= ident
.span
.to(self.prev_token
.span
);
584 let term
= match arg
{
585 Some(GenericArg
::Type(ty
)) => ty
.into(),
586 Some(GenericArg
::Const(c
)) => {
587 self.sess
.gated_spans
.gate(sym
::associated_const_equality
, span
);
590 Some(GenericArg
::Lifetime(lt
)) => {
591 self.struct_span_err(span
, "associated lifetimes are not supported")
592 .span_label(lt
.ident
.span
, "the lifetime is given here")
593 .help("if you meant to specify a trait object, write `dyn Trait + 'lifetime`")
595 self.mk_ty(span
, ast
::TyKind
::Err
).into()
598 let after_eq
= eq
.shrink_to_hi();
599 let before_next
= self.token
.span
.shrink_to_lo();
601 .struct_span_err(after_eq
.to(before_next
), "missing type to the right of `=`");
602 if matches
!(self.token
.kind
, token
::Comma
| token
::Gt
) {
604 self.sess
.source_map().next_point(eq
).to(before_next
),
605 "to constrain the associated type, add a type after `=`",
607 Applicability
::HasPlaceholders
,
611 &format
!("remove the `=` if `{}` is a type", ident
),
613 Applicability
::MaybeIncorrect
,
618 &format
!("expected type, found {}", super::token_descr(&self.token
)),
624 Ok(AssocConstraintKind
::Equality { term }
)
627 /// We do not permit arbitrary expressions as const arguments. They must be one of:
628 /// - An expression surrounded in `{}`.
630 /// - A numeric literal prefixed by `-`.
631 /// - A single-segment path.
632 pub(super) fn expr_is_valid_const_arg(&self, expr
: &P
<rustc_ast
::Expr
>) -> bool
{
634 ast
::ExprKind
::Block(_
, _
) | ast
::ExprKind
::Lit(_
) => true,
635 ast
::ExprKind
::Unary(ast
::UnOp
::Neg
, expr
) => {
636 matches
!(expr
.kind
, ast
::ExprKind
::Lit(_
))
638 // We can only resolve single-segment paths at the moment, because multi-segment paths
639 // require type-checking: see `visit_generic_arg` in `src/librustc_resolve/late.rs`.
640 ast
::ExprKind
::Path(None
, path
)
641 if path
.segments
.len() == 1 && path
.segments
[0].args
.is_none() =>
649 /// Parse a const argument, e.g. `<3>`. It is assumed the angle brackets will be parsed by
651 pub(super) fn parse_const_arg(&mut self) -> PResult
<'a
, AnonConst
> {
652 // Parse const argument.
653 let value
= if let token
::OpenDelim(Delimiter
::Brace
) = self.token
.kind
{
654 self.parse_block_expr(None
, self.token
.span
, BlockCheckMode
::Default
)?
656 self.handle_unambiguous_unbraced_const_arg()?
658 Ok(AnonConst { id: ast::DUMMY_NODE_ID, value }
)
661 /// Parse a generic argument in a path segment.
662 /// This does not include constraints, e.g., `Item = u8`, which is handled in `parse_angle_arg`.
663 pub(super) fn parse_generic_arg(
665 ty_generics
: Option
<&Generics
>,
666 ) -> PResult
<'a
, Option
<GenericArg
>> {
667 let start
= self.token
.span
;
668 let arg
= if self.check_lifetime() && self.look_ahead(1, |t
| !t
.is_like_plus()) {
669 // Parse lifetime argument.
670 GenericArg
::Lifetime(self.expect_lifetime())
671 } else if self.check_const_arg() {
672 // Parse const argument.
673 GenericArg
::Const(self.parse_const_arg()?
)
674 } else if self.check_type() {
675 // Parse type argument.
677 self.look_ahead(1, |t
| t
.kind
== token
::OpenDelim(Delimiter
::Parenthesis
));
678 let mut snapshot
= self.create_snapshot_for_diagnostic();
679 match self.parse_ty() {
680 Ok(ty
) => GenericArg
::Type(ty
),
683 match (*snapshot
).parse_expr_res(Restrictions
::CONST_EXPR
, None
) {
685 self.restore_snapshot(snapshot
);
686 return Ok(Some(self.dummy_const_arg_needs_braces(err
, expr
.span
)));
693 // Try to recover from possible `const` arg without braces.
694 return self.recover_const_arg(start
, err
).map(Some
);
697 } else if self.token
.is_keyword(kw
::Const
) {
698 return self.recover_const_param_declaration(ty_generics
);
700 // Fall back by trying to parse a const-expr expression. If we successfully do so,
701 // then we should report an error that it needs to be wrapped in braces.
702 let snapshot
= self.create_snapshot_for_diagnostic();
703 match self.parse_expr_res(Restrictions
::CONST_EXPR
, None
) {
705 return Ok(Some(self.dummy_const_arg_needs_braces(
706 self.struct_span_err(expr
.span
, "invalid const generic expression"),
711 self.restore_snapshot(snapshot
);
720 /// Given a arg inside of generics, we try to destructure it as if it were the LHS in
721 /// `LHS = ...`, i.e. an associated type binding.
722 /// This returns a bool indicating if there are any `for<'a, 'b>` binder args, the
723 /// identifier, and any GAT arguments.
724 fn get_ident_from_generic_arg(
726 gen_arg
: &GenericArg
,
727 ) -> Result
<(bool
, Ident
, Option
<GenericArgs
>), ()> {
728 if let GenericArg
::Type(ty
) = gen_arg
{
729 if let ast
::TyKind
::Path(qself
, path
) = &ty
.kind
731 && let [seg
] = path
.segments
.as_slice()
733 return Ok((false, seg
.ident
, seg
.args
.as_deref().cloned()));
734 } else if let ast
::TyKind
::TraitObject(bounds
, ast
::TraitObjectSyntax
::None
) = &ty
.kind
735 && let [ast
::GenericBound
::Trait(trait_ref
, ast
::TraitBoundModifier
::None
)] =
737 && let [seg
] = trait_ref
.trait_ref
.path
.segments
.as_slice()
739 return Ok((true, seg
.ident
, seg
.args
.as_deref().cloned()));