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