Skip to content

Commit 6c25005

Browse files
committed
Auto merge of #118842 - Nadrieril:librarify-further, r=<try>
Make exhaustiveness usable outside of rustc With this PR, `rustc_pattern_analysis` compiles on stable (with the `stable` feature)! `rust-analyzer` will be able to use it to provide match-related diagnostics and refactors. Two questions: - Should I name the feature `nightly` instead of `rustc` for consistency with other crates? `rustc` makes more sense imo. - `typed-arena` is an optional dependency but tidy made me add it to the allow-list anyway. Can I avoid that somehow? r? `@compiler-errors`
2 parents 21cce21 + 5d7b823 commit 6c25005

File tree

14 files changed

+668
-442
lines changed

14 files changed

+668
-442
lines changed

Cargo.lock

+7
Original file line numberDiff line numberDiff line change
@@ -4384,6 +4384,7 @@ dependencies = [
43844384
"rustc_target",
43854385
"smallvec",
43864386
"tracing",
4387+
"typed-arena",
43874388
]
43884389

43894390
[[package]]
@@ -5719,6 +5720,12 @@ dependencies = [
57195720
"rustc-hash",
57205721
]
57215722

5723+
[[package]]
5724+
name = "typed-arena"
5725+
version = "2.0.2"
5726+
source = "registry+https://github.com/rust-lang/crates.io-index"
5727+
checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a"
5728+
57225729
[[package]]
57235730
name = "typenum"
57245731
version = "1.16.0"

compiler/rustc_index/src/bit_set.rs

+37-11
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use std::slice;
99
use arrayvec::ArrayVec;
1010
use smallvec::{smallvec, SmallVec};
1111

12+
#[cfg(feature = "nightly")]
1213
use rustc_macros::{Decodable, Encodable};
1314

