Skip to content

Commit 7298174

Browse files
committed
add parser check for multi-reference self
1 parent 1ed3cd7 commit 7298174

File tree

4 files changed

+158
-4
lines changed

4 files changed

+158
-4
lines changed

compiler/rustc_ast/src/ast.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -715,6 +715,15 @@ impl Pat {
715715
}
716716
}
717717

718+
/// Strip off all reference patterns (`&`, `&mut`) and return the inner pattern.
719+
pub fn peel_refs(&self) -> &Pat {
720+
let mut current = self;
721+
while let PatKind::Ref(inner, _) = &current.kind {
722+
current = inner;
723+
}
724+
current
725+
}
726+
718727
/// Is this a `..` pattern?
719728
pub fn is_rest(&self) -> bool {
720729
matches!(self.kind, PatKind::Rest)

compiler/rustc_parse/src/parser/diagnostics.rs

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,12 @@ use std::mem::take;
22
use std::ops::{Deref, DerefMut};
33

44
use ast::token::IdentIsRaw;
5-
use rustc_ast as ast;
65
use rustc_ast::token::{self, Lit, LitKind, Token, TokenKind};
76
use rustc_ast::util::parser::AssocOp;
87
use rustc_ast::{
9-
AngleBracketedArg, AngleBracketedArgs, AnonConst, AttrVec, BinOpKind, BindingMode, Block,
10-
BlockCheckMode, Expr, ExprKind, GenericArg, Generics, Item, ItemKind, Param, Pat, PatKind,
11-
Path, PathSegment, QSelf, Recovered, Ty, TyKind,
8+
self as ast, AngleBracketedArg, AngleBracketedArgs, AnonConst, AttrVec, BinOpKind, BindingMode,
9+
Block, BlockCheckMode, Expr, ExprKind, GenericArg, Generics, Item, ItemKind, Param, Pat,
10+
PatKind, Path, PathSegment, QSelf, Recovered, Ty, TyKind,
1211
};
1312
use rustc_ast_pretty::pprust;
1413
use rustc_data_structures::fx::FxHashSet;
@@ -2290,6 +2289,38 @@ impl<'a> Parser<'a> {
22902289
pat.span.shrink_to_hi(),
22912290
pat.span.shrink_to_lo(),
22922291
),
2292+
PatKind::Ref(ref inner_pat, _)
2293+
// Fix suggestions for multi-reference `self` parameters (e.g. `&&&self`)
2294+
// cc: https://github.com/rust-lang/rust/pull/146305
2295+
if let PatKind::Ref(_, _) = &inner_pat.kind
2296+
&& let PatKind::Path(_, path) = &pat.peel_refs().kind
2297+
&& let [a, ..] = path.segments.as_slice()
2298+
&& a.ident.name == kw::SelfLower =>
2299+
{
2300+
let mut inner = inner_pat;
2301+
let mut span_vec = vec![pat.span];
2302+
2303+
while let PatKind::Ref(ref inner_type, _) = inner.kind {
2304+
inner = inner_type;
2305+
span_vec.push(inner.span.shrink_to_lo());
2306+
}
2307+
2308+
let span = match span_vec.len() {
2309+
// Should be unreachable: match guard ensures at least 2 references
2310+
0 | 1 => unreachable!(),
2311+
2 => span_vec[0].until(inner_pat.span.shrink_to_lo()),
2312+
_ => span_vec[0].until(span_vec[span_vec.len() - 2].shrink_to_lo()),
2313+
};
2314+
2315+
err.span_suggestion_verbose(
2316+
span,
2317+
"`self` should be `self`, `&self` or `&mut self`, consider removing extra references",
2318+
"".to_string(),
2319+
Applicability::MachineApplicable,
2320+
);
2321+
2322+
return None;
2323+
}
22932324
// Also catches `fn foo(&a)`.
22942325
PatKind::Ref(ref inner_pat, mutab)
22952326
if let PatKind::Ident(_, ident, _) = inner_pat.clone().kind =>
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
struct A ;
2+
3+
impl A {
4+
fn a(&&self) {}
5+
//~^ ERROR expected one of
6+
//~| HELP `self` should be `self`, `&self` or `&mut self`, consider removing extra references
7+
fn b(&&&&&&self) {}
8+
//~^ ERROR expected one of
9+
//~| HELP `self` should be `self`, `&self` or `&mut self`, consider removing extra references
10+
fn c(&self) {}
11+
fn d(&mut &self) {}
12+
//~^ ERROR expected one of
13+
//~| HELP `self` should be `self`, `&self` or `&mut self`, consider removing extra references
14+
fn e(&mut &&&self) {}
15+
//~^ ERROR expected one of
16+
//~| HELP `self` should be `self`, `&self` or `&mut self`, consider removing extra references
17+
fn f(&mut &mut &mut self) {}
18+
//~^ ERROR expected one of
19+
//~| HELP `self` should be `self`, `&self` or `&mut self`, consider removing extra references
20+
fn g(&mut & &mut self) {}
21+
//~^ ERROR expected one of
22+
//~| HELP `self` should be `self`, `&self` or `&mut self`, consider removing extra references
23+
fn h(&mut & & & && & & self) {}
24+
//~^ ERROR expected one of
25+
//~| HELP `self` should be `self`, `&self` or `&mut self`, consider removing extra references
26+
}
27+
28+
fn main() {}
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
error: expected one of `!`, `(`, `...`, `..=`, `..`, `::`, `:`, `{`, or `|`, found `)`
2+
--> $DIR/lot-of-references-self.rs:4:16
3+
|
4+
LL | fn a(&&self) {}
5+
| ^ expected one of 9 possible tokens
6+
|
7+
help: `self` should be `self`, `&self` or `&mut self`, consider removing extra references
8+
|
9+
LL - fn a(&&self) {}
10+
LL + fn a(&self) {}
11+
|
12+
13+
error: expected one of `!`, `(`, `...`, `..=`, `..`, `::`, `:`, `{`, or `|`, found `)`
14+
--> $DIR/lot-of-references-self.rs:7:20
15+
|
16+
LL | fn b(&&&&&&self) {}
17+
| ^ expected one of 9 possible tokens
18+
|
19+
help: `self` should be `self`, `&self` or `&mut self`, consider removing extra references
20+
|
21+
LL - fn b(&&&&&&self) {}
22+
LL + fn b(&self) {}
23+
|
24+
25+
error: expected one of `!`, `(`, `...`, `..=`, `..`, `::`, `:`, `{`, or `|`, found `)`
26+
--> $DIR/lot-of-references-self.rs:11:20
27+
|
28+
LL | fn d(&mut &self) {}
29+
| ^ expected one of 9 possible tokens
30+
|
31+
help: `self` should be `self`, `&self` or `&mut self`, consider removing extra references
32+
|
33+
LL - fn d(&mut &self) {}
34+
LL + fn d(&self) {}
35+
|
36+
37+
error: expected one of `!`, `(`, `...`, `..=`, `..`, `::`, `:`, `{`, or `|`, found `)`
38+
--> $DIR/lot-of-references-self.rs:14:22
39+
|
40+
LL | fn e(&mut &&&self) {}
41+
| ^ expected one of 9 possible tokens
42+
|
43+
help: `self` should be `self`, `&self` or `&mut self`, consider removing extra references
44+
|
45+
LL - fn e(&mut &&&self) {}
46+
LL + fn e(&self) {}
47+
|
48+
49+
error: expected one of `!`, `(`, `...`, `..=`, `..`, `::`, `:`, `{`, or `|`, found `)`
50+
--> $DIR/lot-of-references-self.rs:17:29
51+
|
52+
LL | fn f(&mut &mut &mut self) {}
53+
| ^ expected one of 9 possible tokens
54+
|
55+
help: `self` should be `self`, `&self` or `&mut self`, consider removing extra references
56+
|
57+
LL - fn f(&mut &mut &mut self) {}
58+
LL + fn f(&mut self) {}
59+
|
60+
61+
error: expected one of `!`, `(`, `...`, `..=`, `..`, `::`, `:`, `{`, or `|`, found `)`
62+
--> $DIR/lot-of-references-self.rs:20:26
63+
|
64+
LL | fn g(&mut & &mut self) {}
65+
| ^ expected one of 9 possible tokens
66+
|
67+
help: `self` should be `self`, `&self` or `&mut self`, consider removing extra references
68+
|
69+
LL - fn g(&mut & &mut self) {}
70+
LL + fn g(&mut self) {}
71+
|
72+
73+
error: expected one of `!`, `(`, `...`, `..=`, `..`, `::`, `:`, `{`, or `|`, found `)`
74+
--> $DIR/lot-of-references-self.rs:23:39
75+
|
76+
LL | fn h(&mut & & & && & & self) {}
77+
| ^ expected one of 9 possible tokens
78+
|
79+
help: `self` should be `self`, `&self` or `&mut self`, consider removing extra references
80+
|
81+
LL - fn h(&mut & & & && & & self) {}
82+
LL + fn h(& self) {}
83+
|
84+
85+
error: aborting due to 7 previous errors
86+

0 commit comments

Comments
 (0)