diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs index 855da0367de06..c6a12279539c9 100644 --- a/src/librustc/traits/coherence.rs +++ b/src/librustc/traits/coherence.rs @@ -11,10 +11,11 @@ use crate::traits::SkipLeakCheck; use crate::traits::{self, Normalized, Obligation, ObligationCause, SelectionContext}; use crate::ty::fold::TypeFoldable; use crate::ty::subst::Subst; -use crate::ty::{self, Ty, TyCtxt}; +use crate::ty::{self, fast_reject, Ty, TyCtxt}; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_span::symbol::sym; use rustc_span::DUMMY_SP; +use std::iter; /// Whether we do the orphan check relative to this crate or /// to some remote crate. @@ -70,6 +71,37 @@ where impl1_def_id, impl2_def_id, intercrate_mode ); + // 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.input_types()) + .zip(impl2_ref.iter().flat_map(|tref| tref.input_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, intercrate_mode); overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id).is_some()