Skip to content

Commit e70e211

Browse files
committed
Auto merge of rust-lang#95082 - spastorino:overlap-inherent-impls, r=nikomatsakis
Overlap inherent impls r? `@nikomatsakis` Closes rust-lang#94526
2 parents 8a0c550 + 42e986f commit e70e211

File tree

9 files changed

+177
-65
lines changed

9 files changed

+177
-65
lines changed

compiler/rustc_infer/src/infer/at.rs

+24-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
use super::*;
2929

3030
use rustc_middle::ty::relate::{Relate, TypeRelation};
31-
use rustc_middle::ty::Const;
31+
use rustc_middle::ty::{Const, ImplSubject};
3232

3333
pub struct At<'a, 'tcx> {
3434
pub infcx: &'a InferCtxt<'a, 'tcx>,
@@ -272,6 +272,29 @@ impl<'a, 'tcx> Trace<'a, 'tcx> {
272272
}
273273
}
274274

275+
impl<'tcx> ToTrace<'tcx> for ImplSubject<'tcx> {
276+
fn to_trace(
277+
tcx: TyCtxt<'tcx>,
278+
cause: &ObligationCause<'tcx>,
279+
a_is_expected: bool,
280+
a: Self,
281+
b: Self,
282+
) -> TypeTrace<'tcx> {
283+
match (a, b) {
284+
(ImplSubject::Trait(trait_ref_a), ImplSubject::Trait(trait_ref_b)) => {
285+
ToTrace::to_trace(tcx, cause, a_is_expected, trait_ref_a, trait_ref_b)
286+
}
287+
(ImplSubject::Inherent(ty_a), ImplSubject::Inherent(ty_b)) => {
288+
ToTrace::to_trace(tcx, cause, a_is_expected, ty_a, ty_b)
289+
}
290+
(ImplSubject::Trait(_), ImplSubject::Inherent(_))
291+
| (ImplSubject::Inherent(_), ImplSubject::Trait(_)) => {
292+
bug!("can not trace TraitRef and Ty");
293+
}
294+
}
295+
}
296+
}
297+
275298
impl<'tcx> ToTrace<'tcx> for Ty<'tcx> {
276299
fn to_trace(
277300
_: TyCtxt<'tcx>,

compiler/rustc_middle/src/hir/mod.rs

+8-2
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@ pub mod nested_filter;
77
pub mod place;
88

99
use crate::ty::query::Providers;
10-
use crate::ty::TyCtxt;
10+
use crate::ty::{ImplSubject, TyCtxt};
1111
use rustc_data_structures::fingerprint::Fingerprint;
1212
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
13-
use rustc_hir::def_id::LocalDefId;
13+
use rustc_hir::def_id::{DefId, LocalDefId};
1414
use rustc_hir::*;
1515
use rustc_query_system::ich::StableHashingContext;
1616
use rustc_span::DUMMY_SP;
@@ -54,6 +54,12 @@ impl<'tcx> TyCtxt<'tcx> {
5454
pub fn parent_module(self, id: HirId) -> LocalDefId {
5555
self.parent_module_from_def_id(id.owner)
5656
}
57+
58+
pub fn impl_subject(self, def_id: DefId) -> ImplSubject<'tcx> {
59+
self.impl_trait_ref(def_id)
60+
.map(ImplSubject::Trait)
61+
.unwrap_or_else(|| ImplSubject::Inherent(self.type_of(def_id)))
62+
}
5763
}
5864

5965
pub fn provide(providers: &mut Providers) {

compiler/rustc_middle/src/ty/mod.rs

+7
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ use rustc_span::symbol::{kw, Ident, Symbol};
4444
use rustc_span::Span;
4545
use rustc_target::abi::Align;
4646

47+
use std::fmt::Debug;
4748
use std::hash::Hash;
4849
use std::ops::ControlFlow;
4950
use std::{fmt, str};
@@ -172,6 +173,12 @@ pub struct ImplHeader<'tcx> {
172173
pub predicates: Vec<Predicate<'tcx>>,
173174
}
174175

