Skip to content

Migrate mir_build diagnostics 2 of 3 #106097

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 7 commits into from
Jan 12, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
Migrate pattern matching
  • Loading branch information
mejrs authored and dtolnay committed Jan 11, 2023
commit 31c20210b9683f983953e1a4e45db94146b3c7cb
36 changes: 32 additions & 4 deletions compiler/rustc_error_messages/locales/en-US/mir_build.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -326,11 +326,39 @@ mir_build_overlapping_range_endpoints = multiple patterns overlap on their endpo
mir_build_overlapping_range = this range overlaps on `{$range}`...

mir_build_non_exhaustive_omitted_pattern = some variants are not matched explicitly
.label = {$count ->
.help = ensure that all variants are matched explicitly by adding the suggested match arms
.note = the matched value is of type `{$scrut_ty}` and the `non_exhaustive_omitted_patterns` attribute was found

mir_build_uncovered = {$count ->
[1] pattern `{$witness_1}`
[2] patterns `{$witness_1}` and `{$witness_2}`
[3] patterns `{$witness_1}`, `{$witness_2}` and `{$witness_3}`
*[other] patterns `{$witness_1}`, `{$witness_2}`, `{$witness_3}` and more
*[other] patterns `{$witness_1}`, `{$witness_2}`, `{$witness_3}` and {$remainder} more
} not covered
.help = ensure that all variants are matched explicitly by adding the suggested match arms
.note = the matched value is of type `{$scrut_ty}` and the `non_exhaustive_omitted_patterns` attribute was found

mir_build_pattern_not_covered = refutable pattern in {$origin}
.pattern_ty = the matched value is of type `{$pattern_ty}`

mir_build_inform_irrefutable = `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant

mir_build_more_information = for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html

mir_build_res_defined_here = {$res} defined here

mir_build_adt_defined_here = `{$ty}` defined here

mir_build_variant_defined_here = not covered

mir_build_interpreted_as_const = introduce a variable instead

mir_build_confused = missing patterns are not covered because `{$variable}` is interpreted as {$article} {$res} pattern, not a new variable

mir_build_suggest_if_let = you might want to use `if let` to ignore the {$count ->
[one] variant that isn't
*[other] variants that aren't
} matched

mir_build_suggest_let_else = alternatively, you might want to use `let else` to handle the {$count ->
[one] variant that isn't
*[other] variants that aren't
} matched
164 changes: 157 additions & 7 deletions compiler/rustc_mir_build/src/errors.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
use crate::thir::pattern::deconstruct_pat::DeconstructedPat;
use crate::thir::pattern::MatchCheckCtxt;
use rustc_errors::Handler;
use rustc_errors::{
error_code, Applicability, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic, MultiSpan,
error_code, AddToDiagnostic, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
IntoDiagnostic, MultiSpan, SubdiagnosticMessage,
};
use rustc_hir::def::Res;
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
use rustc_middle::thir::Pat;
use rustc_middle::ty::{self, Ty};
Expand Down Expand Up @@ -677,7 +680,6 @@ pub struct OverlappingRangeEndpoints<'tcx> {
pub overlap: Overlap<'tcx>,
}

#[derive(Debug)]
#[derive(Subdiagnostic)]
#[label(mir_build_overlapping_range)]
pub struct Overlap<'tcx> {
Expand All @@ -692,10 +694,158 @@ pub struct Overlap<'tcx> {
#[note]
pub(crate) struct NonExhaustiveOmittedPattern<'tcx> {
pub scrut_ty: Ty<'tcx>,
#[label]
pub uncovered: Span,
#[subdiagnostic]
pub uncovered: Uncovered<'tcx>,
}

#[derive(Subdiagnostic)]
#[label(mir_build_uncovered)]
pub(crate) 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,
cx: &MatchCheckCtxt<'p, 'tcx>,
witnesses: Vec<DeconstructedPat<'p, 'tcx>>,
) -> Self {
let witness_1 = witnesses.get(0).unwrap().to_pat(cx);
Self {
span,
count: witnesses.len(),
// Substitute dummy values if witnesses is smaller than 3. These will never be read.
witness_2: witnesses.get(1).map(|w| w.to_pat(cx)).unwrap_or_else(|| witness_1.clone()),
witness_3: witnesses.get(2).map(|w| w.to_pat(cx)).unwrap_or_else(|| witness_1.clone()),
witness_1,
remainder: witnesses.len().saturating_sub(3),
}
}
}

#[derive(Diagnostic)]
#[diag(mir_build_pattern_not_covered, code = "E0005")]
pub(crate) struct PatternNotCovered<'s, 'tcx> {
#[primary_span]
pub span: Span,
pub origin: &'s str,
#[subdiagnostic]
pub uncovered: Uncovered<'tcx>,
#[subdiagnostic]
pub inform: Option<Inform>,
#[subdiagnostic]
pub interpreted_as_const: Option<InterpretedAsConst>,
#[subdiagnostic]
pub adt_defined_here: Option<AdtDefinedHere<'tcx>>,
#[note(pattern_ty)]
pub _p: (),
pub pattern_ty: Ty<'tcx>,
#[subdiagnostic]
pub if_let_suggestion: Option<SuggestIfLet>,
#[subdiagnostic]
pub let_else_suggestion: Option<SuggestLetElse>,
#[subdiagnostic]
pub res_defined_here: Option<ResDefinedHere>,
}

#[derive(Subdiagnostic)]
#[note(mir_build_inform_irrefutable)]
#[note(mir_build_more_information)]
pub struct Inform;

pub struct AdtDefinedHere<'tcx> {
pub adt_def_span: Span,
pub ty: Ty<'tcx>,
pub variants: Vec<Variant>,
}

pub struct Variant {
pub span: Span,
}

impl<'tcx> AddToDiagnostic for AdtDefinedHere<'tcx> {
fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
where
F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
{
diag.set_arg("ty", self.ty);
let mut spans = MultiSpan::from(self.adt_def_span);

for Variant { span } in self.variants {
spans.push_span_label(span, rustc_errors::fluent::mir_build_variant_defined_here);
}

diag.span_note(spans, rustc_errors::fluent::mir_build_adt_defined_here);
}
}

#[derive(Subdiagnostic)]
#[label(mir_build_res_defined_here)]
pub struct ResDefinedHere {
#[primary_span]
pub def_span: Span,
pub res: Res,
}

#[derive(Subdiagnostic)]
#[suggestion(
mir_build_interpreted_as_const,
code = "{variable}_var",
applicability = "maybe-incorrect"
)]
#[label(mir_build_confused)]
pub struct InterpretedAsConst {
#[primary_span]
pub span: Span,
pub article: &'static str,
pub variable: String,
pub res: Res,
}

#[derive(Subdiagnostic)]
pub enum SuggestIfLet {
#[multipart_suggestion(mir_build_suggest_if_let, applicability = "has-placeholders")]
None {
#[suggestion_part(code = "if ")]
start_span: Span,
#[suggestion_part(code = " {{ todo!() }}")]
semi_span: Span,
count: usize,
},
#[multipart_suggestion(mir_build_suggest_if_let, applicability = "has-placeholders")]
One {
#[suggestion_part(code = "let {binding} = if ")]
start_span: Span,
#[suggestion_part(code = " {{ {binding} }} else {{ todo!() }}")]
end_span: Span,
binding: Ident,
count: usize,
},
#[multipart_suggestion(mir_build_suggest_if_let, applicability = "has-placeholders")]
More {
#[suggestion_part(code = "let ({bindings}) = if ")]
start_span: Span,
#[suggestion_part(code = " {{ ({bindings}) }} else {{ todo!() }}")]
end_span: Span,
bindings: String,
count: usize,
},
}

#[derive(Subdiagnostic)]
#[suggestion(
mir_build_suggest_let_else,
code = " else {{ todo!() }}",
applicability = "has-placeholders"
)]
pub struct SuggestLetElse {
#[primary_span]
pub end_span: Span,
pub count: usize,
pub witness_1: Pat<'tcx>,
pub witness_2: Pat<'tcx>,
pub witness_3: Pat<'tcx>,
}
1 change: 1 addition & 0 deletions compiler/rustc_mir_build/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#![feature(let_chains)]
#![feature(min_specialization)]
#![feature(once_cell)]
#![feature(try_blocks)]
#![recursion_limit = "256"]

#[macro_use]
Expand Down
Loading