1415
use crate::{Idx, IndexVec};
@@ -111,7 +112,8 @@ macro_rules! bit_relations_inherent_impls {
111112
/// to or greater than the domain size. All operations that involve two bitsets
112113
/// will panic if the bitsets have differing domain sizes.
113114
///
114-
#[derive(Eq, PartialEq, Hash, Decodable, Encodable)]
115+
#[cfg_attr(feature = "nightly", derive(Decodable, Encodable))]
116+
#[derive(Eq, PartialEq, Hash)]
115117
pub struct BitSet<T> {
116118
domain_size: usize,
117119
words: SmallVec<[Word; 2]>,
@@ -491,10 +493,21 @@ impl<T: Idx> ChunkedBitSet<T> {
491493
match *chunk {
492494
Zeros(chunk_domain_size) => {
493495
if chunk_domain_size > 1 {
494-
// We take some effort to avoid copying the words.
495-
let words = Rc::<[Word; CHUNK_WORDS]>::new_zeroed();
496-
// SAFETY: `words` can safely be all zeroes.
497-
let mut words = unsafe { words.assume_init() };
496+
#[cfg(feature = "nightly")]
497+
let mut words = {
498+
// We take some effort to avoid copying the words.
499+
let words = Rc::<[Word; CHUNK_WORDS]>::new_zeroed();
500+
// SAFETY: `words` can safely be all zeroes.
501+
unsafe { words.assume_init() }
502+
};
503+
#[cfg(not(feature = "nightly"))]
504+
let mut words = {
505+
let words = mem::MaybeUninit::<[Word; CHUNK_WORDS]>::zeroed();
506+
// SAFETY: `words` can safely be all zeroes.
507+
let words = unsafe { words.assume_init() };
508+
// Unfortunate possibly-large copy
509+
Rc::new(words)
510+
};
498511
let words_ref = Rc::get_mut(&mut words).unwrap();
499512

500513
let (word_index, mask) = chunk_word_index_and_mask(elem);
@@ -545,10 +558,21 @@ impl<T: Idx> ChunkedBitSet<T> {
545558
Zeros(_) => false,
546559
Ones(chunk_domain_size) => {
547560
if chunk_domain_size > 1 {
548-
// We take some effort to avoid copying the words.
549-
let words = Rc::<[Word; CHUNK_WORDS]>::new_zeroed();
550-
// SAFETY: `words` can safely be all zeroes.
551-
let mut words = unsafe { words.assume_init() };
561+
#[cfg(feature = "nightly")]
562+
let mut words = {
563+
// We take some effort to avoid copying the words.
564+
let words = Rc::<[Word; CHUNK_WORDS]>::new_zeroed();
565+
// SAFETY: `words` can safely be all zeroes.
566+
unsafe { words.assume_init() }
567+
};
568+
#[cfg(not(feature = "nightly"))]
569+
let mut words = {
570+
let words = mem::MaybeUninit::<[Word; CHUNK_WORDS]>::zeroed();
571+
// SAFETY: `words` can safely be all zeroes.
572+
let words = unsafe { words.assume_init() };
573+
// Unfortunate possibly-large copy
574+
Rc::new(words)
575+
};
552576
let words_ref = Rc::get_mut(&mut words).unwrap();
553577

554578
// Set only the bits in use.
@@ -1564,7 +1588,8 @@ impl<T: Idx> From<BitSet<T>> for GrowableBitSet<T> {
15641588
///
15651589
/// All operations that involve a row and/or column index will panic if the
15661590
/// index exceeds the relevant bound.
1567-
#[derive(Clone, Eq, PartialEq, Hash, Decodable, Encodable)]
1591+
#[cfg_attr(feature = "nightly", derive(Decodable, Encodable))]
1592+
#[derive(Clone, Eq, PartialEq, Hash)]
15681593
pub struct BitMatrix<R: Idx, C: Idx> {
15691594
num_rows: usize,
15701595
num_columns: usize,
@@ -1993,7 +2018,8 @@ impl std::fmt::Debug for FiniteBitSet<u32> {
19932018

19942019
/// A fixed-sized bitset type represented by an integer type. Indices outwith than the range
19952020
/// representable by `T` are considered set.
1996-
#[derive(Copy, Clone, Eq, PartialEq, Decodable, Encodable)]
2021+
#[cfg_attr(feature = "nightly", derive(Decodable, Encodable))]
2022+
#[derive(Copy, Clone, Eq, PartialEq)]
19972023
pub struct FiniteBitSet<T: FiniteBitSetTy>(pub T);
19982024

19992025
impl<T: FiniteBitSetTy> FiniteBitSet<T> {

compiler/rustc_index/src/lib.rs

-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
)]
1515
#![cfg_attr(feature = "nightly", allow(internal_features))]
1616

17-
#[cfg(feature = "nightly")]
1817
pub mod bit_set;
1918
#[cfg(feature = "nightly")]
2019
pub mod interval;

compiler/rustc_mir_build/src/errors.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use rustc_errors::{
66
};
77
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
88
use rustc_middle::ty::{self, Ty};
9-
use rustc_pattern_analysis::{cx::MatchCheckCtxt, errors::Uncovered};
9+
use rustc_pattern_analysis::{errors::Uncovered, rustc::RustcCtxt};
1010
use rustc_span::symbol::Symbol;
1111
use rustc_span::Span;
1212

@@ -454,7 +454,7 @@ pub enum UnusedUnsafeEnclosing {
454454
}
455455

456456
pub(crate) struct NonExhaustivePatternsTypeNotEmpty<'p, 'tcx, 'm> {
457-
pub cx: &'m MatchCheckCtxt<'p, 'tcx>,
457+
pub cx: &'m RustcCtxt<'p, 'tcx>,
458458
pub expr_span: Span,
459459
pub span: Span,
460460
pub ty: Ty<'tcx>,

compiler/rustc_mir_build/src/thir/pattern/check_match.rs

+29-25
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
use rustc_pattern_analysis::constructor::Constructor;
2-
use rustc_pattern_analysis::cx::MatchCheckCtxt;
31
use rustc_pattern_analysis::errors::Uncovered;
4-
use rustc_pattern_analysis::pat::{DeconstructedPat, WitnessPat};
5-
use rustc_pattern_analysis::usefulness::{Usefulness, UsefulnessReport};
2+
use rustc_pattern_analysis::rustc::{
3+
Constructor, DeconstructedPat, RustcCtxt as MatchCheckCtxt, Usefulness, UsefulnessReport,
4+
WitnessPat,
5+
};
66
use rustc_pattern_analysis::{analyze_match, MatchArm};
77

88
use crate::errors::*;
99

10-
use rustc_arena::TypedArena;
10+
use rustc_arena::{DroplessArena, TypedArena};
1111
use rustc_ast::Mutability;
1212
use rustc_data_structures::fx::FxHashSet;
1313
use rustc_data_structures::stack::ensure_sufficient_stack;
@@ -31,13 +31,15 @@ pub(crate) fn check_match(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), Err
3131
let (thir, expr) = tcx.thir_body(def_id)?;
3232
let thir = thir.borrow();
3333
let pattern_arena = TypedArena::default();
34+
let dropless_arena = DroplessArena::default();
3435
let mut visitor = MatchVisitor {
3536
tcx,
3637
thir: &*thir,
3738
param_env: tcx.param_env(def_id),
3839
lint_level: tcx.local_def_id_to_hir_id(def_id),
3940
let_source: LetSource::None,
4041
pattern_arena: &pattern_arena,
42+
dropless_arena: &dropless_arena,
4143
error: Ok(()),
4244
};
4345
visitor.visit_expr(&thir[expr]);
@@ -82,6 +84,7 @@ struct MatchVisitor<'thir, 'p, 'tcx> {
8284
lint_level: HirId,
8385
let_source: LetSource,
8486
pattern_arena: &'p TypedArena<DeconstructedPat<'p, 'tcx>>,
87+
dropless_arena: &'p DroplessArena,
8588
/// Tracks if we encountered an error while checking this body. That the first function to
8689
/// report it stores it here. Some functions return `Result` to allow callers to short-circuit
8790
/// on error, but callers don't need to store it here again.
@@ -382,6 +385,7 @@ impl<'thir, 'p, 'tcx> MatchVisitor<'thir, 'p, 'tcx> {
382385
param_env: self.param_env,
383386
module: self.tcx.parent_module(self.lint_level).to_def_id(),
384387
pattern_arena: self.pattern_arena,
388+
dropless_arena: self.dropless_arena,
385389
match_lint_level: self.lint_level,
386390
whole_match_span,
387391
scrut_span,
@@ -425,7 +429,8 @@ impl<'thir, 'p, 'tcx> MatchVisitor<'thir, 'p, 'tcx> {
425429
let arm = &self.thir.arms[arm];
426430
let got_error = self.with_lint_level(arm.lint_level, |this| {
427431
let Ok(pat) = this.lower_pattern(&cx, &arm.pattern) else { return true };
428-
let arm = MatchArm { pat, hir_id: this.lint_level, has_guard: arm.guard.is_some() };
432+
let arm =
433+
MatchArm { pat, arm_data: this.lint_level, has_guard: arm.guard.is_some() };
429434
tarms.push(arm);
430435
false
431436
});
@@ -548,7 +553,7 @@ impl<'thir, 'p, 'tcx> MatchVisitor<'thir, 'p, 'tcx> {
548553
) -> Result<(MatchCheckCtxt<'p, 'tcx>, UsefulnessReport<'p, 'tcx>), ErrorGuaranteed> {
549554
let cx = self.new_cx(refutability, None, scrut, pat.span);
550555
let pat = self.lower_pattern(&cx, pat)?;
551-
let arms = [MatchArm { pat, hir_id: self.lint_level, has_guard: false }];
556+
let arms = [MatchArm { pat, arm_data: self.lint_level, has_guard: false }];
552557
let report = analyze_match(&cx, &arms, pat.ty());
553558
Ok((cx, report))
554559
}
@@ -847,34 +852,34 @@ fn report_arm_reachability<'p, 'tcx>(
847852
);
848853
};
849854

850-
use Usefulness::*;
851855
let mut catchall = None;
852856
for (arm, is_useful) in report.arm_usefulness.iter() {
853857
match is_useful {
854-
Redundant => report_unreachable_pattern(arm.pat.span(), arm.hir_id, catchall),
855-
Useful(redundant_spans) if redundant_spans.is_empty() => {}
858+
Usefulness::Redundant => {
859+
report_unreachable_pattern(*arm.pat.span(), arm.arm_data, catchall)
860+
}
861+
Usefulness::Useful(redundant_spans) if redundant_spans.is_empty() => {}
856862
// The arm is reachable, but contains redundant subpatterns (from or-patterns).
857-
Useful(redundant_spans) => {
863+
Usefulness::Useful(redundant_spans) => {
858864
let mut redundant_spans = redundant_spans.clone();
859865
// Emit lints in the order in which they occur in the file.
860866
redundant_spans.sort_unstable();
861867
for span in redundant_spans {
862-
report_unreachable_pattern(span, arm.hir_id, None);
868+
report_unreachable_pattern(span, arm.arm_data, None);
863869
}
864870
}
865871
}
866872
if !arm.has_guard && catchall.is_none() && pat_is_catchall(arm.pat) {
867-
catchall = Some(arm.pat.span());
873+
catchall = Some(*arm.pat.span());
868874
}
869875
}
870876
}
871877

872878
/// Checks for common cases of "catchall" patterns that may not be intended as such.
873879
fn pat_is_catchall(pat: &DeconstructedPat<'_, '_>) -> bool {
874-
use Constructor::*;
875880
match pat.ctor() {
876-
Wildcard => true,
877-
Single => pat.iter_fields().all(|pat| pat_is_catchall(pat)),
881+
Constructor::Wildcard => true,
882+
Constructor::Struct | Constructor::Ref => pat.iter_fields().all(|pat| pat_is_catchall(pat)),
878883
_ => false,
879884
}
880885
}
@@ -885,7 +890,7 @@ fn report_non_exhaustive_match<'p, 'tcx>(
885890
thir: &Thir<'tcx>,
886891
scrut_ty: Ty<'tcx>,
887892
sp: Span,
888-
witnesses: Vec<WitnessPat<'tcx>>,
893+
witnesses: Vec<WitnessPat<'p, 'tcx>>,
889894
arms: &[ArmId],
890895
expr_span: Span,
891896
) -> ErrorGuaranteed {
@@ -1082,10 +1087,10 @@ fn report_non_exhaustive_match<'p, 'tcx>(
10821087

10831088
fn joined_uncovered_patterns<'p, 'tcx>(
10841089
cx: &MatchCheckCtxt<'p, 'tcx>,
1085-
witnesses: &[WitnessPat<'tcx>],
1090+
witnesses: &[WitnessPat<'p, 'tcx>],
10861091
) -> String {
10871092
const LIMIT: usize = 3;
1088-
let pat_to_str = |pat: &WitnessPat<'tcx>| cx.hoist_witness_pat(pat).to_string();
1093+
let pat_to_str = |pat: &WitnessPat<'p, 'tcx>| cx.hoist_witness_pat(pat).to_string();
10891094
match witnesses {
10901095
[] => bug!(),
10911096
[witness] => format!("`{}`", cx.hoist_witness_pat(witness)),
@@ -1103,7 +1108,7 @@ fn joined_uncovered_patterns<'p, 'tcx>(
11031108

11041109
fn collect_non_exhaustive_tys<'tcx>(
11051110
cx: &MatchCheckCtxt<'_, 'tcx>,
1106-
pat: &WitnessPat<'tcx>,
1111+
pat: &WitnessPat<'_, 'tcx>,
11071112
non_exhaustive_tys: &mut FxHashSet<Ty<'tcx>>,
11081113
) {
11091114
if matches!(pat.ctor(), Constructor::NonExhaustive) {
@@ -1122,7 +1127,7 @@ fn collect_non_exhaustive_tys<'tcx>(
11221127
fn report_adt_defined_here<'tcx>(
11231128
tcx: TyCtxt<'tcx>,
11241129
ty: Ty<'tcx>,
1125-
witnesses: &[WitnessPat<'tcx>],
1130+
witnesses: &[WitnessPat<'_, 'tcx>],
11261131
point_at_non_local_ty: bool,
11271132
) -> Option<AdtDefinedHere<'tcx>> {
11281133
let ty = ty.peel_refs();
@@ -1144,15 +1149,14 @@ fn report_adt_defined_here<'tcx>(
11441149
Some(AdtDefinedHere { adt_def_span, ty, variants })
11451150
}
11461151

1147-
fn maybe_point_at_variant<'a, 'tcx: 'a>(
1152+
fn maybe_point_at_variant<'a, 'p: 'a, 'tcx: 'p>(
11481153
tcx: TyCtxt<'tcx>,
11491154
def: AdtDef<'tcx>,
1150-
patterns: impl Iterator<Item = &'a WitnessPat<'tcx>>,
1155+
patterns: impl Iterator<Item = &'a WitnessPat<'p, 'tcx>>,
11511156
) -> Vec<Span> {
1152-
use Constructor::*;
11531157
let mut covered = vec![];
11541158
for pattern in patterns {
1155-
if let Variant(variant_index) = pattern.ctor() {
1159+
if let Constructor::Variant(variant_index) = pattern.ctor() {
11561160
if let ty::Adt(this_def, _) = pattern.ty().kind()
11571161
&& this_def.did() != def.did()
11581162
{

compiler/rustc_pattern_analysis/Cargo.toml

+35-12
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,40 @@ edition = "2021"
66
[dependencies]
77
# tidy-alphabetical-start
88
rustc_apfloat = "0.2.0"
9-
rustc_arena = { path = "../rustc_arena" }
10-
rustc_data_structures = { path = "../rustc_data_structures" }
11-
rustc_errors = { path = "../rustc_errors" }
12-
rustc_fluent_macro = { path = "../rustc_fluent_macro" }
13-
rustc_hir = { path = "../rustc_hir" }
14-
rustc_index = { path = "../rustc_index" }
15-
rustc_macros = { path = "../rustc_macros" }
16-
rustc_middle = { path = "../rustc_middle" }
17-
rustc_session = { path = "../rustc_session" }
18-
rustc_span = { path = "../rustc_span" }
19-
rustc_target = { path = "../rustc_target" }
20-
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
9+
rustc_arena = { path = "../rustc_arena", optional = true }
10+
rustc_data_structures = { path = "../rustc_data_structures", optional = true }
11+
rustc_errors = { path = "../rustc_errors", optional = true }
12+
rustc_fluent_macro = { path = "../rustc_fluent_macro", optional = true }
13+
rustc_hir = { path = "../rustc_hir", optional = true }
14+
rustc_index = { path = "../rustc_index", default-features = false }
15+
rustc_macros = { path = "../rustc_macros", optional = true }
16+
rustc_middle = { path = "../rustc_middle", optional = true }
17+
rustc_session = { path = "../rustc_session", optional = true }
18+
rustc_span = { path = "../rustc_span", optional = true }
19+
rustc_target = { path = "../rustc_target", optional = true }
20+
smallvec = { version = "1.8.1", features = ["union"] }
2121
tracing = "0.1"
22+
typed-arena = { version = "2.0.2", optional = true }
2223
# tidy-alphabetical-end
24+
25+
[features]
26+
default = ["rustc"]
27+
# It's not possible to only enable the `typed_arena` dependency when the `rustc` feature is off, so
28+
# we use another feature instead. The crate won't compile if one of these isn't enabled.
29+
rustc = [
30+
"dep:rustc_arena",
31+
"dep:rustc_data_structures",
32+
"dep:rustc_errors",
33+
"dep:rustc_fluent_macro",
34+
"dep:rustc_hir",
35+
"dep:rustc_macros",
36+
"dep:rustc_middle",
37+
"dep:rustc_session",
38+
"dep:rustc_span",
39+
"dep:rustc_target",
40+
"smallvec/may_dangle",
41+
"rustc_index/nightly",
42+
]
43+
stable = [
44+
"dep:typed-arena",
45+
]

0 commit comments

Comments
 (0)