]> git.lizzy.rs Git - rust.git/commitdiff
fix #102182, recover from impl Trait in type param bound
authoryukang <moorekang@gmail.com>
Tue, 27 Sep 2022 06:25:29 +0000 (14:25 +0800)
committeryukang <moorekang@gmail.com>
Fri, 7 Oct 2022 22:47:26 +0000 (06:47 +0800)
compiler/rustc_parse/src/parser/generics.rs
src/test/ui/parser/issues/issue-102182-impl-trait-recover.rs [new file with mode: 0644]
src/test/ui/parser/issues/issue-102182-impl-trait-recover.stderr [new file with mode: 0644]

index 4d0a8b05eb0271a573affbb80dbbd2312bf7cc59..fa75670b2ed8221008da4f9493f71b2597203767 100644 (file)
@@ -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 (file)
index 0000000..4bfc676
--- /dev/null
@@ -0,0 +1,3 @@
+fn foo<T: impl Trait>() {}
+//~^ 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 (file)
index 0000000..52b6ae5
--- /dev/null
@@ -0,0 +1,14 @@
+error: expected trait bound, found `impl Trait` type
+  --> $DIR/issue-102182-impl-trait-recover.rs:1:11
+   |
+LL | fn foo<T: impl Trait>() {}
+   |           ^^^^^^^^^^ not a trait
+   |
+help: use the trait bounds directly
+   |
+LL - fn foo<T: impl Trait>() {}
+LL + fn foo<T: Trait>() {}
+   |
+
+error: aborting due to previous error
+