desc { "computing whether `{}` needs drop", env.value }
}
+ /// Query backing `TyS::is_structural_eq_shallow`.
+ ///
+ /// This is only correct for ADTs. Call `is_structural_eq_shallow` to handle all types
+ /// correctly.
+ query has_structural_eq_impls(ty: Ty<'tcx>) -> bool {
+ desc {
+ "computing whether `{:?}` implements `PartialStructuralEq` and `StructuralEq`",
+ ty
+ }
+ }
+
/// A list of types where the ADT requires drop if and only if any of
/// those types require drop. If the ADT is known to always need drop
/// then `Err(AlwaysRequiresDrop)` is returned.
}
}
+ /// Returns `true` if equality for this type is both total and structural.
+ ///
+ /// Total equality for a type is indicated by an `Eq` impl for that type.
+ ///
+ /// Primitive types (`u32`, `str`) have structural equality by definition. For composite data
+ /// types, equality for the type as a whole is structural when it is the same as equality
+ /// between all components (fields, array elements, etc.) of that type. For ADTs, structural
+ /// equality is indicated by an implementation of `PartialStructuralEq` and `StructuralEq` for
+ /// that type.
+ ///
+ /// This function is "shallow" because it may return `true` for a composite type whose fields
+ /// are not `StructuralEq`. For example, `[T; 4]` has structural equality regardless of `T`
+ /// because equality for arrays is determined by the equality of each array element. If you
+ /// want to know whether a given call to `PartialEq::eq` will proceed structurally all the way
+ /// down, you will need to use a type visitor.
+ #[inline]
+ pub fn is_structural_eq_shallow(&'tcx self, tcx: TyCtxt<'tcx>) -> bool {
+ match self.kind {
+ // Look for an impl of both `PartialStructuralEq` and `StructuralEq`.
+ Adt(..) => tcx.has_structural_eq_impls(self),
+
+ // Primitive types that satisfy `Eq`.
+ Bool | Char | Int(_) | Uint(_) | Str | Never => true,
+
+ // Composite types that satisfy `Eq` when all of their fields do.
+ //
+ // Because this function is "shallow", we return `true` for these composites regardless
+ // of the type(s) contained within.
+ Ref(..) | Array(..) | Slice(_) | Tuple(..) => true,
+
+ // Raw pointers use bitwise comparison.
+ RawPtr(_) | FnPtr(_) => true,
+
+ // Floating point numbers are not `Eq`.
+ Float(_) => false,
+
+ // Conservatively return `false` for all others...
+
+ // Anonymous function types
+ FnDef(..) | Closure(..) | Dynamic(..) | Generator(..) => false,
+
+ // Generic or inferred types
+ //
+ // FIXME(ecstaticmorse): Maybe we should `bug` here? This should probably only be
+ // called for known, fully-monomorphized types.
+ Projection(_) | Opaque(..) | Param(_) | Bound(..) | Placeholder(_) | Infer(_) => false,
+
+ Foreign(_) | GeneratorWitness(..) | Error => false,
+ }
+ }
+
pub fn same_type(a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
match (&a.kind, &b.kind) {
(&Adt(did_a, substs_a), &Adt(did_b, substs_b)) => {
//!
//! See the `Qualif` trait for more info.
-use rustc_infer::infer::TyCtxtInferExt;
use rustc_middle::mir::*;
use rustc_middle::ty::{self, subst::SubstsRef, AdtDef, Ty};
use rustc_span::DUMMY_SP;
substs: SubstsRef<'tcx>,
) -> bool {
let ty = cx.tcx.mk_ty(ty::Adt(adt, substs));
- let id = cx.tcx.hir().local_def_id_to_hir_id(cx.def_id.as_local().unwrap());
- cx.tcx
- .infer_ctxt()
- .enter(|infcx| !traits::type_marked_structural(id, cx.body.span, &infcx, ty))
+ !ty.is_structural_eq_shallow(cx.tcx)
}
}
}
fn type_marked_structural(&self, ty: Ty<'tcx>) -> bool {
- traits::type_marked_structural(self.id, self.span, &self.infcx, ty)
+ ty.is_structural_eq_shallow(self.infcx.tcx)
}
fn to_pat(
pub fn provide(providers: &mut ty::query::Providers<'_>) {
object_safety::provide(providers);
+ structural_match::provide(providers);
*providers = ty::query::Providers {
specialization_graph_of: specialize::specialization_graph_provider,
specializes: specialize::specializes,
use crate::infer::{InferCtxt, TyCtxtInferExt};
use crate::traits::ObligationCause;
-use crate::traits::{self, ConstPatternStructural, TraitEngine};
+use crate::traits::{self, TraitEngine};
use rustc_data_structures::fx::FxHashSet;
use rustc_hir as hir;
use rustc_hir::lang_items::{StructuralPeqTraitLangItem, StructuralTeqTraitLangItem};
+use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt, TypeFoldable, TypeVisitor};
use rustc_span::Span;
/// that arose when the requirement was not enforced completely, see
/// Rust RFC 1445, rust-lang/rust#61188, and rust-lang/rust#62307.
pub fn search_for_structural_match_violation<'tcx>(
- id: hir::HirId,
+ _id: hir::HirId,
span: Span,
tcx: TyCtxt<'tcx>,
ty: Ty<'tcx>,
) -> Option<NonStructuralMatchTy<'tcx>> {
// FIXME: we should instead pass in an `infcx` from the outside.
tcx.infer_ctxt().enter(|infcx| {
- let mut search = Search { id, span, infcx, found: None, seen: FxHashSet::default() };
+ let mut search = Search { infcx, span, found: None, seen: FxHashSet::default() };
ty.visit_with(&mut search);
search.found
})
/// Note that this does *not* recursively check if the substructure of `adt_ty`
/// implements the traits.
pub fn type_marked_structural(
- id: hir::HirId,
- span: Span,
infcx: &InferCtxt<'_, 'tcx>,
adt_ty: Ty<'tcx>,
+ cause: ObligationCause<'tcx>,
) -> bool {
let mut fulfillment_cx = traits::FulfillmentContext::new();
- let cause = ObligationCause::new(span, id, ConstPatternStructural);
// require `#[derive(PartialEq)]`
- let structural_peq_def_id = infcx.tcx.require_lang_item(StructuralPeqTraitLangItem, Some(span));
+ let structural_peq_def_id =
+ infcx.tcx.require_lang_item(StructuralPeqTraitLangItem, Some(cause.span));
fulfillment_cx.register_bound(
infcx,
ty::ParamEnv::empty(),
adt_ty,
structural_peq_def_id,
- cause,
+ cause.clone(),
);
// for now, require `#[derive(Eq)]`. (Doing so is a hack to work around
// the type `for<'a> fn(&'a ())` failing to implement `Eq` itself.)
- let cause = ObligationCause::new(span, id, ConstPatternStructural);
- let structural_teq_def_id = infcx.tcx.require_lang_item(StructuralTeqTraitLangItem, Some(span));
+ let structural_teq_def_id =
+ infcx.tcx.require_lang_item(StructuralTeqTraitLangItem, Some(cause.span));
fulfillment_cx.register_bound(
infcx,
ty::ParamEnv::empty(),
/// find instances of ADTs (specifically structs or enums) that do not implement
/// the structural-match traits (`StructuralPartialEq` and `StructuralEq`).
struct Search<'a, 'tcx> {
- id: hir::HirId,
span: Span,
infcx: InferCtxt<'a, 'tcx>,
}
fn type_marked_structural(&self, adt_ty: Ty<'tcx>) -> bool {
- type_marked_structural(self.id, self.span, &self.infcx, adt_ty)
+ adt_ty.is_structural_eq_shallow(self.tcx())
}
}
false
}
}
+
+pub fn provide(providers: &mut Providers<'_>) {
+ providers.has_structural_eq_impls = |tcx, ty| {
+ tcx.infer_ctxt().enter(|infcx| {
+ let cause = ObligationCause::dummy();
+ type_marked_structural(&infcx, ty, cause)
+ })
+ };
+}