Gather rustc-specific functions around MatchCheckCtxt

This commit is contained in:
Nadrieril
2023-12-10 22:14:00 +01:00
parent 281002d42c
commit 3691a0aee5
8 changed files with 903 additions and 900 deletions

View File

@@ -551,66 +551,27 @@
//! I (Nadrieril) prefer to put new tests in `ui/pattern/usefulness` unless there's a specific
//! reason not to, for example if they crucially depend on a particular feature like `or_patterns`.
use self::ValidityConstraint::*;
use smallvec::{smallvec, SmallVec};
use std::fmt;
use rustc_data_structures::{captures::Captures, stack::ensure_sufficient_stack};
use rustc_hir::HirId;
use rustc_middle::ty::{self, Ty};
use rustc_session::lint;
use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS;
use rustc_span::{Span, DUMMY_SP};
use crate::constructor::{
Constructor, ConstructorSet, IntRange, MaybeInfiniteInt, SplitConstructorSet,
};
use crate::cx::MatchCheckCtxt;
use crate::errors::{
NonExhaustiveOmittedPattern, NonExhaustiveOmittedPatternLintOnArm, Overlap,
OverlappingRangeEndpoints, Uncovered,
};
use crate::pat::{DeconstructedPat, WitnessPat};
use rustc_arena::TypedArena;
use rustc_data_structures::{captures::Captures, stack::ensure_sufficient_stack};
use rustc_hir::def_id::DefId;
use rustc_hir::HirId;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_session::lint;
use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS;
use rustc_span::{Span, DUMMY_SP};
use smallvec::{smallvec, SmallVec};
use std::fmt;
pub struct MatchCheckCtxt<'p, 'tcx> {
pub tcx: TyCtxt<'tcx>,
/// The module in which the match occurs. This is necessary for
/// checking inhabited-ness of types because whether a type is (visibly)
/// inhabited can depend on whether it was defined in the current module or
/// not. E.g., `struct Foo { _private: ! }` cannot be seen to be empty
/// outside its module and should not be matchable with an empty match statement.
pub module: DefId,
pub param_env: ty::ParamEnv<'tcx>,
pub pattern_arena: &'p TypedArena<DeconstructedPat<'p, 'tcx>>,
/// Lint level at the match.
pub match_lint_level: HirId,
/// The span of the whole match, if applicable.
pub whole_match_span: Option<Span>,
/// Span of the scrutinee.
pub scrut_span: Span,
/// Only produce `NON_EXHAUSTIVE_OMITTED_PATTERNS` lint on refutable patterns.
pub refutable: bool,
/// Whether the data at the scrutinee is known to be valid. This is false if the scrutinee comes
/// from a union field, a pointer deref, or a reference deref (pending opsem decisions).
pub known_valid_scrutinee: bool,
}
impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> {
pub(super) fn is_uninhabited(&self, ty: Ty<'tcx>) -> bool {
!ty.is_inhabited_from(self.tcx, self.module, self.param_env)
}
/// Returns whether the given type is an enum from another crate declared `#[non_exhaustive]`.
pub fn is_foreign_non_exhaustive_enum(&self, ty: Ty<'tcx>) -> bool {
match ty.kind() {
ty::Adt(def, ..) => {
def.is_enum() && def.is_variant_list_non_exhaustive() && !def.did().is_local()
}
_ => false,
}
}
}
use self::ValidityConstraint::*;
#[derive(Copy, Clone)]
pub(super) struct PatCtxt<'a, 'p, 'tcx> {
@@ -1244,7 +1205,9 @@ fn compute_exhaustiveness_and_usefulness<'p, 'tcx>(
// Analyze the constructors present in this column.
let ctors = matrix.heads().map(|p| p.ctor());
let split_set = ConstructorSet::for_ty(cx, ty).split(pcx, ctors);
let ctors_for_ty = &cx.ctors_for_ty(ty);
let is_integers = matches!(ctors_for_ty, ConstructorSet::Integers { .. }); // For diagnostics.
let split_set = ctors_for_ty.split(pcx, ctors);
let all_missing = split_set.present.is_empty();
// Build the set of constructors we will specialize with. It must cover the whole type.
@@ -1259,7 +1222,7 @@ fn compute_exhaustiveness_and_usefulness<'p, 'tcx>(
}
// Decide what constructors to report.
let always_report_all = is_top_level && !IntRange::is_integral(pcx.ty);
let always_report_all = is_top_level && !is_integers;
// Whether we should report "Enum::A and Enum::C are missing" or "_ is missing".
let report_individual_missing_ctors = always_report_all || !all_missing;
// Which constructors are considered missing. We ensure that `!missing_ctors.is_empty() =>
@@ -1362,7 +1325,7 @@ impl<'p, 'tcx> PatternColumn<'p, 'tcx> {
/// Do constructor splitting on the constructors of the column.
fn analyze_ctors(&self, pcx: &PatCtxt<'_, 'p, 'tcx>) -> SplitConstructorSet<'tcx> {
let column_ctors = self.patterns.iter().map(|p| p.ctor());
ConstructorSet::for_ty(pcx.cx, pcx.ty).split(pcx, column_ctors)
pcx.cx.ctors_for_ty(pcx.ty).split(pcx, column_ctors)
}
fn iter<'a>(&'a self) -> impl Iterator<Item = &'p DeconstructedPat<'p, 'tcx>> + Captures<'a> {
@@ -1470,9 +1433,9 @@ fn lint_overlapping_range_endpoints<'p, 'tcx>(
let set = column.analyze_ctors(pcx);
if IntRange::is_integral(ty) {
if matches!(ty.kind(), ty::Char | ty::Int(_) | ty::Uint(_)) {
let emit_lint = |overlap: &IntRange, this_span: Span, overlapped_spans: &[Span]| {
let overlap_as_pat = overlap.to_diagnostic_pat(ty, cx.tcx);
let overlap_as_pat = cx.hoist_pat_range(overlap, ty);
let overlaps: Vec<_> = overlapped_spans
.iter()
.copied()