Skip to content

improve "try ignoring the field" diagnostic #100031

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Aug 15, 2022
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
34 changes: 32 additions & 2 deletions compiler/rustc_passes/src/liveness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{self, DefIdTree, RootVariableMinCaptureList, Ty, TyCtxt};
use rustc_session::lint;
use rustc_span::symbol::{kw, sym, Symbol};
use rustc_span::Span;
use rustc_span::{BytePos, Span};

use std::collections::VecDeque;
use std::io;
Expand Down Expand Up @@ -1549,23 +1549,27 @@ impl<'tcx> Liveness<'_, 'tcx> {
.or_insert_with(|| (ln, var, vec![id_and_sp]));
});

let can_remove = matches!(&pat.kind, hir::PatKind::Struct(_, _, true));

for (_, (ln, var, hir_ids_and_spans)) in vars {
if self.used_on_entry(ln, var) {
let id = hir_ids_and_spans[0].0;
let spans =
hir_ids_and_spans.into_iter().map(|(_, _, ident_span)| ident_span).collect();
on_used_on_entry(spans, id, ln, var);
} else {
self.report_unused(hir_ids_and_spans, ln, var);
self.report_unused(hir_ids_and_spans, ln, var, can_remove);
}
}
}

#[tracing::instrument(skip(self), level = "INFO")]
fn report_unused(
&self,
hir_ids_and_spans: Vec<(HirId, Span, Span)>,
ln: LiveNode,
var: Variable,
can_remove: bool,
) {
let first_hir_id = hir_ids_and_spans[0].0;

Expand All @@ -1590,6 +1594,32 @@ impl<'tcx> Liveness<'_, 'tcx> {
.emit();
},
)
} else if can_remove {
self.ir.tcx.struct_span_lint_hir(
lint::builtin::UNUSED_VARIABLES,
first_hir_id,
hir_ids_and_spans.iter().map(|(_, pat_span, _)| *pat_span).collect::<Vec<_>>(),
|lint| {
let mut err = lint.build(&format!("unused variable: `{}`", name));
err.multipart_suggestion(
"try removing the field",
hir_ids_and_spans
.iter()
.map(|(_, pat_span, _)| {
let span = self
.ir
.tcx
.sess
.source_map()
.span_extend_to_next_char(*pat_span, ',', true);
(span.with_hi(BytePos(span.hi().0 + 1)), String::new())
})
.collect(),
Applicability::MachineApplicable,
);
err.emit();
},
);
} else {
let (shorthands, non_shorthands): (Vec<_>, Vec<_>) =
hir_ids_and_spans.iter().copied().partition(|(hir_id, _, ident_span)| {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_span/src/source_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -722,7 +722,7 @@ impl SourceMap {
})
}

/// Extends the given `Span` to just after the next occurrence of `c`.
/// Extends the given `Span` to just before the next occurrence of `c`.
pub fn span_extend_to_next_char(&self, sp: Span, c: char, accept_newlines: bool) -> Span {
if let Ok(next_source) = self.span_to_next_source(sp) {
let next_source = next_source.split(c).next().unwrap_or("");
Expand Down
17 changes: 17 additions & 0 deletions src/test/ui/suggestions/dont-try-removing-the-field.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// run-pass

#![allow(dead_code)]

struct Foo {
foo: i32,
bar: i32,
baz: (),
}

fn use_foo(x: Foo) -> (i32, i32) {
let Foo { foo, bar, baz } = x; //~ WARNING unused variable: `baz`
//~| help: try ignoring the field
return (foo, bar);
}

fn main() {}
10 changes: 10 additions & 0 deletions src/test/ui/suggestions/dont-try-removing-the-field.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
warning: unused variable: `baz`
--> $DIR/dont-try-removing-the-field.rs:12:25
|
LL | let Foo { foo, bar, baz } = x;
| ^^^ help: try ignoring the field: `baz: _`
|
= note: `#[warn(unused_variables)]` on by default

warning: 1 warning emitted

17 changes: 17 additions & 0 deletions src/test/ui/suggestions/try-removing-the-field.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// run-pass

#![allow(dead_code)]

struct Foo {
foo: i32,
bar: (),
baz: (),
}

fn use_foo(x: Foo) -> i32 {
let Foo { foo, bar, .. } = x; //~ WARNING unused variable: `bar`
//~| help: try removing the field
return foo;
}

fn main() {}
12 changes: 12 additions & 0 deletions src/test/ui/suggestions/try-removing-the-field.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
warning: unused variable: `bar`
--> $DIR/try-removing-the-field.rs:12:20
|
LL | let Foo { foo, bar, .. } = x;
| ^^^-
| |
| help: try removing the field
|
= note: `#[warn(unused_variables)]` on by default

warning: 1 warning emitted