176+
#[derive(Copy, Clone, Debug, TypeFoldable)]
177+
pub enum ImplSubject<'tcx> {
178+
Trait(TraitRef<'tcx>),
179+
Inherent(Ty<'tcx>),
180+
}
181+
175182
#[derive(
176183
Copy,
177184
Clone,

compiler/rustc_middle/src/ty/relate.rs

+25-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
use crate::mir::interpret::{get_slice_bytes, ConstValue, GlobalAlloc, Scalar};
88
use crate::ty::error::{ExpectedFound, TypeError};
99
use crate::ty::subst::{GenericArg, GenericArgKind, Subst, SubstsRef};
10-
use crate::ty::{self, Term, Ty, TyCtxt, TypeFoldable};
10+
use crate::ty::{self, ImplSubject, Term, Ty, TyCtxt, TypeFoldable};
1111
use rustc_hir as ast;
1212
use rustc_hir::def_id::DefId;
1313
use rustc_span::DUMMY_SP;
@@ -356,6 +356,30 @@ impl<'tcx> Relate<'tcx> for GeneratorWitness<'tcx> {
356356
}
357357
}
358358

359+
impl<'tcx> Relate<'tcx> for ImplSubject<'tcx> {
360+
#[inline]
361+
fn relate<R: TypeRelation<'tcx>>(
362+
relation: &mut R,
363+
a: ImplSubject<'tcx>,
364+
b: ImplSubject<'tcx>,
365+
) -> RelateResult<'tcx, ImplSubject<'tcx>> {
366+
match (a, b) {
367+
(ImplSubject::Trait(trait_ref_a), ImplSubject::Trait(trait_ref_b)) => {
368+
let trait_ref = ty::TraitRef::relate(relation, trait_ref_a, trait_ref_b)?;
369+
Ok(ImplSubject::Trait(trait_ref))
370+
}
371+
(ImplSubject::Inherent(ty_a), ImplSubject::Inherent(ty_b)) => {
372+
let ty = Ty::relate(relation, ty_a, ty_b)?;
373+
Ok(ImplSubject::Inherent(ty))
374+
}
375+
(ImplSubject::Trait(_), ImplSubject::Inherent(_))
376+
| (ImplSubject::Inherent(_), ImplSubject::Trait(_)) => {
377+
bug!("can not relate TraitRef and Ty");
378+
}
379+
}
380+
}
381+
}
382+
359383
impl<'tcx> Relate<'tcx> for Ty<'tcx> {
360384
#[inline]
361385
fn relate<R: TypeRelation<'tcx>>(

compiler/rustc_trait_selection/src/traits/coherence.rs

+45-42
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
use crate::infer::outlives::env::OutlivesEnvironment;
88
use crate::infer::{CombinedSnapshot, InferOk, RegionckMode};
99
use crate::traits::select::IntercrateAmbiguityCause;
10-
use crate::traits::util::impl_trait_ref_and_oblig;
10+
use crate::traits::util::impl_subject_and_oblig;
1111
use crate::traits::SkipLeakCheck;
1212
use crate::traits::{
1313
self, FulfillmentContext, Normalized, Obligation, ObligationCause, PredicateObligation,
@@ -23,9 +23,10 @@ use rustc_middle::traits::specialization_graph::OverlapMode;
2323
use rustc_middle::ty::fast_reject::{self, TreatParams};
2424
use rustc_middle::ty::fold::TypeFoldable;
2525
use rustc_middle::ty::subst::Subst;
26-
use rustc_middle::ty::{self, Ty, TyCtxt};
26+
use rustc_middle::ty::{self, ImplSubject, Ty, TyCtxt};
2727
use rustc_span::symbol::sym;
2828
use rustc_span::DUMMY_SP;
29+
use std::fmt::Debug;
2930
use std::iter;
3031

3132
/// Whether we do the orphan check relative to this crate or
@@ -300,60 +301,62 @@ fn negative_impl<'cx, 'tcx>(
300301
debug!("negative_impl(impl1_def_id={:?}, impl2_def_id={:?})", impl1_def_id, impl2_def_id);
301302
let tcx = selcx.infcx().tcx;
302303

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-
307304
// Create an infcx, taking the predicates of impl1 as assumptions:
308305
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(
306+
// create a parameter environment corresponding to a (placeholder) instantiation of impl1
307+
let impl_env = tcx.param_env(impl1_def_id);
308+
let subject1 = match traits::fully_normalize(
312309
&infcx,
313310
FulfillmentContext::new(),
314311
ObligationCause::dummy(),
315-
impl1_env,
316-
impl1_trait_ref,
312+
impl_env,
313+
tcx.impl_subject(impl1_def_id),
317314
) {
318-
Ok(impl1_trait_ref) => impl1_trait_ref,
319-
Err(err) => {
320-
bug!("failed to fully normalize {:?}: {:?}", impl1_trait_ref, err);
321-
}
315+
Ok(s) => s,
316+
Err(err) => bug!("failed to fully normalize {:?}: {:?}", impl1_def_id, err),
322317
};
323318

324319
// Attempt to prove that impl2 applies, given all of the above.
325320
let selcx = &mut SelectionContext::new(&infcx);
326321
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);
329-
330-
// do the impls unify? If not, not disjoint.
331-
let Ok(InferOk { obligations: more_obligations, .. }) = infcx
332-
.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-
};
322+
let (subject2, obligations) =
323+
impl_subject_and_oblig(selcx, impl_env, impl2_def_id, impl2_substs);
341324

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
350-
} else {
351-
false
352-
}
325+
!equate(&infcx, impl_env, impl1_def_id, subject1, subject2, obligations)
353326
})
354327
}
355328

