Skip to content

Commit 532c15e

Browse files
Fix suggestion when shorthand self has erroneous type
1 parent 1c580bc commit 532c15e

File tree

7 files changed

+227
-98
lines changed

7 files changed

+227
-98
lines changed

compiler/rustc_ast/src/ast.rs

+13
Original file line numberDiff line numberDiff line change
@@ -2355,6 +2355,19 @@ pub enum SelfKind {
23552355
Explicit(P<Ty>, Mutability),
23562356
}
23572357

2358+
impl SelfKind {
2359+
pub fn as_suggestion(&self) -> String {
2360+
match self {
2361+
SelfKind::Value(mutbl) => mutbl.prefix_str().to_string(),
2362+
SelfKind::Region(None, mutbl) => mutbl.ref_prefix_str().to_string(),
2363+
SelfKind::Region(Some(lt), mutbl) => format!("&{lt} {}", mutbl.prefix_str()),
2364+
SelfKind::Explicit(_, _) => {
2365+
unreachable!("if we had an explicit self, we wouldn't be here")
2366+
}
2367+
}
2368+
}
2369+
}
2370+
23582371
pub type ExplicitSelf = Spanned<SelfKind>;
23592372

23602373
impl Param {

compiler/rustc_parse/messages.ftl

+3
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,9 @@ parse_incorrect_semicolon =
329329
.suggestion = remove this semicolon
330330
.help = {$name} declarations are not followed by a semicolon
331331
332+
parse_incorrect_type_on_self = type not allowed for shorthand `self` parameter
333+
.suggestion = move the modifiers on `self` to the type
334+
332335
parse_incorrect_use_of_await =
333336
incorrect use of `await`
334337
.parentheses_suggestion = `await` is not a method call, remove the parentheses

compiler/rustc_parse/src/errors.rs

+19
Original file line numberDiff line numberDiff line change
@@ -2974,3 +2974,22 @@ pub(crate) struct AsyncImpl {
29742974
#[primary_span]
29752975
pub span: Span,
29762976
}
2977+
2978+
#[derive(Diagnostic)]
2979+
#[diag(parse_incorrect_type_on_self)]
2980+
pub(crate) struct IncorrectTypeOnSelf {
2981+
#[primary_span]
2982+
pub span: Span,
2983+
#[subdiagnostic]
2984+
pub move_self_modifier: MoveSelfModifier,
2985+
}
2986+
2987+
#[derive(Subdiagnostic)]
2988+
#[multipart_suggestion(parse_suggestion, applicability = "machine-applicable")]
2989+
pub(crate) struct MoveSelfModifier {
2990+
#[suggestion_part(code = "")]
2991+
pub removal_span: Span,
2992+
#[suggestion_part(code = "{modifier}")]
2993+
pub insertion_span: Span,
2994+
pub modifier: String,
2995+
}

compiler/rustc_parse/src/parser/item.rs

+31-1
Original file line numberDiff line numberDiff line change
@@ -2774,6 +2774,33 @@ impl<'a> Parser<'a> {
27742774
};
27752775
Ok((eself, eself_ident, eself_hi))
27762776
};
2777+
let expect_self_ident_not_typed =
2778+
|this: &mut Self, modifier: &SelfKind, modifier_span: Span| {
2779+
let eself_ident = expect_self_ident(this);
2780+
2781+
// Recover `: Type` after a qualified self
2782+
if this.may_recover() && this.check_noexpect(&token::Colon) {
2783+
this.bump();
2784+
let snap = this.create_snapshot_for_diagnostic();
2785+
match this.parse_ty() {
2786+
Ok(ty) => {
2787+
this.dcx().emit_err(errors::IncorrectTypeOnSelf {
2788+
span: ty.span,
2789+
move_self_modifier: errors::MoveSelfModifier {
2790+
removal_span: modifier_span,
2791+
insertion_span: ty.span.shrink_to_lo(),
2792+
modifier: modifier.as_suggestion(),
2793+
},
2794+
});
2795+
}
2796+
Err(diag) => {
2797+
diag.cancel();
2798+
this.restore_snapshot(snap);
2799+
}
2800+
}
2801+
}
2802+
eself_ident
2803+
};
27772804
// Recover for the grammar `*self`, `*const self`, and `*mut self`.
27782805
let recover_self_ptr = |this: &mut Self| {
27792806
this.dcx().emit_err(errors::SelfArgumentPointer { span: this.token.span });
@@ -2787,6 +2814,7 @@ impl<'a> Parser<'a> {
27872814
let eself_lo = self.token.span;
27882815
let (eself, eself_ident, eself_hi) = match self.token.uninterpolate().kind {
27892816
token::BinOp(token::And) => {
2817+
let lo = self.token.span;
27902818
let eself = if is_isolated_self(self, 1) {
27912819
// `&self`
27922820
self.bump();
@@ -2811,7 +2839,9 @@ impl<'a> Parser<'a> {
28112839
// `&not_self`
28122840
return Ok(None);
28132841
};
2814-
(eself, expect_self_ident(self), self.prev_token.span)
2842+
let hi = self.token.span;
2843+
let self_ident = expect_self_ident_not_typed(self, &eself, lo.until(hi));
2844+
(eself, self_ident, hi)
28152845
}
28162846
// `*self`
28172847
token::BinOp(token::Star) if is_isolated_self(self, 1) => {

0 commit comments

Comments
 (0)