Skip to content

Commit 83d3b76

Browse files
Rollup merge of #106097 - mejrs:mir_build2, r=oli-obk
Migrate mir_build diagnostics 2 of 3 The first three commits are fairly boring, however I've made some changes to the output of the match checking diagnostics.
2 parents 2e17a5d + 372ac9c commit 83d3b76

39 files changed

+566
-486
lines changed

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

+61
Original file line numberDiff line numberDiff line change
@@ -303,3 +303,64 @@ mir_build_multiple_mut_borrows = cannot borrow value as mutable more than once a
303303
.mutable_borrow = another mutable borrow, by `{$name_mut}`, occurs here
304304
.immutable_borrow = also borrowed as immutable, by `{$name_immut}`, here
305305
.moved = also moved into `{$name_moved}` here
306+
307+
mir_build_union_pattern = cannot use unions in constant patterns
308+
309+
mir_build_type_not_structural =
310+
to use a constant of type `{$non_sm_ty}` in a pattern, `{$non_sm_ty}` must be annotated with `#[derive(PartialEq, Eq)]`
311+
312+
mir_build_unsized_pattern = cannot use unsized non-slice type `{$non_sm_ty}` in constant patterns
313+
314+
mir_build_invalid_pattern = `{$non_sm_ty}` cannot be used in patterns
315+
316+
mir_build_float_pattern = floating-point types cannot be used in patterns
317+
318+
mir_build_pointer_pattern = function pointers and unsized pointers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
319+
320+
mir_build_indirect_structural_match =
321+
to use a constant of type `{$non_sm_ty}` in a pattern, `{$non_sm_ty}` must be annotated with `#[derive(PartialEq, Eq)]`
322+
323+
mir_build_nontrivial_structural_match =
324+
to use a constant of type `{$non_sm_ty}` in a pattern, the constant's initializer must be trivial or `{$non_sm_ty}` must be annotated with `#[derive(PartialEq, Eq)]`
325+
326+
mir_build_overlapping_range_endpoints = multiple patterns overlap on their endpoints
327+
.range = ... with this range
328+
.note = you likely meant to write mutually exclusive ranges
329+
330+
mir_build_non_exhaustive_omitted_pattern = some variants are not matched explicitly
331+
.help = ensure that all variants are matched explicitly by adding the suggested match arms
332+
.note = the matched value is of type `{$scrut_ty}` and the `non_exhaustive_omitted_patterns` attribute was found
333+
334+
mir_build_uncovered = {$count ->
335+
[1] pattern `{$witness_1}`
336+
[2] patterns `{$witness_1}` and `{$witness_2}`
337+
[3] patterns `{$witness_1}`, `{$witness_2}` and `{$witness_3}`
338+
*[other] patterns `{$witness_1}`, `{$witness_2}`, `{$witness_3}` and {$remainder} more
339+
} not covered
340+
341+
mir_build_pattern_not_covered = refutable pattern in {$origin}
342+
.pattern_ty = the matched value is of type `{$pattern_ty}`
343+
344+
mir_build_inform_irrefutable = `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
345+
346+
mir_build_more_information = for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
347+
348+
mir_build_res_defined_here = {$res} defined here
349+
350+
mir_build_adt_defined_here = `{$ty}` defined here
351+
352+
mir_build_variant_defined_here = not covered
353+
354+
mir_build_interpreted_as_const = introduce a variable instead
355+
356+
mir_build_confused = missing patterns are not covered because `{$variable}` is interpreted as {$article} {$res} pattern, not a new variable
357+
358+
mir_build_suggest_if_let = you might want to use `if let` to ignore the {$count ->
359+
[one] variant that isn't
360+
*[other] variants that aren't
361+
} matched
362+
363+
mir_build_suggest_let_else = you might want to use `let else` to handle the {$count ->
364+
[one] variant that isn't
365+
*[other] variants that aren't
366+
} matched

compiler/rustc_middle/src/thir.rs

+7
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/thir.html
1010
1111
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
12+
use rustc_errors::{DiagnosticArgValue, IntoDiagnosticArg};
1213
use rustc_hir as hir;
1314
use rustc_hir::def_id::DefId;
1415
use rustc_hir::RangeEnd;
@@ -575,6 +576,12 @@ impl<'tcx> Pat<'tcx> {
575576
}
576577
}
577578

579+
impl<'tcx> IntoDiagnosticArg for Pat<'tcx> {
580+
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
581+
format!("{}", self).into_diagnostic_arg()
582+
}
583+
}
584+
578585
#[derive(Clone, Debug, HashStable)]
579586
pub struct Ascription<'tcx> {
580587
pub annotation: CanonicalUserTypeAnnotation<'tcx>,

compiler/rustc_mir_build/src/errors.rs

+225-1
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
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};
10+
use rustc_middle::thir::Pat;
711
use rustc_middle::ty::{self, Ty};
812
use rustc_span::{symbol::Ident, Span};
913

@@ -624,3 +628,223 @@ pub enum MultipleMutBorrowOccurence {
624628
name_moved: Ident,
625629
},
626630
}
631+
632+
#[derive(Diagnostic)]
633+
#[diag(mir_build_union_pattern)]
634+
pub struct UnionPattern {
635+
#[primary_span]
636+
pub span: Span,
637+
}
638+
639+
#[derive(Diagnostic)]
640+
#[diag(mir_build_type_not_structural)]
641+
pub struct TypeNotStructural<'tcx> {
642+
#[primary_span]
643+
pub span: Span,
644+
pub non_sm_ty: Ty<'tcx>,
645+
}
646+
647+
#[derive(Diagnostic)]
648+
#[diag(mir_build_invalid_pattern)]
649+
pub struct InvalidPattern<'tcx> {
650+
#[primary_span]
651+
pub span: Span,
652+
pub non_sm_ty: Ty<'tcx>,
653+
}
654+
655+
#[derive(Diagnostic)]
656+
#[diag(mir_build_unsized_pattern)]
657+
pub struct UnsizedPattern<'tcx> {
658+
#[primary_span]
659+
pub span: Span,
660+
pub non_sm_ty: Ty<'tcx>,
661+
}
662+
663+
#[derive(LintDiagnostic)]
664+
#[diag(mir_build_float_pattern)]
665+
pub struct FloatPattern;
666+
667+
#[derive(LintDiagnostic)]
668+
#[diag(mir_build_pointer_pattern)]
669+
pub struct PointerPattern;
670+
671+
#[derive(LintDiagnostic)]
672+
#[diag(mir_build_indirect_structural_match)]
673+
pub struct IndirectStructuralMatch<'tcx> {
674+
pub non_sm_ty: Ty<'tcx>,
675+
}
676+
677+
#[derive(LintDiagnostic)]
678+
#[diag(mir_build_nontrivial_structural_match)]
679+
pub struct NontrivialStructuralMatch<'tcx> {
680+
pub non_sm_ty: Ty<'tcx>,
681+
}
682+
683+
#[derive(LintDiagnostic)]
684+
#[diag(mir_build_overlapping_range_endpoints)]
685+
#[note]
686+
pub struct OverlappingRangeEndpoints<'tcx> {
687+
#[label(range)]
688+
pub range: Span,
689+
#[subdiagnostic]
690+
pub overlap: Vec<Overlap<'tcx>>,
691+
}
692+
693+
pub struct Overlap<'tcx> {
694+
pub span: Span,
695+
pub range: Pat<'tcx>,
696+
}
697+
698+
impl<'tcx> AddToDiagnostic for Overlap<'tcx> {
699+
fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
700+
where
701+
F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
702+
{
703+
let Overlap { span, range } = self;
704+
705+
// FIXME(mejrs) unfortunately `#[derive(LintDiagnostic)]`
706+
// does not support `#[subdiagnostic(eager)]`...
707+
let message = format!("this range overlaps on `{range}`...");
708+
diag.span_label(span, message);
709+
}
710+
}
711+
712+
#[derive(LintDiagnostic)]
713+
#[diag(mir_build_non_exhaustive_omitted_pattern)]
714+
#[help]
715+
#[note]
716+
pub(crate) struct NonExhaustiveOmittedPattern<'tcx> {
717+
pub scrut_ty: Ty<'tcx>,
718+
#[subdiagnostic]
719+
pub uncovered: Uncovered<'tcx>,
720+
}
721+
722+
#[derive(Subdiagnostic)]
723+
#[label(mir_build_uncovered)]
724+
pub(crate) struct Uncovered<'tcx> {
725+
#[primary_span]
726+
span: Span,
727+
count: usize,
728+
witness_1: Pat<'tcx>,
729+
witness_2: Pat<'tcx>,
730+
witness_3: Pat<'tcx>,
731+
remainder: usize,
732+
}
733+
734+
impl<'tcx> Uncovered<'tcx> {
735+
pub fn new<'p>(
736+
span: Span,
737+
cx: &MatchCheckCtxt<'p, 'tcx>,
738+
witnesses: Vec<DeconstructedPat<'p, 'tcx>>,
739+
) -> Self {
740+
let witness_1 = witnesses.get(0).unwrap().to_pat(cx);
741+
Self {
742+
span,
743+
count: witnesses.len(),
744+
// Substitute dummy values if witnesses is smaller than 3. These will never be read.
745+
witness_2: witnesses.get(1).map(|w| w.to_pat(cx)).unwrap_or_else(|| witness_1.clone()),
746+
witness_3: witnesses.get(2).map(|w| w.to_pat(cx)).unwrap_or_else(|| witness_1.clone()),
747+
witness_1,
748+
remainder: witnesses.len().saturating_sub(3),
749+
}
750+
}
751+
}
752+
753+
#[derive(Diagnostic)]
754+
#[diag(mir_build_pattern_not_covered, code = "E0005")]
755+
pub(crate) struct PatternNotCovered<'s, 'tcx> {
756+
#[primary_span]
757+
pub span: Span,
758+
pub origin: &'s str,
759+
#[subdiagnostic]
760+
pub uncovered: Uncovered<'tcx>,
761+
#[subdiagnostic]
762+
pub inform: Option<Inform>,
763+
#[subdiagnostic]
764+
pub interpreted_as_const: Option<InterpretedAsConst>,
765+
#[subdiagnostic]
766+
pub adt_defined_here: Option<AdtDefinedHere<'tcx>>,
767+
#[note(pattern_ty)]
768+
pub _p: (),
769+
pub pattern_ty: Ty<'tcx>,
770+
#[subdiagnostic]
771+
pub let_suggestion: Option<SuggestLet>,
772+
#[subdiagnostic]
773+
pub res_defined_here: Option<ResDefinedHere>,
774+
}
775+
776+
#[derive(Subdiagnostic)]
777+
#[note(mir_build_inform_irrefutable)]
778+
#[note(mir_build_more_information)]
779+
pub struct Inform;
780+
781+
pub struct AdtDefinedHere<'tcx> {
782+
pub adt_def_span: Span,
783+
pub ty: Ty<'tcx>,
784+
pub variants: Vec<Variant>,
785+
}
786+
787+
pub struct Variant {
788+
pub span: Span,
789+
}
790+
791+
impl<'tcx> AddToDiagnostic for AdtDefinedHere<'tcx> {
792+
fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
793+
where
794+
F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
795+
{
796+
diag.set_arg("ty", self.ty);
797+
let mut spans = MultiSpan::from(self.adt_def_span);
798+
799+
for Variant { span } in self.variants {
800+
spans.push_span_label(span, rustc_errors::fluent::mir_build_variant_defined_here);
801+
}
802+
803+
diag.span_note(spans, rustc_errors::fluent::mir_build_adt_defined_here);
804+
}
805+
}
806+
807+
#[derive(Subdiagnostic)]
808+
#[label(mir_build_res_defined_here)]
809+
pub struct ResDefinedHere {
810+
#[primary_span]
811+
pub def_span: Span,
812+
pub res: Res,
813+
}
814+
815+
#[derive(Subdiagnostic)]
816+
#[suggestion(
817+
mir_build_interpreted_as_const,
818+
code = "{variable}_var",
819+
applicability = "maybe-incorrect"
820+
)]
821+
#[label(mir_build_confused)]
822+
pub struct InterpretedAsConst {
823+
#[primary_span]
824+
pub span: Span,
825+
pub article: &'static str,
826+
pub variable: String,
827+
pub res: Res,
828+
}
829+
830+
#[derive(Subdiagnostic)]
831+
pub enum SuggestLet {
832+
#[multipart_suggestion(mir_build_suggest_if_let, applicability = "has-placeholders")]
833+
If {
834+
#[suggestion_part(code = "if ")]
835+
start_span: Span,
836+
#[suggestion_part(code = " {{ todo!() }}")]
837+
semi_span: Span,
838+
count: usize,
839+
},
840+
#[suggestion(
841+
mir_build_suggest_let_else,
842+
code = " else {{ todo!() }}",
843+
applicability = "has-placeholders"
844+
)]
845+
Else {
846+
#[primary_span]
847+
end_span: Span,
848+
count: usize,
849+
},
850+
}

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)