356-
/// Try to prove that a negative impl exist for the given obligation and their super predicates.
329+
fn equate<'cx, 'tcx>(
330+
infcx: &InferCtxt<'cx, 'tcx>,
331+
impl_env: ty::ParamEnv<'tcx>,
332+
impl1_def_id: DefId,
333+
subject1: ImplSubject<'tcx>,
334+
subject2: ImplSubject<'tcx>,
335+
obligations: impl Iterator<Item = PredicateObligation<'tcx>>,
336+
) -> bool {
337+
// do the impls unify? If not, not disjoint.
338+
let Ok(InferOk { obligations: more_obligations, .. }) =
339+
infcx.at(&ObligationCause::dummy(), impl_env).eq(subject1, subject2)
340+
else {
341+
debug!("explicit_disjoint: {:?} does not unify with {:?}", subject1, subject2);
342+
return true;
343+
};
344+
345+
let selcx = &mut SelectionContext::new(&infcx);
346+
let opt_failing_obligation = obligations
347+
.into_iter()
348+
.chain(more_obligations)
349+
.find(|o| negative_impl_exists(selcx, impl_env, impl1_def_id, o));
350+
351+
if let Some(failing_obligation) = opt_failing_obligation {
352+
debug!("overlap: obligation unsatisfiable {:?}", failing_obligation);
353+
false
354+
} else {
355+
true
356+
}
357+
}
358+
359+
/// Try to prove that a negative impl exist for the given obligation and its super predicates.
357360
#[instrument(level = "debug", skip(selcx))]
358361
fn negative_impl_exists<'cx, 'tcx>(
359362
selcx: &SelectionContext<'cx, 'tcx>,
@@ -367,7 +370,7 @@ fn negative_impl_exists<'cx, 'tcx>(
367370
return true;
368371
}
369372

370-
// Try to prove a negative obligation exist for super predicates
373+
// Try to prove a negative obligation exists for super predicates
371374
for o in util::elaborate_predicates(infcx.tcx, iter::once(o.predicate)) {
372375
if resolve_negative_obligation(infcx, param_env, region_context, &o) {
373376
return true;

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

+11-9
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,12 @@ use rustc_errors::{struct_span_err, EmissionGuarantee};
2020
use rustc_hir::def_id::{DefId, LocalDefId};
2121
use rustc_middle::lint::LintDiagnosticBuilder;
2222
use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef};
23-
use rustc_middle::ty::{self, TyCtxt};
23+
use rustc_middle::ty::{self, ImplSubject, TyCtxt};
2424
use rustc_session::lint::builtin::COHERENCE_LEAK_CHECK;
2525
use rustc_session::lint::builtin::ORDER_DEPENDENT_TRAIT_OBJECTS;
2626
use rustc_span::{Span, DUMMY_SP};
2727

28-
use super::util::impl_trait_ref_and_oblig;
28+
use super::util;
2929
use super::{FulfillmentContext, SelectionContext};
3030

3131
/// Information pertinent to an overlapping impl error.
@@ -186,18 +186,20 @@ fn fulfill_implication<'a, 'tcx>(
186186
param_env, source_trait_ref, target_impl
187187
);
188188

189+
let source_trait = ImplSubject::Trait(source_trait_ref);
190+
189191
let selcx = &mut SelectionContext::new(&infcx);
190192
let target_substs = infcx.fresh_substs_for_item(DUMMY_SP, target_impl);
191-
let (target_trait_ref, obligations) =
192-
impl_trait_ref_and_oblig(selcx, param_env, target_impl, target_substs);
193+
let (target_trait, obligations) =
194+
util::impl_subject_and_oblig(selcx, param_env, target_impl, target_substs);
193195

194196
// do the impls unify? If not, no specialization.
195197
let Ok(InferOk { obligations: more_obligations, .. }) =
196-
infcx.at(&ObligationCause::dummy(), param_env).eq(source_trait_ref, target_trait_ref)
198+
infcx.at(&ObligationCause::dummy(), param_env).eq(source_trait, target_trait)
197199
else {
198200
debug!(
199201
"fulfill_implication: {:?} does not unify with {:?}",
200-
source_trait_ref, target_trait_ref
202+
source_trait, target_trait
201203
);
202204
return Err(());
203205
};
@@ -225,7 +227,7 @@ fn fulfill_implication<'a, 'tcx>(
225227
[] => {
226228
debug!(
227229
"fulfill_implication: an impl for {:?} specializes {:?}",
228-
source_trait_ref, target_trait_ref
230+
source_trait, target_trait
229231
);
230232

231233
// Now resolve the *substitution* we built for the target earlier, replacing
@@ -237,8 +239,8 @@ fn fulfill_implication<'a, 'tcx>(
237239
debug!(
238240
"fulfill_implication: for impls on {:?} and {:?}, \
239241
could not fulfill: {:?} given {:?}",
240-
source_trait_ref,
241-
target_trait_ref,
242+
source_trait,
243+
target_trait,
242244
errors,
243245
param_env.caller_bounds()
244246
);

compiler/rustc_trait_selection/src/traits/util.rs

+10-10
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use smallvec::SmallVec;
66
use rustc_data_structures::fx::FxHashSet;
77
use rustc_hir::def_id::DefId;
88
use rustc_middle::ty::subst::{GenericArg, Subst, SubstsRef};
9-
use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable};
9+
use rustc_middle::ty::{self, ImplSubject, ToPredicate, Ty, TyCtxt, TypeFoldable};
1010

1111
use super::{Normalized, Obligation, ObligationCause, PredicateObligation, SelectionContext};
1212
pub use rustc_infer::traits::{self, util::*};
@@ -190,19 +190,19 @@ impl Iterator for SupertraitDefIds<'_> {
190190
// Other
191191
///////////////////////////////////////////////////////////////////////////
192192

193-
/// Instantiate all bound parameters of the impl with the given substs,
194-
/// returning the resulting trait ref and all obligations that arise.
193+
/// Instantiate all bound parameters of the impl subject with the given substs,
194+
/// returning the resulting subject and all obligations that arise.
195195
/// The obligations are closed under normalization.
196-
pub fn impl_trait_ref_and_oblig<'a, 'tcx>(
196+
pub fn impl_subject_and_oblig<'a, 'tcx>(
197197
selcx: &mut SelectionContext<'a, 'tcx>,
198198
param_env: ty::ParamEnv<'tcx>,
199199
impl_def_id: DefId,
200200
impl_substs: SubstsRef<'tcx>,
201-
) -> (ty::TraitRef<'tcx>, impl Iterator<Item = PredicateObligation<'tcx>>) {
202-
let impl_trait_ref = selcx.tcx().impl_trait_ref(impl_def_id).unwrap();
203-
let impl_trait_ref = impl_trait_ref.subst(selcx.tcx(), impl_substs);
204-
let Normalized { value: impl_trait_ref, obligations: normalization_obligations1 } =
205-
super::normalize(selcx, param_env, ObligationCause::dummy(), impl_trait_ref);
201+
) -> (ImplSubject<'tcx>, impl Iterator<Item = PredicateObligation<'tcx>>) {
202+
let subject = selcx.tcx().impl_subject(impl_def_id);
203+
let subject = subject.subst(selcx.tcx(), impl_substs);
204+
let Normalized { value: subject, obligations: normalization_obligations1 } =
205+
super::normalize(selcx, param_env, ObligationCause::dummy(), subject);
206206

207207
let predicates = selcx.tcx().predicates_of(impl_def_id);
208208
let predicates = predicates.instantiate(selcx.tcx(), impl_substs);
@@ -215,7 +215,7 @@ pub fn impl_trait_ref_and_oblig<'a, 'tcx>(
215215
.chain(normalization_obligations1.into_iter())
216216
.chain(normalization_obligations2.into_iter());
217217

218-
(impl_trait_ref, impl_obligations)
218+
(subject, impl_obligations)
219219
}
220220

221221
pub fn predicates_for_generics<'tcx>(
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// check-pass
2+
3+
#![feature(negative_impls)]
4+
#![feature(rustc_attrs)]
5+
#![feature(with_negative_coherence)]
6+
7+
trait Foo {}
8+
9+
impl !Foo for u32 {}
10+
11+
#[rustc_strict_coherence]
12+
struct MyStruct<T>(T);
13+
14+
impl MyStruct<u32> {
15+
fn method(&self) {}
16+
}
17+
18+
impl<T> MyStruct<T>
19+
where
20+
T: Foo,
21+
{
22+
fn method(&self) {}
23+
}
24+
25+
fn main() {}

0 commit comments

Comments
 (0)