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"
version = "0.0.0"
dependencies = [
"derivative",
"rustc_apfloat",
"rustc_arena",
"rustc_data_structures",

View file

@ -502,6 +502,7 @@ impl<T: Idx> ChunkedBitSet<T> {
};
#[cfg(not(feature = "nightly"))]
let mut words = {
// FIXME: unconditionally use `Rc::new_zeroed` once it is stable (#63291).
let words = mem::MaybeUninit::<[Word; CHUNK_WORDS]>::zeroed();
// SAFETY: `words` can safely be all zeroes.
let words = unsafe { words.assume_init() };
@ -567,6 +568,7 @@ impl<T: Idx> ChunkedBitSet<T> {
};
#[cfg(not(feature = "nightly"))]
let mut words = {
// FIXME: unconditionally use `Rc::new_zeroed` once it is stable (#63291).
let words = mem::MaybeUninit::<[Word; CHUNK_WORDS]>::zeroed();
// SAFETY: `words` can safely be all zeroes.
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() {
match is_useful {
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() => {}
// 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.
redundant_subpats.sort_unstable_by_key(|pat| pat.data());
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) {
catchall = Some(*arm.pat.data());
catchall = Some(*arm.pat.data().unwrap());
}
}
}

View file

@ -5,6 +5,7 @@ edition = "2021"
[dependencies]
# tidy-alphabetical-start
derivative = "2.2.0"
rustc_apfloat = "0.2.0"
rustc_arena = { path = "../rustc_arena", 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
/// constructor. `Constructor::apply` reconstructs the pattern from a pair of `Constructor` and
/// `Fields`.
#[derive(Clone, Debug, PartialEq)]
#[derive(derivative::Derivative)]
#[derivative(Debug(bound = ""), Clone(bound = ""), PartialEq(bound = ""))]
pub enum Constructor<Cx: TypeCx> {
/// Tuples and structs.
Struct,

View file

@ -49,7 +49,7 @@ impl<'a, T: ?Sized> Captures<'a> for T {}
/// Context that provides type information about constructors.
///
/// 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.
type Ty: Copy + Clone + fmt::Debug; // FIXME: remove Copy
/// The index of an enum variant.
@ -58,9 +58,8 @@ pub trait TypeCx: Sized + Clone + fmt::Debug {
type StrLit: Clone + PartialEq + fmt::Debug;
/// Extra data to store in a match arm.
type ArmData: Copy + Clone + fmt::Debug;
/// Extra data to store in a pattern. `Default` needed when we create fictitious wildcard
/// patterns during analysis.
type PatData: Clone + Default;
/// Extra data to store in a pattern.
type PatData: Clone;
/// FIXME(Nadrieril): `Cx` should only give us revealed types.
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.
#[derive(Clone)]
#[derive(derivative::Derivative)]
#[derivative(Clone(bound = ""), Copy(bound = ""))]
pub struct MatchCtxt<'a, 'p, Cx: TypeCx> {
/// The context for type information.
pub tycx: &'a Cx,
@ -94,18 +94,16 @@ pub struct MatchCtxt<'a, 'p, Cx: TypeCx> {
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.
#[derive(Clone, Debug)]
#[derive(Debug)]
#[derive(derivative::Derivative)]
#[derivative(Clone(bound = ""), Copy(bound = ""))]
pub struct MatchArm<'p, Cx: TypeCx> {
pub pat: &'p DeconstructedPat<'p, Cx>,
pub has_guard: bool,
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
/// useful, and runs some lints.
#[cfg(feature = "rustc")]

View file

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

View file

@ -26,14 +26,16 @@ pub struct DeconstructedPat<'p, Cx: TypeCx> {
ctor: Constructor<Cx>,
fields: &'p [DeconstructedPat<'p, Cx>],
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.
useful: Cell<bool>,
}
impl<'p, Cx: TypeCx> DeconstructedPat<'p, Cx> {
pub fn wildcard(ty: Cx::Ty, data: Cx::PatData) -> Self {
Self::new(Wildcard, &[], ty, data)
pub fn wildcard(ty: Cx::Ty) -> Self {
DeconstructedPat { ctor: Wildcard, fields: &[], ty, data: None, useful: Cell::new(false) }
}
pub fn new(
@ -42,7 +44,7 @@ impl<'p, Cx: TypeCx> DeconstructedPat<'p, Cx> {
ty: Cx::Ty,
data: Cx::PatData,
) -> 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 {
@ -63,8 +65,10 @@ impl<'p, Cx: TypeCx> DeconstructedPat<'p, Cx> {
pub fn ty(&self) -> Cx::Ty {
self.ty
}
pub fn data(&self) -> &Cx::PatData {
&self.data
/// Returns the extra data stored in a pattern. Returns `None` if the pattern is a wildcard that
/// does not correspond to a user-supplied pattern.
pub fn data(&self) -> Option<&Cx::PatData> {
self.data.as_ref()
}
pub fn iter_fields<'a>(
@ -83,7 +87,7 @@ impl<'p, Cx: TypeCx> DeconstructedPat<'p, Cx> {
let wildcard_sub_tys = || {
let tys = pcx.ctor_sub_tys(other_ctor);
tys.iter()
.map(|ty| DeconstructedPat::wildcard(*ty, Cx::PatData::default()))
.map(|ty| DeconstructedPat::wildcard(*ty))
.map(|pat| pcx.mcx.wildcard_arena.alloc(pat) as &_)
.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
/// 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> {
ctor: Constructor<Cx>,
pub(crate) fields: Vec<WitnessPat<Cx>>,

View file

@ -416,7 +416,7 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> {
ty::Tuple(fs) => {
ctor = Struct;
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 {
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 {
self.lower_pat(&pat.pattern)
} else {
DeconstructedPat::wildcard(args.type_at(0), pat.span)
DeconstructedPat::wildcard(args.type_at(0))
};
ctor = Struct;
fields = singleton(pat);
@ -464,7 +464,7 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> {
ty
});
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 {
if let Some(i) = field_id_to_id[pat.field.index()] {
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.
#[derive(Clone)]
#[derive(derivative::Derivative)]
#[derivative(Debug(bound = ""), Clone(bound = ""), Copy(bound = ""))]
pub(crate) struct PlaceCtxt<'a, 'p, Cx: TypeCx> {
#[derivative(Debug = "ignore")]
pub(crate) mcx: MatchCtxt<'a, 'p, Cx>,
/// Type of the place under investigation.
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:
/// - 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).
@ -670,7 +664,8 @@ impl fmt::Display for ValidityConstraint {
// - 'a allocated by us
// - 'p coming from the input
// - Cx global compilation context
#[derive(Clone)]
#[derive(derivative::Derivative)]
#[derivative(Clone(bound = ""))]
struct PatStack<'a, 'p, Cx: TypeCx> {
// Rows of len 1 are very common, which is why `SmallVec[_; 2]` works well.
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_validity: ValidityConstraint,
) -> Self {
let wild_pattern =
wildcard_arena.alloc(DeconstructedPat::wildcard(scrut_ty, Default::default()));
let wild_pattern = wildcard_arena.alloc(DeconstructedPat::wildcard(scrut_ty));
let wildcard_row = PatStack::from_pattern(wild_pattern);
let mut matrix = Matrix {
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.
///
/// 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>>);
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
/// 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>>);
impl<Cx: TypeCx> WitnessMatrix<Cx> {