Skip to content

Commit

Permalink
Rollup merge of #119230 - Nadrieril:librarify-even-further, r=compile…
Browse files Browse the repository at this point in the history
…r-errors

Exhaustiveness: clean up after librarification

This cleans up some things that weren't done nicely by #118842.

r? `@compiler-errors`
  • Loading branch information
compiler-errors authored Dec 23, 2023
2 parents eef023c + 5fccaee commit 8c50e3e
Show file tree
Hide file tree
Showing 10 changed files with 45 additions and 41 deletions.
1 change: 1 addition & 0 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4340,6 +4340,7 @@ dependencies = [
name = "rustc_pattern_analysis"
version = "0.0.0"
dependencies = [
"derivative",
"rustc_apfloat",
"rustc_arena",
"rustc_data_structures",
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_index/src/bit_set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() };
Expand Down Expand Up @@ -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() };
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_mir_build/src/thir/pattern/check_match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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).
Expand All @@ -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());
}
}
}
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_pattern_analysis/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_pattern_analysis/src/constructor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
18 changes: 8 additions & 10 deletions compiler/rustc_pattern_analysis/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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;
Expand All @@ -86,26 +85,25 @@ 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,
/// An arena to store the wildcards we produce during analysis.
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")]
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_pattern_analysis/src/lints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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;
Expand Down
21 changes: 13 additions & 8 deletions compiler/rustc_pattern_analysis/src/pat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -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 {
Expand All @@ -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>(
Expand All @@ -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()
};
Expand Down Expand Up @@ -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>>,
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_pattern_analysis/src/rustc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand All @@ -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);
Expand All @@ -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);
Expand Down
24 changes: 10 additions & 14 deletions compiler/rustc_pattern_analysis/src/usefulness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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).
Expand Down Expand Up @@ -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]>,
Expand Down Expand Up @@ -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()),
Expand Down Expand Up @@ -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> {
Expand Down Expand Up @@ -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> {
Expand Down

0 comments on commit 8c50e3e

Please sign in to comment.