2 MultipleWhereClauses
, UnexpectedDefaultValueForLifetimeInGenericParameters
,
3 UnexpectedSelfInGenericParameters
, WhereClauseBeforeTupleStructBody
,
4 WhereClauseBeforeTupleStructBodySugg
,
7 use super::{ForceCollect, Parser, TrailingToken}
;
9 use ast
::token
::Delimiter
;
12 self as ast
, AttrVec
, GenericBounds
, GenericParam
, GenericParamKind
, TyKind
, WhereClause
,
14 use rustc_errors
::{Applicability, PResult}
;
15 use rustc_span
::symbol
::{kw, Ident}
;
17 use thin_vec
::ThinVec
;
19 enum PredicateOrStructBody
{
20 Predicate(ast
::WherePredicate
),
21 StructBody(ThinVec
<ast
::FieldDef
>),
25 /// Parses bounds of a lifetime parameter `BOUND + BOUND + BOUND`, possibly with trailing `+`.
28 /// BOUND = LT_BOUND (e.g., `'a`)
30 fn parse_lt_param_bounds(&mut self) -> GenericBounds
{
31 let mut lifetimes
= Vec
::new();
32 while self.check_lifetime() {
33 lifetimes
.push(ast
::GenericBound
::Outlives(self.expect_lifetime()));
42 /// Matches `typaram = IDENT (`?` unbound)? optbounds ( EQ ty )?`.
43 fn parse_ty_param(&mut self, preceding_attrs
: AttrVec
) -> PResult
<'a
, GenericParam
> {
44 let ident
= self.parse_ident()?
;
46 // Parse optional colon and param bounds.
47 let mut colon_span
= None
;
48 let bounds
= if self.eat(&token
::Colon
) {
49 colon_span
= Some(self.prev_token
.span
);
50 // recover from `impl Trait` in type param bound
51 if self.token
.is_keyword(kw
::Impl
) {
52 let impl_span
= self.token
.span
;
53 let snapshot
= self.create_snapshot_for_diagnostic();
54 match self.parse_ty() {
56 if let TyKind
::ImplTrait(_
, bounds
) = &(*p
).kind
{
57 let span
= impl_span
.to(self.token
.span
.shrink_to_lo());
58 let mut err
= self.struct_span_err(
60 "expected trait bound, found `impl Trait` type",
62 err
.span_label(span
, "not a trait");
63 if let [bound
, ..] = &bounds
[..] {
64 err
.span_suggestion_verbose(
65 impl_span
.until(bound
.span()),
66 "use the trait bounds directly",
68 Applicability
::MachineApplicable
,
79 self.restore_snapshot(snapshot
);
81 self.parse_generic_bounds(colon_span
)?
86 let default = if self.eat(&token
::Eq
) { Some(self.parse_ty()?) }
else { None }
;
89 id
: ast
::DUMMY_NODE_ID
,
90 attrs
: preceding_attrs
,
92 kind
: GenericParamKind
::Type { default }
,
93 is_placeholder
: false,
98 pub(crate) fn parse_const_param(
100 preceding_attrs
: AttrVec
,
101 ) -> PResult
<'a
, GenericParam
> {
102 let const_span
= self.token
.span
;
104 self.expect_keyword(kw
::Const
)?
;
105 let ident
= self.parse_ident()?
;
106 self.expect(&token
::Colon
)?
;
107 let ty
= self.parse_ty()?
;
109 // Parse optional const generics default value.
110 let default = if self.eat(&token
::Eq
) { Some(self.parse_const_arg()?) }
else { None }
;
114 id
: ast
::DUMMY_NODE_ID
,
115 attrs
: preceding_attrs
,
117 kind
: GenericParamKind
::Const { ty, kw_span: const_span, default }
,
118 is_placeholder
: false,
123 /// Parses a (possibly empty) list of lifetime and type parameters, possibly including
124 /// a trailing comma and erroneous trailing attributes.
125 pub(super) fn parse_generic_params(&mut self) -> PResult
<'a
, ThinVec
<ast
::GenericParam
>> {
126 let mut params
= ThinVec
::new();
127 let mut done
= false;
129 let attrs
= self.parse_outer_attributes()?
;
131 self.collect_tokens_trailing_token(attrs
, ForceCollect
::No
, |this
, attrs
| {
132 if this
.eat_keyword_noexpect(kw
::SelfUpper
) {
133 // `Self` as a generic param is invalid. Here we emit the diagnostic and continue parsing
134 // as if `Self` never existed.
135 this
.sess
.emit_err(UnexpectedSelfInGenericParameters
{
136 span
: this
.prev_token
.span
,
139 this
.eat(&token
::Comma
);
142 let param
= if this
.check_lifetime() {
143 let lifetime
= this
.expect_lifetime();
144 // Parse lifetime parameter.
145 let (colon_span
, bounds
) = if this
.eat(&token
::Colon
) {
146 (Some(this
.prev_token
.span
), this
.parse_lt_param_bounds())
151 if this
.check_noexpect(&token
::Eq
)
152 && this
.look_ahead(1, |t
| t
.is_lifetime())
154 let lo
= this
.token
.span
;
155 // Parse `= 'lifetime`.
157 this
.bump(); // `'lifetime`
158 let span
= lo
.to(this
.prev_token
.span
);
160 UnexpectedDefaultValueForLifetimeInGenericParameters { span }
,
164 Some(ast
::GenericParam
{
165 ident
: lifetime
.ident
,
169 kind
: ast
::GenericParamKind
::Lifetime
,
170 is_placeholder
: false,
173 } else if this
.check_keyword(kw
::Const
) {
174 // Parse const parameter.
175 Some(this
.parse_const_param(attrs
)?
)
176 } else if this
.check_ident() {
177 // Parse type parameter.
178 Some(this
.parse_ty_param(attrs
)?
)
179 } else if this
.token
.can_begin_type() {
180 // Trying to write an associated type bound? (#26271)
181 let snapshot
= this
.create_snapshot_for_diagnostic();
182 match this
.parse_ty_where_predicate() {
183 Ok(where_predicate
) => {
184 this
.struct_span_err(
185 where_predicate
.span(),
186 "bounds on associated types do not belong here",
188 .span_label(where_predicate
.span(), "belongs in `where` clause")
190 // FIXME - try to continue parsing other generics?
191 return Ok((None
, TrailingToken
::None
));
195 // FIXME - maybe we should overwrite 'self' outside of `collect_tokens`?
196 this
.restore_snapshot(snapshot
);
197 return Ok((None
, TrailingToken
::None
));
201 // Check for trailing attributes and stop parsing.
202 if !attrs
.is_empty() {
203 if !params
.is_empty() {
204 this
.struct_span_err(
206 "trailing attribute after generic parameter",
208 .span_label(attrs
[0].span
, "attributes must go before parameters")
211 this
.struct_span_err(
213 "attribute without generic parameters",
217 "attributes are only permitted when preceding parameters",
222 return Ok((None
, TrailingToken
::None
));
225 if !this
.eat(&token
::Comma
) {
228 // We just ate the comma, so no need to use `TrailingToken`
229 Ok((param
, TrailingToken
::None
))
232 if let Some(param
) = param
{
241 /// Parses a set of optional generic type parameter declarations. Where
242 /// clauses are not parsed here, and must be added later via
243 /// `parse_where_clause()`.
245 /// matches generics = ( ) | ( < > ) | ( < typaramseq ( , )? > ) | ( < lifetimes ( , )? > )
246 /// | ( < lifetimes , typaramseq ( , )? > )
247 /// where typaramseq = ( typaram ) | ( typaram , typaramseq )
248 pub(super) fn parse_generics(&mut self) -> PResult
<'a
, ast
::Generics
> {
249 let span_lo
= self.token
.span
;
250 let (params
, span
) = if self.eat_lt() {
251 let params
= self.parse_generic_params()?
;
253 (params
, span_lo
.to(self.prev_token
.span
))
255 (ThinVec
::new(), self.prev_token
.span
.shrink_to_hi())
259 where_clause
: WhereClause
{
260 has_where_token
: false,
261 predicates
: ThinVec
::new(),
262 span
: self.prev_token
.span
.shrink_to_hi(),
268 /// Parses an optional where-clause.
270 /// ```ignore (only-for-syntax-highlight)
271 /// where T : Trait<U, V> + 'b, 'a : 'b
273 pub(super) fn parse_where_clause(&mut self) -> PResult
<'a
, WhereClause
> {
274 self.parse_where_clause_common(None
).map(|(clause
, _
)| clause
)
277 pub(super) fn parse_struct_where_clause(
280 body_insertion_point
: Span
,
281 ) -> PResult
<'a
, (WhereClause
, Option
<ThinVec
<ast
::FieldDef
>>)> {
282 self.parse_where_clause_common(Some((struct_name
, body_insertion_point
)))
285 fn parse_where_clause_common(
287 struct_
: Option
<(Ident
, Span
)>,
288 ) -> PResult
<'a
, (WhereClause
, Option
<ThinVec
<ast
::FieldDef
>>)> {
289 let mut where_clause
= WhereClause
{
290 has_where_token
: false,
291 predicates
: ThinVec
::new(),
292 span
: self.prev_token
.span
.shrink_to_hi(),
294 let mut tuple_struct_body
= None
;
296 if !self.eat_keyword(kw
::Where
) {
297 return Ok((where_clause
, None
));
299 where_clause
.has_where_token
= true;
300 let where_lo
= self.prev_token
.span
;
302 // We are considering adding generics to the `where` keyword as an alternative higher-rank
303 // parameter syntax (as in `where<'a>` or `where<T>`. To avoid that being a breaking
304 // change we parse those generics now, but report an error.
305 if self.choose_generics_over_qpath(0) {
306 let generics
= self.parse_generics()?
;
307 self.struct_span_err(
309 "generic parameters on `where` clauses are reserved for future use",
311 .span_label(generics
.span
, "currently unsupported")
316 let where_sp
= where_lo
.to(self.prev_token
.span
);
317 let pred_lo
= self.token
.span
;
318 if self.check_lifetime() && self.look_ahead(1, |t
| !t
.is_like_plus()) {
319 let lifetime
= self.expect_lifetime();
320 // Bounds starting with a colon are mandatory, but possibly empty.
321 self.expect(&token
::Colon
)?
;
322 let bounds
= self.parse_lt_param_bounds();
323 where_clause
.predicates
.push(ast
::WherePredicate
::RegionPredicate(
324 ast
::WhereRegionPredicate
{
325 span
: pred_lo
.to(self.prev_token
.span
),
330 } else if self.check_type() {
331 match self.parse_ty_where_predicate_or_recover_tuple_struct_body(
332 struct_
, pred_lo
, where_sp
,
334 PredicateOrStructBody
::Predicate(pred
) => where_clause
.predicates
.push(pred
),
335 PredicateOrStructBody
::StructBody(body
) => {
336 tuple_struct_body
= Some(body
);
344 let prev_token
= self.prev_token
.span
;
345 let ate_comma
= self.eat(&token
::Comma
);
347 if self.eat_keyword_noexpect(kw
::Where
) {
348 self.sess
.emit_err(MultipleWhereClauses
{
349 span
: self.token
.span
,
351 between
: prev_token
.shrink_to_hi().to(self.prev_token
.span
),
353 } else if !ate_comma
{
358 where_clause
.span
= where_lo
.to(self.prev_token
.span
);
359 Ok((where_clause
, tuple_struct_body
))
362 fn parse_ty_where_predicate_or_recover_tuple_struct_body(
364 struct_
: Option
<(Ident
, Span
)>,
367 ) -> PResult
<'a
, PredicateOrStructBody
> {
368 let mut snapshot
= None
;
370 if let Some(struct_
) = struct_
371 && self.may_recover()
372 && self.token
.kind
== token
::OpenDelim(Delimiter
::Parenthesis
)
374 snapshot
= Some((struct_
, self.create_snapshot_for_diagnostic()));
377 match self.parse_ty_where_predicate() {
378 Ok(pred
) => Ok(PredicateOrStructBody
::Predicate(pred
)),
380 let Some(((struct_name
, body_insertion_point
), mut snapshot
)) = snapshot
else {
381 return Err(type_err
);
384 // Check if we might have encountered an out of place tuple struct body.
385 match snapshot
.parse_tuple_struct_body() {
386 // Since we don't know the exact reason why we failed to parse the
387 // predicate (we might have stumbled upon something bogus like `(T): ?`),
388 // employ a simple heuristic to weed out some pathological cases:
389 // Look for a semicolon (strong indicator) or anything that might mark
390 // the end of the item (weak indicator) following the body.
392 if matches
!(snapshot
.token
.kind
, token
::Semi
| token
::Eof
)
393 || snapshot
.token
.can_begin_item() =>
397 let body_sp
= pred_lo
.to(snapshot
.prev_token
.span
);
398 let map
= self.sess
.source_map();
400 self.sess
.emit_err(WhereClauseBeforeTupleStructBody
{
402 name
: struct_name
.span
,
404 sugg
: map
.span_to_snippet(body_sp
).ok().map(|body
| {
405 WhereClauseBeforeTupleStructBodySugg
{
406 left
: body_insertion_point
.shrink_to_hi(),
408 right
: map
.end_point(where_sp
).to(body_sp
),
413 self.restore_snapshot(snapshot
);
414 Ok(PredicateOrStructBody
::StructBody(body
))
416 Ok(_
) => Err(type_err
),
426 fn parse_ty_where_predicate(&mut self) -> PResult
<'a
, ast
::WherePredicate
> {
427 let lo
= self.token
.span
;
428 // Parse optional `for<'a, 'b>`.
429 // This `for` is parsed greedily and applies to the whole predicate,
430 // the bounded type can have its own `for` applying only to it.
432 // * `for<'a> Trait1<'a>: Trait2<'a /* ok */>`
433 // * `(for<'a> Trait1<'a>): Trait2<'a /* not ok */>`
434 // * `for<'a> for<'b> Trait1<'a, 'b>: Trait2<'a /* ok */, 'b /* not ok */>`
435 let lifetime_defs
= self.parse_late_bound_lifetime_defs()?
;
437 // Parse type with mandatory colon and (possibly empty) bounds,
438 // or with mandatory equality sign and the second type.
439 let ty
= self.parse_ty_for_where_clause()?
;
440 if self.eat(&token
::Colon
) {
441 let bounds
= self.parse_generic_bounds(Some(self.prev_token
.span
))?
;
442 Ok(ast
::WherePredicate
::BoundPredicate(ast
::WhereBoundPredicate
{
443 span
: lo
.to(self.prev_token
.span
),
444 bound_generic_params
: lifetime_defs
,
448 // FIXME: Decide what should be used here, `=` or `==`.
449 // FIXME: We are just dropping the binders in lifetime_defs on the floor here.
450 } else if self.eat(&token
::Eq
) || self.eat(&token
::EqEq
) {
451 let rhs_ty
= self.parse_ty()?
;
452 Ok(ast
::WherePredicate
::EqPredicate(ast
::WhereEqPredicate
{
453 span
: lo
.to(self.prev_token
.span
),
458 self.maybe_recover_bounds_doubled_colon(&ty
)?
;
463 pub(super) fn choose_generics_over_qpath(&self, start
: usize) -> bool
{
464 // There's an ambiguity between generic parameters and qualified paths in impls.
465 // If we see `<` it may start both, so we have to inspect some following tokens.
466 // The following combinations can only start generics,
467 // but not qualified paths (with one exception):
468 // `<` `>` - empty generic parameters
469 // `<` `#` - generic parameters with attributes
470 // `<` (LIFETIME|IDENT) `>` - single generic parameter
471 // `<` (LIFETIME|IDENT) `,` - first generic parameter in a list
472 // `<` (LIFETIME|IDENT) `:` - generic parameter with bounds
473 // `<` (LIFETIME|IDENT) `=` - generic parameter with a default
474 // `<` const - generic const parameter
475 // The only truly ambiguous case is
476 // `<` IDENT `>` `::` IDENT ...
477 // we disambiguate it in favor of generics (`impl<T> ::absolute::Path<T> { ... }`)
478 // because this is what almost always expected in practice, qualified paths in impls
479 // (`impl <Type>::AssocTy { ... }`) aren't even allowed by type checker at the moment.
480 self.look_ahead(start
, |t
| t
== &token
::Lt
)
481 && (self.look_ahead(start
+ 1, |t
| t
== &token
::Pound
|| t
== &token
::Gt
)
482 || self.look_ahead(start
+ 1, |t
| t
.is_lifetime() || t
.is_ident())
483 && self.look_ahead(start
+ 2, |t
| {
484 matches
!(t
.kind
, token
::Gt
| token
::Comma
| token
::Colon
| token
::Eq
)
486 || self.is_keyword_ahead(start
+ 1, &[kw
::Const
]))