]>
Commit | Line | Data |
---|---|---|
fc512014 | 1 | use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign}; |
60c5eb7d XL |
2 | use super::{Parser, TokenType}; |
3 | use crate::maybe_whole; | |
ba9703b0 | 4 | use rustc_ast::ptr::P; |
74b04a01 | 5 | use rustc_ast::token::{self, Token}; |
3c0e092e | 6 | use rustc_ast::{ |
5099ac24 FG |
7 | self as ast, AngleBracketedArg, AngleBracketedArgs, AnonConst, AssocConstraint, |
8 | AssocConstraintKind, BlockCheckMode, GenericArg, GenericArgs, Generics, ParenthesizedArgs, | |
3c0e092e XL |
9 | Path, PathSegment, QSelf, |
10 | }; | |
dfeec247 XL |
11 | use rustc_errors::{pluralize, Applicability, PResult}; |
12 | use rustc_span::source_map::{BytePos, Span}; | |
f9f354fc | 13 | use rustc_span::symbol::{kw, sym, Ident}; |
416331ca | 14 | |
dfeec247 | 15 | use std::mem; |
3dfed10e | 16 | use tracing::debug; |
416331ca XL |
17 | |
18 | /// Specifies how to parse a path. | |
19 | #[derive(Copy, Clone, PartialEq)] | |
20 | pub enum PathStyle { | |
21 | /// In some contexts, notably in expressions, paths with generic arguments are ambiguous | |
22 | /// with something else. For example, in expressions `segment < ....` can be interpreted | |
23 | /// as a comparison and `segment ( ....` can be interpreted as a function call. | |
24 | /// In all such contexts the non-path interpretation is preferred by default for practical | |
25 | /// reasons, but the path interpretation can be forced by the disambiguator `::`, e.g. | |
26 | /// `x<y>` - comparisons, `x::<y>` - unambiguously a path. | |
27 | Expr, | |
28 | /// In other contexts, notably in types, no ambiguity exists and paths can be written | |
29 | /// without the disambiguator, e.g., `x<y>` - unambiguously a path. | |
30 | /// Paths with disambiguators are still accepted, `x::<Y>` - unambiguously a path too. | |
31 | Type, | |
32 | /// A path with generic arguments disallowed, e.g., `foo::bar::Baz`, used in imports, | |
33 | /// visibilities or attributes. | |
34 | /// Technically, this variant is unnecessary and e.g., `Expr` can be used instead | |
35 | /// (paths in "mod" contexts have to be checked later for absence of generic arguments | |
36 | /// anyway, due to macros), but it is used to avoid weird suggestions about expected | |
37 | /// tokens when something goes wrong. | |
38 | Mod, | |
39 | } | |
40 | ||
41 | impl<'a> Parser<'a> { | |
42 | /// Parses a qualified path. | |
43 | /// Assumes that the leading `<` has been parsed already. | |
44 | /// | |
45 | /// `qualified_path = <type [as trait_ref]>::path` | |
46 | /// | |
47 | /// # Examples | |
48 | /// `<T>::default` | |
49 | /// `<T as U>::a` | |
50 | /// `<T as U>::F::a<S>` (without disambiguator) | |
51 | /// `<T as U>::F::a::<S>` (with disambiguator) | |
52 | pub(super) fn parse_qpath(&mut self, style: PathStyle) -> PResult<'a, (QSelf, Path)> { | |
74b04a01 | 53 | let lo = self.prev_token.span; |
416331ca XL |
54 | let ty = self.parse_ty()?; |
55 | ||
56 | // `path` will contain the prefix of the path up to the `>`, | |
57 | // if any (e.g., `U` in the `<T as U>::*` examples | |
58 | // above). `path_span` has the span of that path, or an empty | |
59 | // span in the case of something like `<T>::Bar`. | |
60 | let (mut path, path_span); | |
61 | if self.eat_keyword(kw::As) { | |
62 | let path_lo = self.token.span; | |
63 | path = self.parse_path(PathStyle::Type)?; | |
74b04a01 | 64 | path_span = path_lo.to(self.prev_token.span); |
416331ca XL |
65 | } else { |
66 | path_span = self.token.span.to(self.token.span); | |
1b1a35ee | 67 | path = ast::Path { segments: Vec::new(), span: path_span, tokens: None }; |
416331ca XL |
68 | } |
69 | ||
70 | // See doc comment for `unmatched_angle_bracket_count`. | |
71 | self.expect(&token::Gt)?; | |
72 | if self.unmatched_angle_bracket_count > 0 { | |
73 | self.unmatched_angle_bracket_count -= 1; | |
74 | debug!("parse_qpath: (decrement) count={:?}", self.unmatched_angle_bracket_count); | |
75 | } | |
76 | ||
74b04a01 XL |
77 | if !self.recover_colon_before_qpath_proj() { |
78 | self.expect(&token::ModSep)?; | |
79 | } | |
416331ca XL |
80 | |
81 | let qself = QSelf { ty, path_span, position: path.segments.len() }; | |
3c0e092e | 82 | self.parse_path_segments(&mut path.segments, style, None)?; |
416331ca | 83 | |
1b1a35ee XL |
84 | Ok(( |
85 | qself, | |
86 | Path { segments: path.segments, span: lo.to(self.prev_token.span), tokens: None }, | |
87 | )) | |
74b04a01 XL |
88 | } |
89 | ||
90 | /// Recover from an invalid single colon, when the user likely meant a qualified path. | |
91 | /// We avoid emitting this if not followed by an identifier, as our assumption that the user | |
92 | /// intended this to be a qualified path may not be correct. | |
93 | /// | |
94 | /// ```ignore (diagnostics) | |
95 | /// <Bar as Baz<T>>:Qux | |
96 | /// ^ help: use double colon | |
97 | /// ``` | |
98 | fn recover_colon_before_qpath_proj(&mut self) -> bool { | |
99 | if self.token.kind != token::Colon | |
100 | || self.look_ahead(1, |t| !t.is_ident() || t.is_reserved_ident()) | |
101 | { | |
102 | return false; | |
103 | } | |
104 | ||
105 | self.bump(); // colon | |
106 | ||
107 | self.diagnostic() | |
108 | .struct_span_err( | |
109 | self.prev_token.span, | |
110 | "found single colon before projection in qualified path", | |
111 | ) | |
112 | .span_suggestion( | |
113 | self.prev_token.span, | |
114 | "use double colon", | |
115 | "::".to_string(), | |
116 | Applicability::MachineApplicable, | |
117 | ) | |
118 | .emit(); | |
119 | ||
120 | true | |
416331ca XL |
121 | } |
122 | ||
3c0e092e XL |
123 | pub(super) fn parse_path(&mut self, style: PathStyle) -> PResult<'a, Path> { |
124 | self.parse_path_inner(style, None) | |
125 | } | |
126 | ||
416331ca XL |
127 | /// Parses simple paths. |
128 | /// | |
129 | /// `path = [::] segment+` | |
130 | /// `segment = ident | ident[::]<args> | ident[::](args) [-> type]` | |
131 | /// | |
132 | /// # Examples | |
133 | /// `a::b::C<D>` (without disambiguator) | |
134 | /// `a::b::C::<D>` (with disambiguator) | |
135 | /// `Fn(Args)` (without disambiguator) | |
136 | /// `Fn::(Args)` (with disambiguator) | |
3c0e092e XL |
137 | pub(super) fn parse_path_inner( |
138 | &mut self, | |
139 | style: PathStyle, | |
140 | ty_generics: Option<&Generics>, | |
141 | ) -> PResult<'a, Path> { | |
5099ac24 FG |
142 | let reject_generics_if_mod_style = |parser: &Parser<'_>, path: &Path| { |
143 | // Ensure generic arguments don't end up in attribute paths, such as: | |
144 | // | |
145 | // macro_rules! m { | |
146 | // ($p:path) => { #[$p] struct S; } | |
147 | // } | |
148 | // | |
149 | // m!(inline<u8>); //~ ERROR: unexpected generic arguments in path | |
150 | // | |
dfeec247 XL |
151 | if style == PathStyle::Mod && path.segments.iter().any(|segment| segment.args.is_some()) |
152 | { | |
5099ac24 FG |
153 | parser |
154 | .struct_span_err( | |
155 | path.segments | |
156 | .iter() | |
157 | .filter_map(|segment| segment.args.as_ref()) | |
158 | .map(|arg| arg.span()) | |
159 | .collect::<Vec<_>>(), | |
160 | "unexpected generic arguments in path", | |
161 | ) | |
162 | .emit(); | |
416331ca | 163 | } |
5099ac24 FG |
164 | }; |
165 | ||
166 | maybe_whole!(self, NtPath, |path| { | |
167 | reject_generics_if_mod_style(self, &path); | |
416331ca XL |
168 | path |
169 | }); | |
170 | ||
5099ac24 FG |
171 | if let token::Interpolated(nt) = &self.token.kind { |
172 | if let token::NtTy(ty) = &**nt { | |
173 | if let ast::TyKind::Path(None, path) = &ty.kind { | |
174 | let path = path.clone(); | |
175 | self.bump(); | |
176 | reject_generics_if_mod_style(self, &path); | |
177 | return Ok(path); | |
178 | } | |
179 | } | |
180 | } | |
181 | ||
74b04a01 | 182 | let lo = self.token.span; |
416331ca XL |
183 | let mut segments = Vec::new(); |
184 | let mod_sep_ctxt = self.token.span.ctxt(); | |
185 | if self.eat(&token::ModSep) { | |
186 | segments.push(PathSegment::path_root(lo.shrink_to_lo().with_ctxt(mod_sep_ctxt))); | |
187 | } | |
3c0e092e | 188 | self.parse_path_segments(&mut segments, style, ty_generics)?; |
416331ca | 189 | |
1b1a35ee | 190 | Ok(Path { segments, span: lo.to(self.prev_token.span), tokens: None }) |
416331ca XL |
191 | } |
192 | ||
e74abb32 | 193 | pub(super) fn parse_path_segments( |
e1599b0c XL |
194 | &mut self, |
195 | segments: &mut Vec<PathSegment>, | |
196 | style: PathStyle, | |
3c0e092e | 197 | ty_generics: Option<&Generics>, |
e1599b0c | 198 | ) -> PResult<'a, ()> { |
416331ca | 199 | loop { |
3c0e092e | 200 | let segment = self.parse_path_segment(style, ty_generics)?; |
416331ca XL |
201 | if style == PathStyle::Expr { |
202 | // In order to check for trailing angle brackets, we must have finished | |
203 | // recursing (`parse_path_segment` can indirectly call this function), | |
204 | // that is, the next token must be the highlighted part of the below example: | |
205 | // | |
206 | // `Foo::<Bar as Baz<T>>::Qux` | |
207 | // ^ here | |
208 | // | |
209 | // As opposed to the below highlight (if we had only finished the first | |
210 | // recursion): | |
211 | // | |
212 | // `Foo::<Bar as Baz<T>>::Qux` | |
213 | // ^ here | |
214 | // | |
215 | // `PathStyle::Expr` is only provided at the root invocation and never in | |
216 | // `parse_path_segment` to recurse and therefore can be checked to maintain | |
217 | // this invariant. | |
f035d41b | 218 | self.check_trailing_angle_brackets(&segment, &[&token::ModSep]); |
416331ca XL |
219 | } |
220 | segments.push(segment); | |
221 | ||
222 | if self.is_import_coupler() || !self.eat(&token::ModSep) { | |
223 | return Ok(()); | |
224 | } | |
225 | } | |
226 | } | |
227 | ||
3c0e092e XL |
228 | pub(super) fn parse_path_segment( |
229 | &mut self, | |
230 | style: PathStyle, | |
231 | ty_generics: Option<&Generics>, | |
232 | ) -> PResult<'a, PathSegment> { | |
416331ca | 233 | let ident = self.parse_path_segment_ident()?; |
29967ef6 XL |
234 | let is_args_start = |token: &Token| { |
235 | matches!( | |
236 | token.kind, | |
237 | token::Lt | |
238 | | token::BinOp(token::Shl) | |
239 | | token::OpenDelim(token::Paren) | |
240 | | token::LArrow | |
241 | ) | |
416331ca XL |
242 | }; |
243 | let check_args_start = |this: &mut Self| { | |
dfeec247 XL |
244 | this.expected_tokens.extend_from_slice(&[ |
245 | TokenType::Token(token::Lt), | |
246 | TokenType::Token(token::OpenDelim(token::Paren)), | |
247 | ]); | |
416331ca XL |
248 | is_args_start(&this.token) |
249 | }; | |
250 | ||
dfeec247 XL |
251 | Ok( |
252 | if style == PathStyle::Type && check_args_start(self) | |
253 | || style != PathStyle::Mod | |
254 | && self.check(&token::ModSep) | |
255 | && self.look_ahead(1, |t| is_args_start(t)) | |
256 | { | |
257 | // We use `style == PathStyle::Expr` to check if this is in a recursion or not. If | |
258 | // it isn't, then we reset the unmatched angle bracket count as we're about to start | |
259 | // parsing a new path. | |
260 | if style == PathStyle::Expr { | |
261 | self.unmatched_angle_bracket_count = 0; | |
262 | self.max_angle_bracket_count = 0; | |
263 | } | |
416331ca | 264 | |
dfeec247 XL |
265 | // Generic arguments are found - `<`, `(`, `::<` or `::(`. |
266 | self.eat(&token::ModSep); | |
267 | let lo = self.token.span; | |
268 | let args = if self.eat_lt() { | |
269 | // `<'a, T, A = U>` | |
3c0e092e XL |
270 | let args = self.parse_angle_args_with_leading_angle_bracket_recovery( |
271 | style, | |
272 | lo, | |
273 | ty_generics, | |
274 | )?; | |
dfeec247 | 275 | self.expect_gt()?; |
74b04a01 | 276 | let span = lo.to(self.prev_token.span); |
ba9703b0 | 277 | AngleBracketedArgs { args, span }.into() |
416331ca | 278 | } else { |
dfeec247 XL |
279 | // `(T, U) -> R` |
280 | let (inputs, _) = self.parse_paren_comma_seq(|p| p.parse_ty())?; | |
5869c6ff | 281 | let inputs_span = lo.to(self.prev_token.span); |
fc512014 XL |
282 | let output = |
283 | self.parse_ret_ty(AllowPlus::No, RecoverQPath::No, RecoverReturnSign::No)?; | |
3c0e092e | 284 | let span = ident.span.to(self.prev_token.span); |
5869c6ff | 285 | ParenthesizedArgs { span, inputs, inputs_span, output }.into() |
416331ca | 286 | }; |
416331ca | 287 | |
dfeec247 XL |
288 | PathSegment { ident, args, id: ast::DUMMY_NODE_ID } |
289 | } else { | |
290 | // Generic arguments are not found. | |
291 | PathSegment::from_ident(ident) | |
292 | }, | |
293 | ) | |
416331ca XL |
294 | } |
295 | ||
296 | pub(super) fn parse_path_segment_ident(&mut self) -> PResult<'a, Ident> { | |
74b04a01 XL |
297 | match self.token.ident() { |
298 | Some((ident, false)) if ident.is_path_segment_keyword() => { | |
416331ca | 299 | self.bump(); |
74b04a01 | 300 | Ok(ident) |
416331ca XL |
301 | } |
302 | _ => self.parse_ident(), | |
303 | } | |
304 | } | |
305 | ||
306 | /// Parses generic args (within a path segment) with recovery for extra leading angle brackets. | |
307 | /// For the purposes of understanding the parsing logic of generic arguments, this function | |
ba9703b0 | 308 | /// can be thought of being the same as just calling `self.parse_angle_args()` if the source |
416331ca XL |
309 | /// had the correct amount of leading angle brackets. |
310 | /// | |
311 | /// ```ignore (diagnostics) | |
312 | /// bar::<<<<T as Foo>::Output>(); | |
313 | /// ^^ help: remove extra angle brackets | |
314 | /// ``` | |
ba9703b0 | 315 | fn parse_angle_args_with_leading_angle_bracket_recovery( |
416331ca XL |
316 | &mut self, |
317 | style: PathStyle, | |
318 | lo: Span, | |
3c0e092e | 319 | ty_generics: Option<&Generics>, |
ba9703b0 | 320 | ) -> PResult<'a, Vec<AngleBracketedArg>> { |
416331ca XL |
321 | // We need to detect whether there are extra leading left angle brackets and produce an |
322 | // appropriate error and suggestion. This cannot be implemented by looking ahead at | |
323 | // upcoming tokens for a matching `>` character - if there are unmatched `<` tokens | |
324 | // then there won't be matching `>` tokens to find. | |
325 | // | |
326 | // To explain how this detection works, consider the following example: | |
327 | // | |
328 | // ```ignore (diagnostics) | |
329 | // bar::<<<<T as Foo>::Output>(); | |
330 | // ^^ help: remove extra angle brackets | |
331 | // ``` | |
332 | // | |
333 | // Parsing of the left angle brackets starts in this function. We start by parsing the | |
334 | // `<` token (incrementing the counter of unmatched angle brackets on `Parser` via | |
335 | // `eat_lt`): | |
336 | // | |
337 | // *Upcoming tokens:* `<<<<T as Foo>::Output>;` | |
338 | // *Unmatched count:* 1 | |
339 | // *`parse_path_segment` calls deep:* 0 | |
340 | // | |
341 | // This has the effect of recursing as this function is called if a `<` character | |
342 | // is found within the expected generic arguments: | |
343 | // | |
344 | // *Upcoming tokens:* `<<<T as Foo>::Output>;` | |
345 | // *Unmatched count:* 2 | |
346 | // *`parse_path_segment` calls deep:* 1 | |
347 | // | |
348 | // Eventually we will have recursed until having consumed all of the `<` tokens and | |
349 | // this will be reflected in the count: | |
350 | // | |
351 | // *Upcoming tokens:* `T as Foo>::Output>;` | |
352 | // *Unmatched count:* 4 | |
353 | // `parse_path_segment` calls deep:* 3 | |
354 | // | |
355 | // The parser will continue until reaching the first `>` - this will decrement the | |
356 | // unmatched angle bracket count and return to the parent invocation of this function | |
357 | // having succeeded in parsing: | |
358 | // | |
359 | // *Upcoming tokens:* `::Output>;` | |
360 | // *Unmatched count:* 3 | |
361 | // *`parse_path_segment` calls deep:* 2 | |
362 | // | |
363 | // This will continue until the next `>` character which will also return successfully | |
364 | // to the parent invocation of this function and decrement the count: | |
365 | // | |
366 | // *Upcoming tokens:* `;` | |
367 | // *Unmatched count:* 2 | |
368 | // *`parse_path_segment` calls deep:* 1 | |
369 | // | |
370 | // At this point, this function will expect to find another matching `>` character but | |
371 | // won't be able to and will return an error. This will continue all the way up the | |
372 | // call stack until the first invocation: | |
373 | // | |
374 | // *Upcoming tokens:* `;` | |
375 | // *Unmatched count:* 2 | |
376 | // *`parse_path_segment` calls deep:* 0 | |
377 | // | |
378 | // In doing this, we have managed to work out how many unmatched leading left angle | |
379 | // brackets there are, but we cannot recover as the unmatched angle brackets have | |
380 | // already been consumed. To remedy this, we keep a snapshot of the parser state | |
381 | // before we do the above. We can then inspect whether we ended up with a parsing error | |
382 | // and unmatched left angle brackets and if so, restore the parser state before we | |
383 | // consumed any `<` characters to emit an error and consume the erroneous tokens to | |
384 | // recover by attempting to parse again. | |
385 | // | |
386 | // In practice, the recursion of this function is indirect and there will be other | |
387 | // locations that consume some `<` characters - as long as we update the count when | |
388 | // this happens, it isn't an issue. | |
389 | ||
390 | let is_first_invocation = style == PathStyle::Expr; | |
391 | // Take a snapshot before attempting to parse - we can restore this later. | |
dfeec247 | 392 | let snapshot = if is_first_invocation { Some(self.clone()) } else { None }; |
416331ca XL |
393 | |
394 | debug!("parse_generic_args_with_leading_angle_bracket_recovery: (snapshotting)"); | |
3c0e092e | 395 | match self.parse_angle_args(ty_generics) { |
ba9703b0 | 396 | Ok(args) => Ok(args), |
17df50a5 | 397 | Err(mut e) if is_first_invocation && self.unmatched_angle_bracket_count > 0 => { |
416331ca XL |
398 | // Swap `self` with our backup of the parser state before attempting to parse |
399 | // generic arguments. | |
400 | let snapshot = mem::replace(self, snapshot.unwrap()); | |
401 | ||
416331ca | 402 | // Eat the unmatched angle brackets. |
17df50a5 XL |
403 | let all_angle_brackets = (0..snapshot.unmatched_angle_bracket_count) |
404 | .fold(true, |a, _| a && self.eat_lt()); | |
405 | ||
406 | if !all_angle_brackets { | |
407 | // If there are other tokens in between the extraneous `<`s, we cannot simply | |
408 | // suggest to remove them. This check also prevents us from accidentally ending | |
409 | // up in the middle of a multibyte character (issue #84104). | |
410 | let _ = mem::replace(self, snapshot); | |
411 | Err(e) | |
412 | } else { | |
413 | // Cancel error from being unable to find `>`. We know the error | |
414 | // must have been this due to a non-zero unmatched angle bracket | |
415 | // count. | |
416 | e.cancel(); | |
417 | ||
418 | debug!( | |
419 | "parse_generic_args_with_leading_angle_bracket_recovery: (snapshot failure) \ | |
420 | snapshot.count={:?}", | |
421 | snapshot.unmatched_angle_bracket_count, | |
422 | ); | |
423 | ||
424 | // Make a span over ${unmatched angle bracket count} characters. | |
425 | // This is safe because `all_angle_brackets` ensures that there are only `<`s, | |
426 | // i.e. no multibyte characters, in this range. | |
427 | let span = | |
428 | lo.with_hi(lo.lo() + BytePos(snapshot.unmatched_angle_bracket_count)); | |
429 | self.struct_span_err( | |
430 | span, | |
431 | &format!( | |
432 | "unmatched angle bracket{}", | |
433 | pluralize!(snapshot.unmatched_angle_bracket_count) | |
434 | ), | |
435 | ) | |
436 | .span_suggestion( | |
437 | span, | |
438 | &format!( | |
439 | "remove extra angle bracket{}", | |
440 | pluralize!(snapshot.unmatched_angle_bracket_count) | |
441 | ), | |
442 | String::new(), | |
443 | Applicability::MachineApplicable, | |
444 | ) | |
445 | .emit(); | |
446 | ||
447 | // Try again without unmatched angle bracket characters. | |
3c0e092e | 448 | self.parse_angle_args(ty_generics) |
416331ca | 449 | } |
dfeec247 | 450 | } |
416331ca XL |
451 | Err(e) => Err(e), |
452 | } | |
453 | } | |
454 | ||
ba9703b0 | 455 | /// Parses (possibly empty) list of generic arguments / associated item constraints, |
416331ca | 456 | /// possibly including trailing comma. |
3c0e092e XL |
457 | pub(super) fn parse_angle_args( |
458 | &mut self, | |
459 | ty_generics: Option<&Generics>, | |
460 | ) -> PResult<'a, Vec<AngleBracketedArg>> { | |
416331ca | 461 | let mut args = Vec::new(); |
3c0e092e | 462 | while let Some(arg) = self.parse_angle_arg(ty_generics)? { |
ba9703b0 XL |
463 | args.push(arg); |
464 | if !self.eat(&token::Comma) { | |
29967ef6 XL |
465 | if !self.token.kind.should_end_const_arg() { |
466 | if self.handle_ambiguous_unbraced_const_arg(&mut args)? { | |
467 | // We've managed to (partially) recover, so continue trying to parse | |
468 | // arguments. | |
469 | continue; | |
470 | } | |
471 | } | |
ba9703b0 XL |
472 | break; |
473 | } | |
474 | } | |
475 | Ok(args) | |
476 | } | |
e74abb32 | 477 | |
ba9703b0 | 478 | /// Parses a single argument in the angle arguments `<...>` of a path segment. |
3c0e092e XL |
479 | fn parse_angle_arg( |
480 | &mut self, | |
481 | ty_generics: Option<&Generics>, | |
482 | ) -> PResult<'a, Option<AngleBracketedArg>> { | |
fc512014 | 483 | let lo = self.token.span; |
3c0e092e | 484 | let arg = self.parse_generic_arg(ty_generics)?; |
fc512014 XL |
485 | match arg { |
486 | Some(arg) => { | |
487 | if self.check(&token::Colon) | self.check(&token::Eq) { | |
5869c6ff XL |
488 | let (ident, gen_args) = match self.get_ident_from_generic_arg(arg) { |
489 | Ok(ident_gen_args) => ident_gen_args, | |
490 | Err(arg) => return Ok(Some(AngleBracketedArg::Arg(arg))), | |
491 | }; | |
fc512014 XL |
492 | let kind = if self.eat(&token::Colon) { |
493 | // Parse associated type constraint bound. | |
494 | ||
495 | let bounds = self.parse_generic_bounds(Some(self.prev_token.span))?; | |
5099ac24 | 496 | AssocConstraintKind::Bound { bounds } |
fc512014 | 497 | } else if self.eat(&token::Eq) { |
5099ac24 | 498 | self.parse_assoc_equality_term(ident, self.prev_token.span)? |
fc512014 XL |
499 | } else { |
500 | unreachable!(); | |
501 | }; | |
e74abb32 | 502 | |
fc512014 | 503 | let span = lo.to(self.prev_token.span); |
e74abb32 | 504 | |
fc512014 | 505 | // Gate associated type bounds, e.g., `Iterator<Item: Ord>`. |
5099ac24 | 506 | if let AssocConstraintKind::Bound { .. } = kind { |
fc512014 XL |
507 | self.sess.gated_spans.gate(sym::associated_type_bounds, span); |
508 | } | |
509 | let constraint = | |
5099ac24 | 510 | AssocConstraint { id: ast::DUMMY_NODE_ID, ident, gen_args, kind, span }; |
fc512014 XL |
511 | Ok(Some(AngleBracketedArg::Constraint(constraint))) |
512 | } else { | |
513 | Ok(Some(AngleBracketedArg::Arg(arg))) | |
514 | } | |
416331ca | 515 | } |
fc512014 | 516 | _ => Ok(None), |
416331ca | 517 | } |
ba9703b0 | 518 | } |
416331ca | 519 | |
ba9703b0 XL |
520 | /// Parse the term to the right of an associated item equality constraint. |
521 | /// That is, parse `<term>` in `Item = <term>`. | |
522 | /// Right now, this only admits types in `<term>`. | |
5099ac24 FG |
523 | fn parse_assoc_equality_term( |
524 | &mut self, | |
525 | ident: Ident, | |
526 | eq: Span, | |
527 | ) -> PResult<'a, AssocConstraintKind> { | |
3c0e092e | 528 | let arg = self.parse_generic_arg(None)?; |
ba9703b0 | 529 | let span = ident.span.to(self.prev_token.span); |
5099ac24 FG |
530 | let term = match arg { |
531 | Some(GenericArg::Type(ty)) => ty.into(), | |
532 | Some(GenericArg::Const(c)) => { | |
533 | self.sess.gated_spans.gate(sym::associated_const_equality, span); | |
534 | c.into() | |
ba9703b0 XL |
535 | } |
536 | Some(GenericArg::Lifetime(lt)) => { | |
537 | self.struct_span_err(span, "associated lifetimes are not supported") | |
538 | .span_label(lt.ident.span, "the lifetime is given here") | |
539 | .help("if you meant to specify a trait object, write `dyn Trait + 'lifetime`") | |
540 | .emit(); | |
5099ac24 | 541 | self.mk_ty(span, ast::TyKind::Err).into() |
ba9703b0 XL |
542 | } |
543 | None => { | |
544 | let after_eq = eq.shrink_to_hi(); | |
545 | let before_next = self.token.span.shrink_to_lo(); | |
c295e0f8 XL |
546 | let mut err = self |
547 | .struct_span_err(after_eq.to(before_next), "missing type to the right of `=`"); | |
548 | if matches!(self.token.kind, token::Comma | token::Gt) { | |
549 | err.span_suggestion( | |
ba9703b0 XL |
550 | self.sess.source_map().next_point(eq).to(before_next), |
551 | "to constrain the associated type, add a type after `=`", | |
552 | " TheType".to_string(), | |
553 | Applicability::HasPlaceholders, | |
c295e0f8 XL |
554 | ); |
555 | err.span_suggestion( | |
ba9703b0 XL |
556 | eq.to(before_next), |
557 | &format!("remove the `=` if `{}` is a type", ident), | |
558 | String::new(), | |
559 | Applicability::MaybeIncorrect, | |
560 | ) | |
c295e0f8 XL |
561 | } else { |
562 | err.span_label( | |
563 | self.token.span, | |
564 | &format!("expected type, found {}", super::token_descr(&self.token)), | |
565 | ) | |
566 | }; | |
567 | return Err(err); | |
416331ca | 568 | } |
5099ac24 FG |
569 | }; |
570 | Ok(AssocConstraintKind::Equality { term }) | |
ba9703b0 | 571 | } |
416331ca | 572 | |
29967ef6 XL |
573 | /// We do not permit arbitrary expressions as const arguments. They must be one of: |
574 | /// - An expression surrounded in `{}`. | |
575 | /// - A literal. | |
576 | /// - A numeric literal prefixed by `-`. | |
fc512014 | 577 | /// - A single-segment path. |
29967ef6 XL |
578 | pub(super) fn expr_is_valid_const_arg(&self, expr: &P<rustc_ast::Expr>) -> bool { |
579 | match &expr.kind { | |
580 | ast::ExprKind::Block(_, _) | ast::ExprKind::Lit(_) => true, | |
5869c6ff XL |
581 | ast::ExprKind::Unary(ast::UnOp::Neg, expr) => { |
582 | matches!(expr.kind, ast::ExprKind::Lit(_)) | |
583 | } | |
fc512014 XL |
584 | // We can only resolve single-segment paths at the moment, because multi-segment paths |
585 | // require type-checking: see `visit_generic_arg` in `src/librustc_resolve/late.rs`. | |
586 | ast::ExprKind::Path(None, path) | |
587 | if path.segments.len() == 1 && path.segments[0].args.is_none() => | |
588 | { | |
589 | true | |
590 | } | |
29967ef6 XL |
591 | _ => false, |
592 | } | |
593 | } | |
594 | ||
5869c6ff XL |
595 | /// Parse a const argument, e.g. `<3>`. It is assumed the angle brackets will be parsed by |
596 | /// the caller. | |
597 | pub(super) fn parse_const_arg(&mut self) -> PResult<'a, AnonConst> { | |
598 | // Parse const argument. | |
599 | let value = if let token::OpenDelim(token::Brace) = self.token.kind { | |
600 | self.parse_block_expr( | |
601 | None, | |
602 | self.token.span, | |
603 | BlockCheckMode::Default, | |
604 | ast::AttrVec::new(), | |
605 | )? | |
606 | } else { | |
607 | self.handle_unambiguous_unbraced_const_arg()? | |
608 | }; | |
609 | Ok(AnonConst { id: ast::DUMMY_NODE_ID, value }) | |
610 | } | |
611 | ||
ba9703b0 XL |
612 | /// Parse a generic argument in a path segment. |
613 | /// This does not include constraints, e.g., `Item = u8`, which is handled in `parse_angle_arg`. | |
3c0e092e XL |
614 | pub(super) fn parse_generic_arg( |
615 | &mut self, | |
616 | ty_generics: Option<&Generics>, | |
617 | ) -> PResult<'a, Option<GenericArg>> { | |
29967ef6 | 618 | let start = self.token.span; |
ba9703b0 XL |
619 | let arg = if self.check_lifetime() && self.look_ahead(1, |t| !t.is_like_plus()) { |
620 | // Parse lifetime argument. | |
621 | GenericArg::Lifetime(self.expect_lifetime()) | |
622 | } else if self.check_const_arg() { | |
623 | // Parse const argument. | |
5869c6ff | 624 | GenericArg::Const(self.parse_const_arg()?) |
ba9703b0 XL |
625 | } else if self.check_type() { |
626 | // Parse type argument. | |
29967ef6 XL |
627 | match self.parse_ty() { |
628 | Ok(ty) => GenericArg::Type(ty), | |
629 | Err(err) => { | |
630 | // Try to recover from possible `const` arg without braces. | |
631 | return self.recover_const_arg(start, err).map(Some); | |
632 | } | |
633 | } | |
3c0e092e XL |
634 | } else if self.token.is_keyword(kw::Const) { |
635 | return self.recover_const_param_declaration(ty_generics); | |
ba9703b0 XL |
636 | } else { |
637 | return Ok(None); | |
638 | }; | |
639 | Ok(Some(arg)) | |
416331ca | 640 | } |
fc512014 XL |
641 | |
642 | fn get_ident_from_generic_arg( | |
643 | &self, | |
644 | gen_arg: GenericArg, | |
5869c6ff XL |
645 | ) -> Result<(Ident, Option<GenericArgs>), GenericArg> { |
646 | if let GenericArg::Type(ty) = &gen_arg { | |
647 | if let ast::TyKind::Path(qself, path) = &ty.kind { | |
648 | if qself.is_none() && path.segments.len() == 1 { | |
649 | let seg = &path.segments[0]; | |
650 | return Ok((seg.ident, seg.args.as_deref().cloned())); | |
fc512014 | 651 | } |
fc512014 XL |
652 | } |
653 | } | |
5869c6ff | 654 | Err(gen_arg) |
fc512014 | 655 | } |
416331ca | 656 | } |