From 00887f39d199bc63730d0dd19f8726451fdd5758 Mon Sep 17 00:00:00 2001 From: Wesley Norris Date: Mon, 4 Mar 2019 20:00:28 -0500 Subject: [PATCH 1/2] Adds diagnostic message and UI test. --- src/libsyntax/parse/parser.rs | 10 +++++++++- src/test/ui/issues/issue-56031.rs | 5 +++++ src/test/ui/issues/issue-56031.stderr | 10 ++++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/issues/issue-56031.rs create mode 100644 src/test/ui/issues/issue-56031.stderr diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index fd5038a8614f2..330be1133ca4b 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -6716,8 +6716,16 @@ impl<'a> Parser<'a> { ast::ImplPolarity::Positive }; + let possible_missing_trait = self.look_ahead(0, |t| t.is_keyword(keywords::For)); + // Parse both types and traits as a type, then reinterpret if necessary. - let ty_first = self.parse_ty()?; + let ty_first = self.parse_ty().map_err(|mut err| { + if possible_missing_trait { + err.help("did you forget a trait name after `impl`?"); + } + + err + })?; // If `for` is missing we try to recover. let has_for = self.eat_keyword(keywords::For); diff --git a/src/test/ui/issues/issue-56031.rs b/src/test/ui/issues/issue-56031.rs new file mode 100644 index 0000000000000..7dbda3e46d13c --- /dev/null +++ b/src/test/ui/issues/issue-56031.rs @@ -0,0 +1,5 @@ +struct T; + +impl for T {} + +fn main() {} diff --git a/src/test/ui/issues/issue-56031.stderr b/src/test/ui/issues/issue-56031.stderr new file mode 100644 index 0000000000000..dd4f95341ff22 --- /dev/null +++ b/src/test/ui/issues/issue-56031.stderr @@ -0,0 +1,10 @@ +error: expected `<`, found `T` + --> $DIR/issue-56031.rs:3:10 + | +LL | impl for T {} + | ^ expected `<` here + | + = help: did you forget a trait name after `impl`? + +error: aborting due to previous error + From e19b2289594746ce733588ac444df3fefaad4912 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Thu, 7 Mar 2019 23:18:03 +0300 Subject: [PATCH 2/2] Improve recovery for missing trait in a trait impl --- src/libsyntax/parse/parser.rs | 22 +++++++++++----------- src/test/ui/issues/issue-56031.rs | 1 + src/test/ui/issues/issue-56031.stderr | 8 +++----- 3 files changed, 15 insertions(+), 16 deletions(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 330be1133ca4b..64f413e6dd8ee 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -6716,16 +6716,16 @@ impl<'a> Parser<'a> { ast::ImplPolarity::Positive }; - let possible_missing_trait = self.look_ahead(0, |t| t.is_keyword(keywords::For)); - // Parse both types and traits as a type, then reinterpret if necessary. - let ty_first = self.parse_ty().map_err(|mut err| { - if possible_missing_trait { - err.help("did you forget a trait name after `impl`?"); - } - - err - })?; + let err_path = |span| ast::Path::from_ident(Ident::new(keywords::Invalid.name(), span)); + let ty_first = if self.token.is_keyword(keywords::For) && + self.look_ahead(1, |t| t != &token::Lt) { + let span = self.prev_span.between(self.span); + self.struct_span_err(span, "missing trait in a trait impl").emit(); + P(Ty { node: TyKind::Path(None, err_path(span)), span, id: ast::DUMMY_NODE_ID }) + } else { + self.parse_ty()? + }; // If `for` is missing we try to recover. let has_for = self.eat_keyword(keywords::For); @@ -6734,7 +6734,7 @@ impl<'a> Parser<'a> { let ty_second = if self.token == token::DotDot { // We need to report this error after `cfg` expansion for compatibility reasons self.bump(); // `..`, do not add it to expected tokens - Some(P(Ty { node: TyKind::Err, span: self.prev_span, id: ast::DUMMY_NODE_ID })) + Some(DummyResult::raw_ty(self.prev_span, true)) } else if has_for || self.token.can_begin_type() { Some(self.parse_ty()?) } else { @@ -6764,7 +6764,7 @@ impl<'a> Parser<'a> { TyKind::Path(None, path) => path, _ => { self.span_err(ty_first.span, "expected a trait, found type"); - ast::Path::from_ident(Ident::new(keywords::Invalid.name(), ty_first.span)) + err_path(ty_first.span) } }; let trait_ref = TraitRef { path, ref_id: ty_first.id }; diff --git a/src/test/ui/issues/issue-56031.rs b/src/test/ui/issues/issue-56031.rs index 7dbda3e46d13c..b68f56814678c 100644 --- a/src/test/ui/issues/issue-56031.rs +++ b/src/test/ui/issues/issue-56031.rs @@ -1,5 +1,6 @@ struct T; impl for T {} +//~^ ERROR missing trait in a trait impl fn main() {} diff --git a/src/test/ui/issues/issue-56031.stderr b/src/test/ui/issues/issue-56031.stderr index dd4f95341ff22..3d7acee0a56eb 100644 --- a/src/test/ui/issues/issue-56031.stderr +++ b/src/test/ui/issues/issue-56031.stderr @@ -1,10 +1,8 @@ -error: expected `<`, found `T` - --> $DIR/issue-56031.rs:3:10 +error: missing trait in a trait impl + --> $DIR/issue-56031.rs:3:5 | LL | impl for T {} - | ^ expected `<` here - | - = help: did you forget a trait name after `impl`? + | ^ error: aborting due to previous error