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
This commit is contained in:
commit
0a7401148e
4 changed files with 158 additions and 4 deletions
|
|
@ -714,6 +714,15 @@ impl Pat {
|
|||
}
|
||||
}
|
||||
|
||||
/// Strip off all reference patterns (`&`, `&mut`) and return the inner pattern.
|
||||
pub fn peel_refs(&self) -> &Pat {
|
||||
let mut current = self;
|
||||
while let PatKind::Ref(inner, _) = ¤t.kind {
|
||||
current = inner;
|
||||
}
|
||||
current
|
||||
}
|
||||
|
||||
/// Is this a `..` pattern?
|
||||
pub fn is_rest(&self) -> bool {
|
||||
matches!(self.kind, PatKind::Rest)
|
||||
|
|
|
|||
|
|
@ -2,13 +2,12 @@ use std::mem::take;
|
|||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
use ast::token::IdentIsRaw;
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::token::{self, Lit, LitKind, Token, TokenKind};
|
||||
use rustc_ast::util::parser::AssocOp;
|
||||
use rustc_ast::{
|
||||
AngleBracketedArg, AngleBracketedArgs, AnonConst, AttrVec, BinOpKind, BindingMode, Block,
|
||||
BlockCheckMode, Expr, ExprKind, GenericArg, Generics, Item, ItemKind, Param, Pat, PatKind,
|
||||
Path, PathSegment, QSelf, Recovered, Ty, TyKind,
|
||||
self as ast, AngleBracketedArg, AngleBracketedArgs, AnonConst, AttrVec, BinOpKind, BindingMode,
|
||||
Block, BlockCheckMode, Expr, ExprKind, GenericArg, Generics, Item, ItemKind, Param, Pat,
|
||||
PatKind, Path, PathSegment, QSelf, Recovered, Ty, TyKind,
|
||||
};
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
|
|
@ -2302,6 +2301,38 @@ impl<'a> Parser<'a> {
|
|||
pat.span.shrink_to_hi(),
|
||||
pat.span.shrink_to_lo(),
|
||||
),
|
||||
PatKind::Ref(ref inner_pat, _)
|
||||
// Fix suggestions for multi-reference `self` parameters (e.g. `&&&self`)
|
||||
// cc: https://github.com/rust-lang/rust/pull/146305
|
||||
if let PatKind::Ref(_, _) = &inner_pat.kind
|
||||
&& let PatKind::Path(_, path) = &pat.peel_refs().kind
|
||||
&& let [a, ..] = path.segments.as_slice()
|
||||
&& a.ident.name == kw::SelfLower =>
|
||||
{
|
||||
let mut inner = inner_pat;
|
||||
let mut span_vec = vec![pat.span];
|
||||
|
||||
while let PatKind::Ref(ref inner_type, _) = inner.kind {
|
||||
inner = inner_type;
|
||||
span_vec.push(inner.span.shrink_to_lo());
|
||||
}
|
||||
|
||||
let span = match span_vec.len() {
|
||||
// Should be unreachable: match guard ensures at least 2 references
|
||||
0 | 1 => unreachable!(),
|
||||
2 => span_vec[0].until(inner_pat.span.shrink_to_lo()),
|
||||
_ => span_vec[0].until(span_vec[span_vec.len() - 2].shrink_to_lo()),
|
||||
};
|
||||
|
||||
err.span_suggestion_verbose(
|
||||
span,
|
||||
"`self` should be `self`, `&self` or `&mut self`, consider removing extra references",
|
||||
"".to_string(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
|
||||
return None;
|
||||
}
|
||||
// Also catches `fn foo(&a)`.
|
||||
PatKind::Ref(ref inner_pat, mutab)
|
||||
if let PatKind::Ident(_, ident, _) = inner_pat.clone().kind =>
|
||||
|
|
|
|||
28
tests/ui/self/lot-of-references-self.rs
Normal file
28
tests/ui/self/lot-of-references-self.rs
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
struct A ;
|
||||
|
||||
impl A {
|
||||
fn a(&&self) {}
|
||||
//~^ ERROR expected one of
|
||||
//~| HELP `self` should be `self`, `&self` or `&mut self`, consider removing extra references
|
||||
fn b(&&&&&&self) {}
|
||||
//~^ ERROR expected one of
|
||||
//~| HELP `self` should be `self`, `&self` or `&mut self`, consider removing extra references
|
||||
fn c(&self) {}
|
||||
fn d(&mut &self) {}
|
||||
//~^ ERROR expected one of
|
||||
//~| HELP `self` should be `self`, `&self` or `&mut self`, consider removing extra references
|
||||
fn e(&mut &&&self) {}
|
||||
//~^ ERROR expected one of
|
||||
//~| HELP `self` should be `self`, `&self` or `&mut self`, consider removing extra references
|
||||
fn f(&mut &mut &mut self) {}
|
||||
//~^ ERROR expected one of
|
||||
//~| HELP `self` should be `self`, `&self` or `&mut self`, consider removing extra references
|
||||
fn g(&mut & &mut self) {}
|
||||
//~^ ERROR expected one of
|
||||
//~| HELP `self` should be `self`, `&self` or `&mut self`, consider removing extra references
|
||||
fn h(&mut & & & && & & self) {}
|
||||
//~^ ERROR expected one of
|
||||
//~| HELP `self` should be `self`, `&self` or `&mut self`, consider removing extra references
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
86
tests/ui/self/lot-of-references-self.stderr
Normal file
86
tests/ui/self/lot-of-references-self.stderr
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
error: expected one of `!`, `(`, `...`, `..=`, `..`, `::`, `:`, `{`, or `|`, found `)`
|
||||
--> $DIR/lot-of-references-self.rs:4:16
|
||||
|
|
||||
LL | fn a(&&self) {}
|
||||
| ^ expected one of 9 possible tokens
|
||||
|
|
||||
help: `self` should be `self`, `&self` or `&mut self`, consider removing extra references
|
||||
|
|
||||
LL - fn a(&&self) {}
|
||||
LL + fn a(&self) {}
|
||||
|
|
||||
|
||||
error: expected one of `!`, `(`, `...`, `..=`, `..`, `::`, `:`, `{`, or `|`, found `)`
|
||||
--> $DIR/lot-of-references-self.rs:7:20
|
||||
|
|
||||
LL | fn b(&&&&&&self) {}
|
||||
| ^ expected one of 9 possible tokens
|
||||
|
|
||||
help: `self` should be `self`, `&self` or `&mut self`, consider removing extra references
|
||||
|
|
||||
LL - fn b(&&&&&&self) {}
|
||||
LL + fn b(&self) {}
|
||||
|
|
||||
|
||||
error: expected one of `!`, `(`, `...`, `..=`, `..`, `::`, `:`, `{`, or `|`, found `)`
|
||||
--> $DIR/lot-of-references-self.rs:11:20
|
||||
|
|
||||
LL | fn d(&mut &self) {}
|
||||
| ^ expected one of 9 possible tokens
|
||||
|
|
||||
help: `self` should be `self`, `&self` or `&mut self`, consider removing extra references
|
||||
|
|
||||
LL - fn d(&mut &self) {}
|
||||
LL + fn d(&self) {}
|
||||
|
|
||||
|
||||
error: expected one of `!`, `(`, `...`, `..=`, `..`, `::`, `:`, `{`, or `|`, found `)`
|
||||
--> $DIR/lot-of-references-self.rs:14:22
|
||||
|
|
||||
LL | fn e(&mut &&&self) {}
|
||||
| ^ expected one of 9 possible tokens
|
||||
|
|
||||
help: `self` should be `self`, `&self` or `&mut self`, consider removing extra references
|
||||
|
|
||||
LL - fn e(&mut &&&self) {}
|
||||
LL + fn e(&self) {}
|
||||
|
|
||||
|
||||
error: expected one of `!`, `(`, `...`, `..=`, `..`, `::`, `:`, `{`, or `|`, found `)`
|
||||
--> $DIR/lot-of-references-self.rs:17:29
|
||||
|
|
||||
LL | fn f(&mut &mut &mut self) {}
|
||||
| ^ expected one of 9 possible tokens
|
||||
|
|
||||
help: `self` should be `self`, `&self` or `&mut self`, consider removing extra references
|
||||
|
|
||||
LL - fn f(&mut &mut &mut self) {}
|
||||
LL + fn f(&mut self) {}
|
||||
|
|
||||
|
||||
error: expected one of `!`, `(`, `...`, `..=`, `..`, `::`, `:`, `{`, or `|`, found `)`
|
||||
--> $DIR/lot-of-references-self.rs:20:26
|
||||
|
|
||||
LL | fn g(&mut & &mut self) {}
|
||||
| ^ expected one of 9 possible tokens
|
||||
|
|
||||
help: `self` should be `self`, `&self` or `&mut self`, consider removing extra references
|
||||
|
|
||||
LL - fn g(&mut & &mut self) {}
|
||||
LL + fn g(&mut self) {}
|
||||
|
|
||||
|
||||
error: expected one of `!`, `(`, `...`, `..=`, `..`, `::`, `:`, `{`, or `|`, found `)`
|
||||
--> $DIR/lot-of-references-self.rs:23:39
|
||||
|
|
||||
LL | fn h(&mut & & & && & & self) {}
|
||||
| ^ expected one of 9 possible tokens
|
||||
|
|
||||
help: `self` should be `self`, `&self` or `&mut self`, consider removing extra references
|
||||
|
|
||||
LL - fn h(&mut & & & && & & self) {}
|
||||
LL + fn h(& self) {}
|
||||
|
|
||||
|
||||
error: aborting due to 7 previous errors
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue