]> git.lizzy.rs Git - rust.git/commitdiff
Split check for `PartialEq` impl into a method
authorOliver Scherer <github35764891676564198441@oli-obk.de>
Sun, 20 Sep 2020 14:59:15 +0000 (16:59 +0200)
committerOliver Scherer <github35764891676564198441@oli-obk.de>
Sun, 20 Sep 2020 14:59:15 +0000 (16:59 +0200)
compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs

index d47c3e7e3aba1c1534d46dd1269f00db0e3e239c..ebb71ea24ecc0ec9a71de3a78d5332e48d8a0e21 100644 (file)
@@ -159,34 +159,7 @@ fn to_pat(
                     }
                 });
 
-                // 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 {
@@ -208,6 +181,40 @@ fn to_pat(
         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;