Auto merge of #128246 - GrigorenkoPV:derive-where, r=compiler-errors

Don't manually implement `PartialEq` for some types in `rustc_type_ir`

> > As a follow-up, we should look at not manually implementing PartialEq for these types but instead going thru a derive
>
> I will try to tackle this later in a separate PR

https://github.com/rust-lang/rust/issues/127042#issuecomment-2218838446
This commit is contained in:
bors 2024-07-28 16:28:25 +00:00
commit 188ddf4d6a
5 changed files with 6 additions and 203 deletions

View File

@ -1,5 +1,3 @@
#![allow(clippy::derived_hash_with_manual_eq)]
use derive_where::derive_where; use derive_where::derive_where;
#[cfg(feature = "nightly")] #[cfg(feature = "nightly")]
use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable}; use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable};
@ -141,7 +139,7 @@ pub fn expect_placeholder_index(self) -> usize {
/// Describes the "kind" of the canonical variable. This is a "kind" /// Describes the "kind" of the canonical variable. This is a "kind"
/// in the type-theory sense of the term -- i.e., a "meta" type system /// in the type-theory sense of the term -- i.e., a "meta" type system
/// that analyzes type-like values. /// that analyzes type-like values.
#[derive_where(Clone, Copy, Hash, Eq, Debug; I: Interner)] #[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] #[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
pub enum CanonicalVarKind<I: Interner> { pub enum CanonicalVarKind<I: Interner> {
@ -169,21 +167,6 @@ pub enum CanonicalVarKind<I: Interner> {
PlaceholderConst(I::PlaceholderConst), PlaceholderConst(I::PlaceholderConst),
} }
// FIXME(GrigorenkoPV): consider not implementing PartialEq manually
impl<I: Interner> PartialEq for CanonicalVarKind<I> {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::Ty(l0), Self::Ty(r0)) => l0 == r0,
(Self::PlaceholderTy(l0), Self::PlaceholderTy(r0)) => l0 == r0,
(Self::Region(l0), Self::Region(r0)) => l0 == r0,
(Self::PlaceholderRegion(l0), Self::PlaceholderRegion(r0)) => l0 == r0,
(Self::Const(l0), Self::Const(r0)) => l0 == r0,
(Self::PlaceholderConst(l0), Self::PlaceholderConst(r0)) => l0 == r0,
_ => std::mem::discriminant(self) == std::mem::discriminant(other),
}
}
}
impl<I: Interner> CanonicalVarKind<I> { impl<I: Interner> CanonicalVarKind<I> {
pub fn universe(self) -> UniverseIndex { pub fn universe(self) -> UniverseIndex {
match self { match self {

View File

@ -1,5 +1,3 @@
#![allow(clippy::derived_hash_with_manual_eq)]
use derive_where::derive_where; use derive_where::derive_where;
#[cfg(feature = "nightly")] #[cfg(feature = "nightly")]
use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
@ -10,10 +8,8 @@
use crate::{self as ty, DebruijnIndex, Interner}; use crate::{self as ty, DebruijnIndex, Interner};
use self::ConstKind::*;
/// Represents a constant in Rust. /// Represents a constant in Rust.
#[derive_where(Clone, Copy, Hash, Eq; I: Interner)] #[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)]
#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] #[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))]
pub enum ConstKind<I: Interner> { pub enum ConstKind<I: Interner> {
/// A const generic parameter. /// A const generic parameter.
@ -45,23 +41,6 @@ pub enum ConstKind<I: Interner> {
Expr(I::ExprConst), Expr(I::ExprConst),
} }
// FIXME(GrigorenkoPV): consider not implementing PartialEq manually
impl<I: Interner> PartialEq for ConstKind<I> {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Param(l0), Param(r0)) => l0 == r0,
(Infer(l0), Infer(r0)) => l0 == r0,
(Bound(l0, l1), Bound(r0, r1)) => l0 == r0 && l1 == r1,
(Placeholder(l0), Placeholder(r0)) => l0 == r0,
(Unevaluated(l0), Unevaluated(r0)) => l0 == r0,
(Value(l0, l1), Value(r0, r1)) => l0 == r0 && l1 == r1,
(Error(l0), Error(r0)) => l0 == r0,
(Expr(l0), Expr(r0)) => l0 == r0,
_ => false,
}
}
}
impl<I: Interner> fmt::Debug for ConstKind<I> { impl<I: Interner> fmt::Debug for ConstKind<I> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
use ConstKind::*; use ConstKind::*;
@ -80,7 +59,7 @@ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
} }
/// An unevaluated (potentially generic) constant used in the type-system. /// An unevaluated (potentially generic) constant used in the type-system.
#[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)] #[derive_where(Clone, Copy, Debug, Hash, PartialEq, Eq; I: Interner)]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] #[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
pub struct UnevaluatedConst<I: Interner> { pub struct UnevaluatedConst<I: Interner> {
@ -95,15 +74,6 @@ pub fn new(def: I::DefId, args: I::GenericArgs) -> UnevaluatedConst<I> {
} }
} }
impl<I: Interner> fmt::Debug for UnevaluatedConst<I> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("UnevaluatedConst")
.field("def", &self.def)
.field("args", &self.args)
.finish()
}
}
rustc_index::newtype_index! { rustc_index::newtype_index! {
/// A **`const`** **v**ariable **ID**. /// A **`const`** **v**ariable **ID**.
#[encodable] #[encodable]

View File

@ -1,5 +1,3 @@
#![allow(clippy::derived_hash_with_manual_eq)]
use derive_where::derive_where; use derive_where::derive_where;
#[cfg(feature = "nightly")] #[cfg(feature = "nightly")]
use rustc_macros::{Decodable, Encodable, HashStable_NoContext, TyDecodable, TyEncodable}; use rustc_macros::{Decodable, Encodable, HashStable_NoContext, TyDecodable, TyEncodable};
@ -10,7 +8,7 @@
/// A clause is something that can appear in where bounds or be inferred /// A clause is something that can appear in where bounds or be inferred
/// by implied bounds. /// by implied bounds.
#[derive_where(Clone, Copy, Hash, Eq; I: Interner)] #[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] #[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))]
pub enum ClauseKind<I: Interner> { pub enum ClauseKind<I: Interner> {
@ -40,22 +38,6 @@ pub enum ClauseKind<I: Interner> {
ConstEvaluatable(I::Const), ConstEvaluatable(I::Const),
} }
// FIXME(GrigorenkoPV): consider not implementing PartialEq manually
impl<I: Interner> PartialEq for ClauseKind<I> {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::Trait(l0), Self::Trait(r0)) => l0 == r0,
(Self::RegionOutlives(l0), Self::RegionOutlives(r0)) => l0 == r0,
(Self::TypeOutlives(l0), Self::TypeOutlives(r0)) => l0 == r0,
(Self::Projection(l0), Self::Projection(r0)) => l0 == r0,
(Self::ConstArgHasType(l0, l1), Self::ConstArgHasType(r0, r1)) => l0 == r0 && l1 == r1,
(Self::WellFormed(l0), Self::WellFormed(r0)) => l0 == r0,
(Self::ConstEvaluatable(l0), Self::ConstEvaluatable(r0)) => l0 == r0,
_ => false,
}
}
}
#[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)] #[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] #[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))]

