Skip to content

Commit 3f5aee2

Browse files
committed
Auto merge of rust-lang#81744 - rylev:overlapping-early-exit2, r=lcnr
Try fast_reject::simplify_type in coherence before doing full check This is a reattempt at landing rust-lang#69010 (by `@jonas-schievink).` The change adds a fast path for coherence checking to see if there's no way for types to unify since full coherence checking can be somewhat expensive. This has big effects on code generated by the [`windows`](https://github.com/microsoft/windows-rs) which in some cases spends as much as 20% of compilation time in the `specialization_graph_of` query. In local benchmarks this took a compilation that previously took ~500 seconds down to ~380 seconds. This is surely not going to make a difference on much smaller crates, so the question is whether it will have a negative impact. rust-lang#69010 was closed because some of the perf suite crates did show small regressions. Additional discussion of this issue is happening [here](https://rust-lang.zulipchat.com/#narrow/stream/247081-t-compiler.2Fperformance/topic/windows-rs.20perf).
2 parents d416093 + 0cc35f5 commit 3f5aee2

File tree

2 files changed

+38
-1
lines changed

2 files changed

+38
-1
lines changed

compiler/rustc_middle/src/ty/sty.rs

+9
Original file line numberDiff line numberDiff line change
@@ -1845,6 +1845,15 @@ impl<'tcx> TyS<'tcx> {
18451845
)
18461846
}
18471847

1848+
/// Get the mutability of the reference or `None` when not a reference
1849+
#[inline]
1850+
pub fn ref_mutability(&self) -> Option<hir::Mutability> {
1851+
match self.kind() {
1852+
Ref(_, _, mutability) => Some(*mutability),
1853+
_ => None,
1854+
}
1855+
}
1856+
18481857
#[inline]
18491858
pub fn is_unsafe_ptr(&self) -> bool {
18501859
matches!(self.kind(), RawPtr(_))

compiler/rustc_trait_selection/src/traits/coherence.rs

+29-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use crate::traits::{self, Normalized, Obligation, ObligationCause, SelectionCont
1111
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
1212
use rustc_middle::ty::fold::TypeFoldable;
1313
use rustc_middle::ty::subst::Subst;
14-
use rustc_middle::ty::{self, Ty, TyCtxt};
14+
use rustc_middle::ty::{self, fast_reject, Ty, TyCtxt};
1515
use rustc_span::symbol::sym;
1616
use rustc_span::DUMMY_SP;
1717
use std::iter;
@@ -67,6 +67,34 @@ where
6767
impl2_def_id={:?})",
6868
impl1_def_id, impl2_def_id,
6969
);
70+
// Before doing expensive operations like entering an inference context, do
71+
// a quick check via fast_reject to tell if the impl headers could possibly
72+
// unify.
73+
let impl1_ref = tcx.impl_trait_ref(impl1_def_id);
74+
let impl2_ref = tcx.impl_trait_ref(impl2_def_id);
75+
76+
// Check if any of the input types definitely do not unify.
77+
if impl1_ref
78+
.iter()
79+
.flat_map(|tref| tref.substs.types())
80+
.zip(impl2_ref.iter().flat_map(|tref| tref.substs.types()))
81+
.any(|(ty1, ty2)| {
82+
let t1 = fast_reject::simplify_type(tcx, ty1, false);
83+
let t2 = fast_reject::simplify_type(tcx, ty2, false);
84+
if let (Some(t1), Some(t2)) = (t1, t2) {
85+
// Simplified successfully
86+
// Types cannot unify if they differ in their reference mutability or simplify to different types
87+
t1 != t2 || ty1.ref_mutability() != ty2.ref_mutability()
88+
} else {
89+
// Types might unify
90+
false
91+
}
92+
})
93+
{
94+
// Some types involved are definitely different, so the impls couldn't possibly overlap.
95+
debug!("overlapping_impls: fast_reject early-exit");
96+
return no_overlap();
97+
}
7098

7199
let overlaps = tcx.infer_ctxt().enter(|infcx| {
72100
let selcx = &mut SelectionContext::intercrate(&infcx);

0 commit comments

Comments
 (0)