From 463e623ca967c2bd301cc0291fae219130b53daf Mon Sep 17 00:00:00 2001 From: David Wood Date: Thu, 24 Jan 2019 23:24:58 +0100 Subject: [PATCH] Suggestion moving types before associated types. This commit extends existing suggestions to move lifetimes before types in generic arguments to also suggest moving types behind associated type bindings. --- src/libsyntax/parse/parser.rs | 69 ++++++++++++++----- src/test/ui/parser/issue-32214.stderr | 4 ++ src/test/ui/suggestions/suggest-move-types.rs | 42 +++++++++++ .../ui/suggestions/suggest-move-types.stderr | 49 +++++++++++++ 4 files changed, 148 insertions(+), 16 deletions(-) create mode 100644 src/test/ui/suggestions/suggest-move-types.rs create mode 100644 src/test/ui/suggestions/suggest-move-types.stderr diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index c7e33a165642..232b8bb5966c 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -5530,22 +5530,31 @@ fn parse_generics(&mut self) -> PResult<'a, ast::Generics> { fn parse_generic_args(&mut self) -> PResult<'a, (Vec, Vec)> { let mut args = Vec::new(); let mut bindings = Vec::new(); + let mut seen_type = false; let mut seen_binding = false; - let mut first_type_or_binding_span: Option = None; - let mut bad_lifetime_pos = vec![]; + let mut last_comma_span = None; - let mut suggestions = vec![]; + let mut first_type_or_binding_span: Option = None; + let mut first_binding_span: Option = None; + + let mut bad_lifetime_pos = vec![]; + let mut bad_type_pos = vec![]; + + let mut lifetime_suggestions = vec![]; + let mut type_suggestions = vec![]; loop { if self.check_lifetime() && self.look_ahead(1, |t| !t.is_like_plus()) { // Parse lifetime argument. args.push(GenericArg::Lifetime(self.expect_lifetime())); + if seen_type || seen_binding { let remove_sp = last_comma_span.unwrap_or(self.prev_span).to(self.prev_span); bad_lifetime_pos.push(self.prev_span); + if let Ok(snippet) = self.sess.source_map().span_to_snippet(self.prev_span) { - suggestions.push((remove_sp, String::new())); - suggestions.push(( + lifetime_suggestions.push((remove_sp, String::new())); + lifetime_suggestions.push(( first_type_or_binding_span.unwrap().shrink_to_lo(), format!("{}, ", snippet))); } @@ -5563,24 +5572,29 @@ fn parse_generic_args(&mut self) -> PResult<'a, (Vec, Vec PResult<'a, (Vec, Vec PResult<'a, (Vec, Vec 1 { "s" } else { "" }, ), - suggestions, + lifetime_suggestions, Applicability::MachineApplicable, ); } err.emit(); } + + if !bad_type_pos.is_empty() { + let mut err = self.struct_span_err( + bad_type_pos.clone(), + "type parameters must be declared prior to associated type bindings" + ); + for sp in &bad_type_pos { + err.span_label(*sp, "must be declared prior to associated type bindings"); + } + if !type_suggestions.is_empty() { + err.multipart_suggestion_with_applicability( + &format!( + "move the type parameter{} prior to the first associated type binding", + if bad_type_pos.len() > 1 { "s" } else { "" }, + ), + type_suggestions, + Applicability::MachineApplicable, + ); + } + err.emit(); + } + Ok((args, bindings)) } diff --git a/src/test/ui/parser/issue-32214.stderr b/src/test/ui/parser/issue-32214.stderr index a889513eaee5..660e517c85a1 100644 --- a/src/test/ui/parser/issue-32214.stderr +++ b/src/test/ui/parser/issue-32214.stderr @@ -3,6 +3,10 @@ error: type parameters must be declared prior to associated type bindings | LL | pub fn test >() {} | ^ must be declared prior to associated type bindings +help: move the type parameter prior to the first associated type binding + | +LL | pub fn test >() {} + | ^^ -- error: aborting due to previous error diff --git a/src/test/ui/suggestions/suggest-move-types.rs b/src/test/ui/suggestions/suggest-move-types.rs new file mode 100644 index 000000000000..8f35e4ecbcac --- /dev/null +++ b/src/test/ui/suggestions/suggest-move-types.rs @@ -0,0 +1,42 @@ +#![allow(warnings)] + +// This test verifies that the suggestion to move types before associated type bindings +// is correct. + +trait One { + type A; +} + +trait Three { + type A; + type B; + type C; +} + +struct A> { //~ ERROR type parameters must be declared + m: M, + t: T, +} + +struct B> { //~ ERROR type parameters must be declared + m: M, + t: T, + u: U, + v: V, +} + +struct C> { //~ ERROR type parameters must be declared + m: M, + t: T, + u: U, + v: V, +} + +struct D> { //~ ERROR type parameters must be declared + m: M, + t: T, + u: U, + v: V, +} + +fn main() {} diff --git a/src/test/ui/suggestions/suggest-move-types.stderr b/src/test/ui/suggestions/suggest-move-types.stderr new file mode 100644 index 000000000000..c74f79a00c78 --- /dev/null +++ b/src/test/ui/suggestions/suggest-move-types.stderr @@ -0,0 +1,49 @@ +error: type parameters must be declared prior to associated type bindings + --> $DIR/suggest-move-types.rs:16:26 + | +LL | struct A> { //~ ERROR type parameters must be declared + | ^ must be declared prior to associated type bindings +help: move the type parameter prior to the first associated type binding + | +LL | struct A> { //~ ERROR type parameters must be declared + | ^^ -- + +error: type parameters must be declared prior to associated type bindings + --> $DIR/suggest-move-types.rs:21:46 + | +LL | struct B> { //~ ERROR type parameters must be declared + | ^ ^ ^ must be declared prior to associated type bindings + | | | + | | must be declared prior to associated type bindings + | must be declared prior to associated type bindings +help: move the type parameters prior to the first associated type binding + | +LL | struct B> { //~ ERROR type parameters must be declared + | ^^ ^^ ^^ -- + +error: type parameters must be declared prior to associated type bindings + --> $DIR/suggest-move-types.rs:28:49 + | +LL | struct C> { //~ ERROR type parameters must be declared + | ^ ^ must be declared prior to associated type bindings + | | + | must be declared prior to associated type bindings +help: move the type parameters prior to the first associated type binding + | +LL | struct C> { //~ ERROR type parameters must be declared + | ^^ ^^ -- + +error: type parameters must be declared prior to associated type bindings + --> $DIR/suggest-move-types.rs:35:43 + | +LL | struct D> { //~ ERROR type parameters must be declared + | ^ ^ must be declared prior to associated type bindings + | | + | must be declared prior to associated type bindings +help: move the type parameters prior to the first associated type binding + | +LL | struct D> { //~ ERROR type parameters must be declared + | ^^ ^^ -- -- + +error: aborting due to 4 previous errors +