Skip to content
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
9 changes: 9 additions & 0 deletions compiler/rustc_ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -715,6 +715,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, _) = &current.kind {
current = inner;
}
current
}

/// Is this a `..` pattern?
pub fn is_rest(&self) -> bool {
matches!(self.kind, PatKind::Rest)
Expand Down
39 changes: 35 additions & 4 deletions compiler/rustc_parse/src/parser/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -2290,6 +2289,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 =>
Expand Down
28 changes: 28 additions & 0 deletions tests/ui/self/lot-of-references-self.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 86 additions & 0 deletions tests/ui/self/lot-of-references-self.stderr
Original file line number Diff line number Diff line change
@@ -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