2024-02-22 23:20:45 +00:00
|
|
|
use rustc_errors::{AddToDiagnostic, Diag, EmissionGuarantee, SubdiagnosticMessageOp};
|
2023-12-10 19:42:30 +00:00
|
|
|
use rustc_macros::{LintDiagnostic, Subdiagnostic};
|
|
|
|
use rustc_middle::thir::Pat;
|
|
|
|
use rustc_middle::ty::Ty;
|
|
|
|
use rustc_span::Span;
|
|
|
|
|
2023-12-14 16:54:11 +00:00
|
|
|
use crate::rustc::{RustcMatchCheckCtxt, WitnessPat};
|
2023-12-11 19:01:02 +00:00
|
|
|
|
2023-12-10 19:42:30 +00:00
|
|
|
#[derive(Subdiagnostic)]
|
|
|
|
#[label(pattern_analysis_uncovered)]
|
|
|
|
pub struct Uncovered<'tcx> {
|
|
|
|
#[primary_span]
|
|
|
|
span: Span,
|
|
|
|
count: usize,
|
|
|
|
witness_1: Pat<'tcx>,
|
|
|
|
witness_2: Pat<'tcx>,
|
|
|
|
witness_3: Pat<'tcx>,
|
|
|
|
remainder: usize,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'tcx> Uncovered<'tcx> {
|
|
|
|
pub fn new<'p>(
|
|
|
|
span: Span,
|
2023-12-14 16:54:11 +00:00
|
|
|
cx: &RustcMatchCheckCtxt<'p, 'tcx>,
|
2023-12-11 19:01:02 +00:00
|
|
|
witnesses: Vec<WitnessPat<'p, 'tcx>>,
|
2024-01-25 03:35:09 +00:00
|
|
|
) -> Self
|
|
|
|
where
|
|
|
|
'tcx: 'p,
|
|
|
|
{
|
2023-12-10 21:14:00 +00:00
|
|
|
let witness_1 = cx.hoist_witness_pat(witnesses.get(0).unwrap());
|
2023-12-10 19:42:30 +00:00
|
|
|
Self {
|
|
|
|
span,
|
|
|
|
count: witnesses.len(),
|
|
|
|
// Substitute dummy values if witnesses is smaller than 3. These will never be read.
|
|
|
|
witness_2: witnesses
|
|
|
|
.get(1)
|
2023-12-10 21:14:00 +00:00
|
|
|
.map(|w| cx.hoist_witness_pat(w))
|
2023-12-10 19:42:30 +00:00
|
|
|
.unwrap_or_else(|| witness_1.clone()),
|
|
|
|
witness_3: witnesses
|
|
|
|
.get(2)
|
2023-12-10 21:14:00 +00:00
|
|
|
.map(|w| cx.hoist_witness_pat(w))
|
2023-12-10 19:42:30 +00:00
|
|
|
.unwrap_or_else(|| witness_1.clone()),
|
|
|
|
witness_1,
|
|
|
|
remainder: witnesses.len().saturating_sub(3),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(LintDiagnostic)]
|
|
|
|
#[diag(pattern_analysis_overlapping_range_endpoints)]
|
|
|
|
#[note]
|
|
|
|
pub struct OverlappingRangeEndpoints<'tcx> {
|
|
|
|
#[label]
|
|
|
|
pub range: Span,
|
|
|
|
#[subdiagnostic]
|
|
|
|
pub overlap: Vec<Overlap<'tcx>>,
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct Overlap<'tcx> {
|
|
|
|
pub span: Span,
|
|
|
|
pub range: Pat<'tcx>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'tcx> AddToDiagnostic for Overlap<'tcx> {
|
Reduce capabilities of `Diagnostic`.
Currently many diagnostic modifier methods are available on both
`Diagnostic` and `DiagnosticBuilder`. This commit removes most of them
from `Diagnostic`. To minimize the diff size, it keeps them within
`diagnostic.rs` but changes the surrounding `impl Diagnostic` block to
`impl DiagnosticBuilder`. (I intend to move things around later, to give
a more sensible code layout.)
`Diagnostic` keeps a few methods that it still needs, like `sub`,
`arg`, and `replace_args`.
The `forward!` macro, which defined two additional methods per call
(e.g. `note` and `with_note`), is replaced by the `with_fn!` macro,
which defines one additional method per call (e.g. `with_note`). It's
now also only used when necessary -- not all modifier methods currently
need a `with_*` form. (New ones can be easily added as necessary.)
All this also requires changing `trait AddToDiagnostic` so its methods
take `DiagnosticBuilder` instead of `Diagnostic`, which leads to many
mechanical changes. `SubdiagnosticMessageOp` gains a type parameter `G`.
There are three subdiagnostics -- `DelayedAtWithoutNewline`,
`DelayedAtWithNewline`, and `InvalidFlushedDelayedDiagnosticLevel` --
that are created within the diagnostics machinery and appended to
external diagnostics. These are handled at the `Diagnostic` level, which
means it's now hard to construct them via `derive(Diagnostic)`, so
instead we construct them by hand. This has no effect on what they look
like when printed.
There are lots of new `allow` markers for `untranslatable_diagnostics`
and `diagnostics_outside_of_impl`. This is because
`#[rustc_lint_diagnostics]` annotations were present on the `Diagnostic`
modifier methods, but missing from the `DiagnosticBuilder` modifier
methods. They're now present.
2024-02-06 05:44:30 +00:00
|
|
|
fn add_to_diagnostic_with<G: EmissionGuarantee, F: SubdiagnosticMessageOp<G>>(
|
|
|
|
self,
|
2024-02-22 23:20:45 +00:00
|
|
|
diag: &mut Diag<'_, G>,
|
Reduce capabilities of `Diagnostic`.
Currently many diagnostic modifier methods are available on both
`Diagnostic` and `DiagnosticBuilder`. This commit removes most of them
from `Diagnostic`. To minimize the diff size, it keeps them within
`diagnostic.rs` but changes the surrounding `impl Diagnostic` block to
`impl DiagnosticBuilder`. (I intend to move things around later, to give
a more sensible code layout.)
`Diagnostic` keeps a few methods that it still needs, like `sub`,
`arg`, and `replace_args`.
The `forward!` macro, which defined two additional methods per call
(e.g. `note` and `with_note`), is replaced by the `with_fn!` macro,
which defines one additional method per call (e.g. `with_note`). It's
now also only used when necessary -- not all modifier methods currently
need a `with_*` form. (New ones can be easily added as necessary.)
All this also requires changing `trait AddToDiagnostic` so its methods
take `DiagnosticBuilder` instead of `Diagnostic`, which leads to many
mechanical changes. `SubdiagnosticMessageOp` gains a type parameter `G`.
There are three subdiagnostics -- `DelayedAtWithoutNewline`,
`DelayedAtWithNewline`, and `InvalidFlushedDelayedDiagnosticLevel` --
that are created within the diagnostics machinery and appended to
external diagnostics. These are handled at the `Diagnostic` level, which
means it's now hard to construct them via `derive(Diagnostic)`, so
instead we construct them by hand. This has no effect on what they look
like when printed.
There are lots of new `allow` markers for `untranslatable_diagnostics`
and `diagnostics_outside_of_impl`. This is because
`#[rustc_lint_diagnostics]` annotations were present on the `Diagnostic`
modifier methods, but missing from the `DiagnosticBuilder` modifier
methods. They're now present.
2024-02-06 05:44:30 +00:00
|
|
|
_: F,
|
|
|
|
) {
|
2023-12-10 19:42:30 +00:00
|
|
|
let Overlap { span, range } = self;
|
|
|
|
|
|
|
|
// FIXME(mejrs) unfortunately `#[derive(LintDiagnostic)]`
|
|
|
|
// does not support `#[subdiagnostic(eager)]`...
|
|
|
|
let message = format!("this range overlaps on `{range}`...");
|
|
|
|
diag.span_label(span, message);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(LintDiagnostic)]
|
|
|
|
#[diag(pattern_analysis_non_exhaustive_omitted_pattern)]
|
|
|
|
#[help]
|
|
|
|
#[note]
|
|
|
|
pub(crate) struct NonExhaustiveOmittedPattern<'tcx> {
|
|
|
|
pub scrut_ty: Ty<'tcx>,
|
|
|
|
#[subdiagnostic]
|
|
|
|
pub uncovered: Uncovered<'tcx>,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(LintDiagnostic)]
|
|
|
|
#[diag(pattern_analysis_non_exhaustive_omitted_pattern_lint_on_arm)]
|
|
|
|
#[help]
|
|
|
|
pub(crate) struct NonExhaustiveOmittedPatternLintOnArm {
|
|
|
|
#[label]
|
|
|
|
pub lint_span: Span,
|
|
|
|
#[suggestion(code = "#[{lint_level}({lint_name})]\n", applicability = "maybe-incorrect")]
|
|
|
|
pub suggest_lint_on_match: Option<Span>,
|
|
|
|
pub lint_level: &'static str,
|
|
|
|
pub lint_name: &'static str,
|
|
|
|
}
|