Skip to content

Stop using derivative in rustc_pattern_analysis #120420

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 29, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion Cargo.lock
Original file line number Diff line number Diff line change
@@ -4342,7 +4342,6 @@ dependencies = [
name = "rustc_pattern_analysis"
version = "0.0.0"
dependencies = [
"derivative",
"rustc-hash",
"rustc_apfloat",
"rustc_arena",
1 change: 0 additions & 1 deletion compiler/rustc_pattern_analysis/Cargo.toml
Original file line number Diff line number Diff line change
@@ -5,7 +5,6 @@ edition = "2021"

[dependencies]
# tidy-alphabetical-start
derivative = "2.2.0"
rustc-hash = "1.1.0"
rustc_apfloat = "0.2.0"
rustc_arena = { path = "../rustc_arena", optional = true }
98 changes: 96 additions & 2 deletions compiler/rustc_pattern_analysis/src/constructor.rs
Original file line number Diff line number Diff line change
@@ -151,6 +151,7 @@
use std::cmp::{self, max, min, Ordering};
use std::fmt;
use std::iter::once;
use std::mem;

use smallvec::SmallVec;

@@ -648,8 +649,6 @@ 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(derivative::Derivative)]
#[derivative(Debug(bound = ""), Clone(bound = ""), PartialEq(bound = ""))]
pub enum Constructor<Cx: TypeCx> {
/// Tuples and structs.
Struct,
@@ -692,6 +691,101 @@ pub enum Constructor<Cx: TypeCx> {
Missing,
}

impl<Cx: TypeCx> Clone for Constructor<Cx> {
fn clone(&self) -> Self {
match self {
Constructor::Struct => Constructor::Struct,
Constructor::Variant(idx) => Constructor::Variant(idx.clone()),
Constructor::Ref => Constructor::Ref,
Constructor::Slice(slice) => Constructor::Slice(slice.clone()),
Constructor::UnionField => Constructor::UnionField,
Constructor::Bool(b) => Constructor::Bool(b.clone()),
Constructor::IntRange(range) => Constructor::IntRange(range.clone()),
Constructor::F32Range(lo, hi, end) => {
Constructor::F32Range(lo.clone(), hi.clone(), end.clone())
}
Constructor::F64Range(lo, hi, end) => {
Constructor::F64Range(lo.clone(), hi.clone(), end.clone())
}
Constructor::Str(value) => Constructor::Str(value.clone()),
Constructor::Opaque(inner) => Constructor::Opaque(inner.clone()),
Constructor::Or => Constructor::Or,
Constructor::Wildcard => Constructor::Wildcard,
Constructor::NonExhaustive => Constructor::NonExhaustive,
Constructor::Hidden => Constructor::Hidden,
Constructor::Missing => Constructor::Missing,
}
}
}

impl<Cx: TypeCx> fmt::Debug for Constructor<Cx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Constructor::Struct => f.debug_tuple("Struct").finish(),
Constructor::Variant(idx) => f.debug_tuple("Variant").field(idx).finish(),
Constructor::Ref => f.debug_tuple("Ref").finish(),
Constructor::Slice(slice) => f.debug_tuple("Slice").field(slice).finish(),
Constructor::UnionField => f.debug_tuple("UnionField").finish(),
Constructor::Bool(b) => f.debug_tuple("Bool").field(b).finish(),
Constructor::IntRange(range) => f.debug_tuple("IntRange").field(range).finish(),
Constructor::F32Range(lo, hi, end) => {
f.debug_tuple("F32Range").field(lo).field(hi).field(end).finish()
}
Constructor::F64Range(lo, hi, end) => {
f.debug_tuple("F64Range").field(lo).field(hi).field(end).finish()
}
Constructor::Str(value) => f.debug_tuple("Str").field(value).finish(),
Constructor::Opaque(inner) => f.debug_tuple("Opaque").field(inner).finish(),
Constructor::Or => f.debug_tuple("Or").finish(),
Constructor::Wildcard => f.debug_tuple("Wildcard").finish(),
Constructor::NonExhaustive => f.debug_tuple("NonExhaustive").finish(),
Constructor::Hidden => f.debug_tuple("Hidden").finish(),
Constructor::Missing => f.debug_tuple("Missing").finish(),
}
}
}

