From 79ee8f329d1d3105555fd40be5b0eac56c9a8e8f Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Sun, 25 Nov 2018 12:41:38 -0800 Subject: Suggest appropriate place for lifetime when declared after type arguments --- src/libsyntax/parse/parser.rs | 43 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 35 insertions(+), 8 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index e2f09affd4f..07e13ffc314 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -5178,8 +5178,10 @@ 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> { + let mut lifetimes = Vec::new(); let mut params = Vec::new(); - let mut seen_ty_param = false; + let mut seen_ty_param: Option = None; + let mut last_comma_span = None; loop { let attrs = self.parse_outer_attributes()?; if self.check_lifetime() { @@ -5190,25 +5192,48 @@ 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) + }; + let mut err = self.struct_span_err( + self.prev_span, + "lifetime parameters must be declared prior to type parameters", + ); + if let Ok(snippet) = self.sess.source_map().span_to_snippet(param_span) { + err.multipart_suggestion( + "move the lifetime parameter prior to the first type parameter", + vec![ + (remove_sp, String::new()), + (sp.shrink_to_lo(), format!("{}, ", snippet)), + ], + ); + } + err.emit(); + 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; + 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)); } @@ -5218,8 +5243,10 @@ impl<'a> Parser<'a> { if !self.eat(&token::Comma) { break } + last_comma_span = Some(self.prev_span); } - 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 -- cgit 1.4.1-3-g733a5 From 234d043d18175aff37200a91df2a1b7c3064fc80 Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Sun, 25 Nov 2018 12:46:42 -0800 Subject: Move lifetimes before the *first* type argument --- src/libsyntax/parse/parser.rs | 4 +++- src/test/ui/suggestions/suggest-move-lifetimes.stderr | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 07e13ffc314..1fdf86d4867 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -5229,7 +5229,9 @@ impl<'a> Parser<'a> { } else if self.check_ident() { // Parse type parameter. params.push(self.parse_ty_param(attrs)?); - seen_ty_param = Some(self.prev_span); + 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() { diff --git a/src/test/ui/suggestions/suggest-move-lifetimes.stderr b/src/test/ui/suggestions/suggest-move-lifetimes.stderr index 57e6780b359..fa1cfe66ab5 100644 --- a/src/test/ui/suggestions/suggest-move-lifetimes.stderr +++ b/src/test/ui/suggestions/suggest-move-lifetimes.stderr @@ -25,8 +25,8 @@ LL | struct C { | ^^ help: move the lifetime parameter prior to the first type parameter | -LL | struct C { - | ^^^ -- +LL | struct C<'a, T, U> { + | ^^^ -- error: aborting due to 3 previous errors -- cgit 1.4.1-3-g733a5 From 45dfe43887fee6c2ce4cbc3e46b31626330be094 Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Mon, 26 Nov 2018 08:32:47 -0800 Subject: Emit one diagnostic for multiple misplaced lifetimes --- src/libsyntax/parse/parser.rs | 31 +++++++++++++--------- src/test/ui/suggestions/suggest-move-lifetimes.rs | 6 +++++ .../ui/suggestions/suggest-move-lifetimes.stderr | 16 ++++++++--- 3 files changed, 38 insertions(+), 15 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 1fdf86d4867..ab5afaf3d99 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -5182,6 +5182,8 @@ impl<'a> Parser<'a> { let mut params = Vec::new(); let mut seen_ty_param: Option = 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() { @@ -5207,20 +5209,12 @@ impl<'a> Parser<'a> { } else { last_comma_span.unwrap_or(param_span).to(param_span) }; - let mut err = self.struct_span_err( - self.prev_span, - "lifetime parameters must be declared prior to type parameters", - ); + bad_lifetime_pos.push(param_span); + if let Ok(snippet) = self.sess.source_map().span_to_snippet(param_span) { - err.multipart_suggestion( - "move the lifetime parameter prior to the first type parameter", - vec![ - (remove_sp, String::new()), - (sp.shrink_to_lo(), format!("{}, ", snippet)), - ], - ); + suggestions.push((remove_sp, String::new())); + suggestions.push((sp.shrink_to_lo(), format!("{}, ", snippet))); } - err.emit(); if ate_comma { last_comma_span = Some(self.prev_span); continue @@ -5247,6 +5241,19 @@ impl<'a> Parser<'a> { } 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( + "move the lifetime parameter prior to the first type parameter", + suggestions, + ); + } + err.emit(); + } lifetimes.extend(params); // ensure the correct order of lifetimes and type params Ok(lifetimes) } diff --git a/src/test/ui/suggestions/suggest-move-lifetimes.rs b/src/test/ui/suggestions/suggest-move-lifetimes.rs index be6d29d9337..5051a406078 100644 --- a/src/test/ui/suggestions/suggest-move-lifetimes.rs +++ b/src/test/ui/suggestions/suggest-move-lifetimes.rs @@ -12,4 +12,10 @@ struct C { u: U, } +struct D { + t: &'a T, + u: &'b U, + v: &'c V, +} + fn main() {} diff --git a/src/test/ui/suggestions/suggest-move-lifetimes.stderr b/src/test/ui/suggestions/suggest-move-lifetimes.stderr index fa1cfe66ab5..f3d6469b512 100644 --- a/src/test/ui/suggestions/suggest-move-lifetimes.stderr +++ b/src/test/ui/suggestions/suggest-move-lifetimes.stderr @@ -9,10 +9,10 @@ LL | struct A<'a, T> { | ^^^ -- error: lifetime parameters must be declared prior to type parameters - --> $DIR/suggest-move-lifetimes.rs:5:15 + --> $DIR/suggest-move-lifetimes.rs:5:13 | LL | struct B { - | ^ + | ^^ help: move the lifetime parameter prior to the first type parameter | LL | struct B<'a, T, U> { @@ -28,5 +28,15 @@ help: move the lifetime parameter prior to the first type parameter LL | struct C<'a, T, U> { | ^^^ -- -error: aborting due to 3 previous errors +error: lifetime parameters must be declared prior to type parameters + --> $DIR/suggest-move-lifetimes.rs:15:16 + | +LL | struct D { + | ^^ ^^ ^^ +help: move the lifetime parameter prior to the first type parameter + | +LL | struct D<'a, 'b, 'c, T, U, V> { + | ^^^ ^^^ ^^^ --- + +error: aborting due to 4 previous errors -- cgit 1.4.1-3-g733a5 From cd20be50912170842689e4f936c31c5a28184432 Mon Sep 17 00:00:00 2001 From: Jason Langenauer Date: Mon, 26 Nov 2018 21:21:17 +0100 Subject: Update outdated code comments in StringReader --- src/libsyntax/parse/lexer/mod.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index 0584cd5a3df..c90c62c13f9 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -60,11 +60,11 @@ pub struct StringReader<'a> { // cache a direct reference to the source text, so that we don't have to // retrieve it via `self.source_file.src.as_ref().unwrap()` all the time. src: Lrc, - /// Stack of open delimiters and their spans. Used for error message. token: token::Token, span: Span, /// The raw source span which *does not* take `override_span` into account span_src_raw: Span, + /// Stack of open delimiters and their spans. Used for error message. open_braces: Vec<(token::DelimToken, Span)>, /// The type and spans for all braces /// @@ -506,8 +506,7 @@ impl<'a> StringReader<'a> { } } - /// Advance the StringReader by one character. If a newline is - /// discovered, add it to the SourceFile's list of line start offsets. + /// Advance the StringReader by one character. crate fn bump(&mut self) { let next_src_index = self.src_index(self.next_pos); if next_src_index < self.end_src_index { -- cgit 1.4.1-3-g733a5 From 6f028fe8e0db8c1251f24d694fc001aa933cf0ea Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Mon, 26 Nov 2018 13:58:46 -0800 Subject: Specify suggestion applicability --- src/libsyntax/parse/parser.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index ab5afaf3d99..c224f182592 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -5247,9 +5247,10 @@ impl<'a> Parser<'a> { "lifetime parameters must be declared prior to type parameters", ); if !suggestions.is_empty() { - err.multipart_suggestion( + err.multipart_suggestion_with_applicability( "move the lifetime parameter prior to the first type parameter", suggestions, + Applicability::MachineApplicable, ); } err.emit(); -- cgit 1.4.1-3-g733a5 From 66a2c39290daddf8cc32284fe635591b9dde4b0a Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Wed, 28 Nov 2018 16:05:02 -0800 Subject: Clean up span in non-trailing `..` suggestion --- src/libsyntax/parse/parser.rs | 4 ++-- src/test/ui/issues/issue-49257.stderr | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index e2f09affd4f..ac0bde7856a 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -3956,7 +3956,7 @@ impl<'a> Parser<'a> { ); err.emit(); } - self.bump(); // `..` || `...`:w + self.bump(); // `..` || `...` if self.token == token::CloseDelim(token::Brace) { etc_span = Some(etc_sp); @@ -3976,7 +3976,7 @@ impl<'a> Parser<'a> { ate_comma = true; } - etc_span = Some(etc_sp); + etc_span = Some(etc_sp.until(self.span)); if self.token == token::CloseDelim(token::Brace) { // If the struct looks otherwise well formed, recover and continue. if let Some(sp) = comma_sp { diff --git a/src/test/ui/issues/issue-49257.stderr b/src/test/ui/issues/issue-49257.stderr index 40179832b49..644df1f56b4 100644 --- a/src/test/ui/issues/issue-49257.stderr +++ b/src/test/ui/issues/issue-49257.stderr @@ -8,8 +8,8 @@ LL | let Point { .., y, } = p; //~ ERROR expected `}`, found `,` | `..` must be at the end and cannot have a trailing comma help: move the `..` to the end of the field list | -LL | let Point { y, .. } = p; //~ ERROR expected `}`, found `,` - | -- ^^^^ +LL | let Point { y, .. } = p; //~ ERROR expected `}`, found `,` + | -- ^^^^ error: expected `}`, found `,` --> $DIR/issue-49257.rs:21:19 @@ -21,8 +21,8 @@ LL | let Point { .., y } = p; //~ ERROR expected `}`, found `,` | `..` must be at the end and cannot have a trailing comma help: move the `..` to the end of the field list | -LL | let Point { y , .. } = p; //~ ERROR expected `}`, found `,` - | -- ^^^^^^ +LL | let Point { y , .. } = p; //~ ERROR expected `}`, found `,` + | -- ^^^^^^ error: expected `}`, found `,` --> $DIR/issue-49257.rs:22:19 -- cgit 1.4.1-3-g733a5