Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix suggestion when shorthand self has erroneous type #122161

Merged
merged 1 commit into from
Dec 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions compiler/rustc_ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2566,6 +2566,18 @@ pub enum SelfKind {
Explicit(P<Ty>, Mutability),
}

impl SelfKind {
pub fn to_ref_suggestion(&self) -> String {
match self {
SelfKind::Region(None, mutbl) => mutbl.ref_prefix_str().to_string(),
SelfKind::Region(Some(lt), mutbl) => format!("&{lt} {}", mutbl.prefix_str()),
SelfKind::Value(_) | SelfKind::Explicit(_, _) => {
unreachable!("if we had an explicit self, we wouldn't be here")
compiler-errors marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
}

pub type ExplicitSelf = Spanned<SelfKind>;

impl Param {
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_parse/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,9 @@ parse_incorrect_semicolon =
.suggestion = remove this semicolon
.help = {$name} declarations are not followed by a semicolon

parse_incorrect_type_on_self = type not allowed for shorthand `self` parameter
.suggestion = move the modifiers on `self` to the type

parse_incorrect_use_of_await = incorrect use of `await`
.parentheses_suggestion = `await` is not a method call, remove the parentheses

Expand Down
19 changes: 19 additions & 0 deletions compiler/rustc_parse/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3409,3 +3409,22 @@ pub(crate) struct PolarityAndModifiers {
pub polarity: &'static str,
pub modifiers_concatenated: String,
}

#[derive(Diagnostic)]
#[diag(parse_incorrect_type_on_self)]
pub(crate) struct IncorrectTypeOnSelf {
#[primary_span]
pub span: Span,
#[subdiagnostic]
pub move_self_modifier: MoveSelfModifier,
}

#[derive(Subdiagnostic)]
#[multipart_suggestion(parse_suggestion, applicability = "machine-applicable")]
pub(crate) struct MoveSelfModifier {
#[suggestion_part(code = "")]
pub removal_span: Span,
#[suggestion_part(code = "{modifier}")]
pub insertion_span: Span,
pub modifier: String,
}
30 changes: 29 additions & 1 deletion compiler/rustc_parse/src/parser/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2941,6 +2941,32 @@ impl<'a> Parser<'a> {
};
Ok((eself, eself_ident, eself_hi))
};
let expect_self_ident_not_typed =
|this: &mut Self, modifier: &SelfKind, modifier_span: Span| {
let eself_ident = expect_self_ident(this);

// Recover `: Type` after a qualified self
if this.may_recover() && this.eat_noexpect(&token::Colon) {
let snap = this.create_snapshot_for_diagnostic();
match this.parse_ty() {
Ok(ty) => {
this.dcx().emit_err(errors::IncorrectTypeOnSelf {
span: ty.span,
move_self_modifier: errors::MoveSelfModifier {
removal_span: modifier_span,
insertion_span: ty.span.shrink_to_lo(),
modifier: modifier.to_ref_suggestion(),
},
});
}
Err(diag) => {
diag.cancel();
this.restore_snapshot(snap);
}
}
}
eself_ident
};
// Recover for the grammar `*self`, `*const self`, and `*mut self`.
let recover_self_ptr = |this: &mut Self| {
this.dcx().emit_err(errors::SelfArgumentPointer { span: this.token.span });
Expand Down Expand Up @@ -2978,7 +3004,9 @@ impl<'a> Parser<'a> {
// `&not_self`
return Ok(None);
};
(eself, expect_self_ident(self), self.prev_token.span)
let hi = self.token.span;
let self_ident = expect_self_ident_not_typed(self, &eself, eself_lo.until(hi));
(eself, self_ident, hi)
}
// `*self`
token::BinOp(token::Star) if is_isolated_self(self, 1) => {
Expand Down
14 changes: 14 additions & 0 deletions tests/ui/parser/typed-self-param.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
struct S;

impl S {
fn a(&self: Self) {}
//~^ ERROR type not allowed for shorthand `self` parameter
fn b(&mut self: Self) {}
//~^ ERROR type not allowed for shorthand `self` parameter
fn c<'c>(&'c mut self: Self) {}
//~^ ERROR type not allowed for shorthand `self` parameter
fn d<'d>(&'d self: Self) {}
//~^ ERROR type not allowed for shorthand `self` parameter
}

fn main() {}
50 changes: 50 additions & 0 deletions tests/ui/parser/typed-self-param.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
error: type not allowed for shorthand `self` parameter
--> $DIR/typed-self-param.rs:4:17
|
LL | fn a(&self: Self) {}
| ^^^^
|
help: move the modifiers on `self` to the type
|
LL - fn a(&self: Self) {}
LL + fn a(self: &Self) {}
|

error: type not allowed for shorthand `self` parameter
--> $DIR/typed-self-param.rs:6:21
|
LL | fn b(&mut self: Self) {}
| ^^^^
|
help: move the modifiers on `self` to the type
|
LL - fn b(&mut self: Self) {}
LL + fn b(self: &mut Self) {}
|

error: type not allowed for shorthand `self` parameter
--> $DIR/typed-self-param.rs:8:28
|
LL | fn c<'c>(&'c mut self: Self) {}
| ^^^^
|
help: move the modifiers on `self` to the type
|
LL - fn c<'c>(&'c mut self: Self) {}
LL + fn c<'c>(self: &'c mut Self) {}
|

error: type not allowed for shorthand `self` parameter
--> $DIR/typed-self-param.rs:10:24
|
LL | fn d<'d>(&'d self: Self) {}
| ^^^^
|
help: move the modifiers on `self` to the type
|
LL - fn d<'d>(&'d self: Self) {}
LL + fn d<'d>(self: &'d Self) {}
|

error: aborting due to 4 previous errors

Loading