Skip to content

Commit 89fdb62

Browse files
committed
Fix inherent impls on negative coherence
1 parent a8adf76 commit 89fdb62

File tree

2 files changed

+89
-43
lines changed

2 files changed

+89
-43
lines changed

compiler/rustc_trait_selection/src/traits/coherence.rs

Lines changed: 67 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -300,55 +300,79 @@ fn negative_impl<'cx, 'tcx>(
300300
debug!("negative_impl(impl1_def_id={:?}, impl2_def_id={:?})", impl1_def_id, impl2_def_id);
301301
let tcx = selcx.infcx().tcx;
302302

303-
// create a parameter environment corresponding to a (placeholder) instantiation of impl1
304-
let impl1_env = tcx.param_env(impl1_def_id);
305-
let impl1_trait_ref = tcx.impl_trait_ref(impl1_def_id).unwrap();
306-
307303
// Create an infcx, taking the predicates of impl1 as assumptions:
308304
tcx.infer_ctxt().enter(|infcx| {
309-
// Normalize the trait reference. The WF rules ought to ensure
310-
// that this always succeeds.
311-
let impl1_trait_ref = match traits::fully_normalize(
312-
&infcx,
313-
FulfillmentContext::new(),
314-
ObligationCause::dummy(),
315-
impl1_env,
316-
impl1_trait_ref,
317-
) {
318-
Ok(impl1_trait_ref) => impl1_trait_ref,
319-
Err(err) => {
320-
bug!("failed to fully normalize {:?}: {:?}", impl1_trait_ref, err);
321-
}
322-
};
305+
// create a parameter environment corresponding to a (placeholder) instantiation of impl1
306+
let impl1_env = tcx.param_env(impl1_def_id);
307+
308+
if let Some(impl1_trait_ref) = tcx.impl_trait_ref(impl1_def_id) {
309+
// Normalize the trait reference. The WF rules ought to ensure
310+
// that this always succeeds.
311+
let impl1_trait_ref = match traits::fully_normalize(
312+
&infcx,
313+
FulfillmentContext::new(),
314+
ObligationCause::dummy(),
315+
impl1_env,
316+
impl1_trait_ref,
317+
) {
318+
Ok(impl1_trait_ref) => impl1_trait_ref,
319+
Err(err) => {
320+
bug!("failed to fully normalize {:?}: {:?}", impl1_trait_ref, err);
321+
}
322+
};
323323

324-
// Attempt to prove that impl2 applies, given all of the above.
325-
let selcx = &mut SelectionContext::new(&infcx);
326-
let impl2_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl2_def_id);
327-
let (impl2_trait_ref, obligations) =
328-
impl_trait_ref_and_oblig(selcx, impl1_env, impl2_def_id, impl2_substs);
324+
// Attempt to prove that impl2 applies, given all of the above.
325+
let selcx = &mut SelectionContext::new(&infcx);
326+
let impl2_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl2_def_id);
327+
let (impl2_trait_ref, obligations) =
328+
impl_trait_ref_and_oblig(selcx, impl1_env, impl2_def_id, impl2_substs);
329329

330-
// do the impls unify? If not, not disjoint.
331-
let Ok(InferOk { obligations: more_obligations, .. }) = infcx
330+
// do the impls unify? If not, not disjoint.
331+
let Ok(InferOk { obligations: more_obligations, .. }) = infcx
332332
.at(&ObligationCause::dummy(), impl1_env)
333-
.eq(impl1_trait_ref, impl2_trait_ref)
334-
else {
335-
debug!(
336-
"explicit_disjoint: {:?} does not unify with {:?}",
337-
impl1_trait_ref, impl2_trait_ref
338-
);
339-
return false;
340-
};
341-
342-
let opt_failing_obligation = obligations
343-
.into_iter()
344-
.chain(more_obligations)
345-
.find(|o| negative_impl_exists(selcx, impl1_env, impl1_def_id, o));
346-
347-
if let Some(failing_obligation) = opt_failing_obligation {
348-
debug!("overlap: obligation unsatisfiable {:?}", failing_obligation);
349-
true
333+
.eq(impl1_trait_ref, impl2_trait_ref) else {
334+
debug!(
335+
"explicit_disjoint: {:?} does not unify with {:?}",
336+
impl1_trait_ref, impl2_trait_ref
337+
);
338+
return false;
339+
};
340+
341+
let opt_failing_obligation = obligations
342+
.into_iter()
343+
.chain(more_obligations)
344+
.find(|o| negative_impl_exists(selcx, impl1_env, impl1_def_id, o));
345+
346+
if let Some(failing_obligation) = opt_failing_obligation {
347+
debug!("overlap: obligation unsatisfiable {:?}", failing_obligation);
348+
true
349+
} else {
350+
false
351+
}
350352
} else {
351-
false
353+
let ty1 = tcx.type_of(impl1_def_id);
354+
let ty2 = tcx.type_of(impl2_def_id);
355+
356+
let Ok(InferOk { obligations, .. }) = infcx
357+
.at(&ObligationCause::dummy(), impl1_env)
358+
.eq(ty1, ty2) else {
359+
debug!(
360+
"explicit_disjoint: {:?} does not unify with {:?}",
361+
ty1, ty2
362+
);
363+
return false;
364+
};
365+
366+
let opt_failing_obligation = obligations
367+
.into_iter()
368+
.find(|o| negative_impl_exists(selcx, impl1_env, impl1_def_id, o));
369+
370+
if let Some(failing_obligation) = opt_failing_obligation {
371+
debug!("overlap: obligation unsatisfiable {:?}", failing_obligation);
372+
true
373+
} else {
374+
false
375+
}
352376
}
353377
})
354378
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// check-pass
2+
3+
#![feature(negative_impls)]
4+
#![feature(rustc_attrs)]
5+
#![feature(with_negative_coherence)]
6+
7+
#[rustc_strict_coherence]
8+
trait Foo {}
9+
10+
impl !Foo for u32 {}
11+
12+
struct MyStruct<T>(T);
13+
14+
impl<T: Foo> MyStruct<T> {
15+
fn method(&self) {}
16+
}
17+
18+
impl MyStruct<u32> {
19+
fn method(&self) {}
20+
}
21+
22+
fn main() {}

0 commit comments

Comments
 (0)