Rollup merge of #119230 - Nadrieril:librarify-even-further, r=compiler-errors

Exhaustiveness: clean up after librarification

This cleans up some things that weren't done nicely by https://github.com/rust-lang/rust/pull/118842.

r? `@compiler-errors`
This commit is contained in:
Michael Goulet 2023-12-22 21:41:05 -05:00 committed by GitHub
commit 8c50e3eaee
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 45 additions and 41 deletions

View file

@ -4340,6 +4340,7 @@ dependencies = [
name = "rustc_pattern_analysis" name = "rustc_pattern_analysis"
version = "0.0.0" version = "0.0.0"
dependencies = [ dependencies = [
"derivative",
"rustc_apfloat", "rustc_apfloat",
"rustc_arena", "rustc_arena",
"rustc_data_structures", "rustc_data_structures",

View file

@ -502,6 +502,7 @@ impl<T: Idx> ChunkedBitSet<T> {
}; };
#[cfg(not(feature = "nightly"))] #[cfg(not(feature = "nightly"))]
let mut words = { let mut words = {
// FIXME: unconditionally use `Rc::new_zeroed` once it is stable (#63291).
let words = mem::MaybeUninit::<[Word; CHUNK_WORDS]>::zeroed(); let words = mem::MaybeUninit::<[Word; CHUNK_WORDS]>::zeroed();
// SAFETY: `words` can safely be all zeroes. // SAFETY: `words` can safely be all zeroes.
let words = unsafe { words.assume_init() }; let words = unsafe { words.assume_init() };
@ -567,6 +568,7 @@ impl<T: Idx> ChunkedBitSet<T> {
}; };
#[cfg(not(feature = "nightly"))] #[cfg(not(feature = "nightly"))]
let mut words = { let mut words = {
// FIXME: unconditionally use `Rc::new_zeroed` once it is stable (#63291).
let words = mem::MaybeUninit::<[Word; CHUNK_WORDS]>::zeroed(); let words = mem::MaybeUninit::<[Word; CHUNK_WORDS]>::zeroed();
// SAFETY: `words` can safely be all zeroes. // SAFETY: `words` can safely be all zeroes.
let words = unsafe { words.assume_init() }; let words = unsafe { words.assume_init() };

View file

@ -856,7 +856,7 @@ fn report_arm_reachability<'p, 'tcx>(
for (arm, is_useful) in report.arm_usefulness.iter() { for (arm, is_useful) in report.arm_usefulness.iter() {
match is_useful { match is_useful {
Usefulness::Redundant => { Usefulness::Redundant => {
report_unreachable_pattern(*arm.pat.data(), arm.arm_data, catchall) report_unreachable_pattern(*arm.pat.data().unwrap(), arm.arm_data, catchall)
} }
Usefulness::Useful(redundant_subpats) if redundant_subpats.is_empty() => {} Usefulness::Useful(redundant_subpats) if redundant_subpats.is_empty() => {}
// The arm is reachable, but contains redundant subpatterns (from or-patterns). // The arm is reachable, but contains redundant subpatterns (from or-patterns).
@ -865,12 +865,12 @@ fn report_arm_reachability<'p, 'tcx>(
// Emit lints in the order in which they occur in the file. // Emit lints in the order in which they occur in the file.
redundant_subpats.sort_unstable_by_key(|pat| pat.data()); redundant_subpats.sort_unstable_by_key(|pat| pat.data());
for pat in redundant_subpats { for pat in redundant_subpats {
report_unreachable_pattern(*pat.data(), arm.arm_data, None); report_unreachable_pattern(*pat.data().unwrap(), arm.arm_data, None);
} }
} }
} }
if !arm.has_guard && catchall.is_none() && pat_is_catchall(arm.pat) { if !arm.has_guard && catchall.is_none() && pat_is_catchall(arm.pat) {
catchall = Some(*arm.pat.data()); catchall = Some(*arm.pat.data().unwrap());
} }
} }
} }

View file

@ -5,6 +5,7 @@ edition = "2021"
[dependencies] [dependencies]
# tidy-alphabetical-start # tidy-alphabetical-start
derivative = "2.2.0"
rustc_apfloat = "0.2.0" rustc_apfloat = "0.2.0"
rustc_arena = { path = "../rustc_arena", optional = true } rustc_arena = { path = "../rustc_arena", optional = true }
rustc_data_structures = { path = "../rustc_data_structures", optional = true } rustc_data_structures = { path = "../rustc_data_structures", optional = true }

View file

@ -642,7 +642,8 @@ impl OpaqueId {
/// `specialize_constructor` returns the list of fields corresponding to a pattern, given a /// `specialize_constructor` returns the list of fields corresponding to a pattern, given a
/// constructor. `Constructor::apply` reconstructs the pattern from a pair of `Constructor` and /// constructor. `Constructor::apply` reconstructs the pattern from a pair of `Constructor` and
/// `Fields`. /// `Fields`.
#[derive(Clone, Debug, PartialEq)] #[derive(derivative::Derivative)]
#[derivative(Debug(bound = ""), Clone(bound = ""), PartialEq(bound = ""))]
pub enum Constructor<Cx: TypeCx> { pub enum Constructor<Cx: TypeCx> {
/// Tuples and structs. /// Tuples and structs.
Struct, Struct,

View file

@ -49,7 +49,7 @@ impl<'a, T: ?Sized> Captures<'a> for T {}
/// Context that provides type information about constructors. /// Context that provides type information about constructors.
/// ///
/// Most of the crate is parameterized on a type that implements this trait. /// Most of the crate is parameterized on a type that implements this trait.
pub trait TypeCx: Sized + Clone + fmt::Debug { pub trait TypeCx: Sized + fmt::Debug {
/// The type of a pattern. /// The type of a pattern.
type Ty: Copy + Clone + fmt::Debug; // FIXME: remove Copy type Ty: Copy + Clone + fmt::Debug; // FIXME: remove Copy
/// The index of an enum variant. /// The index of an enum variant.
@ -58,9 +58,8 @@ pub trait TypeCx: Sized + Clone + fmt::Debug {
type StrLit: Clone + PartialEq + fmt::Debug; type StrLit: Clone + PartialEq + fmt::Debug;
/// Extra data to store in a match arm. /// Extra data to store in a match arm.
type ArmData: Copy + Clone + fmt::Debug; type ArmData: Copy + Clone + fmt::Debug;
/// Extra data to store in a pattern. `Default` needed when we create fictitious wildcard /// Extra data to store in a pattern.
/// patterns during analysis. type PatData: Clone;
type PatData: Clone + Default;
/// FIXME(Nadrieril): `Cx` should only give us revealed types. /// FIXME(Nadrieril): `Cx` should only give us revealed types.
fn reveal_opaque_ty(&self, ty: Self::Ty) -> Self::Ty; fn reveal_opaque_ty(&self, ty: Self::Ty) -> Self::Ty;
@ -86,7 +85,8 @@ pub trait TypeCx: Sized + Clone + fmt::Debug {
} }
/// Context that provides information global to a match. /// Context that provides information global to a match.
#[derive(Clone)] #[derive(derivative::Derivative)]
#[derivative(Clone(bound = ""), Copy(bound = ""))]
pub struct MatchCtxt<'a, 'p, Cx: TypeCx> { pub struct MatchCtxt<'a, 'p, Cx: TypeCx> {
/// The context for type information. /// The context for type information.
pub tycx: &'a Cx, pub tycx: &'a Cx,
@ -94,18 +94,16 @@ pub struct MatchCtxt<'a, 'p, Cx: TypeCx> {
pub wildcard_arena: &'a TypedArena<DeconstructedPat<'p, Cx>>, pub wildcard_arena: &'a TypedArena<DeconstructedPat<'p, Cx>>,
} }
impl<'a, 'p, Cx: TypeCx> Copy for MatchCtxt<'a, 'p, Cx> {}
/// The arm of a match expression. /// The arm of a match expression.
#[derive(Clone, Debug)] #[derive(Debug)]
#[derive(derivative::Derivative)]
#[derivative(Clone(bound = ""), Copy(bound = ""))]
pub struct MatchArm<'p, Cx: TypeCx> { pub struct MatchArm<'p, Cx: TypeCx> {
pub pat: &'p DeconstructedPat<'p, Cx>, pub pat: &'p DeconstructedPat<'p, Cx>,
pub has_guard: bool, pub has_guard: bool,
pub arm_data: Cx::ArmData, pub arm_data: Cx::ArmData,
} }
impl<'p, Cx: TypeCx> Copy for MatchArm<'p, Cx> {}
/// The entrypoint for this crate. Computes whether a match is exhaustive and which of its arms are /// The entrypoint for this crate. Computes whether a match is exhaustive and which of its arms are
/// useful, and runs some lints. /// useful, and runs some lints.
#[cfg(feature = "rustc")] #[cfg(feature = "rustc")]

View file

@ -203,7 +203,7 @@ pub(crate) fn lint_nonexhaustive_missing_variants<'a, 'p, 'tcx>(
}; };
use rustc_errors::DecorateLint; use rustc_errors::DecorateLint;
let mut err = rcx.tcx.sess.struct_span_warn(*arm.pat.data(), ""); let mut err = rcx.tcx.sess.struct_span_warn(*arm.pat.data().unwrap(), "");
err.set_primary_message(decorator.msg()); err.set_primary_message(decorator.msg());
decorator.decorate_lint(&mut err); decorator.decorate_lint(&mut err);
err.emit(); err.emit();
@ -253,8 +253,8 @@ pub(crate) fn lint_overlapping_range_endpoints<'a, 'p, 'tcx>(
let mut suffixes: SmallVec<[_; 1]> = Default::default(); let mut suffixes: SmallVec<[_; 1]> = Default::default();
// Iterate on patterns that contained `overlap`. // Iterate on patterns that contained `overlap`.
for pat in column.iter() { for pat in column.iter() {
let this_span = *pat.data();
let Constructor::IntRange(this_range) = pat.ctor() else { continue }; let Constructor::IntRange(this_range) = pat.ctor() else { continue };
let this_span = *pat.data().unwrap();
if this_range.is_singleton() { if this_range.is_singleton() {
// Don't lint when one of the ranges is a singleton. // Don't lint when one of the ranges is a singleton.
continue; continue;

View file

@ -26,14 +26,16 @@ pub struct DeconstructedPat<'p, Cx: TypeCx> {
ctor: Constructor<Cx>, ctor: Constructor<Cx>,
fields: &'p [DeconstructedPat<'p, Cx>], fields: &'p [DeconstructedPat<'p, Cx>],
ty: Cx::Ty, ty: Cx::Ty,
data: Cx::PatData, /// Extra data to store in a pattern. `None` if the pattern is a wildcard that does not
/// correspond to a user-supplied pattern.
data: Option<Cx::PatData>,
/// Whether removing this arm would change the behavior of the match expression. /// Whether removing this arm would change the behavior of the match expression.
useful: Cell<bool>, useful: Cell<bool>,
} }
impl<'p, Cx: TypeCx> DeconstructedPat<'p, Cx> { impl<'p, Cx: TypeCx> DeconstructedPat<'p, Cx> {
pub fn wildcard(ty: Cx::Ty, data: Cx::PatData) -> Self { pub fn wildcard(ty: Cx::Ty) -> Self {
Self::new(Wildcard, &[], ty, data) DeconstructedPat { ctor: Wildcard, fields: &[], ty, data: None, useful: Cell::new(false) }
} }
pub fn new( pub fn new(
@ -42,7 +44,7 @@ impl<'p, Cx: TypeCx> DeconstructedPat<'p, Cx> {
ty: Cx::Ty, ty: Cx::Ty,
data: Cx::PatData, data: Cx::PatData,
) -> Self { ) -> Self {
DeconstructedPat { ctor, fields, ty, data, useful: Cell::new(false) } DeconstructedPat { ctor, fields, ty, data: Some(data), useful: Cell::new(false) }
} }
pub(crate) fn is_or_pat(&self) -> bool { pub(crate) fn is_or_pat(&self) -> bool {
@ -63,8 +65,10 @@ impl<'p, Cx: TypeCx> DeconstructedPat<'p, Cx> {
pub fn ty(&self) -> Cx::Ty { pub fn ty(&self) -> Cx::Ty {
self.ty self.ty
} }
pub fn data(&self) -> &Cx::PatData { /// Returns the extra data stored in a pattern. Returns `None` if the pattern is a wildcard that
&self.data /// does not correspond to a user-supplied pattern.
pub fn data(&self) -> Option<&Cx::PatData> {
self.data.as_ref()
} }
pub fn iter_fields<'a>( pub fn iter_fields<'a>(
@ -83,7 +87,7 @@ impl<'p, Cx: TypeCx> DeconstructedPat<'p, Cx> {
let wildcard_sub_tys = || { let wildcard_sub_tys = || {
let tys = pcx.ctor_sub_tys(other_ctor); let tys = pcx.ctor_sub_tys(other_ctor);
tys.iter() tys.iter()
.map(|ty| DeconstructedPat::wildcard(*ty, Cx::PatData::default())) .map(|ty| DeconstructedPat::wildcard(*ty))
.map(|pat| pcx.mcx.wildcard_arena.alloc(pat) as &_) .map(|pat| pcx.mcx.wildcard_arena.alloc(pat) as &_)
.collect() .collect()
}; };
@ -160,7 +164,8 @@ impl<'p, Cx: TypeCx> fmt::Debug for DeconstructedPat<'p, Cx> {
/// Same idea as `DeconstructedPat`, except this is a fictitious pattern built up for diagnostics /// Same idea as `DeconstructedPat`, except this is a fictitious pattern built up for diagnostics
/// purposes. As such they don't use interning and can be cloned. /// purposes. As such they don't use interning and can be cloned.
#[derive(Debug, Clone)] #[derive(derivative::Derivative)]
#[derivative(Debug(bound = ""), Clone(bound = ""))]
pub struct WitnessPat<Cx: TypeCx> { pub struct WitnessPat<Cx: TypeCx> {
ctor: Constructor<Cx>, ctor: Constructor<Cx>,
pub(crate) fields: Vec<WitnessPat<Cx>>, pub(crate) fields: Vec<WitnessPat<Cx>>,

View file

@ -416,7 +416,7 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> {
ty::Tuple(fs) => { ty::Tuple(fs) => {
ctor = Struct; ctor = Struct;
let mut wilds: SmallVec<[_; 2]> = let mut wilds: SmallVec<[_; 2]> =
fs.iter().map(|ty| DeconstructedPat::wildcard(ty, pat.span)).collect(); fs.iter().map(|ty| DeconstructedPat::wildcard(ty)).collect();
for pat in subpatterns { for pat in subpatterns {
wilds[pat.field.index()] = self.lower_pat(&pat.pattern); wilds[pat.field.index()] = self.lower_pat(&pat.pattern);
} }
@ -439,7 +439,7 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> {
let pat = if let Some(pat) = pattern { let pat = if let Some(pat) = pattern {
self.lower_pat(&pat.pattern) self.lower_pat(&pat.pattern)
} else { } else {
DeconstructedPat::wildcard(args.type_at(0), pat.span) DeconstructedPat::wildcard(args.type_at(0))
}; };
ctor = Struct; ctor = Struct;
fields = singleton(pat); fields = singleton(pat);
@ -464,7 +464,7 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> {
ty ty
}); });
let mut wilds: SmallVec<[_; 2]> = let mut wilds: SmallVec<[_; 2]> =
tys.map(|ty| DeconstructedPat::wildcard(ty, pat.span)).collect(); tys.map(|ty| DeconstructedPat::wildcard(ty)).collect();
for pat in subpatterns { for pat in subpatterns {
if let Some(i) = field_id_to_id[pat.field.index()] { if let Some(i) = field_id_to_id[pat.field.index()] {
wilds[i] = self.lower_pat(&pat.pattern); wilds[i] = self.lower_pat(&pat.pattern);

View file

@ -569,8 +569,10 @@ pub fn ensure_sufficient_stack<R>(f: impl FnOnce() -> R) -> R {
} }
/// Context that provides information local to a place under investigation. /// Context that provides information local to a place under investigation.
#[derive(Clone)] #[derive(derivative::Derivative)]
#[derivative(Debug(bound = ""), Clone(bound = ""), Copy(bound = ""))]
pub(crate) struct PlaceCtxt<'a, 'p, Cx: TypeCx> { pub(crate) struct PlaceCtxt<'a, 'p, Cx: TypeCx> {
#[derivative(Debug = "ignore")]
pub(crate) mcx: MatchCtxt<'a, 'p, Cx>, pub(crate) mcx: MatchCtxt<'a, 'p, Cx>,
/// Type of the place under investigation. /// Type of the place under investigation.
pub(crate) ty: Cx::Ty, pub(crate) ty: Cx::Ty,
@ -596,14 +598,6 @@ impl<'a, 'p, Cx: TypeCx> PlaceCtxt<'a, 'p, Cx> {
} }
} }
impl<'a, 'p, Cx: TypeCx> Copy for PlaceCtxt<'a, 'p, Cx> {}
impl<'a, 'p, Cx: TypeCx> fmt::Debug for PlaceCtxt<'a, 'p, Cx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("PlaceCtxt").field("ty", &self.ty).finish()
}
}
/// Serves two purposes: /// Serves two purposes:
/// - in a wildcard, tracks whether the wildcard matches only valid values (i.e. is a binding `_a`) /// - in a wildcard, tracks whether the wildcard matches only valid values (i.e. is a binding `_a`)
/// or also invalid values (i.e. is a true `_` pattern). /// or also invalid values (i.e. is a true `_` pattern).
@ -670,7 +664,8 @@ impl fmt::Display for ValidityConstraint {
// - 'a allocated by us // - 'a allocated by us
// - 'p coming from the input // - 'p coming from the input
// - Cx global compilation context // - Cx global compilation context
#[derive(Clone)] #[derive(derivative::Derivative)]
#[derivative(Clone(bound = ""))]
struct PatStack<'a, 'p, Cx: TypeCx> { struct PatStack<'a, 'p, Cx: TypeCx> {
// Rows of len 1 are very common, which is why `SmallVec[_; 2]` works well. // Rows of len 1 are very common, which is why `SmallVec[_; 2]` works well.
pats: SmallVec<[&'a DeconstructedPat<'p, Cx>; 2]>, pats: SmallVec<[&'a DeconstructedPat<'p, Cx>; 2]>,
@ -845,8 +840,7 @@ impl<'a, 'p, Cx: TypeCx> Matrix<'a, 'p, Cx> {
scrut_ty: Cx::Ty, scrut_ty: Cx::Ty,
scrut_validity: ValidityConstraint, scrut_validity: ValidityConstraint,
) -> Self { ) -> Self {
let wild_pattern = let wild_pattern = wildcard_arena.alloc(DeconstructedPat::wildcard(scrut_ty));
wildcard_arena.alloc(DeconstructedPat::wildcard(scrut_ty, Default::default()));
let wildcard_row = PatStack::from_pattern(wild_pattern); let wildcard_row = PatStack::from_pattern(wild_pattern);
let mut matrix = Matrix { let mut matrix = Matrix {
rows: Vec::with_capacity(arms.len()), rows: Vec::with_capacity(arms.len()),
@ -1022,7 +1016,8 @@ impl<'a, 'p, Cx: TypeCx> fmt::Debug for Matrix<'a, 'p, Cx> {
/// The final `Pair(Some(_), true)` is then the resulting witness. /// The final `Pair(Some(_), true)` is then the resulting witness.
/// ///
/// See the top of the file for more detailed explanations and examples. /// See the top of the file for more detailed explanations and examples.
#[derive(Debug, Clone)] #[derive(derivative::Derivative)]
#[derivative(Debug(bound = ""), Clone(bound = ""))]
struct WitnessStack<Cx: TypeCx>(Vec<WitnessPat<Cx>>); struct WitnessStack<Cx: TypeCx>(Vec<WitnessPat<Cx>>);
impl<Cx: TypeCx> WitnessStack<Cx> { impl<Cx: TypeCx> WitnessStack<Cx> {
@ -1069,7 +1064,8 @@ impl<Cx: TypeCx> WitnessStack<Cx> {
/// ///
/// Just as the `Matrix` starts with a single column, by the end of the algorithm, this has a single /// Just as the `Matrix` starts with a single column, by the end of the algorithm, this has a single
/// column, which contains the patterns that are missing for the match to be exhaustive. /// column, which contains the patterns that are missing for the match to be exhaustive.
#[derive(Debug, Clone)] #[derive(derivative::Derivative)]
#[derivative(Debug(bound = ""), Clone(bound = ""))]
struct WitnessMatrix<Cx: TypeCx>(Vec<WitnessStack<Cx>>); struct WitnessMatrix<Cx: TypeCx>(Vec<WitnessStack<Cx>>);
impl<Cx: TypeCx> WitnessMatrix<Cx> { impl<Cx: TypeCx> WitnessMatrix<Cx> {