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