From cdfc52fbd638ee3b7b1debad0aef84e730543e8a Mon Sep 17 00:00:00 2001 From: Ryan Levick Date: Thu, 4 Feb 2021 10:45:17 +0100 Subject: [PATCH] Try fast_reject::simplify_type in coherence before doing full check Co-authored-by: Jonas Schievink Co-authored-by: Ryan Levick --- .../src/traits/coherence.rs | 32 ++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 99b96f6096476..87f2ea16f8ae3 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);