未验证 提交 d3b31065 编写于 作者: M Mara Bos 提交者: GitHub

Rollup merge of #80017 - camelid:sugg-rest-pattern, r=estebank

Suggest `_` and `..` if a pattern has too few fields

Fixes #80010.
......@@ -15,6 +15,7 @@
use rustc_span::lev_distance::find_best_match_for_name;
use rustc_span::source_map::{Span, Spanned};
use rustc_span::symbol::Ident;
use rustc_span::{BytePos, DUMMY_SP};
use rustc_trait_selection::traits::{ObligationCause, Pattern};
use std::cmp;
......@@ -1001,7 +1002,7 @@ fn e0023(
// More generally, the expected type wants a tuple variant with one field of an
// N-arity-tuple, e.g., `V_i((p_0, .., p_N))`. Meanwhile, the user supplied a pattern
// with the subpatterns directly in the tuple variant pattern, e.g., `V_i(p_0, .., p_N)`.
let missing_parenthesis = match (&expected.kind(), fields, had_err) {
let missing_parentheses = match (&expected.kind(), fields, had_err) {
// #67037: only do this if we could successfully type-check the expected type against
// the tuple struct pattern. Otherwise the substs could get out of range on e.g.,
// `let P() = U;` where `P != U` with `struct P<T>(T);`.
......@@ -1014,13 +1015,13 @@ fn e0023(
}
_ => false,
};
if missing_parenthesis {
if missing_parentheses {
let (left, right) = match subpats {
// This is the zero case; we aim to get the "hi" part of the `QPath`'s
// span as the "lo" and then the "hi" part of the pattern's span as the "hi".
// This looks like:
//
// help: missing parenthesis
// help: missing parentheses
// |
// L | let A(()) = A(());
// | ^ ^
......@@ -1029,17 +1030,63 @@ fn e0023(
// last sub-pattern. In the case of `A(x)` the first and last may coincide.
// This looks like:
//
// help: missing parenthesis
// help: missing parentheses
// |
// L | let A((x, y)) = A((1, 2));
// | ^ ^
[first, ..] => (first.span.shrink_to_lo(), subpats.last().unwrap().span),
};
err.multipart_suggestion(
"missing parenthesis",
"missing parentheses",
vec![(left, "(".to_string()), (right.shrink_to_hi(), ")".to_string())],
Applicability::MachineApplicable,
);
} else if fields.len() > subpats.len() {
let after_fields_span = if pat_span == DUMMY_SP {
pat_span
} else {
pat_span.with_hi(pat_span.hi() - BytePos(1)).shrink_to_hi()
};
let all_fields_span = match subpats {
[] => after_fields_span,
[field] => field.span,
[first, .., last] => first.span.to(last.span),
};
// Check if all the fields in the pattern are wildcards.
let all_wildcards = subpats.iter().all(|pat| matches!(pat.kind, PatKind::Wild));
let mut wildcard_sugg = vec!["_"; fields.len() - subpats.len()].join(", ");
if !subpats.is_empty() {
wildcard_sugg = String::from(", ") + &wildcard_sugg;
}
err.span_suggestion_verbose(
after_fields_span,
"use `_` to explicitly ignore each field",
wildcard_sugg,
Applicability::MaybeIncorrect,
);
// Only suggest `..` if more than one field is missing
// or the pattern consists of all wildcards.
if fields.len() - subpats.len() > 1 || all_wildcards {
if subpats.is_empty() || all_wildcards {
err.span_suggestion_verbose(
all_fields_span,
"use `..` to ignore all fields",
String::from(".."),
Applicability::MaybeIncorrect,
);
} else {
err.span_suggestion_verbose(
after_fields_span,
"use `..` to ignore the rest of the fields",
String::from(", .."),
Applicability::MaybeIncorrect,
);
}
}
}
err.emit();
......
......@@ -31,6 +31,15 @@ LL | struct TupleStruct<S, T>(S, T);
...
LL | TupleStruct(_) = TupleStruct(1, 2);
| ^^^^^^^^^^^^^^ expected 2 fields, found 1
|
help: use `_` to explicitly ignore each field
|
LL | TupleStruct(_, _) = TupleStruct(1, 2);
| ^^^
help: use `..` to ignore all fields
|
LL | TupleStruct(..) = TupleStruct(1, 2);
| ^^
error[E0023]: this pattern has 3 fields, but the corresponding tuple variant has 2 fields
--> $DIR/tuple_struct_destructure_fail.rs:34:5
......@@ -49,6 +58,15 @@ LL | SingleVariant(S, T)
...
LL | Enum::SingleVariant(_) = Enum::SingleVariant(1, 2);
| ^^^^^^^^^^^^^^^^^^^^^^ expected 2 fields, found 1
|
help: use `_` to explicitly ignore each field
|
LL | Enum::SingleVariant(_, _) = Enum::SingleVariant(1, 2);
| ^^^
help: use `..` to ignore all fields
|
LL | Enum::SingleVariant(..) = Enum::SingleVariant(1, 2);
| ^^
error[E0070]: invalid left-hand side of assignment
--> $DIR/tuple_struct_destructure_fail.rs:40:12
......
......@@ -6,6 +6,11 @@ LL | Apple(String, String),
...
LL | Fruit::Apple(a) => {},
| ^^^^^^^^^^^^^^^ expected 2 fields, found 1
|
help: use `_` to explicitly ignore each field
|
LL | Fruit::Apple(a, _) => {},
| ^^^
error[E0023]: this pattern has 3 fields, but the corresponding tuple variant has 2 fields
--> $DIR/E0023.rs:12:9
......@@ -34,7 +39,7 @@ LL | Orange((String, String)),
LL | Fruit::Orange(a, b) => {},
| ^^^^^^^^^^^^^^^^^^^ expected 1 field, found 2
|
help: missing parenthesis
help: missing parentheses
|
LL | Fruit::Orange((a, b)) => {},
| ^ ^
......@@ -48,7 +53,7 @@ LL | Banana(()),
LL | Fruit::Banana() => {},
| ^^^^^^^^^^^^^^^ expected 1 field, found 0
|
help: missing parenthesis
help: missing parentheses
|
LL | Fruit::Banana(()) => {},
| ^ ^
......
......@@ -17,6 +17,15 @@ LL | struct P<T>(T); // 1 type parameter wanted
...
LL | let P() = U {};
| ^^^ expected 1 field, found 0
|
help: use `_` to explicitly ignore each field
|
LL | let P(_) = U {};
| ^
help: use `..` to ignore all fields
|
LL | let P(..) = U {};
| ^^
error: aborting due to 2 previous errors
......
......@@ -26,6 +26,11 @@ LL | struct Binder(i32, i32, i32);
...
LL | Binder(_a, _x @ ..) => {}
| ^^^^^^^^^^^^^^^^^^^ expected 3 fields, found 2
|
help: use `_` to explicitly ignore each field
|
LL | Binder(_a, _x @ .., _) => {}
| ^^^
error: aborting due to 3 previous errors
......
......@@ -6,6 +6,15 @@ LL | Rgb(usize, usize, usize),
...
LL | Color::Rgb(_, _) => { }
| ^^^^^^^^^^^^^^^^ expected 3 fields, found 2
|
help: use `_` to explicitly ignore each field
|
LL | Color::Rgb(_, _, _) => { }
| ^^^
help: use `..` to ignore all fields
|
LL | Color::Rgb(..) => { }
| ^^
error: aborting due to previous error
......
......@@ -26,6 +26,11 @@ LL | A(u8, u8),
...
LL | E::A(x @ ..) => {
| ^^^^^^^^^^^^ expected 2 fields, found 1
|
help: use `_` to explicitly ignore each field
|
LL | E::A(x @ .., _) => {
| ^^^
error: aborting due to 3 previous errors
......
struct S(i32, f32);
enum E {
S(i32, f32),
}
struct Point4(i32, i32, i32, i32);
fn main() {
match S(0, 1.0) {
S(x) => {}
//~^ ERROR this pattern has 1 field, but the corresponding tuple struct has 2 fields
//~| HELP use `_` to explicitly ignore each field
}
match S(0, 1.0) {
S(_) => {}
//~^ ERROR this pattern has 1 field, but the corresponding tuple struct has 2 fields
//~| HELP use `_` to explicitly ignore each field
//~| HELP use `..` to ignore all fields
}
match S(0, 1.0) {
S() => {}
//~^ ERROR this pattern has 0 fields, but the corresponding tuple struct has 2 fields
//~| HELP use `_` to explicitly ignore each field
//~| HELP use `..` to ignore all fields
}
match E::S(0, 1.0) {
E::S(x) => {}
//~^ ERROR this pattern has 1 field, but the corresponding tuple variant has 2 fields
//~| HELP use `_` to explicitly ignore each field
}
match E::S(0, 1.0) {
E::S(_) => {}
//~^ ERROR this pattern has 1 field, but the corresponding tuple variant has 2 fields
//~| HELP use `_` to explicitly ignore each field
//~| HELP use `..` to ignore all fields
}
match E::S(0, 1.0) {
E::S() => {}
//~^ ERROR this pattern has 0 fields, but the corresponding tuple variant has 2 fields
//~| HELP use `_` to explicitly ignore each field
//~| HELP use `..` to ignore all fields
}
match E::S(0, 1.0) {
E::S => {}
//~^ ERROR expected unit struct, unit variant or constant, found tuple variant `E::S`
//~| HELP use the tuple variant pattern syntax instead
}
match Point4(0, 1, 2, 3) {
Point4( a , _ ) => {}
//~^ ERROR this pattern has 2 fields, but the corresponding tuple struct has 4 fields
//~| HELP use `_` to explicitly ignore each field
//~| HELP use `..` to ignore the rest of the fields
}
}
error[E0532]: expected unit struct, unit variant or constant, found tuple variant `E::S`
--> $DIR/pat-tuple-underfield.rs:44:9
|
LL | S(i32, f32),
| ----------- `E::S` defined here
...
LL | E::S => {}
| ^^^^ help: use the tuple variant pattern syntax instead: `E::S(_, _)`
error[E0023]: this pattern has 1 field, but the corresponding tuple struct has 2 fields
--> $DIR/pat-tuple-underfield.rs:9:9
|
LL | struct S(i32, f32);
| ------------------- tuple struct defined here
...
LL | S(x) => {}
| ^^^^ expected 2 fields, found 1
|
help: use `_` to explicitly ignore each field
|
LL | S(x, _) => {}
| ^^^
error[E0023]: this pattern has 1 field, but the corresponding tuple struct has 2 fields
--> $DIR/pat-tuple-underfield.rs:14:9
|
LL | struct S(i32, f32);
| ------------------- tuple struct defined here
...
LL | S(_) => {}
| ^^^^ expected 2 fields, found 1
|
help: use `_` to explicitly ignore each field
|
LL | S(_, _) => {}
| ^^^
help: use `..` to ignore all fields
|
LL | S(..) => {}
| ^^
error[E0023]: this pattern has 0 fields, but the corresponding tuple struct has 2 fields
--> $DIR/pat-tuple-underfield.rs:20:9
|
LL | struct S(i32, f32);
| ------------------- tuple struct defined here
...
LL | S() => {}
| ^^^ expected 2 fields, found 0
|
help: use `_` to explicitly ignore each field
|
LL | S(_, _) => {}
| ^^^^
help: use `..` to ignore all fields
|
LL | S(..) => {}
| ^^
error[E0023]: this pattern has 1 field, but the corresponding tuple variant has 2 fields
--> $DIR/pat-tuple-underfield.rs:27:9
|
LL | S(i32, f32),
| ----------- tuple variant defined here
...
LL | E::S(x) => {}
| ^^^^^^^ expected 2 fields, found 1
|
help: use `_` to explicitly ignore each field
|
LL | E::S(x, _) => {}
| ^^^
error[E0023]: this pattern has 1 field, but the corresponding tuple variant has 2 fields
--> $DIR/pat-tuple-underfield.rs:32:9
|
LL | S(i32, f32),
| ----------- tuple variant defined here
...
LL | E::S(_) => {}
| ^^^^^^^ expected 2 fields, found 1
|
help: use `_` to explicitly ignore each field
|
LL | E::S(_, _) => {}
| ^^^
help: use `..` to ignore all fields
|
LL | E::S(..) => {}
| ^^
error[E0023]: this pattern has 0 fields, but the corresponding tuple variant has 2 fields
--> $DIR/pat-tuple-underfield.rs:38:9
|
LL | S(i32, f32),
| ----------- tuple variant defined here
...
LL | E::S() => {}
| ^^^^^^ expected 2 fields, found 0
|
help: use `_` to explicitly ignore each field
|
LL | E::S(_, _) => {}
| ^^^^
help: use `..` to ignore all fields
|
LL | E::S(..) => {}
| ^^
error[E0023]: this pattern has 2 fields, but the corresponding tuple struct has 4 fields
--> $DIR/pat-tuple-underfield.rs:50:9
|
LL | struct Point4(i32, i32, i32, i32);
| ---------------------------------- tuple struct defined here
...
LL | Point4( a , _ ) => {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 4 fields, found 2
|
help: use `_` to explicitly ignore each field
|
LL | Point4( a , _ , _, _) => {}
| ^^^^^^
help: use `..` to ignore the rest of the fields
|
LL | Point4( a , _ , ..) => {}
| ^^^^
error: aborting due to 8 previous errors
Some errors have detailed explanations: E0023, E0532.
For more information about an error, try `rustc --explain E0023`.
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册