Skip to content

Commit d791a2e

Browse files
Auto merge of #147502 - camsteffen:split-overlapping-impls, r=<try>
Split overlapping_{inherent,trait}_impls
2 parents 4422885 + 9cce78a commit d791a2e

File tree

4 files changed

+98
-29
lines changed

4 files changed

+98
-29
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: 93 additions & 25 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,32 +110,75 @@ 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, None, impl2_def_id, None, skip_leak_check, overlap_mode)
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_trait_ref = tcx.impl_trait_ref(impl1_def_id).unwrap();
141+
let impl2_trait_ref = tcx.impl_trait_ref(impl2_def_id).unwrap();
142+
let impl1_args = impl1_trait_ref.skip_binder().args;
143+
let impl2_args = impl2_trait_ref.skip_binder().args;
144+
let may_overlap =
145+
DeepRejectCtxt::relate_infer_infer(tcx).args_may_unify(impl1_args, impl2_args);
125146

126147
if !may_overlap {
127148
// Some types involved are definitely different, so the impls couldn't possibly overlap.
128149
debug!("overlapping_impls: fast_reject early-exit");
129150
return None;
130151
}
131152

153+
overlapping_impls(
154+
tcx,
155+
impl1_def_id,
156+
Some(impl1_trait_ref),
157+
impl2_def_id,
158+
Some(impl2_trait_ref),
159+
skip_leak_check,
160+
overlap_mode,
161+
)
162+
}
163+
164+
fn overlapping_impls<'tcx>(
165+
tcx: TyCtxt<'tcx>,
166+
impl1_def_id: DefId,
167+
impl1_trait_ref: Option<ty::EarlyBinder<'tcx, ty::TraitRef<'tcx>>>,
168+
impl2_def_id: DefId,
169+
impl2_trait_ref: Option<ty::EarlyBinder<'tcx, ty::TraitRef<'tcx>>>,
170+
skip_leak_check: SkipLeakCheck,
171+
overlap_mode: OverlapMode,
172+
) -> Option<OverlapResult<'tcx>> {
132173
if tcx.next_trait_solver_in_coherence() {
133174
overlap(
134175
tcx,
135176
TrackAmbiguityCauses::Yes,
136177
skip_leak_check,
137178
impl1_def_id,
179+
impl1_trait_ref,
138180
impl2_def_id,
181+
impl2_trait_ref,
139182
overlap_mode,
140183
)
141184
} else {
@@ -144,7 +187,9 @@ pub fn overlapping_impls(
144187
TrackAmbiguityCauses::No,
145188
skip_leak_check,
146189
impl1_def_id,
190+
impl1_trait_ref,
147191
impl2_def_id,
192+
impl2_trait_ref,
148193
overlap_mode,
149194
)?;
150195

@@ -156,23 +201,29 @@ pub fn overlapping_impls(
156201
TrackAmbiguityCauses::Yes,
157202
skip_leak_check,
158203
impl1_def_id,
204+
impl1_trait_ref,
159205
impl2_def_id,
206+
impl2_trait_ref,
160207
overlap_mode,
161208
)
162209
.unwrap();
163210
Some(overlap)
164211
}
165212
}
166213

167-
fn fresh_impl_header<'tcx>(infcx: &InferCtxt<'tcx>, impl_def_id: DefId) -> ImplHeader<'tcx> {
214+
fn fresh_impl_header<'tcx>(
215+
infcx: &InferCtxt<'tcx>,
216+
impl_def_id: DefId,
217+
trait_ref: Option<ty::EarlyBinder<'tcx, ty::TraitRef<'tcx>>>,
218+
) -> ImplHeader<'tcx> {
168219
let tcx = infcx.tcx;
169220
let impl_args = infcx.fresh_args_for_item(DUMMY_SP, impl_def_id);
170221

