mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-30 10:45:18 +00:00
When recovering from a :
in a pattern, use adequate AST pattern
This commit is contained in:
parent
862962b90e
commit
d6e34ad108
@ -3,13 +3,17 @@ use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
|
||||
use rustc_ast::mut_visit::{noop_visit_pat, MutVisitor};
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::token;
|
||||
use rustc_ast::{self as ast, AttrVec, Attribute, MacCall, Pat, PatField, PatKind, RangeEnd};
|
||||
use rustc_ast::{BindingMode, Expr, ExprKind, Mutability, Path, QSelf, RangeSyntax};
|
||||
use rustc_ast::{
|
||||
self as ast, AttrVec, Attribute, BindingMode, Expr, ExprKind, MacCall, Mutability, Pat,
|
||||
PatField, PatKind, Path, PathSegment, QSelf, RangeEnd, RangeSyntax,
|
||||
};
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, PResult};
|
||||
use rustc_span::source_map::{respan, Span, Spanned};
|
||||
use rustc_span::symbol::{kw, sym, Ident};
|
||||
|
||||
use std::mem::take;
|
||||
|
||||
type Expected = Option<&'static str>;
|
||||
|
||||
/// `Expected` for function and lambda parameter patterns.
|
||||
@ -101,11 +105,8 @@ impl<'a> Parser<'a> {
|
||||
let mut first_pat = first_pat;
|
||||
|
||||
if let (RecoverColon::Yes, token::Colon) = (ra, &self.token.kind) {
|
||||
if matches!(
|
||||
first_pat.kind,
|
||||
PatKind::Ident(BindingMode::ByValue(Mutability::Not), _, None)
|
||||
| PatKind::Path(..)
|
||||
) && self.look_ahead(1, |token| token.is_ident() && !token.is_reserved_ident())
|
||||
if matches!(first_pat.kind, PatKind::Ident(_, _, None) | PatKind::Path(..))
|
||||
&& self.look_ahead(1, |token| token.is_ident() && !token.is_reserved_ident())
|
||||
{
|
||||
// The pattern looks like it might be a path with a `::` -> `:` typo:
|
||||
// `match foo { bar:baz => {} }`
|
||||
@ -126,17 +127,87 @@ impl<'a> Parser<'a> {
|
||||
err.cancel();
|
||||
*self = snapshot;
|
||||
}
|
||||
Ok(pat) => {
|
||||
Ok(mut pat) => {
|
||||
// We've parsed the rest of the pattern.
|
||||
err.span_suggestion(
|
||||
span,
|
||||
"maybe write a path separator here",
|
||||
"::".to_string(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
let new_span = first_pat.span.to(pat.span);
|
||||
let mut show_sugg = false;
|
||||
match &mut pat.kind {
|
||||
PatKind::Struct(qself @ None, path, ..)
|
||||
| PatKind::TupleStruct(qself @ None, path, _)
|
||||
| PatKind::Path(qself @ None, path) => {
|
||||
match &first_pat.kind {
|
||||
PatKind::Ident(_, ident, _) => {
|
||||
path.segments.insert(
|
||||
0,
|
||||
PathSegment::from_ident(ident.clone()),
|
||||
);
|
||||
path.span = new_span;
|
||||
show_sugg = true;
|
||||
first_pat = pat;
|
||||
}
|
||||
PatKind::Path(old_qself, old_path) => {
|
||||
path.segments = old_path
|
||||
.segments
|
||||
.iter()
|
||||
.cloned()
|
||||
.chain(take(&mut path.segments))
|
||||
.collect();
|
||||
path.span = new_span;
|
||||
*qself = old_qself.clone();
|
||||
first_pat = pat;
|
||||
show_sugg = true;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
PatKind::Ident(
|
||||
BindingMode::ByValue(Mutability::Not),
|
||||
ident,
|
||||
None,
|
||||
) => match &first_pat.kind {
|
||||
PatKind::Ident(_, old_ident, _) => {
|
||||
let path = PatKind::Path(
|
||||
None,
|
||||
Path {
|
||||
span: new_span,
|
||||
segments: vec![
|
||||
PathSegment::from_ident(
|
||||
old_ident.clone(),
|
||||
),
|
||||
PathSegment::from_ident(ident.clone()),
|
||||
],
|
||||
tokens: None,
|
||||
},
|
||||
);
|
||||
first_pat = self.mk_pat(new_span, path);
|
||||
show_sugg = true;
|
||||
}
|
||||
PatKind::Path(old_qself, old_path) => {
|
||||
let mut segments = old_path.segments.clone();
|
||||
segments
|
||||
.push(PathSegment::from_ident(ident.clone()));
|
||||
let path = PatKind::Path(
|
||||
old_qself.clone(),
|
||||
Path { span: new_span, segments, tokens: None },
|
||||
);
|
||||
first_pat = self.mk_pat(new_span, path);
|
||||
show_sugg = true;
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
if show_sugg {
|
||||
err.span_suggestion(
|
||||
span,
|
||||
"maybe write a path separator here",
|
||||
"::".to_string(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
} else {
|
||||
first_pat = self.mk_pat(new_span, PatKind::Wild);
|
||||
}
|
||||
err.emit();
|
||||
first_pat =
|
||||
self.mk_pat(first_pat.span.to(pat.span), PatKind::Wild);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,15 @@
|
||||
// Tests that a suggestion is issued if the user wrote a colon instead of
|
||||
// a path separator in a match arm.
|
||||
|
||||
enum Foo {
|
||||
Bar,
|
||||
Baz,
|
||||
mod qux {
|
||||
pub enum Foo {
|
||||
Bar,
|
||||
Baz,
|
||||
}
|
||||
}
|
||||
|
||||
use qux::Foo;
|
||||
|
||||
fn f() -> Foo { Foo::Bar }
|
||||
|
||||
fn g1() {
|
||||
@ -16,24 +20,24 @@ fn g1() {
|
||||
_ => {}
|
||||
}
|
||||
match f() {
|
||||
Foo::Bar:Baz => {}
|
||||
qux::Foo:Bar => {}
|
||||
//~^ ERROR: expected one of
|
||||
//~| HELP: maybe write a path separator here
|
||||
_ => {}
|
||||
}
|
||||
match f() {
|
||||
Foo:Bar::Baz => {}
|
||||
qux:Foo::Baz => {}
|
||||
//~^ ERROR: expected one of
|
||||
//~| HELP: maybe write a path separator here
|
||||
_ => {}
|
||||
}
|
||||
match f() {
|
||||
Foo: Bar::Baz if true => {}
|
||||
qux: Foo::Baz if true => {}
|
||||
//~^ ERROR: expected one of
|
||||
//~| HELP: maybe write a path separator here
|
||||
_ => {}
|
||||
}
|
||||
if let Bar:Baz = f() {
|
||||
if let Foo:Bar = f() {
|
||||
//~^ ERROR: expected one of
|
||||
//~| HELP: maybe write a path separator here
|
||||
}
|
||||
@ -41,16 +45,18 @@ fn g1() {
|
||||
|
||||
fn g1_neg() {
|
||||
match f() {
|
||||
ref Foo: Bar::Baz => {}
|
||||
ref qux: Foo::Baz => {}
|
||||
//~^ ERROR: expected one of
|
||||
//~| HELP: maybe write a path separator here
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn g2_neg() {
|
||||
match f() {
|
||||
mut Foo: Bar::Baz => {}
|
||||
mut qux: Foo::Baz => {}
|
||||
//~^ ERROR: expected one of
|
||||
//~| HELP: maybe write a path separator here
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
@ -62,5 +68,12 @@ fn main() {
|
||||
Foo:Bar::Baz => {}
|
||||
//~^ ERROR: expected one of
|
||||
//~| HELP: maybe write a path separator here
|
||||
//~| ERROR: failed to resolve: `Bar` is a variant, not a module
|
||||
}
|
||||
match myfoo {
|
||||
Foo::Bar => {}
|
||||
Foo:Bar => {}
|
||||
//~^ ERROR: expected one of
|
||||
//~| HELP: maybe write a path separator here
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: expected one of `@` or `|`, found `:`
|
||||
--> $DIR/issue-87086-colon-path-sep.rs:13:12
|
||||
--> $DIR/issue-87086-colon-path-sep.rs:17:12
|
||||
|
|
||||
LL | Foo:Bar => {}
|
||||
| ^
|
||||
@ -8,55 +8,61 @@ LL | Foo:Bar => {}
|
||||
| help: maybe write a path separator here: `::`
|
||||
|
||||
error: expected one of `!`, `(`, `...`, `..=`, `..`, `::`, `{`, or `|`, found `:`
|
||||
--> $DIR/issue-87086-colon-path-sep.rs:19:17
|
||||
--> $DIR/issue-87086-colon-path-sep.rs:23:17
|
||||
|
|
||||
LL | Foo::Bar:Baz => {}
|
||||
LL | qux::Foo:Bar => {}
|
||||
| ^
|
||||
| |
|
||||
| expected one of 8 possible tokens
|
||||
| help: maybe write a path separator here: `::`
|
||||
|
||||
error: expected one of `@` or `|`, found `:`
|
||||
--> $DIR/issue-87086-colon-path-sep.rs:25:12
|
||||
--> $DIR/issue-87086-colon-path-sep.rs:29:12
|
||||
|
|
||||
LL | Foo:Bar::Baz => {}
|
||||
LL | qux:Foo::Baz => {}
|
||||
| ^
|
||||
| |
|
||||
| expected one of `@` or `|`
|
||||
| help: maybe write a path separator here: `::`
|
||||
|
||||
error: expected one of `@` or `|`, found `:`
|
||||
--> $DIR/issue-87086-colon-path-sep.rs:31:12
|
||||
--> $DIR/issue-87086-colon-path-sep.rs:35:12
|
||||
|
|
||||
LL | Foo: Bar::Baz if true => {}
|
||||
LL | qux: Foo::Baz if true => {}
|
||||
| ^
|
||||
| |
|
||||
| expected one of `@` or `|`
|
||||
| help: maybe write a path separator here: `::`
|
||||
|
||||
error: expected one of `@` or `|`, found `:`
|
||||
--> $DIR/issue-87086-colon-path-sep.rs:36:15
|
||||
--> $DIR/issue-87086-colon-path-sep.rs:40:15
|
||||
|
|
||||
LL | if let Bar:Baz = f() {
|
||||
LL | if let Foo:Bar = f() {
|
||||
| ^
|
||||
| |
|
||||
| expected one of `@` or `|`
|
||||
| help: maybe write a path separator here: `::`
|
||||
|
||||
error: expected one of `=>`, `@`, `if`, or `|`, found `:`
|
||||
--> $DIR/issue-87086-colon-path-sep.rs:44:16
|
||||
error: expected one of `@` or `|`, found `:`
|
||||
--> $DIR/issue-87086-colon-path-sep.rs:48:16
|
||||
|
|
||||
LL | ref Foo: Bar::Baz => {}
|
||||
| ^ expected one of `=>`, `@`, `if`, or `|`
|
||||
|
||||
error: expected one of `=>`, `@`, `if`, or `|`, found `:`
|
||||
--> $DIR/issue-87086-colon-path-sep.rs:52:16
|
||||
|
|
||||
LL | mut Foo: Bar::Baz => {}
|
||||
| ^ expected one of `=>`, `@`, `if`, or `|`
|
||||
LL | ref qux: Foo::Baz => {}
|
||||
| ^
|
||||
| |
|
||||
| expected one of `@` or `|`
|
||||
| help: maybe write a path separator here: `::`
|
||||
|
||||
error: expected one of `@` or `|`, found `:`
|
||||
--> $DIR/issue-87086-colon-path-sep.rs:62:12
|
||||
--> $DIR/issue-87086-colon-path-sep.rs:57:16
|
||||
|
|
||||
LL | mut qux: Foo::Baz => {}
|
||||
| ^
|
||||
| |
|
||||
| expected one of `@` or `|`
|
||||
| help: maybe write a path separator here: `::`
|
||||
|
||||
error: expected one of `@` or `|`, found `:`
|
||||
--> $DIR/issue-87086-colon-path-sep.rs:68:12
|
||||
|
|
||||
LL | Foo:Bar::Baz => {}
|
||||
| ^
|
||||
@ -64,5 +70,21 @@ LL | Foo:Bar::Baz => {}
|
||||
| expected one of `@` or `|`
|
||||
| help: maybe write a path separator here: `::`
|
||||
|
||||
error: aborting due to 8 previous errors
|
||||
error: expected one of `@` or `|`, found `:`
|
||||
--> $DIR/issue-87086-colon-path-sep.rs:75:12
|
||||
|
|
||||
LL | Foo:Bar => {}
|
||||
| ^
|
||||
| |
|
||||
| expected one of `@` or `|`
|
||||
| help: maybe write a path separator here: `::`
|
||||
|
||||
error[E0433]: failed to resolve: `Bar` is a variant, not a module
|
||||
--> $DIR/issue-87086-colon-path-sep.rs:68:13
|
||||
|
|
||||
LL | Foo:Bar::Baz => {}
|
||||
| ^^^ `Bar` is a variant, not a module
|
||||
|
||||
error: aborting due to 10 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0433`.
|
||||
|
Loading…
Reference in New Issue
Block a user