impl<Cx: TypeCx> PartialEq for Constructor<Cx> {
fn eq(&self, other: &Self) -> bool {
(mem::discriminant(self) == mem::discriminant(other))
&& match (self, other) {
(Constructor::Struct, Constructor::Struct) => true,
(Constructor::Variant(self_variant), Constructor::Variant(other_variant)) => {
self_variant == other_variant
}
(Constructor::Ref, Constructor::Ref) => true,
(Constructor::Slice(self_slice), Constructor::Slice(other_slice)) => {
self_slice == other_slice
}
(Constructor::UnionField, Constructor::UnionField) => true,
(Constructor::Bool(self_b), Constructor::Bool(other_b)) => self_b == other_b,
(Constructor::IntRange(self_range), Constructor::IntRange(other_range)) => {
self_range == other_range
}
(
Constructor::F32Range(self_lo, self_hi, self_end),
Constructor::F32Range(other_lo, other_hi, other_end),
) => self_lo == other_lo && self_hi == other_hi && self_end == other_end,
(
Constructor::F64Range(self_lo, self_hi, self_end),
Constructor::F64Range(other_lo, other_hi, other_end),
) => self_lo == other_lo && self_hi == other_hi && self_end == other_end,
(Constructor::Str(self_value), Constructor::Str(other_value)) => {
self_value == other_value
}
(Constructor::Opaque(self_inner), Constructor::Opaque(other_inner)) => {
self_inner == other_inner
}
(Constructor::Or, Constructor::Or) => true,
(Constructor::Wildcard, Constructor::Wildcard) => true,
(Constructor::NonExhaustive, Constructor::NonExhaustive) => true,
(Constructor::Hidden, Constructor::Hidden) => true,
(Constructor::Missing, Constructor::Missing) => true,
_ => unreachable!(),
}
}
}

impl<Cx: TypeCx> Constructor<Cx> {
pub(crate) fn is_non_exhaustive(&self) -> bool {
matches!(self, NonExhaustive)
20 changes: 16 additions & 4 deletions compiler/rustc_pattern_analysis/src/lib.rs
Original file line number Diff line number Diff line change
@@ -136,23 +136,35 @@ pub trait TypeCx: Sized + fmt::Debug {
}

/// Context that provides information global to a match.
#[derive(derivative::Derivative)]
#[derivative(Clone(bound = ""), Copy(bound = ""))]
pub struct MatchCtxt<'a, Cx: TypeCx> {
/// The context for type information.
pub tycx: &'a Cx,
}

impl<'a, Cx: TypeCx> Clone for MatchCtxt<'a, Cx> {
fn clone(&self) -> Self {
Self { tycx: self.tycx }
}
}

impl<'a, Cx: TypeCx> Copy for MatchCtxt<'a, Cx> {}

/// The arm of a match expression.
#[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> Clone for MatchArm<'p, Cx> {
fn clone(&self) -> Self {
Self { pat: self.pat, has_guard: self.has_guard, arm_data: self.arm_data }
}
}

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")]
31 changes: 27 additions & 4 deletions compiler/rustc_pattern_analysis/src/pat.rs
Original file line number Diff line number Diff line change
@@ -218,15 +218,24 @@ impl<'p, Cx: TypeCx> fmt::Debug for DeconstructedPat<'p, Cx> {
/// algorithm. Do not use `Wild` to represent a wildcard pattern comping from user input.
///
/// This is morally `Option<&'p DeconstructedPat>` where `None` is interpreted as a wildcard.
#[derive(derivative::Derivative)]
#[derivative(Clone(bound = ""), Copy(bound = ""))]
pub(crate) enum PatOrWild<'p, Cx: TypeCx> {
/// A non-user-provided wildcard, created during specialization.
Wild,
/// A user-provided pattern.
Pat(&'p DeconstructedPat<'p, Cx>),
}

impl<'p, Cx: TypeCx> Clone for PatOrWild<'p, Cx> {
fn clone(&self) -> Self {
match self {
PatOrWild::Wild => PatOrWild::Wild,
PatOrWild::Pat(pat) => PatOrWild::Pat(pat),
}
}
}

impl<'p, Cx: TypeCx> Copy for PatOrWild<'p, Cx> {}

impl<'p, Cx: TypeCx> PatOrWild<'p, Cx> {
pub(crate) fn as_pat(&self) -> Option<&'p DeconstructedPat<'p, Cx>> {
match self {
@@ -289,14 +298,28 @@ impl<'p, Cx: TypeCx> fmt::Debug for PatOrWild<'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(derivative::Derivative)]
#[derivative(Debug(bound = ""), Clone(bound = ""))]
pub struct WitnessPat<Cx: TypeCx> {
ctor: Constructor<Cx>,
pub(crate) fields: Vec<WitnessPat<Cx>>,
ty: Cx::Ty,
}

impl<Cx: TypeCx> Clone for WitnessPat<Cx> {
fn clone(&self) -> Self {
Self { ctor: self.ctor.clone(), fields: self.fields.clone(), ty: self.ty.clone() }
}
}

impl<Cx: TypeCx> fmt::Debug for WitnessPat<Cx> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.debug_struct("WitnessPat")
.field("ctor", &self.ctor)
.field("fields", &self.fields)
.field("ty", &self.ty)
.finish()
}
}

impl<Cx: TypeCx> WitnessPat<Cx> {
pub(crate) fn new(ctor: Constructor<Cx>, fields: Vec<Self>, ty: Cx::Ty) -> Self {
Self { ctor, fields, ty }
8 changes: 6 additions & 2 deletions compiler/rustc_pattern_analysis/src/rustc.rs
Original file line number Diff line number Diff line change
@@ -46,11 +46,15 @@ pub type WitnessPat<'p, 'tcx> = crate::pat::WitnessPat<RustcMatchCheckCtxt<'p, '
///
/// Use `.inner()` or deref to get to the `Ty<'tcx>`.
#[repr(transparent)]
#[derive(derivative::Derivative)]
#[derive(Clone, Copy)]
#[derivative(Debug = "transparent")]
pub struct RevealedTy<'tcx>(Ty<'tcx>);

impl<'tcx> fmt::Debug for RevealedTy<'tcx> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(fmt)
}
}

