From 3c91bdca1d552055e2b92ecac5275c1ebe9a4ee8 Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Wed, 29 Jan 2020 20:34:28 +0000 Subject: [PATCH 1/5] Suggest path separator for single-colon typos This commit adds guidance for when a user means to type a path, but ends up typing a single colon, such as `<:Ty>`. This change seemed pertinent as the current error message is particularly misleading, emitting `error: unmatched angle bracket`, despite the angle bracket being matched later on, leaving the user to track down the typo'd colon. --- src/librustc_parse/parser/path.rs | 18 +++++++++++++++++- .../parser/qualified-path-in-turbofish.fixed | 19 +++++++++++++++++++ .../ui/parser/qualified-path-in-turbofish.rs | 19 +++++++++++++++++++ .../parser/qualified-path-in-turbofish.stderr | 8 ++++++++ 4 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/parser/qualified-path-in-turbofish.fixed create mode 100644 src/test/ui/parser/qualified-path-in-turbofish.rs create mode 100644 src/test/ui/parser/qualified-path-in-turbofish.stderr diff --git a/src/librustc_parse/parser/path.rs b/src/librustc_parse/parser/path.rs index 0358458c0991d..25ba571a6a494 100644 --- a/src/librustc_parse/parser/path.rs +++ b/src/librustc_parse/parser/path.rs @@ -71,7 +71,23 @@ impl<'a> Parser<'a> { debug!("parse_qpath: (decrement) count={:?}", self.unmatched_angle_bracket_count); } - self.expect(&token::ModSep)?; + let lo_colon = self.token.span; + if self.eat(&token::Colon) { + // >:Qux + // ^ + let span = lo_colon.to(self.prev_span); + self.diagnostic() + .struct_span_err(span, "found single colon where type path was expected") + .span_suggestion( + span, + "use double colon", + "::".to_string(), + Applicability::MachineApplicable, + ) + .emit(); + } else { + self.expect(&token::ModSep)?; + } let qself = QSelf { ty, path_span, position: path.segments.len() }; self.parse_path_segments(&mut path.segments, style)?; diff --git a/src/test/ui/parser/qualified-path-in-turbofish.fixed b/src/test/ui/parser/qualified-path-in-turbofish.fixed new file mode 100644 index 0000000000000..a4213bdd3fb34 --- /dev/null +++ b/src/test/ui/parser/qualified-path-in-turbofish.fixed @@ -0,0 +1,19 @@ +// run-rustfix +trait T { + type Ty; +} + +struct Impl; + +impl T for Impl { + type Ty = u32; +} + +fn template() -> i64 { + 3 +} + +fn main() { + template::<::Ty>(); + //~^ ERROR found single colon where type path was expected +} diff --git a/src/test/ui/parser/qualified-path-in-turbofish.rs b/src/test/ui/parser/qualified-path-in-turbofish.rs new file mode 100644 index 0000000000000..75b2af2aa2e08 --- /dev/null +++ b/src/test/ui/parser/qualified-path-in-turbofish.rs @@ -0,0 +1,19 @@ +// run-rustfix +trait T { + type Ty; +} + +struct Impl; + +impl T for Impl { + type Ty = u32; +} + +fn template() -> i64 { + 3 +} + +fn main() { + template::<:Ty>(); + //~^ ERROR found single colon where type path was expected +} diff --git a/src/test/ui/parser/qualified-path-in-turbofish.stderr b/src/test/ui/parser/qualified-path-in-turbofish.stderr new file mode 100644 index 0000000000000..1fe6353b7a013 --- /dev/null +++ b/src/test/ui/parser/qualified-path-in-turbofish.stderr @@ -0,0 +1,8 @@ +error: found single colon where type path was expected + --> $DIR/qualified-path-in-turbofish.rs:17:27 + | +LL | template::<:Ty>(); + | ^ help: use double colon: `::` + +error: aborting due to previous error + From 88d64a09314d7f19201eebc1b92377afed31b5c2 Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Sat, 1 Feb 2020 19:06:15 +0000 Subject: [PATCH 2/5] Simplify span usage and avoid .eat() --- src/librustc_parse/parser/path.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/librustc_parse/parser/path.rs b/src/librustc_parse/parser/path.rs index 25ba571a6a494..a4541046c6c14 100644 --- a/src/librustc_parse/parser/path.rs +++ b/src/librustc_parse/parser/path.rs @@ -71,15 +71,15 @@ impl<'a> Parser<'a> { debug!("parse_qpath: (decrement) count={:?}", self.unmatched_angle_bracket_count); } - let lo_colon = self.token.span; - if self.eat(&token::Colon) { + if self.token.kind == token::Colon { // >:Qux // ^ - let span = lo_colon.to(self.prev_span); + self.bump(); + self.diagnostic() - .struct_span_err(span, "found single colon where type path was expected") + .struct_span_err(self.prev_span, "found single colon where type path was expected") .span_suggestion( - span, + self.prev_span, "use double colon", "::".to_string(), Applicability::MachineApplicable, From 45fb7232abc893a06272550ebcad7b39a3cb26c1 Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Sat, 1 Feb 2020 19:10:42 +0000 Subject: [PATCH 3/5] Move colon-check to recover_colon_before_qpath_proj() --- src/librustc_parse/parser/path.rs | 38 +++++++++++++++++++------------ 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/src/librustc_parse/parser/path.rs b/src/librustc_parse/parser/path.rs index a4541046c6c14..027380eaa2a69 100644 --- a/src/librustc_parse/parser/path.rs +++ b/src/librustc_parse/parser/path.rs @@ -71,21 +71,7 @@ impl<'a> Parser<'a> { debug!("parse_qpath: (decrement) count={:?}", self.unmatched_angle_bracket_count); } - if self.token.kind == token::Colon { - // >:Qux - // ^ - self.bump(); - - self.diagnostic() - .struct_span_err(self.prev_span, "found single colon where type path was expected") - .span_suggestion( - self.prev_span, - "use double colon", - "::".to_string(), - Applicability::MachineApplicable, - ) - .emit(); - } else { + if !self.recover_colon_before_qpath_proj() { self.expect(&token::ModSep)?; } @@ -95,6 +81,28 @@ impl<'a> Parser<'a> { Ok((qself, Path { segments: path.segments, span: lo.to(self.prev_span) })) } + fn recover_colon_before_qpath_proj(&mut self) -> bool { + if self.token.kind != token::Colon { + return false; + } + + // >:Qux + // ^ + self.bump(); + + self.diagnostic() + .struct_span_err(self.prev_span, "found single colon where type path was expected") + .span_suggestion( + self.prev_span, + "use double colon", + "::".to_string(), + Applicability::MachineApplicable, + ) + .emit(); + + true + } + /// Parses simple paths. /// /// `path = [::] segment+` From 991d2ee282837a0ca3ec5a730e081274d37fa8b0 Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Sat, 1 Feb 2020 19:21:54 +0000 Subject: [PATCH 4/5] Improve wording and docs for qualified path recovery --- src/librustc_parse/parser/path.rs | 15 +++++++++++---- .../ui/parser/qualified-path-in-turbofish.fixed | 2 +- src/test/ui/parser/qualified-path-in-turbofish.rs | 2 +- .../ui/parser/qualified-path-in-turbofish.stderr | 2 +- 4 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/librustc_parse/parser/path.rs b/src/librustc_parse/parser/path.rs index 027380eaa2a69..5aa14c1739ff6 100644 --- a/src/librustc_parse/parser/path.rs +++ b/src/librustc_parse/parser/path.rs @@ -81,17 +81,24 @@ impl<'a> Parser<'a> { Ok((qself, Path { segments: path.segments, span: lo.to(self.prev_span) })) } + /// Recover from an invalid single colon, when the user likely meant a qualified path. + /// + /// ```ignore (diagnostics) + /// >:Qux + /// ^ help: use double colon + /// ``` fn recover_colon_before_qpath_proj(&mut self) -> bool { if self.token.kind != token::Colon { return false; } - // >:Qux - // ^ - self.bump(); + self.bump(); // colon self.diagnostic() - .struct_span_err(self.prev_span, "found single colon where type path was expected") + .struct_span_err( + self.prev_span, + "found single colon before projection in qualified path", + ) .span_suggestion( self.prev_span, "use double colon", diff --git a/src/test/ui/parser/qualified-path-in-turbofish.fixed b/src/test/ui/parser/qualified-path-in-turbofish.fixed index a4213bdd3fb34..404d2f7762df4 100644 --- a/src/test/ui/parser/qualified-path-in-turbofish.fixed +++ b/src/test/ui/parser/qualified-path-in-turbofish.fixed @@ -15,5 +15,5 @@ fn template() -> i64 { fn main() { template::<::Ty>(); - //~^ ERROR found single colon where type path was expected + //~^ ERROR found single colon before projection in qualified path } diff --git a/src/test/ui/parser/qualified-path-in-turbofish.rs b/src/test/ui/parser/qualified-path-in-turbofish.rs index 75b2af2aa2e08..2f4b2ed348b9c 100644 --- a/src/test/ui/parser/qualified-path-in-turbofish.rs +++ b/src/test/ui/parser/qualified-path-in-turbofish.rs @@ -15,5 +15,5 @@ fn template() -> i64 { fn main() { template::<:Ty>(); - //~^ ERROR found single colon where type path was expected + //~^ ERROR found single colon before projection in qualified path } diff --git a/src/test/ui/parser/qualified-path-in-turbofish.stderr b/src/test/ui/parser/qualified-path-in-turbofish.stderr index 1fe6353b7a013..8857d2ef30cfc 100644 --- a/src/test/ui/parser/qualified-path-in-turbofish.stderr +++ b/src/test/ui/parser/qualified-path-in-turbofish.stderr @@ -1,4 +1,4 @@ -error: found single colon where type path was expected +error: found single colon before projection in qualified path --> $DIR/qualified-path-in-turbofish.rs:17:27 | LL | template::<:Ty>(); From 07ee472cd18925be45d424d9cfd59c441ea9c9a7 Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Sat, 1 Feb 2020 19:24:51 +0000 Subject: [PATCH 5/5] Avoid qualified path recovery when not followed by identifier --- src/librustc_parse/parser/path.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/librustc_parse/parser/path.rs b/src/librustc_parse/parser/path.rs index 5aa14c1739ff6..a09eb42dcfe6a 100644 --- a/src/librustc_parse/parser/path.rs +++ b/src/librustc_parse/parser/path.rs @@ -82,13 +82,17 @@ impl<'a> Parser<'a> { } /// Recover from an invalid single colon, when the user likely meant a qualified path. + /// We avoid emitting this if not followed by an identifier, as our assumption that the user + /// intended this to be a qualified path may not be correct. /// /// ```ignore (diagnostics) /// >:Qux /// ^ help: use double colon /// ``` fn recover_colon_before_qpath_proj(&mut self) -> bool { - if self.token.kind != token::Colon { + if self.token.kind != token::Colon + || self.look_ahead(1, |t| !t.is_ident() || t.is_reserved_ident()) + { return false; }