171222
ImplHeader {
172223
impl_def_id,
173224
impl_args,
174225
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)),
226+
trait_ref: trait_ref.map(|trait_ref| trait_ref.instantiate(tcx, impl_args)),
176227
predicates: tcx
177228
.predicates_of(impl_def_id)
178229
.instantiate(tcx, impl_args)
@@ -186,8 +237,9 @@ fn fresh_impl_header_normalized<'tcx>(
186237
infcx: &InferCtxt<'tcx>,
187238
param_env: ty::ParamEnv<'tcx>,
188239
impl_def_id: DefId,
240+
trait_ref: Option<ty::EarlyBinder<'tcx, ty::TraitRef<'tcx>>>,
189241
) -> ImplHeader<'tcx> {
190-
let header = fresh_impl_header(infcx, impl_def_id);
242+
let header = fresh_impl_header(infcx, impl_def_id, trait_ref);
191243

192244
let InferOk { value: mut header, obligations } =
193245
infcx.at(&ObligationCause::dummy(), param_env).normalize(header);
@@ -204,13 +256,25 @@ fn overlap<'tcx>(
204256
track_ambiguity_causes: TrackAmbiguityCauses,
205257
skip_leak_check: SkipLeakCheck,
206258
impl1_def_id: DefId,
259+
impl1_trait_ref: Option<ty::EarlyBinder<'tcx, ty::TraitRef<'tcx>>>,
207260
impl2_def_id: DefId,
261+
impl2_trait_ref: Option<ty::EarlyBinder<'tcx, ty::TraitRef<'tcx>>>,
208262
overlap_mode: OverlapMode,
209263
) -> Option<OverlapResult<'tcx>> {
210264
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)
213-
{
265+
if impl_intersection_has_negative_obligation(
266+
tcx,
267+
impl1_def_id,
268+
impl1_trait_ref,
269+
impl2_def_id,
270+
impl2_trait_ref,
271+
) || impl_intersection_has_negative_obligation(
272+
tcx,
273+
impl2_def_id,
274+
impl2_trait_ref,
275+
impl1_def_id,
276+
impl1_trait_ref,
277+
) {
214278
return None;
215279
}
216280
}
@@ -231,8 +295,10 @@ fn overlap<'tcx>(
231295
// empty environment.
232296
let param_env = ty::ParamEnv::empty();
233297

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);
298+
let impl1_header =
299+
fresh_impl_header_normalized(selcx.infcx, param_env, impl1_def_id, impl1_trait_ref);
300+
let impl2_header =
301+
fresh_impl_header_normalized(selcx.infcx, param_env, impl2_def_id, impl2_trait_ref);
236302

237303
// Equate the headers to find their intersection (the general type, with infer vars,
238304
// that may apply both impls).
@@ -442,10 +508,12 @@ fn impl_intersection_has_impossible_obligation<'a, 'cx, 'tcx>(
442508
/// after negating, giving us `&str: !Error`. This is a negative impl provided by
443509
/// libstd, and therefore we can guarantee for certain that libstd will never add
444510
/// a positive impl for `&str: Error` (without it being a breaking change).
445-
fn impl_intersection_has_negative_obligation(
446-
tcx: TyCtxt<'_>,
511+
fn impl_intersection_has_negative_obligation<'tcx>(
512+
tcx: TyCtxt<'tcx>,
447513
impl1_def_id: DefId,
514+
impl1_trait_ref: Option<ty::EarlyBinder<'tcx, ty::TraitRef<'tcx>>>,
448515
impl2_def_id: DefId,
516+
impl2_trait_ref: Option<ty::EarlyBinder<'tcx, ty::TraitRef<'tcx>>>,
449517
) -> bool {
450518
debug!("negative_impl(impl1_def_id={:?}, impl2_def_id={:?})", impl1_def_id, impl2_def_id);
451519

@@ -455,11 +523,11 @@ fn impl_intersection_has_negative_obligation(
455523
let root_universe = infcx.universe();
456524
assert_eq!(root_universe, ty::UniverseIndex::ROOT);
457525

458-
let impl1_header = fresh_impl_header(infcx, impl1_def_id);
526+
let impl1_header = fresh_impl_header(infcx, impl1_def_id, impl1_trait_ref);
459527
let param_env =
460528
ty::EarlyBinder::bind(tcx.param_env(impl1_def_id)).instantiate(tcx, impl1_header.impl_args);
461529

462-
let impl2_header = fresh_impl_header(infcx, impl2_def_id);
530+
let impl2_header = fresh_impl_header(infcx, impl2_def_id, impl2_trait_ref);
463531

464532
// Equate the headers to find their intersection (the general type, with infer vars,
465533
// 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)