Support struct patterns

This commit is contained in:
est31 2023-06-02 01:25:22 +02:00
parent 86d57b7bd4
commit f538402701
3 changed files with 111 additions and 6 deletions

View File

@ -147,8 +147,8 @@ fn emit_manual_let_else(
"this could be rewritten as `let...else`",
|diag| {
// This is far from perfect, for example there needs to be:
// * tracking for multi-binding cases: let (foo, bar) = if let (Some(foo), Ok(bar)) = ...
// * renamings of the bindings for many `PatKind`s like structs, slices, etc.
// * renamings of the bindings for many `PatKind`s like slices, etc.
// * limitations in the existing replacement algorithms
// * unused binding collision detection with existing ones
// for this to be machine applicable.
let mut app = Applicability::HasPlaceholders;
@ -227,6 +227,33 @@ fn replace_in_pattern(
}
return or_pat;
},
PatKind::Struct(path, fields, has_dot_dot) => {
let fields = fields
.iter()
.map(|fld| {
if let PatKind::Binding(_, _, name, None) = fld.pat.kind &&
let Some(pat_to_put) = ident_map.get(&name.name)
{
let (sn_fld_name, _) = snippet_with_context(cx, fld.ident.span, span.ctxt(), "", app);
let (sn_ptp, _) = snippet_with_context(cx, pat_to_put.span, span.ctxt(), "", app);
// TODO: this is a bit of a hack, but it does its job. Ideally, we'd check if pat_to_put is
// a PatKind::Binding but that is also hard to get right.
if sn_fld_name == sn_ptp {
// Field init shorthand
return format!("{sn_fld_name}");
}
return format!("{sn_fld_name}: {sn_ptp}");
}
let (sn_fld, _) = snippet_with_context(cx, fld.span, span.ctxt(), "", app);
sn_fld.into_owned()
})
.collect::<Vec<_>>();
let fields_string = fields.join(", ");
let dot_dot_str = if has_dot_dot { " .." } else { "" };
let (sn_pth, _) = snippet_with_context(cx, path.span(), span.ctxt(), "", app);
return format!("{sn_pth} {{ {fields_string}{dot_dot_str} }}");
},
// Replace the variable name iff `TupleStruct` has one argument like `Variant(v)`.
PatKind::TupleStruct(ref w, args, dot_dot_pos) => {
let mut args = args

View File

@ -163,6 +163,27 @@ fn fire() {
// () is preserved: a bit of an edge case but make sure it stays around
let w = if let (Some(v), ()) = (g(), ()) { v } else { return };
// Tuple structs work
let w = if let Some(S { v: x }) = Some(S { v: 0 }) {
x
} else {
return;
};
// Field init shorthand is suggested
let v = if let Some(S { v: x }) = Some(S { v: 0 }) {
x
} else {
return;
};
// Multi-field structs also work
let (x, S { v }, w) = if let Some(U { v, w, x }) = None::<U<S<()>>> {
(x, v, w)
} else {
return;
};
}
fn not_fire() {
@ -298,6 +319,12 @@ fn not_fire() {
};
}
struct S {
v: u32,
struct S<T> {
v: T,
}
struct U<T> {
v: T,
w: T,
x: T,
}

View File

@ -301,7 +301,58 @@ LL | let w = if let (Some(v), ()) = (g(), ()) { v } else { return };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let (Some(w), ()) = (g(), ()) else { return };`
error: this could be rewritten as `let...else`
--> $DIR/manual_let_else.rs:275:5
--> $DIR/manual_let_else.rs:168:5
|
LL | / let w = if let Some(S { v: x }) = Some(S { v: 0 }) {
LL | | x
LL | | } else {
LL | | return;
LL | | };
| |______^
|
help: consider writing
|
LL ~ let Some(S { v: w }) = Some(S { v: 0 }) else {
LL + return;
LL + };
|
error: this could be rewritten as `let...else`
--> $DIR/manual_let_else.rs:175:5
|
LL | / let v = if let Some(S { v: x }) = Some(S { v: 0 }) {
LL | | x
LL | | } else {
LL | | return;
LL | | };
| |______^
|
help: consider writing
|
LL ~ let Some(S { v }) = Some(S { v: 0 }) else {
LL + return;
LL + };
|
error: this could be rewritten as `let...else`
--> $DIR/manual_let_else.rs:182:5
|
LL | / let (x, S { v }, w) = if let Some(U { v, w, x }) = None::<U<S<()>>> {
LL | | (x, v, w)
LL | | } else {
LL | | return;
LL | | };
| |______^
|
help: consider writing
|
LL ~ let Some(U { v: S { v }, w, x }) = None::<U<S<()>>> else {
LL + return;
LL + };
|
error: this could be rewritten as `let...else`
--> $DIR/manual_let_else.rs:296:5
|
LL | / let _ = match ff {
LL | | Some(value) => value,
@ -309,5 +360,5 @@ LL | | _ => macro_call!(),
LL | | };
| |______^ help: consider writing: `let Some(_) = ff else { macro_call!() };`
error: aborting due to 23 previous errors
error: aborting due to 26 previous errors