Skip to content

Commit 77cc941

Browse files
authored
Unrolled build for #146305
Rollup merge of #146305 - Kivooeo:a-lot-of-references-in-self, r=JonathanBrouwer Add correct suggestion for multi-references for self type in method Currently the suggestion for this code ```rust fn main() {} struct A { field: i32, } impl A { fn f(&&self) {} } ``` looks like this, which is incorrect and missleading ```rust Compiling playground v0.0.1 (/playground) error: expected one of `!`, `(`, `...`, `..=`, `..`, `::`, `:`, `{`, or `|`, found `)` --> src/main.rs:8:16 | 8 | fn f(&&self) {} | ^ expected one of 9 possible tokens | = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) help: explicitly ignore the parameter name | 8 | fn f(_: &&self) {} | ++ ``` So this fixes it and make more correct suggestions ```rust error: expected one of `!`, `(`, `...`, `..=`, `..`, `::`, `:`, `{`, or `|`, found `)` --> /home/gh-Kivooeo/test_/src/main.rs:8:16 | 8 | fn f(&&self) {} | ^ expected one of 9 possible tokens | help: `self` should be `self`, `&self` or `&mut self`, please remove extra references | 8 - fn f(&&self) {} 8 + fn f(&self) {} ``` Implementation is pretty self-documenting, but if you have suggestions on how to improve this (according to current test, which may be not fully covering all cases, this is works very well) or have some funny edge cases to show, I would appreciate it r? compiler
2 parents acda5e9 + 7298174 commit 77cc941

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
@@ -714,6 +714,15 @@ impl Pat {
714714
}
715715
}
716716

717+
/// Strip off all reference patterns (`&`, `&mut`) and return the inner pattern.
718+
pub fn peel_refs(&self) -> &Pat {
719+
let mut current = self;
720+
while let PatKind::Ref(inner, _) = &current.kind {
721+
current = inner;
722+
}
723+
current
724+
}
725+
717726
/// Is this a `..` pattern?
718727
pub fn is_rest(&self) -> bool {
719728
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;
@@ -2302,6 +2301,38 @@ impl<'a> Parser<'a> {
23022301
pat.span.shrink_to_hi(),
23032302
pat.span.shrink_to_lo(),
23042303
),
2304+
PatKind::Ref(ref inner_pat, _)
2305+
// Fix suggestions for multi-reference `self` parameters (e.g. `&&&self`)
2306+
// cc: https://github.com/rust-lang/rust/pull/146305
2307+
if let PatKind::Ref(_, _) = &inner_pat.kind
2308+
&& let PatKind::Path(_, path) = &pat.peel_refs().kind
2309+
&& let [a, ..] = path.segments.as_slice()
2310+
&& a.ident.name == kw::SelfLower =>
2311+
{
2312+
let mut inner = inner_pat;
2313+
let mut span_vec = vec![pat.span];
2314+
2315+
while let PatKind::Ref(ref inner_type, _) = inner.kind {
2316+
inner = inner_type;
2317+
span_vec.push(inner.span.shrink_to_lo());
2318+
}
2319+
2320+
let span = match span_vec.len() {
2321+
// Should be unreachable: match guard ensures at least 2 references
2322+
0 | 1 => unreachable!(),
2323+
2 => span_vec[0].until(inner_pat.span.shrink_to_lo()),
2324+
_ => span_vec[0].until(span_vec[span_vec.len() - 2].shrink_to_lo()),
2325+
};
2326+
2327+
err.span_suggestion_verbose(
2328+
span,
2329+
"`self` should be `self`, `&self` or `&mut self`, consider removing extra references",
2330+
"".to_string(),
2331+
Applicability::MachineApplicable,
2332+
);
2333+
2334+
return None;
2335+
}
23052336
// Also catches `fn foo(&a)`.
23062337
PatKind::Ref(ref inner_pat, mutab)
23072338
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)