Skip to content

Commit

Permalink
Split check for PartialEq impl into a method
Browse files Browse the repository at this point in the history
  • Loading branch information
oli-obk committed Sep 20, 2020
1 parent b2532a8 commit 3795886
Showing 1 changed file with 35 additions and 28 deletions.
63 changes: 35 additions & 28 deletions compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
Expand Up @@ -159,34 +159,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
}
});

// double-check there even *is* a semantic `PartialEq` to dispatch to.
//
// (If there isn't, then we can safely issue a hard
// error, because that's never worked, due to compiler
// using `PartialEq::eq` in this scenario in the past.)
//
// Note: To fix rust-lang/rust#65466, one could lift this check
// *before* any structural-match checking, and unconditionally error
// if `PartialEq` is not implemented. However, that breaks stable
// code at the moment, because types like `for <'a> fn(&'a ())` do
// not *yet* implement `PartialEq`. So for now we leave this here.
let ty_is_partial_eq: bool = {
let partial_eq_trait_id =
self.tcx().require_lang_item(hir::LangItem::PartialEq, Some(self.span));
let obligation: PredicateObligation<'_> = predicate_for_trait_def(
self.tcx(),
self.param_env,
ObligationCause::misc(self.span, self.id),
partial_eq_trait_id,
0,
cv.ty,
&[],
);
// FIXME: should this call a `predicate_must_hold` variant instead?
self.infcx.predicate_may_hold(&obligation)
};

if !ty_is_partial_eq {
if !self.type_has_partial_eq_impl(cv.ty) {
// span_fatal avoids ICE from resolution of non-existent method (rare case).
self.tcx().sess.span_fatal(self.span, &msg);
} else if mir_structural_match_violation {
Expand All @@ -208,6 +181,40 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
inlined_const_as_pat
}

fn type_has_partial_eq_impl(&self, ty: Ty<'tcx>) -> bool {
// double-check there even *is* a semantic `PartialEq` to dispatch to.
//
// (If there isn't, then we can safely issue a hard
// error, because that's never worked, due to compiler
// using `PartialEq::eq` in this scenario in the past.)
let partial_eq_trait_id =
self.tcx().require_lang_item(hir::LangItem::PartialEq, Some(self.span));
let obligation: PredicateObligation<'_> = predicate_for_trait_def(
self.tcx(),
self.param_env,
ObligationCause::misc(self.span, self.id),
partial_eq_trait_id,
0,
ty,
&[],
);
// FIXME: should this call a `predicate_must_hold` variant instead?

let has_impl = self.infcx.predicate_may_hold(&obligation);

// Note: To fix rust-lang/rust#65466, we could just remove this type
// walk hack for function pointers, and unconditionally error
// if `PartialEq` is not implemented. However, that breaks stable
// code at the moment, because types like `for <'a> fn(&'a ())` do
// not *yet* implement `PartialEq`. So for now we leave this here.
has_impl
|| ty.walk().any(|t| match t.unpack() {
ty::subst::GenericArgKind::Lifetime(_) => false,
ty::subst::GenericArgKind::Type(t) => t.is_fn_ptr(),
ty::subst::GenericArgKind::Const(_) => false,
})
}

// Recursive helper for `to_pat`; invoke that (instead of calling this directly).
fn recur(&self, cv: &'tcx ty::Const<'tcx>) -> Pat<'tcx> {
let id = self.id;
Expand Down

0 comments on commit 3795886

Please sign in to comment.