Skip to content

Commit

Permalink
Fix suggestion when shorthand self has erroneous type
Browse files Browse the repository at this point in the history
  • Loading branch information
compiler-errors committed Mar 8, 2024
1 parent 1c580bc commit dc9108a
Show file tree
Hide file tree
Showing 6 changed files with 130 additions and 1 deletion.
13 changes: 13 additions & 0 deletions compiler/rustc_ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2355,6 +2355,19 @@ pub enum SelfKind {
Explicit(P<Ty>, Mutability),
}

impl SelfKind {
pub fn as_suggestion(&self) -> String {
match self {
SelfKind::Value(mutbl) => mutbl.prefix_str().to_string(),
SelfKind::Region(None, mutbl) => mutbl.ref_prefix_str().to_string(),
SelfKind::Region(Some(lt), mutbl) => format!("&{lt} {}", mutbl.prefix_str()),
SelfKind::Explicit(_, _) => {
unreachable!("if we had an explicit self, we wouldn't be here")
}
}
}
}

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 @@ -329,6 +329,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 @@ -2974,3 +2974,22 @@ pub(crate) struct AsyncImpl {
#[primary_span]
pub span: Span,
}

#[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,
}
32 changes: 31 additions & 1 deletion compiler/rustc_parse/src/parser/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2774,6 +2774,33 @@ 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.check_noexpect(&token::Colon) {
this.bump();
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.as_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 All @@ -2787,6 +2814,7 @@ impl<'a> Parser<'a> {
let eself_lo = self.token.span;
let (eself, eself_ident, eself_hi) = match self.token.uninterpolate().kind {
token::BinOp(token::And) => {
let lo = self.token.span;
let eself = if is_isolated_self(self, 1) {
// `&self`
self.bump();
Expand All @@ -2811,7 +2839,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, 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

0 comments on commit dc9108a

Please sign in to comment.