]> git.lizzy.rs Git - rust.git/commitdiff
Recover on `const impl<> X for Y`
authorNoah <33094578+coolreader18@users.noreply.github.com>
Thu, 3 Dec 2020 18:37:19 +0000 (12:37 -0600)
committerNoah <33094578+coolreader18@users.noreply.github.com>
Sat, 12 Dec 2020 20:45:54 +0000 (14:45 -0600)
compiler/rustc_parse/src/parser/item.rs
src/test/ui/rfc-2632-const-trait-impl/const-impl-norecover.rs [new file with mode: 0644]
src/test/ui/rfc-2632-const-trait-impl/const-impl-norecover.stderr [new file with mode: 0644]
src/test/ui/rfc-2632-const-trait-impl/const-impl-recovery.rs [new file with mode: 0644]
src/test/ui/rfc-2632-const-trait-impl/const-impl-recovery.stderr [new file with mode: 0644]

index 5954b370e6d986b57e01d436f6aae256904b6da5..4c92c198679f99ad8cf09883cba6bd488d5fac20 100644 (file)
@@ -247,9 +247,14 @@ fn parse_item_kind(
             (ident, ItemKind::Static(ty, m, expr))
         } else if let Const::Yes(const_span) = self.parse_constness() {
             // CONST ITEM
-            self.recover_const_mut(const_span);
-            let (ident, ty, expr) = self.parse_item_global(None)?;
-            (ident, ItemKind::Const(def(), ty, expr))
+            if self.token.is_keyword(kw::Impl) {
+                // recover from `const impl`, suggest `impl const`
+                self.recover_const_impl(const_span, attrs, def())?
+            } else {
+                self.recover_const_mut(const_span);
+                let (ident, ty, expr) = self.parse_item_global(None)?;
+                (ident, ItemKind::Const(def(), ty, expr))
+            }
         } else if self.check_keyword(kw::Trait) || self.check_auto_or_unsafe_trait_item() {
             // TRAIT ITEM
             self.parse_item_trait(attrs, lo)?
@@ -988,6 +993,36 @@ fn recover_const_mut(&mut self, const_span: Span) {
         }
     }
 
+    /// Recover on `const impl` with `const` already eaten.
+    fn recover_const_impl(
+        &mut self,
+        const_span: Span,
+        attrs: &mut Vec<Attribute>,
+        defaultness: Defaultness,
+    ) -> PResult<'a, ItemInfo> {
+        let impl_span = self.token.span;
+        let mut err = self.expected_ident_found();
+        let mut impl_info = self.parse_item_impl(attrs, defaultness)?;
+        match impl_info.1 {
+            // only try to recover if this is implementing a trait for a type
+            ItemKind::Impl { of_trait: Some(ref trai), ref mut constness, .. } => {
+                *constness = Const::Yes(const_span);
+
+                let before_trait = trai.path.span.shrink_to_lo();
+                let const_up_to_impl = const_span.with_hi(impl_span.lo());
+                err.multipart_suggestion(
+                    "you might have meant to write a const trait impl",
+                    vec![(const_up_to_impl, "".to_owned()), (before_trait, "const ".to_owned())],
+                    Applicability::MaybeIncorrect,
+                )
+                .emit();
+            }
+            ItemKind::Impl { .. } => return Err(err),
+            _ => unreachable!(),
+        }
+        Ok(impl_info)
+    }
+
     /// Parse `["const" | ("static" "mut"?)] $ident ":" $ty (= $expr)?` with
     /// `["const" | ("static" "mut"?)]` already parsed and stored in `m`.
     ///
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-impl-norecover.rs b/src/test/ui/rfc-2632-const-trait-impl/const-impl-norecover.rs
new file mode 100644 (file)
index 0000000..936c90e
--- /dev/null
@@ -0,0 +1,13 @@
+#![feature(const_trait_impl)]
+#![allow(incomplete_features)]
+
+struct Foo;
+
+const impl Foo { //~ ERROR: expected identifier, found keyword
+    fn bar() {}
+}
+
+fn main() {
+     // shouldn't error here because we shouldn't have been able to recover above
+     Foo::bar();
+}
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-impl-norecover.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-impl-norecover.stderr
new file mode 100644 (file)
index 0000000..612511a
--- /dev/null
@@ -0,0 +1,8 @@
+error: expected identifier, found keyword `impl`
+  --> $DIR/const-impl-norecover.rs:6:7
+   |
+LL | const impl Foo {
+   |       ^^^^ expected identifier, found keyword
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-impl-recovery.rs b/src/test/ui/rfc-2632-const-trait-impl/const-impl-recovery.rs
new file mode 100644 (file)
index 0000000..fd3dd2c
--- /dev/null
@@ -0,0 +1,16 @@
+#![feature(const_trait_impl)]
+#![allow(incomplete_features)]
+
+trait Foo {}
+
+const impl Foo for i32 {} //~ ERROR: expected identifier, found keyword
+
+trait Bar {}
+
+const impl<T: Foo> Bar for T {} //~ ERROR: expected identifier, found keyword
+
+const fn still_implements<T: Bar>() {}
+
+const _: () = still_implements::<i32>();
+
+fn main() {}
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-impl-recovery.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-impl-recovery.stderr
new file mode 100644 (file)
index 0000000..84fb619
--- /dev/null
@@ -0,0 +1,24 @@
+error: expected identifier, found keyword `impl`
+  --> $DIR/const-impl-recovery.rs:6:7
+   |
+LL | const impl Foo for i32 {}
+   |       ^^^^ expected identifier, found keyword
+   |
+help: you might have meant to write a const trait impl
+   |
+LL | impl const Foo for i32 {}
+   |--    ^^^^^
+
+error: expected identifier, found keyword `impl`
+  --> $DIR/const-impl-recovery.rs:10:7
+   |
+LL | const impl<T: Foo> Bar for T {}
+   |       ^^^^ expected identifier, found keyword
+   |
+help: you might have meant to write a const trait impl
+   |
+LL | impl<T: Foo> const Bar for T {}
+   |--            ^^^^^
+
+error: aborting due to 2 previous errors
+