Skip to content

Commit 057937b

Browse files
committed
Auto merge of rust-lang#79668 - coolreader18:recover-const-impl, r=petrochenkov
Recover on `const impl<> X for Y` `@leonardo-m` mentioned that `const impl Foo for Bar` could be recovered from in rust-lang#79287. I'm not sure about the error strings as they are, I think it should probably be something like the error that `expected_one_of_not_found` makes + the suggestion to flip the keywords, but I'm not sure how exactly to do that. Also, I decided not to try to handle `const unsafe impl` or `unsafe const impl` cause I figured that `unsafe impl const` would be pretty rare anyway (if it's even valid?), and it wouldn't be worth making the code more messy.
2 parents d149b65 + 1e27b65 commit 057937b

File tree

5 files changed

+99
-3
lines changed

5 files changed

+99
-3
lines changed

compiler/rustc_parse/src/parser/item.rs

+38-3
Original file line numberDiff line numberDiff line change
@@ -247,9 +247,14 @@ impl<'a> Parser<'a> {
247247
(ident, ItemKind::Static(ty, m, expr))
248248
} else if let Const::Yes(const_span) = self.parse_constness() {
249249
// CONST ITEM
250-
self.recover_const_mut(const_span);
251-
let (ident, ty, expr) = self.parse_item_global(None)?;
252-
(ident, ItemKind::Const(def(), ty, expr))
250+
if self.token.is_keyword(kw::Impl) {
251+
// recover from `const impl`, suggest `impl const`
252+
self.recover_const_impl(const_span, attrs, def())?
253+
} else {
254+
self.recover_const_mut(const_span);
255+
let (ident, ty, expr) = self.parse_item_global(None)?;
256+
(ident, ItemKind::Const(def(), ty, expr))
257+
}
253258
} else if self.check_keyword(kw::Trait) || self.check_auto_or_unsafe_trait_item() {
254259
// TRAIT ITEM
255260
self.parse_item_trait(attrs, lo)?
@@ -988,6 +993,36 @@ impl<'a> Parser<'a> {
988993
}
989994
}
990995

996+
/// Recover on `const impl` with `const` already eaten.
997+
fn recover_const_impl(
998+
&mut self,
999+
const_span: Span,
1000+
attrs: &mut Vec<Attribute>,
1001+
defaultness: Defaultness,
1002+
) -> PResult<'a, ItemInfo> {
1003+
let impl_span = self.token.span;
1004+
let mut err = self.expected_ident_found();
1005+
let mut impl_info = self.parse_item_impl(attrs, defaultness)?;
1006+
match impl_info.1 {
1007+
// only try to recover if this is implementing a trait for a type
1008+
ItemKind::Impl { of_trait: Some(ref trai), ref mut constness, .. } => {
1009+
*constness = Const::Yes(const_span);
1010+
1011+
let before_trait = trai.path.span.shrink_to_lo();
1012+
let const_up_to_impl = const_span.with_hi(impl_span.lo());
1013+
err.multipart_suggestion(
1014+
"you might have meant to write a const trait impl",
1015+
vec![(const_up_to_impl, "".to_owned()), (before_trait, "const ".to_owned())],
1016+
Applicability::MaybeIncorrect,
1017+
)
1018+
.emit();
1019+
}
1020+
ItemKind::Impl { .. } => return Err(err),
1021+
_ => unreachable!(),
1022+
}
1023+
Ok(impl_info)
1024+
}
1025+
9911026
/// Parse `["const" | ("static" "mut"?)] $ident ":" $ty (= $expr)?` with
9921027
/// `["const" | ("static" "mut"?)]` already parsed and stored in `m`.
9931028
///
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#![feature(const_trait_impl)]
2+
#![allow(incomplete_features)]
3+
4+
struct Foo;
5+
6+
const impl Foo { //~ ERROR: expected identifier, found keyword
7+
fn bar() {}
8+
}
9+
10+
fn main() {
11+
// shouldn't error here because we shouldn't have been able to recover above
12+
Foo::bar();
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
error: expected identifier, found keyword `impl`
2+
--> $DIR/const-impl-norecover.rs:6:7
3+
|
4+
LL | const impl Foo {
5+
| ^^^^ expected identifier, found keyword
6+
7+
error: aborting due to previous error
8+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#![feature(const_trait_impl)]
2+
#![allow(incomplete_features)]
3+
4+
trait Foo {}
5+
6+
const impl Foo for i32 {} //~ ERROR: expected identifier, found keyword
7+
8+
trait Bar {}
9+
10+
const impl<T: Foo> Bar for T {} //~ ERROR: expected identifier, found keyword
11+
12+
const fn still_implements<T: Bar>() {}
13+
14+
const _: () = still_implements::<i32>();
15+
16+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
error: expected identifier, found keyword `impl`
2+
--> $DIR/const-impl-recovery.rs:6:7
3+
|
4+
LL | const impl Foo for i32 {}
5+
| ^^^^ expected identifier, found keyword
6+
|
7+
help: you might have meant to write a const trait impl
8+
|
9+
LL | impl const Foo for i32 {}
10+
|-- ^^^^^
11+
12+
error: expected identifier, found keyword `impl`
13+
--> $DIR/const-impl-recovery.rs:10:7
14+
|
15+
LL | const impl<T: Foo> Bar for T {}
16+
| ^^^^ expected identifier, found keyword
17+
|
18+
help: you might have meant to write a const trait impl
19+
|
20+
LL | impl<T: Foo> const Bar for T {}
21+
|-- ^^^^^
22+
23+
error: aborting due to 2 previous errors
24+

0 commit comments

Comments
 (0)