Skip to content

Commit 9074fa7

Browse files
Auto merge of #147502 - camsteffen:split-overlapping-impls, r=<try>
Split overlapping_{inherent,trait}_impls
2 parents 61efd19 + 735ddcc commit 9074fa7

File tree

4 files changed

+75
-26
lines changed

4 files changed

+75
-26
lines changed

compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ impl<'tcx> InherentOverlapChecker<'tcx> {
154154
impl1_def_id: DefId,
155155
impl2_def_id: DefId,
156156
) -> Result<(), ErrorGuaranteed> {
157-
let maybe_overlap = traits::overlapping_impls(
157+
let maybe_overlap = traits::overlapping_inherent_impls(
158158
self.tcx,
159159
impl1_def_id,
160160
impl2_def_id,

compiler/rustc_trait_selection/src/traits/coherence.rs

Lines changed: 70 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ impl TrackAmbiguityCauses {
100100
/// with a suitably-freshened `ImplHeader` with those types
101101
/// instantiated. Otherwise, returns `None`.
102102
#[instrument(skip(tcx, skip_leak_check), level = "debug")]
103-
pub fn overlapping_impls(
103+
pub fn overlapping_inherent_impls(
104104
tcx: TyCtxt<'_>,
105105
impl1_def_id: DefId,
106106
impl2_def_id: DefId,
@@ -110,25 +110,55 @@ pub fn overlapping_impls(
110110
// Before doing expensive operations like entering an inference context, do
111111
// a quick check via fast_reject to tell if the impl headers could possibly
112112
// unify.
113-
let drcx = DeepRejectCtxt::relate_infer_infer(tcx);
114-
let impl1_ref = tcx.impl_trait_ref(impl1_def_id);
115-
let impl2_ref = tcx.impl_trait_ref(impl2_def_id);
116-
let may_overlap = match (impl1_ref, impl2_ref) {
117-
(Some(a), Some(b)) => drcx.args_may_unify(a.skip_binder().args, b.skip_binder().args),
118-
(None, None) => {
119-
let self_ty1 = tcx.type_of(impl1_def_id).skip_binder();
120-
let self_ty2 = tcx.type_of(impl2_def_id).skip_binder();
121-
drcx.types_may_unify(self_ty1, self_ty2)
122-
}
123-
_ => bug!("unexpected impls: {impl1_def_id:?} {impl2_def_id:?}"),
124-
};
113+
let self_ty1 = tcx.type_of(impl1_def_id).skip_binder();
114+
let self_ty2 = tcx.type_of(impl2_def_id).skip_binder();
115+
let may_overlap = DeepRejectCtxt::relate_infer_infer(tcx).types_may_unify(self_ty1, self_ty2);
116+
117+
if !may_overlap {
118+
// Some types involved are definitely different, so the impls couldn't possibly overlap.
119+
debug!("overlapping_inherent_impls: fast_reject early-exit");
120+
return None;
121+
}
122+
123+
overlapping_impls(tcx, impl1_def_id, impl2_def_id, skip_leak_check, overlap_mode, false)
124+
}
125+
126+
/// If there are types that satisfy both impls, returns `Some`
127+
/// with a suitably-freshened `ImplHeader` with those types
128+
/// instantiated. Otherwise, returns `None`.
129+
#[instrument(skip(tcx, skip_leak_check), level = "debug")]
130+
pub fn overlapping_trait_impls(
131+
tcx: TyCtxt<'_>,
132+
impl1_def_id: DefId,
133+
impl2_def_id: DefId,
134+
skip_leak_check: SkipLeakCheck,
135+
overlap_mode: OverlapMode,
136+
) -> Option<OverlapResult<'_>> {
137+
// Before doing expensive operations like entering an inference context, do
138+
// a quick check via fast_reject to tell if the impl headers could possibly
139+
// unify.
140+
let impl1_args = tcx.impl_trait_ref(impl1_def_id).unwrap().skip_binder().args;
141+
let impl2_args = tcx.impl_trait_ref(impl2_def_id).unwrap().skip_binder().args;
142+
let may_overlap =
143+
DeepRejectCtxt::relate_infer_infer(tcx).args_may_unify(impl1_args, impl2_args);
125144

126145
if !may_overlap {
127146
// Some types involved are definitely different, so the impls couldn't possibly overlap.
128147
debug!("overlapping_impls: fast_reject early-exit");
129148
return None;
130149
}
131150

151+
overlapping_impls(tcx, impl1_def_id, impl2_def_id, skip_leak_check, overlap_mode, true)
152+
}
153+
154+
fn overlapping_impls(
155+
tcx: TyCtxt<'_>,
156+
impl1_def_id: DefId,
157+
impl2_def_id: DefId,
158+
skip_leak_check: SkipLeakCheck,
159+
overlap_mode: OverlapMode,
160+
is_of_trait: bool,
161+
) -> Option<OverlapResult<'_>> {
132162
if tcx.next_trait_solver_in_coherence() {
133163
overlap(
134164
tcx,
@@ -137,6 +167,7 @@ pub fn overlapping_impls(
137167
impl1_def_id,
138168
impl2_def_id,
139169
overlap_mode,
170+
is_of_trait,
140171
)
141172
} else {
142173
let _overlap_with_bad_diagnostics = overlap(
@@ -146,6 +177,7 @@ pub fn overlapping_impls(
146177
impl1_def_id,
147178
impl2_def_id,
148179
overlap_mode,
180+
is_of_trait,
149181
)?;
150182

151183
// In the case where we detect an error, run the check again, but
@@ -158,21 +190,27 @@ pub fn overlapping_impls(
158190
impl1_def_id,
159191
impl2_def_id,
160192
overlap_mode,
193+
is_of_trait,
161194
)
162195
.unwrap();
163196
Some(overlap)
164197
}
165198
}
166199

167-
fn fresh_impl_header<'tcx>(infcx: &InferCtxt<'tcx>, impl_def_id: DefId) -> ImplHeader<'tcx> {
200+
fn fresh_impl_header<'tcx>(
201+
infcx: &InferCtxt<'tcx>,
202+
impl_def_id: DefId,
203+
is_of_trait: bool,
204+
) -> ImplHeader<'tcx> {
168205
let tcx = infcx.tcx;
169206
let impl_args = infcx.fresh_args_for_item(DUMMY_SP, impl_def_id);
170207

171208
ImplHeader {
172209
impl_def_id,
173210
impl_args,
174211
self_ty: tcx.type_of(impl_def_id).instantiate(tcx, impl_args),
175-
trait_ref: tcx.impl_trait_ref(impl_def_id).map(|i| i.instantiate(tcx, impl_args)),
212+
trait_ref: is_of_trait
213+
.then(|| tcx.impl_trait_ref(impl_def_id).unwrap().instantiate(tcx, impl_args)),
176214
predicates: tcx
177215
.predicates_of(impl_def_id)
178216
.instantiate(tcx, impl_args)
@@ -186,8 +224,9 @@ fn fresh_impl_header_normalized<'tcx>(
186224
infcx: &InferCtxt<'tcx>,
187225
param_env: ty::ParamEnv<'tcx>,
188226
impl_def_id: DefId,
227+
is_of_trait: bool,
189228
) -> ImplHeader<'tcx> {
190-
let header = fresh_impl_header(infcx, impl_def_id);
229+
let header = fresh_impl_header(infcx, impl_def_id, is_of_trait);
191230

192231
let InferOk { value: mut header, obligations } =
193232
infcx.at(&ObligationCause::dummy(), param_env).normalize(header);
@@ -206,10 +245,16 @@ fn overlap<'tcx>(
206245
impl1_def_id: DefId,
207246
impl2_def_id: DefId,
208247
overlap_mode: OverlapMode,
248+
is_of_trait: bool,
209249
) -> Option<OverlapResult<'tcx>> {
210250
if overlap_mode.use_negative_impl() {
211-
if impl_intersection_has_negative_obligation(tcx, impl1_def_id, impl2_def_id)
212-
|| impl_intersection_has_negative_obligation(tcx, impl2_def_id, impl1_def_id)
251+
if impl_intersection_has_negative_obligation(tcx, impl1_def_id, impl2_def_id, is_of_trait)
252+
|| impl_intersection_has_negative_obligation(
253+
tcx,
254+
impl2_def_id,
255+
impl1_def_id,
256+
is_of_trait,
257+
)
213258
{
214259
return None;
215260
}
@@ -231,8 +276,10 @@ fn overlap<'tcx>(
231276
// empty environment.
232277
let param_env = ty::ParamEnv::empty();
233278

234-
let impl1_header = fresh_impl_header_normalized(selcx.infcx, param_env, impl1_def_id);
235-
let impl2_header = fresh_impl_header_normalized(selcx.infcx, param_env, impl2_def_id);
279+
let impl1_header =
280+
fresh_impl_header_normalized(selcx.infcx, param_env, impl1_def_id, is_of_trait);
281+
let impl2_header =
282+
fresh_impl_header_normalized(selcx.infcx, param_env, impl2_def_id, is_of_trait);
236283

237284
// Equate the headers to find their intersection (the general type, with infer vars,
238285
// that may apply both impls).
@@ -446,6 +493,7 @@ fn impl_intersection_has_negative_obligation(
446493
tcx: TyCtxt<'_>,
447494
impl1_def_id: DefId,
448495
impl2_def_id: DefId,
496+
is_of_trait: bool,
449497
) -> bool {
450498
debug!("negative_impl(impl1_def_id={:?}, impl2_def_id={:?})", impl1_def_id, impl2_def_id);
451499

@@ -455,11 +503,11 @@ fn impl_intersection_has_negative_obligation(
455503
let root_universe = infcx.universe();
456504
assert_eq!(root_universe, ty::UniverseIndex::ROOT);
457505

458-
let impl1_header = fresh_impl_header(infcx, impl1_def_id);
506+
let impl1_header = fresh_impl_header(infcx, impl1_def_id, is_of_trait);
459507
let param_env =
460508
ty::EarlyBinder::bind(tcx.param_env(impl1_def_id)).instantiate(tcx, impl1_header.impl_args);
461509

462-
let impl2_header = fresh_impl_header(infcx, impl2_def_id);
510+
let impl2_header = fresh_impl_header(infcx, impl2_def_id, is_of_trait);
463511

464512
// Equate the headers to find their intersection (the general type, with infer vars,
465513
// that may apply both impls).

compiler/rustc_trait_selection/src/traits/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ use tracing::{debug, instrument};
4242

4343
pub use self::coherence::{
4444
InCrate, IsFirstInputType, OrphanCheckErr, OrphanCheckMode, OverlapResult, UncoveredTyParams,
45-
add_placeholder_note, orphan_check_trait_ref, overlapping_impls,
45+
add_placeholder_note, orphan_check_trait_ref, overlapping_inherent_impls,
46+
overlapping_trait_impls,
4647
};
4748
pub use self::dyn_compatibility::{
4849
DynCompatibilityViolation, dyn_compatibility_violations_for_assoc_item,

compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ impl<'tcx> Children {
113113
// Found overlap, but no specialization; error out or report future-compat warning.
114114

115115
// Do we *still* get overlap if we disable the future-incompatible modes?
116-
let should_err = traits::overlapping_impls(
116+
let should_err = traits::overlapping_trait_impls(
117117
tcx,
118118
possible_sibling,
119119
impl_def_id,
@@ -137,7 +137,7 @@ impl<'tcx> Children {
137137
};
138138

139139
let last_lint_mut = &mut last_lint;
140-
let (le, ge) = traits::overlapping_impls(
140+
let (le, ge) = traits::overlapping_trait_impls(
141141
tcx,
142142
possible_sibling,
143143
impl_def_id,

0 commit comments

Comments
 (0)