Rollup merge of #121236 - long-long-float:rust-fix-consider-slicing, r=Nadrieril
Don't show suggestion if slice pattern is not top-level Close #120605 Don't show suggestion to add slicing (`[..]`) if the slice pattern is enclosed by struct like `Struct { a: [] }`. For example, current rustc makes a suggestion as a comment. However, the pattern `a: []` is wrong, not scrutinee `&self.a`. In this case, the structure type `a: Vec<Struct>` and the pattern `a: []` are different so I think the pattern should be fixed, not the scrutinee. If the parent of the pattern that was the target of the error is a structure, I made the compiler not show a suggestion. ```rs pub struct Struct { a: Vec<Struct>, } impl Struct { pub fn test(&self) { if let [Struct { a: [] }] = &self.a { // ^^^^^^^^^^^^^^^^^^ ------- help: consider slicing here: `&self.a[..]` println!("matches!") } } } ``` Note: * ~~I created `PatInfo.history` to store parent-child relationships for patterns, but this may be inefficient.~~ * I use two fields `parent_kind` and `current_kind` instead of vec. It may not performance issue. * Currently only looking at direct parents, but may need to look at deeper ancestry.
This commit is contained in:
commit
3ec2b7bd1d
@ -83,6 +83,9 @@ struct PatInfo<'tcx, 'a> {
|
|||||||
binding_mode: BindingMode,
|
binding_mode: BindingMode,
|
||||||
top_info: TopInfo<'tcx>,
|
top_info: TopInfo<'tcx>,
|
||||||
decl_origin: Option<DeclOrigin<'a>>,
|
decl_origin: Option<DeclOrigin<'a>>,
|
||||||
|
|
||||||
|
/// The depth of current pattern
|
||||||
|
current_depth: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> FnCtxt<'_, 'tcx> {
|
impl<'tcx> FnCtxt<'_, 'tcx> {
|
||||||
@ -152,7 +155,8 @@ pub(crate) fn check_pat_top(
|
|||||||
decl_origin: Option<DeclOrigin<'tcx>>,
|
decl_origin: Option<DeclOrigin<'tcx>>,
|
||||||
) {
|
) {
|
||||||
let info = TopInfo { expected, origin_expr, span };
|
let info = TopInfo { expected, origin_expr, span };
|
||||||
let pat_info = PatInfo { binding_mode: INITIAL_BM, top_info: info, decl_origin };
|
let pat_info =
|
||||||
|
PatInfo { binding_mode: INITIAL_BM, top_info: info, decl_origin, current_depth: 0 };
|
||||||
self.check_pat(pat, expected, pat_info);
|
self.check_pat(pat, expected, pat_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -163,7 +167,8 @@ pub(crate) fn check_pat_top(
|
|||||||
/// Conversely, inside this module, `check_pat_top` should never be used.
|
/// Conversely, inside this module, `check_pat_top` should never be used.
|
||||||
#[instrument(level = "debug", skip(self, pat_info))]
|
#[instrument(level = "debug", skip(self, pat_info))]
|
||||||
fn check_pat(&self, pat: &'tcx Pat<'tcx>, expected: Ty<'tcx>, pat_info: PatInfo<'tcx, '_>) {
|
fn check_pat(&self, pat: &'tcx Pat<'tcx>, expected: Ty<'tcx>, pat_info: PatInfo<'tcx, '_>) {
|
||||||
let PatInfo { binding_mode: def_bm, top_info: ti, .. } = pat_info;
|
let PatInfo { binding_mode: def_bm, top_info: ti, current_depth, .. } = pat_info;
|
||||||
|
|
||||||
let path_res = match &pat.kind {
|
let path_res = match &pat.kind {
|
||||||
PatKind::Path(qpath) => Some(
|
PatKind::Path(qpath) => Some(
|
||||||
self.resolve_ty_and_res_fully_qualified_call(qpath, pat.hir_id, pat.span, None),
|
self.resolve_ty_and_res_fully_qualified_call(qpath, pat.hir_id, pat.span, None),
|
||||||
@ -172,8 +177,12 @@ fn check_pat(&self, pat: &'tcx Pat<'tcx>, expected: Ty<'tcx>, pat_info: PatInfo<
|
|||||||
};
|
};
|
||||||
let adjust_mode = self.calc_adjust_mode(pat, path_res.map(|(res, ..)| res));
|
let adjust_mode = self.calc_adjust_mode(pat, path_res.map(|(res, ..)| res));
|
||||||
let (expected, def_bm) = self.calc_default_binding_mode(pat, expected, def_bm, adjust_mode);
|
let (expected, def_bm) = self.calc_default_binding_mode(pat, expected, def_bm, adjust_mode);
|
||||||
let pat_info =
|
let pat_info = PatInfo {
|
||||||
PatInfo { binding_mode: def_bm, top_info: ti, decl_origin: pat_info.decl_origin };
|
binding_mode: def_bm,
|
||||||
|
top_info: ti,
|
||||||
|
decl_origin: pat_info.decl_origin,
|
||||||
|
current_depth: current_depth + 1,
|
||||||
|
};
|
||||||
|
|
||||||
let ty = match pat.kind {
|
let ty = match pat.kind {
|
||||||
PatKind::Wild | PatKind::Err(_) => expected,
|
PatKind::Wild | PatKind::Err(_) => expected,
|
||||||
@ -1046,14 +1055,14 @@ fn check_pat_tuple_struct(
|
|||||||
expected: Ty<'tcx>,
|
expected: Ty<'tcx>,
|
||||||
pat_info: PatInfo<'tcx, '_>,
|
pat_info: PatInfo<'tcx, '_>,
|
||||||
) -> Ty<'tcx> {
|
) -> Ty<'tcx> {
|
||||||
let PatInfo { binding_mode: def_bm, top_info: ti, decl_origin } = pat_info;
|
let PatInfo { binding_mode: def_bm, top_info: ti, decl_origin, current_depth } = pat_info;
|
||||||
let tcx = self.tcx;
|
let tcx = self.tcx;
|
||||||
let on_error = |e| {
|
let on_error = |e| {
|
||||||
for pat in subpats {
|
for pat in subpats {
|
||||||
self.check_pat(
|
self.check_pat(
|
||||||
pat,
|
pat,
|
||||||
Ty::new_error(tcx, e),
|
Ty::new_error(tcx, e),
|
||||||
PatInfo { binding_mode: def_bm, top_info: ti, decl_origin },
|
PatInfo { binding_mode: def_bm, top_info: ti, decl_origin, current_depth },
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -1120,7 +1129,7 @@ fn check_pat_tuple_struct(
|
|||||||
self.check_pat(
|
self.check_pat(
|
||||||
subpat,
|
subpat,
|
||||||
field_ty,
|
field_ty,
|
||||||
PatInfo { binding_mode: def_bm, top_info: ti, decl_origin },
|
PatInfo { binding_mode: def_bm, top_info: ti, decl_origin, current_depth },
|
||||||
);
|
);
|
||||||
|
|
||||||
self.tcx.check_stability(
|
self.tcx.check_stability(
|
||||||
@ -2134,7 +2143,7 @@ fn check_pat_slice(
|
|||||||
// The expected type must be an array or slice, but was neither, so error.
|
// The expected type must be an array or slice, but was neither, so error.
|
||||||
_ => {
|
_ => {
|
||||||
let guar = expected.error_reported().err().unwrap_or_else(|| {
|
let guar = expected.error_reported().err().unwrap_or_else(|| {
|
||||||
self.error_expected_array_or_slice(span, expected, pat_info.top_info)
|
self.error_expected_array_or_slice(span, expected, pat_info)
|
||||||
});
|
});
|
||||||
let err = Ty::new_error(self.tcx, guar);
|
let err = Ty::new_error(self.tcx, guar);
|
||||||
(err, Some(err), err)
|
(err, Some(err), err)
|
||||||
@ -2273,8 +2282,10 @@ fn error_expected_array_or_slice(
|
|||||||
&self,
|
&self,
|
||||||
span: Span,
|
span: Span,
|
||||||
expected_ty: Ty<'tcx>,
|
expected_ty: Ty<'tcx>,
|
||||||
ti: TopInfo<'tcx>,
|
pat_info: PatInfo<'tcx, '_>,
|
||||||
) -> ErrorGuaranteed {
|
) -> ErrorGuaranteed {
|
||||||
|
let PatInfo { top_info: ti, current_depth, .. } = pat_info;
|
||||||
|
|
||||||
let mut err = struct_span_code_err!(
|
let mut err = struct_span_code_err!(
|
||||||
self.dcx(),
|
self.dcx(),
|
||||||
span,
|
span,
|
||||||
@ -2292,9 +2303,10 @@ fn error_expected_array_or_slice(
|
|||||||
&& let Some(_) = ti.origin_expr
|
&& let Some(_) = ti.origin_expr
|
||||||
&& let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
|
&& let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
|
||||||
{
|
{
|
||||||
let ty = self.resolve_vars_if_possible(ti.expected);
|
let resolved_ty = self.resolve_vars_if_possible(ti.expected);
|
||||||
let is_slice_or_array_or_vector = self.is_slice_or_array_or_vector(ty);
|
let (is_slice_or_array_or_vector, resolved_ty) =
|
||||||
match is_slice_or_array_or_vector.1.kind() {
|
self.is_slice_or_array_or_vector(resolved_ty);
|
||||||
|
match resolved_ty.kind() {
|
||||||
ty::Adt(adt_def, _)
|
ty::Adt(adt_def, _)
|
||||||
if self.tcx.is_diagnostic_item(sym::Option, adt_def.did())
|
if self.tcx.is_diagnostic_item(sym::Option, adt_def.did())
|
||||||
|| self.tcx.is_diagnostic_item(sym::Result, adt_def.did()) =>
|
|| self.tcx.is_diagnostic_item(sym::Result, adt_def.did()) =>
|
||||||
@ -2309,7 +2321,9 @@ fn error_expected_array_or_slice(
|
|||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
if is_slice_or_array_or_vector.0 {
|
|
||||||
|
let is_top_level = current_depth <= 1;
|
||||||
|
if is_slice_or_array_or_vector && is_top_level {
|
||||||
err.span_suggestion(
|
err.span_suggestion(
|
||||||
span,
|
span,
|
||||||
"consider slicing here",
|
"consider slicing here",
|
||||||
|
@ -0,0 +1,20 @@
|
|||||||
|
pub struct Struct {
|
||||||
|
a: Vec<Struct>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Struct {
|
||||||
|
pub fn test(&self) {
|
||||||
|
if let [Struct { a: [] }] = &self.a {
|
||||||
|
//~^ ERROR expected an array or slice
|
||||||
|
//~| ERROR expected an array or slice
|
||||||
|
println!("matches!")
|
||||||
|
}
|
||||||
|
|
||||||
|
if let [Struct { a: [] }] = &self.a[..] {
|
||||||
|
//~^ ERROR expected an array or slice
|
||||||
|
println!("matches!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
@ -0,0 +1,23 @@
|
|||||||
|
error[E0529]: expected an array or slice, found `Vec<Struct>`
|
||||||
|
--> $DIR/suppress-consider-slicing-issue-120605.rs:7:16
|
||||||
|
|
|
||||||
|
LL | if let [Struct { a: [] }] = &self.a {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^ ------- help: consider slicing here: `&self.a[..]`
|
||||||
|
| |
|
||||||
|
| pattern cannot match with input type `Vec<Struct>`
|
||||||
|
|
||||||
|
error[E0529]: expected an array or slice, found `Vec<Struct>`
|
||||||
|
--> $DIR/suppress-consider-slicing-issue-120605.rs:7:29
|
||||||
|
|
|
||||||
|
LL | if let [Struct { a: [] }] = &self.a {
|
||||||
|
| ^^ pattern cannot match with input type `Vec<Struct>`
|
||||||
|
|
||||||
|
error[E0529]: expected an array or slice, found `Vec<Struct>`
|
||||||
|
--> $DIR/suppress-consider-slicing-issue-120605.rs:13:29
|
||||||
|
|
|
||||||
|
LL | if let [Struct { a: [] }] = &self.a[..] {
|
||||||
|
| ^^ pattern cannot match with input type `Vec<Struct>`
|
||||||
|
|
||||||
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0529`.
|
Loading…
Reference in New Issue
Block a user