]>
Commit | Line | Data |
---|---|---|
416331ca XL |
1 | use super::{Parser, PResult}; |
2 | ||
3 | use crate::ast::{self, WhereClause, GenericParam, GenericParamKind, GenericBounds, Attribute}; | |
4 | use crate::parse::token; | |
5 | use crate::source_map::DUMMY_SP; | |
6 | use crate::symbol::kw; | |
7 | ||
8 | impl<'a> Parser<'a> { | |
9 | /// Parses bounds of a lifetime parameter `BOUND + BOUND + BOUND`, possibly with trailing `+`. | |
10 | /// | |
11 | /// ``` | |
12 | /// BOUND = LT_BOUND (e.g., `'a`) | |
13 | /// ``` | |
14 | fn parse_lt_param_bounds(&mut self) -> GenericBounds { | |
15 | let mut lifetimes = Vec::new(); | |
16 | while self.check_lifetime() { | |
17 | lifetimes.push(ast::GenericBound::Outlives(self.expect_lifetime())); | |
18 | ||
19 | if !self.eat_plus() { | |
20 | break | |
21 | } | |
22 | } | |
23 | lifetimes | |
24 | } | |
25 | ||
26 | /// Matches `typaram = IDENT (`?` unbound)? optbounds ( EQ ty )?`. | |
27 | fn parse_ty_param(&mut self, | |
28 | preceding_attrs: Vec<Attribute>) | |
29 | -> PResult<'a, GenericParam> { | |
30 | let ident = self.parse_ident()?; | |
31 | ||
32 | // Parse optional colon and param bounds. | |
33 | let bounds = if self.eat(&token::Colon) { | |
34 | self.parse_generic_bounds(Some(self.prev_span))? | |
35 | } else { | |
36 | Vec::new() | |
37 | }; | |
38 | ||
39 | let default = if self.eat(&token::Eq) { | |
40 | Some(self.parse_ty()?) | |
41 | } else { | |
42 | None | |
43 | }; | |
44 | ||
45 | Ok(GenericParam { | |
46 | ident, | |
47 | id: ast::DUMMY_NODE_ID, | |
48 | attrs: preceding_attrs.into(), | |
49 | bounds, | |
50 | kind: GenericParamKind::Type { | |
51 | default, | |
e1599b0c XL |
52 | }, |
53 | is_placeholder: false | |
416331ca XL |
54 | }) |
55 | } | |
56 | ||
57 | fn parse_const_param(&mut self, preceding_attrs: Vec<Attribute>) -> PResult<'a, GenericParam> { | |
e74abb32 XL |
58 | let lo = self.token.span; |
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 | ||
e74abb32 XL |
65 | self.sess.gated_spans.const_generics.borrow_mut().push(lo.to(self.prev_span)); |
66 | ||
416331ca XL |
67 | Ok(GenericParam { |
68 | ident, | |
69 | id: ast::DUMMY_NODE_ID, | |
70 | attrs: preceding_attrs.into(), | |
71 | bounds: Vec::new(), | |
72 | kind: GenericParamKind::Const { | |
73 | ty, | |
e1599b0c XL |
74 | }, |
75 | is_placeholder: false | |
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 XL |
82 | let mut params = Vec::new(); |
83 | loop { | |
84 | let attrs = self.parse_outer_attributes()?; | |
85 | if self.check_lifetime() { | |
86 | let lifetime = self.expect_lifetime(); | |
87 | // Parse lifetime parameter. | |
88 | let bounds = if self.eat(&token::Colon) { | |
89 | self.parse_lt_param_bounds() | |
90 | } else { | |
91 | Vec::new() | |
92 | }; | |
93 | params.push(ast::GenericParam { | |
94 | ident: lifetime.ident, | |
95 | id: lifetime.id, | |
96 | attrs: attrs.into(), | |
97 | bounds, | |
98 | kind: ast::GenericParamKind::Lifetime, | |
e1599b0c | 99 | is_placeholder: false |
416331ca XL |
100 | }); |
101 | } else if self.check_keyword(kw::Const) { | |
102 | // Parse const parameter. | |
103 | params.push(self.parse_const_param(attrs)?); | |
104 | } else if self.check_ident() { | |
105 | // Parse type parameter. | |
106 | params.push(self.parse_ty_param(attrs)?); | |
e1599b0c XL |
107 | } else if self.token.can_begin_type() { |
108 | // Trying to write an associated type bound? (#26271) | |
109 | let snapshot = self.clone(); | |
110 | match self.parse_ty_where_predicate() { | |
111 | Ok(where_predicate) => { | |
112 | self.struct_span_err( | |
113 | where_predicate.span(), | |
114 | "bounds on associated types do not belong here", | |
115 | ) | |
116 | .span_label(where_predicate.span(), "belongs in `where` clause") | |
117 | .emit(); | |
118 | } | |
119 | Err(mut err) => { | |
120 | err.cancel(); | |
121 | std::mem::replace(self, snapshot); | |
122 | break | |
123 | } | |
124 | } | |
416331ca XL |
125 | } else { |
126 | // Check for trailing attributes and stop parsing. | |
127 | if !attrs.is_empty() { | |
128 | if !params.is_empty() { | |
129 | self.struct_span_err( | |
130 | attrs[0].span, | |
e1599b0c | 131 | "trailing attribute after generic parameter", |
416331ca XL |
132 | ) |
133 | .span_label(attrs[0].span, "attributes must go before parameters") | |
134 | .emit(); | |
135 | } else { | |
136 | self.struct_span_err( | |
137 | attrs[0].span, | |
138 | &format!("attribute without generic parameters"), | |
139 | ) | |
140 | .span_label( | |
141 | attrs[0].span, | |
142 | "attributes are only permitted when preceding parameters", | |
143 | ) | |
144 | .emit(); | |
145 | } | |
146 | } | |
147 | break | |
148 | } | |
149 | ||
150 | if !self.eat(&token::Comma) { | |
151 | break | |
152 | } | |
153 | } | |
154 | Ok(params) | |
155 | } | |
156 | ||
157 | /// Parses a set of optional generic type parameter declarations. Where | |
158 | /// clauses are not parsed here, and must be added later via | |
159 | /// `parse_where_clause()`. | |
160 | /// | |
161 | /// matches generics = ( ) | ( < > ) | ( < typaramseq ( , )? > ) | ( < lifetimes ( , )? > ) | |
162 | /// | ( < lifetimes , typaramseq ( , )? > ) | |
163 | /// where typaramseq = ( typaram ) | ( typaram , typaramseq ) | |
164 | pub(super) fn parse_generics(&mut self) -> PResult<'a, ast::Generics> { | |
165 | let span_lo = self.token.span; | |
166 | let (params, span) = if self.eat_lt() { | |
167 | let params = self.parse_generic_params()?; | |
168 | self.expect_gt()?; | |
169 | (params, span_lo.to(self.prev_span)) | |
170 | } else { | |
171 | (vec![], self.prev_span.between(self.token.span)) | |
172 | }; | |
173 | Ok(ast::Generics { | |
174 | params, | |
175 | where_clause: WhereClause { | |
176 | predicates: Vec::new(), | |
177 | span: DUMMY_SP, | |
178 | }, | |
179 | span, | |
180 | }) | |
181 | } | |
182 | ||
183 | /// Parses an optional where-clause and places it in `generics`. | |
184 | /// | |
185 | /// ```ignore (only-for-syntax-highlight) | |
186 | /// where T : Trait<U, V> + 'b, 'a : 'b | |
187 | /// ``` | |
188 | pub(super) fn parse_where_clause(&mut self) -> PResult<'a, WhereClause> { | |
189 | let mut where_clause = WhereClause { | |
190 | predicates: Vec::new(), | |
191 | span: self.prev_span.to(self.prev_span), | |
192 | }; | |
193 | ||
194 | if !self.eat_keyword(kw::Where) { | |
195 | return Ok(where_clause); | |
196 | } | |
197 | let lo = self.prev_span; | |
198 | ||
199 | // We are considering adding generics to the `where` keyword as an alternative higher-rank | |
200 | // parameter syntax (as in `where<'a>` or `where<T>`. To avoid that being a breaking | |
201 | // change we parse those generics now, but report an error. | |
202 | if self.choose_generics_over_qpath() { | |
203 | let generics = self.parse_generics()?; | |
204 | self.struct_span_err( | |
205 | generics.span, | |
206 | "generic parameters on `where` clauses are reserved for future use", | |
207 | ) | |
208 | .span_label(generics.span, "currently unsupported") | |
209 | .emit(); | |
210 | } | |
211 | ||
212 | loop { | |
213 | let lo = self.token.span; | |
214 | if self.check_lifetime() && self.look_ahead(1, |t| !t.is_like_plus()) { | |
215 | let lifetime = self.expect_lifetime(); | |
216 | // Bounds starting with a colon are mandatory, but possibly empty. | |
217 | self.expect(&token::Colon)?; | |
218 | let bounds = self.parse_lt_param_bounds(); | |
219 | where_clause.predicates.push(ast::WherePredicate::RegionPredicate( | |
220 | ast::WhereRegionPredicate { | |
221 | span: lo.to(self.prev_span), | |
222 | lifetime, | |
223 | bounds, | |
224 | } | |
225 | )); | |
226 | } else if self.check_type() { | |
e1599b0c | 227 | where_clause.predicates.push(self.parse_ty_where_predicate()?); |
416331ca XL |
228 | } else { |
229 | break | |
230 | } | |
231 | ||
232 | if !self.eat(&token::Comma) { | |
233 | break | |
234 | } | |
235 | } | |
236 | ||
237 | where_clause.span = lo.to(self.prev_span); | |
238 | Ok(where_clause) | |
239 | } | |
240 | ||
e1599b0c XL |
241 | fn parse_ty_where_predicate(&mut self) -> PResult<'a, ast::WherePredicate> { |
242 | let lo = self.token.span; | |
243 | // Parse optional `for<'a, 'b>`. | |
244 | // This `for` is parsed greedily and applies to the whole predicate, | |
245 | // the bounded type can have its own `for` applying only to it. | |
246 | // Examples: | |
247 | // * `for<'a> Trait1<'a>: Trait2<'a /* ok */>` | |
248 | // * `(for<'a> Trait1<'a>): Trait2<'a /* not ok */>` | |
249 | // * `for<'a> for<'b> Trait1<'a, 'b>: Trait2<'a /* ok */, 'b /* not ok */>` | |
250 | let lifetime_defs = self.parse_late_bound_lifetime_defs()?; | |
251 | ||
252 | // Parse type with mandatory colon and (possibly empty) bounds, | |
253 | // or with mandatory equality sign and the second type. | |
254 | let ty = self.parse_ty()?; | |
255 | if self.eat(&token::Colon) { | |
256 | let bounds = self.parse_generic_bounds(Some(self.prev_span))?; | |
257 | Ok(ast::WherePredicate::BoundPredicate( | |
258 | ast::WhereBoundPredicate { | |
259 | span: lo.to(self.prev_span), | |
260 | bound_generic_params: lifetime_defs, | |
261 | bounded_ty: ty, | |
262 | bounds, | |
263 | } | |
264 | )) | |
265 | // FIXME: Decide what should be used here, `=` or `==`. | |
266 | // FIXME: We are just dropping the binders in lifetime_defs on the floor here. | |
267 | } else if self.eat(&token::Eq) || self.eat(&token::EqEq) { | |
268 | let rhs_ty = self.parse_ty()?; | |
269 | Ok(ast::WherePredicate::EqPredicate( | |
270 | ast::WhereEqPredicate { | |
271 | span: lo.to(self.prev_span), | |
272 | lhs_ty: ty, | |
273 | rhs_ty, | |
274 | id: ast::DUMMY_NODE_ID, | |
275 | } | |
276 | )) | |
277 | } else { | |
278 | self.unexpected() | |
279 | } | |
280 | } | |
281 | ||
416331ca XL |
282 | pub(super) fn choose_generics_over_qpath(&self) -> bool { |
283 | // There's an ambiguity between generic parameters and qualified paths in impls. | |
284 | // If we see `<` it may start both, so we have to inspect some following tokens. | |
285 | // The following combinations can only start generics, | |
286 | // but not qualified paths (with one exception): | |
287 | // `<` `>` - empty generic parameters | |
288 | // `<` `#` - generic parameters with attributes | |
289 | // `<` (LIFETIME|IDENT) `>` - single generic parameter | |
290 | // `<` (LIFETIME|IDENT) `,` - first generic parameter in a list | |
291 | // `<` (LIFETIME|IDENT) `:` - generic parameter with bounds | |
292 | // `<` (LIFETIME|IDENT) `=` - generic parameter with a default | |
293 | // `<` const - generic const parameter | |
294 | // The only truly ambiguous case is | |
295 | // `<` IDENT `>` `::` IDENT ... | |
296 | // we disambiguate it in favor of generics (`impl<T> ::absolute::Path<T> { ... }`) | |
297 | // because this is what almost always expected in practice, qualified paths in impls | |
298 | // (`impl <Type>::AssocTy { ... }`) aren't even allowed by type checker at the moment. | |
299 | self.token == token::Lt && | |
300 | (self.look_ahead(1, |t| t == &token::Pound || t == &token::Gt) || | |
301 | self.look_ahead(1, |t| t.is_lifetime() || t.is_ident()) && | |
302 | self.look_ahead(2, |t| t == &token::Gt || t == &token::Comma || | |
303 | t == &token::Colon || t == &token::Eq) || | |
304 | self.is_keyword_ahead(1, &[kw::Const])) | |
305 | } | |
306 | } |