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