impl<'tcx> std::ops::Deref for RevealedTy<'tcx> {
type Target = Ty<'tcx>;
fn deref(&self) -> &Self::Target {
58 changes: 46 additions & 12 deletions compiler/rustc_pattern_analysis/src/usefulness.rs
Original file line number Diff line number Diff line change
@@ -731,16 +731,26 @@ pub fn ensure_sufficient_stack<R>(f: impl FnOnce() -> R) -> R {
}

/// Context that provides information local to a place under investigation.
#[derive(derivative::Derivative)]
#[derivative(Debug(bound = ""), Clone(bound = ""), Copy(bound = ""))]
pub(crate) struct PlaceCtxt<'a, Cx: TypeCx> {
#[derivative(Debug = "ignore")]
pub(crate) mcx: MatchCtxt<'a, Cx>,
/// Type of the place under investigation.
#[derivative(Clone(clone_with = "Clone::clone"))] // See rust-derivative#90
pub(crate) ty: &'a Cx::Ty,
}

impl<'a, Cx: TypeCx> Clone for PlaceCtxt<'a, Cx> {
fn clone(&self) -> Self {
Self { mcx: self.mcx, ty: self.ty }
}
}

impl<'a, Cx: TypeCx> Copy for PlaceCtxt<'a, Cx> {}

impl<'a, Cx: TypeCx> fmt::Debug for PlaceCtxt<'a, Cx> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.debug_struct("PlaceCtxt").field("ty", self.ty).finish()
}
}

impl<'a, Cx: TypeCx> PlaceCtxt<'a, Cx> {
/// A `PlaceCtxt` when code other than `is_useful` needs one.
#[cfg_attr(not(feature = "rustc"), allow(dead_code))]
@@ -813,8 +823,6 @@ impl fmt::Display for ValidityConstraint {
// The three lifetimes are:
// - 'p coming from the input
// - Cx global compilation context
#[derive(derivative::Derivative)]
#[derivative(Clone(bound = ""))]
struct PatStack<'p, Cx: TypeCx> {
// Rows of len 1 are very common, which is why `SmallVec[_; 2]` works well.
pats: SmallVec<[PatOrWild<'p, Cx>; 2]>,
@@ -824,6 +832,12 @@ struct PatStack<'p, Cx: TypeCx> {
relevant: bool,
}

impl<'p, Cx: TypeCx> Clone for PatStack<'p, Cx> {
fn clone(&self) -> Self {
Self { pats: self.pats.clone(), relevant: self.relevant }
}
}

impl<'p, Cx: TypeCx> PatStack<'p, Cx> {
fn from_pattern(pat: &'p DeconstructedPat<'p, Cx>) -> Self {
PatStack { pats: smallvec![PatOrWild::Pat(pat)], relevant: true }
@@ -1184,10 +1198,20 @@ impl<'p, Cx: TypeCx> fmt::Debug for Matrix<'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(derivative::Derivative)]
#[derivative(Debug(bound = ""), Clone(bound = ""))]
struct WitnessStack<Cx: TypeCx>(Vec<WitnessPat<Cx>>);

impl<Cx: TypeCx> Clone for WitnessStack<Cx> {
fn clone(&self) -> Self {
Self(self.0.clone())
}
}

impl<Cx: TypeCx> fmt::Debug for WitnessStack<Cx> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.debug_tuple("WitnessStack").field(&self.0).finish()
}
}

impl<Cx: TypeCx> WitnessStack<Cx> {
/// Asserts that the witness contains a single pattern, and returns it.
fn single_pattern(self) -> WitnessPat<Cx> {
@@ -1232,18 +1256,28 @@ 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(derivative::Derivative)]
#[derivative(Debug(bound = ""), Clone(bound = ""))]
struct WitnessMatrix<Cx: TypeCx>(Vec<WitnessStack<Cx>>);

impl<Cx: TypeCx> Clone for WitnessMatrix<Cx> {
fn clone(&self) -> Self {
Self(self.0.clone())
}
}

impl<Cx: TypeCx> fmt::Debug for WitnessMatrix<Cx> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.debug_tuple("WitnessMatrix").field(&self.0).finish()
}
}

impl<Cx: TypeCx> WitnessMatrix<Cx> {
/// New matrix with no witnesses.
fn empty() -> Self {
WitnessMatrix(vec![])
WitnessMatrix(Vec::new())
}
/// New matrix with one `()` witness, i.e. with no columns.
fn unit_witness() -> Self {
WitnessMatrix(vec![WitnessStack(vec![])])
WitnessMatrix(vec![WitnessStack(Vec::new())])
}

/// Whether this has any witnesses.