Skip to content

Commit 31c2021

Browse files
mejrsdtolnay
mejrs
authored andcommitted
Migrate pattern matching
1 parent ef33072 commit 31c2021

35 files changed

+415
-324
lines changed

compiler/rustc_error_messages/locales/en-US/mir_build.ftl

+32-4
Original file line numberDiff line numberDiff line change
@@ -326,11 +326,39 @@ mir_build_overlapping_range_endpoints = multiple patterns overlap on their endpo
326326
mir_build_overlapping_range = this range overlaps on `{$range}`...
327327
328328
mir_build_non_exhaustive_omitted_pattern = some variants are not matched explicitly
329-
.label = {$count ->
329+
.help = ensure that all variants are matched explicitly by adding the suggested match arms
330+
.note = the matched value is of type `{$scrut_ty}` and the `non_exhaustive_omitted_patterns` attribute was found
331+
332+
mir_build_uncovered = {$count ->
330333
[1] pattern `{$witness_1}`
331334
[2] patterns `{$witness_1}` and `{$witness_2}`
332335
[3] patterns `{$witness_1}`, `{$witness_2}` and `{$witness_3}`
333-
*[other] patterns `{$witness_1}`, `{$witness_2}`, `{$witness_3}` and more
336+
*[other] patterns `{$witness_1}`, `{$witness_2}`, `{$witness_3}` and {$remainder} more
334337
} not covered
335-
.help = ensure that all variants are matched explicitly by adding the suggested match arms
336-
.note = the matched value is of type `{$scrut_ty}` and the `non_exhaustive_omitted_patterns` attribute was found
338+
339+
mir_build_pattern_not_covered = refutable pattern in {$origin}
340+
.pattern_ty = the matched value is of type `{$pattern_ty}`
341+
342+
mir_build_inform_irrefutable = `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
343+
344+
mir_build_more_information = for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
345+
346+
mir_build_res_defined_here = {$res} defined here
347+
348+
mir_build_adt_defined_here = `{$ty}` defined here
349+
350+
mir_build_variant_defined_here = not covered
351+
352+
mir_build_interpreted_as_const = introduce a variable instead
353+
354+
mir_build_confused = missing patterns are not covered because `{$variable}` is interpreted as {$article} {$res} pattern, not a new variable
355+
356+
mir_build_suggest_if_let = you might want to use `if let` to ignore the {$count ->
357+
[one] variant that isn't
358+
*[other] variants that aren't
359+
} matched
360+
361+
mir_build_suggest_let_else = alternatively, you might want to use `let else` to handle the {$count ->
362+
[one] variant that isn't
363+
*[other] variants that aren't
364+
} matched

compiler/rustc_mir_build/src/errors.rs

+157-7
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1+
use crate::thir::pattern::deconstruct_pat::DeconstructedPat;
12
use crate::thir::pattern::MatchCheckCtxt;
23
use rustc_errors::Handler;
34
use rustc_errors::{
4-
error_code, Applicability, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic, MultiSpan,
5+
error_code, AddToDiagnostic, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
6+
IntoDiagnostic, MultiSpan, SubdiagnosticMessage,
57
};
8+
use rustc_hir::def::Res;
69
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
710
use rustc_middle::thir::Pat;
811
use rustc_middle::ty::{self, Ty};
@@ -677,7 +680,6 @@ pub struct OverlappingRangeEndpoints<'tcx> {
677680
pub overlap: Overlap<'tcx>,
678681
}
679682

680-
#[derive(Debug)]
681683
#[derive(Subdiagnostic)]
682684
#[label(mir_build_overlapping_range)]
683685
pub struct Overlap<'tcx> {
@@ -692,10 +694,158 @@ pub struct Overlap<'tcx> {
692694
#[note]
693695
pub(crate) struct NonExhaustiveOmittedPattern<'tcx> {
694696
pub scrut_ty: Ty<'tcx>,
695-
#[label]
696-
pub uncovered: Span,
697+
#[subdiagnostic]
698+
pub uncovered: Uncovered<'tcx>,
699+
}
700+
701+
#[derive(Subdiagnostic)]
702+
#[label(mir_build_uncovered)]
703+
pub(crate) struct Uncovered<'tcx> {
704+
#[primary_span]
705+
span: Span,
706+
count: usize,
707+
witness_1: Pat<'tcx>,
708+
witness_2: Pat<'tcx>,
709+
witness_3: Pat<'tcx>,
710+
remainder: usize,
711+
}
712+
713+
impl<'tcx> Uncovered<'tcx> {
714+
pub fn new<'p>(
715+
span: Span,
716+
cx: &MatchCheckCtxt<'p, 'tcx>,
717+
witnesses: Vec<DeconstructedPat<'p, 'tcx>>,
718+
) -> Self {
719+
let witness_1 = witnesses.get(0).unwrap().to_pat(cx);
720+
Self {
721+
span,
722+
count: witnesses.len(),
723+
// Substitute dummy values if witnesses is smaller than 3. These will never be read.
724+
witness_2: witnesses.get(1).map(|w| w.to_pat(cx)).unwrap_or_else(|| witness_1.clone()),
725+
witness_3: witnesses.get(2).map(|w| w.to_pat(cx)).unwrap_or_else(|| witness_1.clone()),
726+
witness_1,
727+
remainder: witnesses.len().saturating_sub(3),
728+
}
729+
}
730+
}
731+
732+
#[derive(Diagnostic)]
733+
#[diag(mir_build_pattern_not_covered, code = "E0005")]
734+
pub(crate) struct PatternNotCovered<'s, 'tcx> {
735+
#[primary_span]
736+
pub span: Span,
737+
pub origin: &'s str,
738+
#[subdiagnostic]
739+
pub uncovered: Uncovered<'tcx>,
740+
#[subdiagnostic]
741+
pub inform: Option<Inform>,
742+
#[subdiagnostic]
743+
pub interpreted_as_const: Option<InterpretedAsConst>,
744+
#[subdiagnostic]
745+
pub adt_defined_here: Option<AdtDefinedHere<'tcx>>,
746+
#[note(pattern_ty)]
747+
pub _p: (),
748+
pub pattern_ty: Ty<'tcx>,
749+
#[subdiagnostic]
750+
pub if_let_suggestion: Option<SuggestIfLet>,
751+
#[subdiagnostic]
752+
pub let_else_suggestion: Option<SuggestLetElse>,
753+
#[subdiagnostic]
754+
pub res_defined_here: Option<ResDefinedHere>,
755+
}
756+
757+
#[derive(Subdiagnostic)]
758+
#[note(mir_build_inform_irrefutable)]
759+
#[note(mir_build_more_information)]
760+
pub struct Inform;
761+
762+
pub struct AdtDefinedHere<'tcx> {
763+
pub adt_def_span: Span,
764+
pub ty: Ty<'tcx>,
765+
pub variants: Vec<Variant>,
766+
}
767+
768+
pub struct Variant {
769+
pub span: Span,
770+
}
771+
772+
impl<'tcx> AddToDiagnostic for AdtDefinedHere<'tcx> {
773+
fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
774+
where
775+
F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
776+
{
777+
diag.set_arg("ty", self.ty);
778+
let mut spans = MultiSpan::from(self.adt_def_span);
779+
780+
for Variant { span } in self.variants {
781+
spans.push_span_label(span, rustc_errors::fluent::mir_build_variant_defined_here);
782+
}
783+
784+
diag.span_note(spans, rustc_errors::fluent::mir_build_adt_defined_here);
785+
}
786+
}
787+
788+
#[derive(Subdiagnostic)]
789+
#[label(mir_build_res_defined_here)]
790+
pub struct ResDefinedHere {
791+
#[primary_span]
792+
pub def_span: Span,
793+
pub res: Res,
794+
}
795+
796+
#[derive(Subdiagnostic)]
797+
#[suggestion(
798+
mir_build_interpreted_as_const,
799+
code = "{variable}_var",
800+
applicability = "maybe-incorrect"
801+
)]
802+
#[label(mir_build_confused)]
803+
pub struct InterpretedAsConst {
804+
#[primary_span]
805+
pub span: Span,
806+
pub article: &'static str,
807+
pub variable: String,
808+
pub res: Res,
809+
}
810+
811+
#[derive(Subdiagnostic)]
812+
pub enum SuggestIfLet {
813+
#[multipart_suggestion(mir_build_suggest_if_let, applicability = "has-placeholders")]
814+
None {
815+
#[suggestion_part(code = "if ")]
816+
start_span: Span,
817+
#[suggestion_part(code = " {{ todo!() }}")]
818+
semi_span: Span,
819+
count: usize,
820+
},
821+
#[multipart_suggestion(mir_build_suggest_if_let, applicability = "has-placeholders")]
822+
One {
823+
#[suggestion_part(code = "let {binding} = if ")]
824+
start_span: Span,
825+
#[suggestion_part(code = " {{ {binding} }} else {{ todo!() }}")]
826+
end_span: Span,
827+
binding: Ident,
828+
count: usize,
829+
},
830+
#[multipart_suggestion(mir_build_suggest_if_let, applicability = "has-placeholders")]
831+
More {
832+
#[suggestion_part(code = "let ({bindings}) = if ")]
833+
start_span: Span,
834+
#[suggestion_part(code = " {{ ({bindings}) }} else {{ todo!() }}")]
835+
end_span: Span,
836+
bindings: String,
837+
count: usize,
838+
},
839+
}
840+
841+
#[derive(Subdiagnostic)]
842+
#[suggestion(
843+
mir_build_suggest_let_else,
844+
code = " else {{ todo!() }}",
845+
applicability = "has-placeholders"
846+
)]
847+
pub struct SuggestLetElse {
848+
#[primary_span]
849+
pub end_span: Span,
697850
pub count: usize,
698-
pub witness_1: Pat<'tcx>,
699-
pub witness_2: Pat<'tcx>,
700-
pub witness_3: Pat<'tcx>,
701851
}

compiler/rustc_mir_build/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#![feature(let_chains)]
1111
#![feature(min_specialization)]
1212
#![feature(once_cell)]
13+
#![feature(try_blocks)]
1314
#![recursion_limit = "256"]
1415

1516
#[macro_use]

0 commit comments

Comments
 (0)