]>
Commit | Line | Data |
---|---|---|
6a06907d | 1 | use super::{ForceCollect, Parser, TrailingToken}; |
60c5eb7d | 2 | |
74b04a01 | 3 | use rustc_ast::token; |
2b03887a FG |
4 | use rustc_ast::{ |
5 | self as ast, AttrVec, GenericBounds, GenericParam, GenericParamKind, TyKind, WhereClause, | |
6 | }; | |
5099ac24 | 7 | use rustc_errors::{Applicability, PResult}; |
a2a8927a | 8 | use rustc_span::symbol::kw; |
416331ca XL |
9 | |
10 | impl<'a> Parser<'a> { | |
11 | /// Parses bounds of a lifetime parameter `BOUND + BOUND + BOUND`, possibly with trailing `+`. | |
12 | /// | |
ba9703b0 | 13 | /// ```text |
416331ca XL |
14 | /// BOUND = LT_BOUND (e.g., `'a`) |
15 | /// ``` | |
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())); | |
20 | ||
21 | if !self.eat_plus() { | |
dfeec247 | 22 | break; |
416331ca XL |
23 | } |
24 | } | |
25 | lifetimes | |
26 | } | |
27 | ||
28 | /// Matches `typaram = IDENT (`?` unbound)? optbounds ( EQ ty )?`. | |
f2b60f7d | 29 | fn parse_ty_param(&mut self, preceding_attrs: AttrVec) -> PResult<'a, GenericParam> { |
416331ca XL |
30 | let ident = self.parse_ident()?; |
31 | ||
32 | // Parse optional colon and param bounds. | |
04454e1e | 33 | let mut colon_span = None; |
416331ca | 34 | let bounds = if self.eat(&token::Colon) { |
04454e1e | 35 | colon_span = Some(self.prev_token.span); |
2b03887a FG |
36 | // recover from `impl Trait` in type param bound |
37 | if self.token.is_keyword(kw::Impl) { | |
38 | let impl_span = self.token.span; | |
39 | let snapshot = self.create_snapshot_for_diagnostic(); | |
40 | match self.parse_ty() { | |
41 | Ok(p) => { | |
42 | if let TyKind::ImplTrait(_, bounds) = &(*p).kind { | |
43 | let span = impl_span.to(self.token.span.shrink_to_lo()); | |
44 | let mut err = self.struct_span_err( | |
45 | span, | |
46 | "expected trait bound, found `impl Trait` type", | |
47 | ); | |
48 | err.span_label(span, "not a trait"); | |
49 | if let [bound, ..] = &bounds[..] { | |
50 | err.span_suggestion_verbose( | |
51 | impl_span.until(bound.span()), | |
52 | "use the trait bounds directly", | |
53 | String::new(), | |
54 | Applicability::MachineApplicable, | |
55 | ); | |
56 | } | |
57 | err.emit(); | |
58 | return Err(err); | |
59 | } | |
60 | } | |
61 | Err(err) => { | |
62 | err.cancel(); | |
63 | } | |
64 | } | |
65 | self.restore_snapshot(snapshot); | |
66 | } | |
04454e1e | 67 | self.parse_generic_bounds(colon_span)? |
416331ca XL |
68 | } else { |
69 | Vec::new() | |
70 | }; | |
71 | ||
dfeec247 | 72 | let default = if self.eat(&token::Eq) { Some(self.parse_ty()?) } else { None }; |
416331ca XL |
73 | Ok(GenericParam { |
74 | ident, | |
75 | id: ast::DUMMY_NODE_ID, | |
f2b60f7d | 76 | attrs: preceding_attrs, |
416331ca | 77 | bounds, |
dfeec247 XL |
78 | kind: GenericParamKind::Type { default }, |
79 | is_placeholder: false, | |
04454e1e | 80 | colon_span, |
416331ca XL |
81 | }) |
82 | } | |
83 | ||
923072b8 | 84 | pub(crate) fn parse_const_param( |
3c0e092e | 85 | &mut self, |
f2b60f7d | 86 | preceding_attrs: AttrVec, |
3c0e092e | 87 | ) -> PResult<'a, GenericParam> { |
f035d41b | 88 | let const_span = self.token.span; |
e74abb32 | 89 | |
416331ca XL |
90 | self.expect_keyword(kw::Const)?; |
91 | let ident = self.parse_ident()?; | |
92 | self.expect(&token::Colon)?; | |
93 | let ty = self.parse_ty()?; | |
94 | ||
a2a8927a XL |
95 | // Parse optional const generics default value. |
96 | let default = if self.eat(&token::Eq) { Some(self.parse_const_arg()?) } else { None }; | |
e74abb32 | 97 | |
416331ca XL |
98 | Ok(GenericParam { |
99 | ident, | |
100 | id: ast::DUMMY_NODE_ID, | |
f2b60f7d | 101 | attrs: preceding_attrs, |
416331ca | 102 | bounds: Vec::new(), |
5869c6ff | 103 | kind: GenericParamKind::Const { ty, kw_span: const_span, default }, |
dfeec247 | 104 | is_placeholder: false, |
04454e1e | 105 | colon_span: None, |
416331ca XL |
106 | }) |
107 | } | |
108 | ||
109 | /// Parses a (possibly empty) list of lifetime and type parameters, possibly including | |
110 | /// a trailing comma and erroneous trailing attributes. | |
e74abb32 | 111 | pub(super) fn parse_generic_params(&mut self) -> PResult<'a, Vec<ast::GenericParam>> { |
416331ca | 112 | let mut params = Vec::new(); |
6a06907d XL |
113 | let mut done = false; |
114 | while !done { | |
416331ca | 115 | let attrs = self.parse_outer_attributes()?; |
6a06907d XL |
116 | let param = |
117 | self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| { | |
a2a8927a XL |
118 | if this.eat_keyword_noexpect(kw::SelfUpper) { |
119 | // `Self` as a generic param is invalid. Here we emit the diagnostic and continue parsing | |
120 | // as if `Self` never existed. | |
121 | this.struct_span_err( | |
122 | this.prev_token.span, | |
123 | "unexpected keyword `Self` in generic parameters", | |
124 | ) | |
125 | .note("you cannot use `Self` as a generic parameter because it is reserved for associated items") | |
126 | .emit(); | |
127 | ||
128 | this.eat(&token::Comma); | |
129 | } | |
130 | ||
6a06907d XL |
131 | let param = if this.check_lifetime() { |
132 | let lifetime = this.expect_lifetime(); | |
133 | // Parse lifetime parameter. | |
04454e1e FG |
134 | let (colon_span, bounds) = if this.eat(&token::Colon) { |
135 | (Some(this.prev_token.span), this.parse_lt_param_bounds()) | |
6a06907d | 136 | } else { |
04454e1e | 137 | (None, Vec::new()) |
6a06907d XL |
138 | }; |
139 | Some(ast::GenericParam { | |
140 | ident: lifetime.ident, | |
141 | id: lifetime.id, | |
f2b60f7d | 142 | attrs, |
6a06907d XL |
143 | bounds, |
144 | kind: ast::GenericParamKind::Lifetime, | |
145 | is_placeholder: false, | |
04454e1e | 146 | colon_span, |
6a06907d XL |
147 | }) |
148 | } else if this.check_keyword(kw::Const) { | |
149 | // Parse const parameter. | |
150 | Some(this.parse_const_param(attrs)?) | |
151 | } else if this.check_ident() { | |
152 | // Parse type parameter. | |
153 | Some(this.parse_ty_param(attrs)?) | |
154 | } else if this.token.can_begin_type() { | |
155 | // Trying to write an associated type bound? (#26271) | |
5e7ed085 | 156 | let snapshot = this.create_snapshot_for_diagnostic(); |
6a06907d XL |
157 | match this.parse_ty_where_predicate() { |
158 | Ok(where_predicate) => { | |
159 | this.struct_span_err( | |
160 | where_predicate.span(), | |
161 | "bounds on associated types do not belong here", | |
162 | ) | |
163 | .span_label(where_predicate.span(), "belongs in `where` clause") | |
164 | .emit(); | |
165 | // FIXME - try to continue parsing other generics? | |
166 | return Ok((None, TrailingToken::None)); | |
167 | } | |
5e7ed085 | 168 | Err(err) => { |
6a06907d XL |
169 | err.cancel(); |
170 | // FIXME - maybe we should overwrite 'self' outside of `collect_tokens`? | |
5e7ed085 | 171 | this.restore_snapshot(snapshot); |
6a06907d XL |
172 | return Ok((None, TrailingToken::None)); |
173 | } | |
174 | } | |
416331ca | 175 | } else { |
6a06907d XL |
176 | // Check for trailing attributes and stop parsing. |
177 | if !attrs.is_empty() { | |
178 | if !params.is_empty() { | |
179 | this.struct_span_err( | |
180 | attrs[0].span, | |
181 | "trailing attribute after generic parameter", | |
182 | ) | |
183 | .span_label(attrs[0].span, "attributes must go before parameters") | |
184 | .emit(); | |
185 | } else { | |
186 | this.struct_span_err( | |
187 | attrs[0].span, | |
188 | "attribute without generic parameters", | |
189 | ) | |
190 | .span_label( | |
191 | attrs[0].span, | |
192 | "attributes are only permitted when preceding parameters", | |
193 | ) | |
194 | .emit(); | |
195 | } | |
196 | } | |
197 | return Ok((None, TrailingToken::None)); | |
198 | }; | |
199 | ||
200 | if !this.eat(&token::Comma) { | |
201 | done = true; | |
416331ca | 202 | } |
6a06907d XL |
203 | // We just ate the comma, so no need to use `TrailingToken` |
204 | Ok((param, TrailingToken::None)) | |
205 | })?; | |
416331ca | 206 | |
6a06907d XL |
207 | if let Some(param) = param { |
208 | params.push(param); | |
209 | } else { | |
dfeec247 | 210 | break; |
416331ca XL |
211 | } |
212 | } | |
213 | Ok(params) | |
214 | } | |
215 | ||
216 | /// Parses a set of optional generic type parameter declarations. Where | |
217 | /// clauses are not parsed here, and must be added later via | |
218 | /// `parse_where_clause()`. | |
219 | /// | |
220 | /// matches generics = ( ) | ( < > ) | ( < typaramseq ( , )? > ) | ( < lifetimes ( , )? > ) | |
221 | /// | ( < lifetimes , typaramseq ( , )? > ) | |
222 | /// where typaramseq = ( typaram ) | ( typaram , typaramseq ) | |
223 | pub(super) fn parse_generics(&mut self) -> PResult<'a, ast::Generics> { | |
224 | let span_lo = self.token.span; | |
225 | let (params, span) = if self.eat_lt() { | |
226 | let params = self.parse_generic_params()?; | |
227 | self.expect_gt()?; | |
74b04a01 | 228 | (params, span_lo.to(self.prev_token.span)) |
416331ca | 229 | } else { |
74b04a01 | 230 | (vec![], self.prev_token.span.shrink_to_hi()) |
416331ca XL |
231 | }; |
232 | Ok(ast::Generics { | |
233 | params, | |
74b04a01 | 234 | where_clause: WhereClause { |
f035d41b | 235 | has_where_token: false, |
74b04a01 XL |
236 | predicates: Vec::new(), |
237 | span: self.prev_token.span.shrink_to_hi(), | |
238 | }, | |
416331ca XL |
239 | span, |
240 | }) | |
241 | } | |
242 | ||
243 | /// Parses an optional where-clause and places it in `generics`. | |
244 | /// | |
245 | /// ```ignore (only-for-syntax-highlight) | |
246 | /// where T : Trait<U, V> + 'b, 'a : 'b | |
247 | /// ``` | |
248 | pub(super) fn parse_where_clause(&mut self) -> PResult<'a, WhereClause> { | |
f035d41b XL |
249 | let mut where_clause = WhereClause { |
250 | has_where_token: false, | |
251 | predicates: Vec::new(), | |
252 | span: self.prev_token.span.shrink_to_hi(), | |
253 | }; | |
416331ca XL |
254 | |
255 | if !self.eat_keyword(kw::Where) { | |
256 | return Ok(where_clause); | |
257 | } | |
f035d41b | 258 | where_clause.has_where_token = true; |
74b04a01 | 259 | let lo = self.prev_token.span; |
416331ca XL |
260 | |
261 | // We are considering adding generics to the `where` keyword as an alternative higher-rank | |
262 | // parameter syntax (as in `where<'a>` or `where<T>`. To avoid that being a breaking | |
263 | // change we parse those generics now, but report an error. | |
ba9703b0 | 264 | if self.choose_generics_over_qpath(0) { |
416331ca XL |
265 | let generics = self.parse_generics()?; |
266 | self.struct_span_err( | |
267 | generics.span, | |
268 | "generic parameters on `where` clauses are reserved for future use", | |
269 | ) | |
dfeec247 XL |
270 | .span_label(generics.span, "currently unsupported") |
271 | .emit(); | |
416331ca XL |
272 | } |
273 | ||
274 | loop { | |
275 | let lo = self.token.span; | |
276 | if self.check_lifetime() && self.look_ahead(1, |t| !t.is_like_plus()) { | |
277 | let lifetime = self.expect_lifetime(); | |
278 | // Bounds starting with a colon are mandatory, but possibly empty. | |
279 | self.expect(&token::Colon)?; | |
280 | let bounds = self.parse_lt_param_bounds(); | |
281 | where_clause.predicates.push(ast::WherePredicate::RegionPredicate( | |
74b04a01 XL |
282 | ast::WhereRegionPredicate { |
283 | span: lo.to(self.prev_token.span), | |
284 | lifetime, | |
285 | bounds, | |
286 | }, | |
416331ca XL |
287 | )); |
288 | } else if self.check_type() { | |
e1599b0c | 289 | where_clause.predicates.push(self.parse_ty_where_predicate()?); |
416331ca | 290 | } else { |
dfeec247 | 291 | break; |
416331ca XL |
292 | } |
293 | ||
5099ac24 FG |
294 | let prev_token = self.prev_token.span; |
295 | let ate_comma = self.eat(&token::Comma); | |
296 | ||
297 | if self.eat_keyword_noexpect(kw::Where) { | |
298 | let msg = "cannot define duplicate `where` clauses on an item"; | |
299 | let mut err = self.struct_span_err(self.token.span, msg); | |
300 | err.span_label(lo, "previous `where` clause starts here"); | |
301 | err.span_suggestion_verbose( | |
302 | prev_token.shrink_to_hi().to(self.prev_token.span), | |
303 | "consider joining the two `where` clauses into one", | |
923072b8 | 304 | ",", |
5099ac24 FG |
305 | Applicability::MaybeIncorrect, |
306 | ); | |
307 | err.emit(); | |
308 | } else if !ate_comma { | |
dfeec247 | 309 | break; |
416331ca XL |
310 | } |
311 | } | |
312 | ||
74b04a01 | 313 | where_clause.span = lo.to(self.prev_token.span); |
416331ca XL |
314 | Ok(where_clause) |
315 | } | |
316 | ||
e1599b0c XL |
317 | fn parse_ty_where_predicate(&mut self) -> PResult<'a, ast::WherePredicate> { |
318 | let lo = self.token.span; | |
319 | // Parse optional `for<'a, 'b>`. | |
320 | // This `for` is parsed greedily and applies to the whole predicate, | |
321 | // the bounded type can have its own `for` applying only to it. | |
322 | // Examples: | |
323 | // * `for<'a> Trait1<'a>: Trait2<'a /* ok */>` | |
324 | // * `(for<'a> Trait1<'a>): Trait2<'a /* not ok */>` | |
325 | // * `for<'a> for<'b> Trait1<'a, 'b>: Trait2<'a /* ok */, 'b /* not ok */>` | |
326 | let lifetime_defs = self.parse_late_bound_lifetime_defs()?; | |
327 | ||
328 | // Parse type with mandatory colon and (possibly empty) bounds, | |
329 | // or with mandatory equality sign and the second type. | |
fc512014 | 330 | let ty = self.parse_ty_for_where_clause()?; |
e1599b0c | 331 | if self.eat(&token::Colon) { |
74b04a01 | 332 | let bounds = self.parse_generic_bounds(Some(self.prev_token.span))?; |
dfeec247 | 333 | Ok(ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate { |
74b04a01 | 334 | span: lo.to(self.prev_token.span), |
dfeec247 XL |
335 | bound_generic_params: lifetime_defs, |
336 | bounded_ty: ty, | |
337 | bounds, | |
338 | })) | |
e1599b0c XL |
339 | // FIXME: Decide what should be used here, `=` or `==`. |
340 | // FIXME: We are just dropping the binders in lifetime_defs on the floor here. | |
341 | } else if self.eat(&token::Eq) || self.eat(&token::EqEq) { | |
342 | let rhs_ty = self.parse_ty()?; | |
dfeec247 | 343 | Ok(ast::WherePredicate::EqPredicate(ast::WhereEqPredicate { |
74b04a01 | 344 | span: lo.to(self.prev_token.span), |
dfeec247 XL |
345 | lhs_ty: ty, |
346 | rhs_ty, | |
dfeec247 | 347 | })) |
e1599b0c | 348 | } else { |
5e7ed085 | 349 | self.maybe_recover_bounds_doubled_colon(&ty)?; |
e1599b0c XL |
350 | self.unexpected() |
351 | } | |
352 | } | |
353 | ||
ba9703b0 | 354 | pub(super) fn choose_generics_over_qpath(&self, start: usize) -> bool { |
416331ca XL |
355 | // There's an ambiguity between generic parameters and qualified paths in impls. |
356 | // If we see `<` it may start both, so we have to inspect some following tokens. | |
357 | // The following combinations can only start generics, | |
358 | // but not qualified paths (with one exception): | |
359 | // `<` `>` - empty generic parameters | |
360 | // `<` `#` - generic parameters with attributes | |
361 | // `<` (LIFETIME|IDENT) `>` - single generic parameter | |
362 | // `<` (LIFETIME|IDENT) `,` - first generic parameter in a list | |
363 | // `<` (LIFETIME|IDENT) `:` - generic parameter with bounds | |
364 | // `<` (LIFETIME|IDENT) `=` - generic parameter with a default | |
365 | // `<` const - generic const parameter | |
366 | // The only truly ambiguous case is | |
367 | // `<` IDENT `>` `::` IDENT ... | |
368 | // we disambiguate it in favor of generics (`impl<T> ::absolute::Path<T> { ... }`) | |
369 | // because this is what almost always expected in practice, qualified paths in impls | |
370 | // (`impl <Type>::AssocTy { ... }`) aren't even allowed by type checker at the moment. | |
ba9703b0 XL |
371 | self.look_ahead(start, |t| t == &token::Lt) |
372 | && (self.look_ahead(start + 1, |t| t == &token::Pound || t == &token::Gt) | |
373 | || self.look_ahead(start + 1, |t| t.is_lifetime() || t.is_ident()) | |
374 | && self.look_ahead(start + 2, |t| { | |
375 | matches!(t.kind, token::Gt | token::Comma | token::Colon | token::Eq) | |
dfeec247 | 376 | }) |
ba9703b0 | 377 | || self.is_keyword_ahead(start + 1, &[kw::Const])) |
416331ca XL |
378 | } |
379 | } |