View File

@ -1,5 +1,3 @@
#![allow(clippy::derived_hash_with_manual_eq)]
use derive_where::derive_where; use derive_where::derive_where;
#[cfg(feature = "nightly")] #[cfg(feature = "nightly")]
use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
@ -127,7 +125,7 @@ pub struct RegionVid {}
/// [1]: https://smallcultfollowing.com/babysteps/blog/2013/10/29/intermingled-parameter-lists/ /// [1]: https://smallcultfollowing.com/babysteps/blog/2013/10/29/intermingled-parameter-lists/
/// [2]: https://smallcultfollowing.com/babysteps/blog/2013/11/04/intermingled-parameter-lists/ /// [2]: https://smallcultfollowing.com/babysteps/blog/2013/11/04/intermingled-parameter-lists/
/// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html /// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html
#[derive_where(Clone, Copy, Hash, Eq; I: Interner)] #[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)]
#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable))] #[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable))]
pub enum RegionKind<I: Interner> { pub enum RegionKind<I: Interner> {
/// A region parameter; for example `'a` in `impl<'a> Trait for &'a ()`. /// A region parameter; for example `'a` in `impl<'a> Trait for &'a ()`.
@ -179,48 +177,6 @@ pub enum RegionKind<I: Interner> {
ReError(I::ErrorGuaranteed), ReError(I::ErrorGuaranteed),
} }
// This is manually implemented for `RegionKind` because `std::mem::discriminant`
// returns an opaque value that is `PartialEq` but not `PartialOrd`
#[inline]
const fn regionkind_discriminant<I: Interner>(value: &RegionKind<I>) -> usize {
match value {
ReEarlyParam(_) => 0,
ReBound(_, _) => 1,
ReLateParam(_) => 2,
ReStatic => 3,
ReVar(_) => 4,
RePlaceholder(_) => 5,
ReErased => 6,
ReError(_) => 7,
}
}
// FIXME(GrigorenkoPV): consider not implementing PartialEq manually
// This is manually implemented because a derive would require `I: PartialEq`
impl<I: Interner> PartialEq for RegionKind<I> {
#[inline]
fn eq(&self, other: &RegionKind<I>) -> bool {
regionkind_discriminant(self) == regionkind_discriminant(other)
&& match (self, other) {
(ReEarlyParam(a_r), ReEarlyParam(b_r)) => a_r == b_r,
(ReBound(a_d, a_r), ReBound(b_d, b_r)) => a_d == b_d && a_r == b_r,
(ReLateParam(a_r), ReLateParam(b_r)) => a_r == b_r,
(ReStatic, ReStatic) => true,
(ReVar(a_r), ReVar(b_r)) => a_r == b_r,
(RePlaceholder(a_r), RePlaceholder(b_r)) => a_r == b_r,
(ReErased, ReErased) => true,
(ReError(_), ReError(_)) => true,
_ => {
debug_assert!(
false,
"This branch must be unreachable, maybe the match is missing an arm? self = {self:?}, other = {other:?}"
);
true
}
}
}
}
impl<I: Interner> fmt::Debug for RegionKind<I> { impl<I: Interner> fmt::Debug for RegionKind<I> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self { match self {

View File

@ -1,5 +1,3 @@
#![allow(clippy::derived_hash_with_manual_eq)]
use derive_where::derive_where; use derive_where::derive_where;
#[cfg(feature = "nightly")] #[cfg(feature = "nightly")]
@ -68,7 +66,7 @@ pub fn descr(self) -> &'static str {
/// Types written by the user start out as `hir::TyKind` and get /// Types written by the user start out as `hir::TyKind` and get
/// converted to this representation using `<dyn HirTyLowerer>::lower_ty`. /// converted to this representation using `<dyn HirTyLowerer>::lower_ty`.
#[cfg_attr(feature = "nightly", rustc_diagnostic_item = "IrTyKind")] #[cfg_attr(feature = "nightly", rustc_diagnostic_item = "IrTyKind")]
#[derive_where(Clone, Copy, Hash, Eq; I: Interner)] #[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)]
#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] #[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))]
pub enum TyKind<I: Interner> { pub enum TyKind<I: Interner> {
/// The primitive boolean type. Written as `bool`. /// The primitive boolean type. Written as `bool`.
@ -259,92 +257,6 @@ pub fn is_primitive(&self) -> bool {
} }
} }
// This is manually implemented for `TyKind` because `std::mem::discriminant`
// returns an opaque value that is `PartialEq` but not `PartialOrd`
#[inline]
const fn tykind_discriminant<I: Interner>(value: &TyKind<I>) -> usize {
match value {
Bool => 0,
Char => 1,
Int(_) => 2,
Uint(_) => 3,
Float(_) => 4,
Adt(_, _) => 5,
Foreign(_) => 6,
Str => 7,
Array(_, _) => 8,
Slice(_) => 9,
RawPtr(_, _) => 10,
Ref(_, _, _) => 11,
FnDef(_, _) => 12,
FnPtr(_) => 13,
Dynamic(..) => 14,
Closure(_, _) => 15,
CoroutineClosure(_, _) => 16,
Coroutine(_, _) => 17,
CoroutineWitness(_, _) => 18,
Never => 19,
Tuple(_) => 20,
Pat(_, _) => 21,
Alias(_, _) => 22,
Param(_) => 23,
Bound(_, _) => 24,
Placeholder(_) => 25,
Infer(_) => 26,
Error(_) => 27,
}
}
// FIXME(GrigorenkoPV): consider not implementing PartialEq manually
// This is manually implemented because a derive would require `I: PartialEq`
impl<I: Interner> PartialEq for TyKind<I> {
#[inline]
fn eq(&self, other: &TyKind<I>) -> bool {
// You might expect this `match` to be preceded with this:
//
// tykind_discriminant(self) == tykind_discriminant(other) &&
//
// but the data patterns in practice are such that a comparison
// succeeds 99%+ of the time, and it's faster to omit it.
match (self, other) {
(Int(a_i), Int(b_i)) => a_i == b_i,
(Uint(a_u), Uint(b_u)) => a_u == b_u,
(Float(a_f), Float(b_f)) => a_f == b_f,
(Adt(a_d, a_s), Adt(b_d, b_s)) => a_d == b_d && a_s == b_s,
(Foreign(a_d), Foreign(b_d)) => a_d == b_d,
(Array(a_t, a_c), Array(b_t, b_c)) => a_t == b_t && a_c == b_c,
(Pat(a_t, a_c), Pat(b_t, b_c)) => a_t == b_t && a_c == b_c,
(Slice(a_t), Slice(b_t)) => a_t == b_t,
(RawPtr(a_t, a_m), RawPtr(b_t, b_m)) => a_t == b_t && a_m == b_m,
(Ref(a_r, a_t, a_m), Ref(b_r, b_t, b_m)) => a_r == b_r && a_t == b_t && a_m == b_m,
(FnDef(a_d, a_s), FnDef(b_d, b_s)) => a_d == b_d && a_s == b_s,
(FnPtr(a_s), FnPtr(b_s)) => a_s == b_s,
(Dynamic(a_p, a_r, a_repr), Dynamic(b_p, b_r, b_repr)) => {
a_p == b_p && a_r == b_r && a_repr == b_repr
}
(Closure(a_d, a_s), Closure(b_d, b_s)) => a_d == b_d && a_s == b_s,
(CoroutineClosure(a_d, a_s), CoroutineClosure(b_d, b_s)) => a_d == b_d && a_s == b_s,
(Coroutine(a_d, a_s), Coroutine(b_d, b_s)) => a_d == b_d && a_s == b_s,
(CoroutineWitness(a_d, a_s), CoroutineWitness(b_d, b_s)) => a_d == b_d && a_s == b_s,
(Tuple(a_t), Tuple(b_t)) => a_t == b_t,
(Alias(a_i, a_p), Alias(b_i, b_p)) => a_i == b_i && a_p == b_p,
(Param(a_p), Param(b_p)) => a_p == b_p,
(Bound(a_d, a_b), Bound(b_d, b_b)) => a_d == b_d && a_b == b_b,
(Placeholder(a_p), Placeholder(b_p)) => a_p == b_p,
(Infer(a_t), Infer(b_t)) => a_t == b_t,
(Error(a_e), Error(b_e)) => a_e == b_e,
(Bool, Bool) | (Char, Char) | (Str, Str) | (Never, Never) => true,
_ => {
debug_assert!(
tykind_discriminant(self) != tykind_discriminant(other),
"This branch must be unreachable, maybe the match is missing an arm? self = {self:?}, other = {other:?}"
);
false
}
}
}
}
// This is manually implemented because a derive would require `I: Debug` // This is manually implemented because a derive would require `I: Debug`
impl<I: Interner> fmt::Debug for TyKind<I> { impl<I: Interner> fmt::Debug for TyKind<I> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {