about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRyan Levick <me@ryanlevick.com>2021-02-04 10:45:17 +0100
committerRyan Levick <me@ryanlevick.com>2021-02-04 10:45:17 +0100
commitcdfc52fbd638ee3b7b1debad0aef84e730543e8a (patch)
tree7ad2fbd1d65644afe6b960c8600640032bc7e2a2
parentd6a28a97e697bd4af5870a9b9f72c53e979c1fe2 (diff)
downloadrust-cdfc52fbd638ee3b7b1debad0aef84e730543e8a.tar.gz
rust-cdfc52fbd638ee3b7b1debad0aef84e730543e8a.zip
Try fast_reject::simplify_type in coherence before doing full check
Co-authored-by: Jonas Schievink <jonasschievink@gmail.com>
Co-authored-by: Ryan Levick <me@ryanlevick.com>
-rw-r--r--compiler/rustc_trait_selection/src/traits/coherence.rs32
1 files changed, 31 insertions, 1 deletions
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index 99b96f60964..87f2ea16f8a 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -11,7 +11,7 @@ use crate::traits::{self, Normalized, Obligation, ObligationCause, SelectionCont
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::subst::Subst;
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{self, fast_reject, Ty, TyCtxt};
 use rustc_span::symbol::sym;
 use rustc_span::DUMMY_SP;
 use std::iter;
@@ -67,6 +67,36 @@ where
            impl2_def_id={:?})",
         impl1_def_id, impl2_def_id,
     );
+    // Before doing expensive operations like entering an inference context, do
+    // a quick check via fast_reject to tell if the impl headers could possibly
+    // unify.
+    let impl1_self = tcx.type_of(impl1_def_id);
+    let impl2_self = tcx.type_of(impl2_def_id);
+    let impl1_ref = tcx.impl_trait_ref(impl1_def_id);
+    let impl2_ref = tcx.impl_trait_ref(impl2_def_id);
+
+    // Check if any of the input types definitely mismatch.
+    if impl1_ref
+        .iter()
+        .flat_map(|tref| tref.substs.types())
+        .zip(impl2_ref.iter().flat_map(|tref| tref.substs.types()))
+        .chain(iter::once((impl1_self, impl2_self)))
+        .any(|(ty1, ty2)| {
+            let ty1 = fast_reject::simplify_type(tcx, ty1, false);
+            let ty2 = fast_reject::simplify_type(tcx, ty2, false);
+            if let (Some(ty1), Some(ty2)) = (ty1, ty2) {
+                // Simplified successfully
+                ty1 != ty2
+            } else {
+                // Types might unify
+                false
+            }
+        })
+    {
+        // Some types involved are definitely different, so the impls couldn't possibly overlap.
+        debug!("overlapping_impls: fast_reject early-exit");
+        return no_overlap();
+    }
 
     let overlaps = tcx.infer_ctxt().enter(|infcx| {
         let selcx = &mut SelectionContext::intercrate(&infcx);