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