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