Skip to content

Commit 37270ae

Browse files
Add query to deterimine if type implements StructuralEq
1 parent dd927a5 commit 37270ae

File tree

6 files changed

+50
-21
lines changed

6 files changed

+50
-21
lines changed

src/librustc_middle/query/mod.rs

+5
Original file line numberDiff line numberDiff line change
@@ -719,6 +719,11 @@ rustc_queries! {
719719
desc { "computing whether `{}` needs drop", env.value }
720720
}
721721

722+
/// Query backing `TyS::is_structural_eq_shallow`.
723+
query is_structural_eq_raw(ty: Ty<'tcx>) -> bool {
724+
desc { "computing whether `{:?}` has a derived implementation of `PartialEq` and `Eq`", ty }
725+
}
726+
722727
/// A list of types where the ADT requires drop if and only if any of
723728
/// those types require drop. If the ADT is known to always need drop
724729
/// then `Err(AlwaysRequiresDrop)` is returned.

src/librustc_middle/ty/util.rs

+21
Original file line numberDiff line numberDiff line change
@@ -778,6 +778,27 @@ impl<'tcx> ty::TyS<'tcx> {
778778
}
779779
}
780780

781+
/// Returns `true` if this type implements both `PartialStructuralEq` and `StructuralEq`.
782+
///
783+
/// These marker traits are implemented along with `PartialEq` and `Eq` when implementations
784+
/// for those traits are derived. They indicate that two values of this type are equal if all
785+
/// of their fields are equal. A quirk of the marker traits is that their implementation is
786+
/// never conditional on generic parameter bounds. For that reason, this helper function does
787+
/// not take a `ParamEnv`.
788+
///
789+
/// This function is "shallow" because it may return `true` for a type whose fields are not
790+
/// `StructuralEq`. You will need to use a type visitor if you want to know whether a call to
791+
/// `PartialEq::eq` will proceed structurally for a given type.
792+
#[inline]
793+
pub fn is_structural_eq_shallow(&'tcx self, tcx: TyCtxt<'tcx>) -> bool {
794+
// Fast path for some builtin types
795+
if self.is_primitive() || self.is_str() {
796+
return true;
797+
}
798+
799+
tcx.is_structural_eq_raw(self)
800+
}
801+
781802
pub fn same_type(a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
782803
match (&a.kind, &b.kind) {
783804
(&Adt(did_a, substs_a), &Adt(did_b, substs_b)) => {

src/librustc_mir/transform/check_consts/qualifs.rs

+1-5
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
//!
33
//! See the `Qualif` trait for more info.
44
5-
use rustc_infer::infer::TyCtxtInferExt;
65
use rustc_middle::mir::*;
76
use rustc_middle::ty::{self, subst::SubstsRef, AdtDef, Ty};
87
use rustc_span::DUMMY_SP;
@@ -137,10 +136,7 @@ impl Qualif for CustomEq {
137136
substs: SubstsRef<'tcx>,
138137
) -> bool {
139138
let ty = cx.tcx.mk_ty(ty::Adt(adt, substs));
140-
let id = cx.tcx.hir().local_def_id_to_hir_id(cx.def_id.as_local().unwrap());
141-
cx.tcx
142-
.infer_ctxt()
143-
.enter(|infcx| !traits::type_marked_structural(id, cx.body.span, &infcx, ty))
139+
!ty.is_structural_eq_shallow(cx.tcx)
144140
}
145141
}
146142

src/librustc_mir_build/hair/pattern/const_to_pat.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
8080
}
8181

8282
fn type_marked_structural(&self, ty: Ty<'tcx>) -> bool {
83-
traits::type_marked_structural(self.id, self.span, &self.infcx, ty)
83+
ty.is_structural_eq_shallow(self.infcx.tcx)
8484
}
8585

8686
fn to_pat(

src/librustc_trait_selection/traits/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -564,6 +564,7 @@ fn type_implements_trait<'tcx>(
564564

565565
pub fn provide(providers: &mut ty::query::Providers<'_>) {
566566
object_safety::provide(providers);
567+
structural_match::provide(providers);
567568
*providers = ty::query::Providers {
568569
specialization_graph_of: specialize::specialization_graph_provider,
569570
specializes: specialize::specializes,

src/librustc_trait_selection/traits/structural_match.rs

+21-15
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
use crate::infer::{InferCtxt, TyCtxtInferExt};
22
use crate::traits::ObligationCause;
3-
use crate::traits::{self, ConstPatternStructural, TraitEngine};
3+
use crate::traits::{self, TraitEngine};
44

55
use rustc_data_structures::fx::FxHashSet;
66
use rustc_hir as hir;
77
use rustc_hir::lang_items::{StructuralPeqTraitLangItem, StructuralTeqTraitLangItem};
8+
use rustc_middle::ty::query::Providers;
89
use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt, TypeFoldable, TypeVisitor};
910
use rustc_span::Span;
1011

@@ -41,14 +42,14 @@ pub enum NonStructuralMatchTy<'tcx> {
4142
/// that arose when the requirement was not enforced completely, see
4243
/// Rust RFC 1445, rust-lang/rust#61188, and rust-lang/rust#62307.
4344
pub fn search_for_structural_match_violation<'tcx>(
44-
id: hir::HirId,
45-
span: Span,
45+
_id: hir::HirId,
46+
_span: Span,
4647
tcx: TyCtxt<'tcx>,
4748
ty: Ty<'tcx>,
4849
) -> Option<NonStructuralMatchTy<'tcx>> {
4950
// FIXME: we should instead pass in an `infcx` from the outside.
5051
tcx.infer_ctxt().enter(|infcx| {
51-
let mut search = Search { id, span, infcx, found: None, seen: FxHashSet::default() };
52+
let mut search = Search { infcx, found: None, seen: FxHashSet::default() };
5253
ty.visit_with(&mut search);
5354
search.found
5455
})
@@ -62,26 +63,25 @@ pub fn search_for_structural_match_violation<'tcx>(
6263
/// Note that this does *not* recursively check if the substructure of `adt_ty`
6364
/// implements the traits.
6465
pub fn type_marked_structural(
65-
id: hir::HirId,
66-
span: Span,
6766
infcx: &InferCtxt<'_, 'tcx>,
6867
adt_ty: Ty<'tcx>,
68+
cause: ObligationCause<'tcx>,
6969
) -> bool {
7070
let mut fulfillment_cx = traits::FulfillmentContext::new();
71-
let cause = ObligationCause::new(span, id, ConstPatternStructural);
7271
// require `#[derive(PartialEq)]`
73-
let structural_peq_def_id = infcx.tcx.require_lang_item(StructuralPeqTraitLangItem, Some(span));
72+
let structural_peq_def_id =
73+
infcx.tcx.require_lang_item(StructuralPeqTraitLangItem, Some(cause.span));
7474
fulfillment_cx.register_bound(
7575
infcx,
7676
ty::ParamEnv::empty(),
7777
adt_ty,
7878
structural_peq_def_id,
79-
cause,
79+
cause.clone(),
8080
);
8181
// for now, require `#[derive(Eq)]`. (Doing so is a hack to work around
8282
// the type `for<'a> fn(&'a ())` failing to implement `Eq` itself.)
83-
let cause = ObligationCause::new(span, id, ConstPatternStructural);
84-
let structural_teq_def_id = infcx.tcx.require_lang_item(StructuralTeqTraitLangItem, Some(span));
83+
let structural_teq_def_id =
84+
infcx.tcx.require_lang_item(StructuralTeqTraitLangItem, Some(cause.span));
8585
fulfillment_cx.register_bound(
8686
infcx,
8787
ty::ParamEnv::empty(),
@@ -106,9 +106,6 @@ pub fn type_marked_structural(
106106
/// find instances of ADTs (specifically structs or enums) that do not implement
107107
/// the structural-match traits (`StructuralPartialEq` and `StructuralEq`).
108108
struct Search<'a, 'tcx> {
109-
id: hir::HirId,
110-
span: Span,
111-
112109
infcx: InferCtxt<'a, 'tcx>,
113110

114111
/// Records first ADT that does not implement a structural-match trait.
@@ -125,7 +122,7 @@ impl Search<'a, 'tcx> {
125122
}
126123

127124
fn type_marked_structural(&self, adt_ty: Ty<'tcx>) -> bool {
128-
type_marked_structural(self.id, self.span, &self.infcx, adt_ty)
125+
adt_ty.is_structural_eq_shallow(self.tcx())
129126
}
130127
}
131128

@@ -220,3 +217,12 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> {
220217
false
221218
}
222219
}
220+
221+
pub fn provide(providers: &mut Providers<'_>) {
222+
providers.is_structural_eq_raw = |tcx, ty| {
223+
tcx.infer_ctxt().enter(|infcx| {
224+
let cause = ObligationCause::dummy();
225+
type_marked_structural(&infcx, ty, cause)
226+
})
227+
};
228+
}

0 commit comments

Comments
 (0)