diff options
| author | Guillaume Gomez <guillaume1.gomez@gmail.com> | 2018-11-29 13:10:39 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-11-29 13:10:39 +0100 |
| commit | 796892e0ef6b57c6497244e7618d2e1ecde0e29a (patch) | |
| tree | 1d0f0931dd5ede18421d87d122a27138d3a87913 /src/libsyntax/parse | |
| parent | 40ec10988847ccac9cdadcecdb93131cbe052e61 (diff) | |
| parent | 6f028fe8e0db8c1251f24d694fc001aa933cf0ea (diff) | |
| download | rust-796892e0ef6b57c6497244e7618d2e1ecde0e29a.tar.gz rust-796892e0ef6b57c6497244e7618d2e1ecde0e29a.zip | |
Rollup merge of #56220 - estebank:suggest-lifetime-move, r=nikomatsakis
Suggest appropriate place for lifetime when declared after type arguments
Diffstat (limited to 'src/libsyntax/parse')
| -rw-r--r-- | src/libsyntax/parse/parser.rs | 53 |
1 files changed, 45 insertions, 8 deletions
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index c82ebd6aa51..e0436cc7380 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -5172,8 +5172,12 @@ impl<'a> Parser<'a> { /// Parses (possibly empty) list of lifetime and type parameters, possibly including /// trailing comma and erroneous trailing attributes. crate fn parse_generic_params(&mut self) -> PResult<'a, Vec<ast::GenericParam>> { + let mut lifetimes = Vec::new(); let mut params = Vec::new(); - let mut seen_ty_param = false; + let mut seen_ty_param: Option<Span> = None; + let mut last_comma_span = None; + let mut bad_lifetime_pos = vec![]; + let mut suggestions = vec![]; loop { let attrs = self.parse_outer_attributes()?; if self.check_lifetime() { @@ -5184,25 +5188,42 @@ impl<'a> Parser<'a> { } else { Vec::new() }; - params.push(ast::GenericParam { + lifetimes.push(ast::GenericParam { ident: lifetime.ident, id: lifetime.id, attrs: attrs.into(), bounds, kind: ast::GenericParamKind::Lifetime, }); - if seen_ty_param { - self.span_err(self.prev_span, - "lifetime parameters must be declared prior to type parameters"); + if let Some(sp) = seen_ty_param { + let param_span = self.prev_span; + let ate_comma = self.eat(&token::Comma); + let remove_sp = if ate_comma { + param_span.until(self.span) + } else { + last_comma_span.unwrap_or(param_span).to(param_span) + }; + bad_lifetime_pos.push(param_span); + + if let Ok(snippet) = self.sess.source_map().span_to_snippet(param_span) { + suggestions.push((remove_sp, String::new())); + suggestions.push((sp.shrink_to_lo(), format!("{}, ", snippet))); + } + if ate_comma { + last_comma_span = Some(self.prev_span); + continue + } } } else if self.check_ident() { // Parse type parameter. params.push(self.parse_ty_param(attrs)?); - seen_ty_param = true; + if seen_ty_param.is_none() { + seen_ty_param = Some(self.prev_span); + } } else { // Check for trailing attributes and stop parsing. if !attrs.is_empty() { - let param_kind = if seen_ty_param { "type" } else { "lifetime" }; + let param_kind = if seen_ty_param.is_some() { "type" } else { "lifetime" }; self.span_err(attrs[0].span, &format!("trailing attribute after {} parameters", param_kind)); } @@ -5212,8 +5233,24 @@ impl<'a> Parser<'a> { if !self.eat(&token::Comma) { break } + last_comma_span = Some(self.prev_span); + } + if !bad_lifetime_pos.is_empty() { + let mut err = self.struct_span_err( + bad_lifetime_pos, + "lifetime parameters must be declared prior to type parameters", + ); + if !suggestions.is_empty() { + err.multipart_suggestion_with_applicability( + "move the lifetime parameter prior to the first type parameter", + suggestions, + Applicability::MachineApplicable, + ); + } + err.emit(); } - Ok(params) + lifetimes.extend(params); // ensure the correct order of lifetimes and type params + Ok(lifetimes) } /// Parse a set of optional generic type parameter declarations. Where |
