Skip to content

Commit d0bbdc3

Browse files
Add an early-exit to overlapping_impls
This triggers in approx. 37% of all calls when building the stm32f0(x2) crate, saving a small amount of time.
1 parent 07a34df commit d0bbdc3

File tree

1 file changed

+33
-1
lines changed

1 file changed

+33
-1
lines changed

src/librustc/traits/coherence.rs

+33-1
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,11 @@ use crate::traits::SkipLeakCheck;
1111
use crate::traits::{self, Normalized, Obligation, ObligationCause, SelectionContext};
1212
use crate::ty::fold::TypeFoldable;
1313
use crate::ty::subst::Subst;
14-
use crate::ty::{self, Ty, TyCtxt};
14+
use crate::ty::{self, fast_reject, Ty, TyCtxt};
1515
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
1616
use rustc_span::symbol::sym;
1717
use rustc_span::DUMMY_SP;
18+
use std::iter;
1819

1920
/// Whether we do the orphan check relative to this crate or
2021
/// to some remote crate.
@@ -70,6 +71,37 @@ where
7071
impl1_def_id, impl2_def_id, intercrate_mode
7172
);
7273

74+
// Before doing expensive operations like entering an inference context, do
75+
// a quick check via fast_reject to tell if the impl headers could possibly
76+
// unify.
77+
let impl1_self = tcx.type_of(impl1_def_id);
78+
let impl2_self = tcx.type_of(impl2_def_id);
79+
let impl1_ref = tcx.impl_trait_ref(impl1_def_id);
80+
let impl2_ref = tcx.impl_trait_ref(impl2_def_id);
81+
82+
// Check if any of the input types definitely mismatch.
83+
if impl1_ref
84+
.iter()
85+
.flat_map(|tref| tref.input_types())
86+
.zip(impl2_ref.iter().flat_map(|tref| tref.input_types()))
87+
.chain(iter::once((impl1_self, impl2_self)))
88+
.any(|(ty1, ty2)| {
89+
let ty1 = fast_reject::simplify_type(tcx, ty1, false);
90+
let ty2 = fast_reject::simplify_type(tcx, ty2, false);
91+
if let (Some(ty1), Some(ty2)) = (ty1, ty2) {
92+
// Simplified successfully
93+
ty1 != ty2
94+
} else {
95+
// Types might unify
96+
false
97+
}
98+
})
99+
{
100+
// Some types involved are definitely different, so the impls couldn't possibly overlap.
101+
debug!("overlapping_impls: fast_reject early-exit");
102+
return no_overlap();
103+
}
104+
73105
let overlaps = tcx.infer_ctxt().enter(|infcx| {
74106
let selcx = &mut SelectionContext::intercrate(&infcx, intercrate_mode);
75107
overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id).is_some()

0 commit comments

Comments
 (0)