From 7b2f04a2b3e895477a96bb8ad2fe875eff411798 Mon Sep 17 00:00:00 2001 From: yukang Date: Tue, 27 Sep 2022 14:25:29 +0800 Subject: [PATCH] fix #102182, recover from impl Trait in type param bound --- compiler/rustc_parse/src/parser/generics.rs | 36 +++++++++++++++++-- .../issues/issue-102182-impl-trait-recover.rs | 3 ++ .../issue-102182-impl-trait-recover.stderr | 14 ++++++++ 3 files changed, 51 insertions(+), 2 deletions(-) create mode 100644 src/test/ui/parser/issues/issue-102182-impl-trait-recover.rs create mode 100644 src/test/ui/parser/issues/issue-102182-impl-trait-recover.stderr diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs index 4d0a8b05eb0..fa75670b2ed 100644 --- a/compiler/rustc_parse/src/parser/generics.rs +++ b/compiler/rustc_parse/src/parser/generics.rs @@ -1,7 +1,9 @@ use super::{ForceCollect, Parser, TrailingToken}; use rustc_ast::token; -use rustc_ast::{self as ast, AttrVec, GenericBounds, GenericParam, GenericParamKind, WhereClause}; +use rustc_ast::{ + self as ast, AttrVec, GenericBounds, GenericParam, GenericParamKind, TyKind, WhereClause, +}; use rustc_errors::{Applicability, PResult}; use rustc_span::symbol::kw; @@ -31,13 +33,43 @@ fn parse_ty_param(&mut self, preceding_attrs: AttrVec) -> PResult<'a, GenericPar let mut colon_span = None; let bounds = if self.eat(&token::Colon) { colon_span = Some(self.prev_token.span); + // recover from `impl Trait` in type param bound + if self.token.is_keyword(kw::Impl) { + let impl_span = self.token.span; + let snapshot = self.create_snapshot_for_diagnostic(); + match self.parse_ty() { + Ok(p) => { + if let TyKind::ImplTrait(_, bounds) = &(*p).kind { + let span = impl_span.to(self.token.span.shrink_to_lo()); + let mut err = self.struct_span_err( + span, + "expected trait bound, found `impl Trait` type", + ); + err.span_label(span, "not a trait"); + if let [bound, ..] = &bounds[..] { + err.span_suggestion_verbose( + impl_span.until(bound.span()), + "use the trait bounds directly", + String::new(), + Applicability::MachineApplicable, + ); + } + err.emit(); + return Err(err); + } + } + Err(err) => { + err.cancel(); + } + } + self.restore_snapshot(snapshot); + } self.parse_generic_bounds(colon_span)? } else { Vec::new() }; let default = if self.eat(&token::Eq) { Some(self.parse_ty()?) } else { None }; - Ok(GenericParam { ident, id: ast::DUMMY_NODE_ID, diff --git a/src/test/ui/parser/issues/issue-102182-impl-trait-recover.rs b/src/test/ui/parser/issues/issue-102182-impl-trait-recover.rs new file mode 100644 index 00000000000..4bfc676d6f6 --- /dev/null +++ b/src/test/ui/parser/issues/issue-102182-impl-trait-recover.rs @@ -0,0 +1,3 @@ +fn foo() {} +//~^ ERROR expected trait bound, found `impl Trait` type +fn main() {} diff --git a/src/test/ui/parser/issues/issue-102182-impl-trait-recover.stderr b/src/test/ui/parser/issues/issue-102182-impl-trait-recover.stderr new file mode 100644 index 00000000000..52b6ae5df35 --- /dev/null +++ b/src/test/ui/parser/issues/issue-102182-impl-trait-recover.stderr @@ -0,0 +1,14 @@ +error: expected trait bound, found `impl Trait` type + --> $DIR/issue-102182-impl-trait-recover.rs:1:11 + | +LL | fn foo() {} + | ^^^^^^^^^^ not a trait + | +help: use the trait bounds directly + | +LL - fn foo() {} +LL + fn foo() {} + | + +error: aborting due to previous error +