1 use super::{ForceCollect, Parser, TrailingToken}
;
5 self as ast
, Attribute
, GenericBounds
, GenericParam
, GenericParamKind
, WhereClause
,
7 use rustc_errors
::{Applicability, PResult}
;
8 use rustc_span
::symbol
::kw
;
11 /// Parses bounds of a lifetime parameter `BOUND + BOUND + BOUND`, possibly with trailing `+`.
14 /// BOUND = LT_BOUND (e.g., `'a`)
16 fn parse_lt_param_bounds(&mut self) -> GenericBounds
{
17 let mut lifetimes
= Vec
::new();
18 while self.check_lifetime() {
19 lifetimes
.push(ast
::GenericBound
::Outlives(self.expect_lifetime()));
28 /// Matches `typaram = IDENT (`?` unbound)? optbounds ( EQ ty )?`.
29 fn parse_ty_param(&mut self, preceding_attrs
: Vec
<Attribute
>) -> PResult
<'a
, GenericParam
> {
30 let ident
= self.parse_ident()?
;
32 // Parse optional colon and param bounds.
33 let bounds
= if self.eat(&token
::Colon
) {
34 self.parse_generic_bounds(Some(self.prev_token
.span
))?
39 let default = if self.eat(&token
::Eq
) { Some(self.parse_ty()?) }
else { None }
;
43 id
: ast
::DUMMY_NODE_ID
,
44 attrs
: preceding_attrs
.into(),
46 kind
: GenericParamKind
::Type { default }
,
47 is_placeholder
: false,
51 crate fn parse_const_param(
53 preceding_attrs
: Vec
<Attribute
>,
54 ) -> PResult
<'a
, GenericParam
> {
55 let const_span
= self.token
.span
;
57 self.expect_keyword(kw
::Const
)?
;
58 let ident
= self.parse_ident()?
;
59 self.expect(&token
::Colon
)?
;
60 let ty
= self.parse_ty()?
;
62 // Parse optional const generics default value.
63 let default = if self.eat(&token
::Eq
) { Some(self.parse_const_arg()?) }
else { None }
;
67 id
: ast
::DUMMY_NODE_ID
,
68 attrs
: preceding_attrs
.into(),
70 kind
: GenericParamKind
::Const { ty, kw_span: const_span, default }
,
71 is_placeholder
: false,
75 /// Parses a (possibly empty) list of lifetime and type parameters, possibly including
76 /// a trailing comma and erroneous trailing attributes.
77 pub(super) fn parse_generic_params(&mut self) -> PResult
<'a
, Vec
<ast
::GenericParam
>> {
78 let mut params
= Vec
::new();
81 let attrs
= self.parse_outer_attributes()?
;
83 self.collect_tokens_trailing_token(attrs
, ForceCollect
::No
, |this
, attrs
| {
84 if this
.eat_keyword_noexpect(kw
::SelfUpper
) {
85 // `Self` as a generic param is invalid. Here we emit the diagnostic and continue parsing
86 // as if `Self` never existed.
89 "unexpected keyword `Self` in generic parameters",
91 .note("you cannot use `Self` as a generic parameter because it is reserved for associated items")
94 this
.eat(&token
::Comma
);
97 let param
= if this
.check_lifetime() {
98 let lifetime
= this
.expect_lifetime();
99 // Parse lifetime parameter.
100 let bounds
= if this
.eat(&token
::Colon
) {
101 this
.parse_lt_param_bounds()
105 Some(ast
::GenericParam
{
106 ident
: lifetime
.ident
,
110 kind
: ast
::GenericParamKind
::Lifetime
,
111 is_placeholder
: false,
113 } else if this
.check_keyword(kw
::Const
) {
114 // Parse const parameter.
115 Some(this
.parse_const_param(attrs
)?
)
116 } else if this
.check_ident() {
117 // Parse type parameter.
118 Some(this
.parse_ty_param(attrs
)?
)
119 } else if this
.token
.can_begin_type() {
120 // Trying to write an associated type bound? (#26271)
121 let snapshot
= this
.create_snapshot_for_diagnostic();
122 match this
.parse_ty_where_predicate() {
123 Ok(where_predicate
) => {
124 this
.struct_span_err(
125 where_predicate
.span(),
126 "bounds on associated types do not belong here",
128 .span_label(where_predicate
.span(), "belongs in `where` clause")
130 // FIXME - try to continue parsing other generics?
131 return Ok((None
, TrailingToken
::None
));
135 // FIXME - maybe we should overwrite 'self' outside of `collect_tokens`?
136 this
.restore_snapshot(snapshot
);
137 return Ok((None
, TrailingToken
::None
));
141 // Check for trailing attributes and stop parsing.
142 if !attrs
.is_empty() {
143 if !params
.is_empty() {
144 this
.struct_span_err(
146 "trailing attribute after generic parameter",
148 .span_label(attrs
[0].span
, "attributes must go before parameters")
151 this
.struct_span_err(
153 "attribute without generic parameters",
157 "attributes are only permitted when preceding parameters",
162 return Ok((None
, TrailingToken
::None
));
165 if !this
.eat(&token
::Comma
) {
168 // We just ate the comma, so no need to use `TrailingToken`
169 Ok((param
, TrailingToken
::None
))
172 if let Some(param
) = param
{
181 /// Parses a set of optional generic type parameter declarations. Where
182 /// clauses are not parsed here, and must be added later via
183 /// `parse_where_clause()`.
185 /// matches generics = ( ) | ( < > ) | ( < typaramseq ( , )? > ) | ( < lifetimes ( , )? > )
186 /// | ( < lifetimes , typaramseq ( , )? > )
187 /// where typaramseq = ( typaram ) | ( typaram , typaramseq )
188 pub(super) fn parse_generics(&mut self) -> PResult
<'a
, ast
::Generics
> {
189 let span_lo
= self.token
.span
;
190 let (params
, span
) = if self.eat_lt() {
191 let params
= self.parse_generic_params()?
;
193 (params
, span_lo
.to(self.prev_token
.span
))
195 (vec
![], self.prev_token
.span
.shrink_to_hi())
199 where_clause
: WhereClause
{
200 has_where_token
: false,
201 predicates
: Vec
::new(),
202 span
: self.prev_token
.span
.shrink_to_hi(),
208 /// Parses an optional where-clause and places it in `generics`.
210 /// ```ignore (only-for-syntax-highlight)
211 /// where T : Trait<U, V> + 'b, 'a : 'b
213 pub(super) fn parse_where_clause(&mut self) -> PResult
<'a
, WhereClause
> {
214 let mut where_clause
= WhereClause
{
215 has_where_token
: false,
216 predicates
: Vec
::new(),
217 span
: self.prev_token
.span
.shrink_to_hi(),
220 if !self.eat_keyword(kw
::Where
) {
221 return Ok(where_clause
);
223 where_clause
.has_where_token
= true;
224 let lo
= self.prev_token
.span
;
226 // We are considering adding generics to the `where` keyword as an alternative higher-rank
227 // parameter syntax (as in `where<'a>` or `where<T>`. To avoid that being a breaking
228 // change we parse those generics now, but report an error.
229 if self.choose_generics_over_qpath(0) {
230 let generics
= self.parse_generics()?
;
231 self.struct_span_err(
233 "generic parameters on `where` clauses are reserved for future use",
235 .span_label(generics
.span
, "currently unsupported")
240 let lo
= self.token
.span
;
241 if self.check_lifetime() && self.look_ahead(1, |t
| !t
.is_like_plus()) {
242 let lifetime
= self.expect_lifetime();
243 // Bounds starting with a colon are mandatory, but possibly empty.
244 self.expect(&token
::Colon
)?
;
245 let bounds
= self.parse_lt_param_bounds();
246 where_clause
.predicates
.push(ast
::WherePredicate
::RegionPredicate(
247 ast
::WhereRegionPredicate
{
248 span
: lo
.to(self.prev_token
.span
),
253 } else if self.check_type() {
254 where_clause
.predicates
.push(self.parse_ty_where_predicate()?
);
259 let prev_token
= self.prev_token
.span
;
260 let ate_comma
= self.eat(&token
::Comma
);
262 if self.eat_keyword_noexpect(kw
::Where
) {
263 let msg
= "cannot define duplicate `where` clauses on an item";
264 let mut err
= self.struct_span_err(self.token
.span
, msg
);
265 err
.span_label(lo
, "previous `where` clause starts here");
266 err
.span_suggestion_verbose(
267 prev_token
.shrink_to_hi().to(self.prev_token
.span
),
268 "consider joining the two `where` clauses into one",
270 Applicability
::MaybeIncorrect
,
273 } else if !ate_comma
{
278 where_clause
.span
= lo
.to(self.prev_token
.span
);
282 fn parse_ty_where_predicate(&mut self) -> PResult
<'a
, ast
::WherePredicate
> {
283 let lo
= self.token
.span
;
284 // Parse optional `for<'a, 'b>`.
285 // This `for` is parsed greedily and applies to the whole predicate,
286 // the bounded type can have its own `for` applying only to it.
288 // * `for<'a> Trait1<'a>: Trait2<'a /* ok */>`
289 // * `(for<'a> Trait1<'a>): Trait2<'a /* not ok */>`
290 // * `for<'a> for<'b> Trait1<'a, 'b>: Trait2<'a /* ok */, 'b /* not ok */>`
291 let lifetime_defs
= self.parse_late_bound_lifetime_defs()?
;
293 // Parse type with mandatory colon and (possibly empty) bounds,
294 // or with mandatory equality sign and the second type.
295 let ty
= self.parse_ty_for_where_clause()?
;
296 if self.eat(&token
::Colon
) {
297 let bounds
= self.parse_generic_bounds(Some(self.prev_token
.span
))?
;
298 Ok(ast
::WherePredicate
::BoundPredicate(ast
::WhereBoundPredicate
{
299 span
: lo
.to(self.prev_token
.span
),
300 bound_generic_params
: lifetime_defs
,
304 // FIXME: Decide what should be used here, `=` or `==`.
305 // FIXME: We are just dropping the binders in lifetime_defs on the floor here.
306 } else if self.eat(&token
::Eq
) || self.eat(&token
::EqEq
) {
307 let rhs_ty
= self.parse_ty()?
;
308 Ok(ast
::WherePredicate
::EqPredicate(ast
::WhereEqPredicate
{
309 span
: lo
.to(self.prev_token
.span
),
312 id
: ast
::DUMMY_NODE_ID
,
315 self.maybe_recover_bounds_doubled_colon(&ty
)?
;
320 pub(super) fn choose_generics_over_qpath(&self, start
: usize) -> bool
{
321 // There's an ambiguity between generic parameters and qualified paths in impls.
322 // If we see `<` it may start both, so we have to inspect some following tokens.
323 // The following combinations can only start generics,
324 // but not qualified paths (with one exception):
325 // `<` `>` - empty generic parameters
326 // `<` `#` - generic parameters with attributes
327 // `<` (LIFETIME|IDENT) `>` - single generic parameter
328 // `<` (LIFETIME|IDENT) `,` - first generic parameter in a list
329 // `<` (LIFETIME|IDENT) `:` - generic parameter with bounds
330 // `<` (LIFETIME|IDENT) `=` - generic parameter with a default
331 // `<` const - generic const parameter
332 // The only truly ambiguous case is
333 // `<` IDENT `>` `::` IDENT ...
334 // we disambiguate it in favor of generics (`impl<T> ::absolute::Path<T> { ... }`)
335 // because this is what almost always expected in practice, qualified paths in impls
336 // (`impl <Type>::AssocTy { ... }`) aren't even allowed by type checker at the moment.
337 self.look_ahead(start
, |t
| t
== &token
::Lt
)
338 && (self.look_ahead(start
+ 1, |t
| t
== &token
::Pound
|| t
== &token
::Gt
)
339 || self.look_ahead(start
+ 1, |t
| t
.is_lifetime() || t
.is_ident())
340 && self.look_ahead(start
+ 2, |t
| {
341 matches
!(t
.kind
, token
::Gt
| token
::Comma
| token
::Colon
| token
::Eq
)
343 || self.is_keyword_ahead(start
+ 1, &[kw
::Const
]))