Skip to content

Commit bb80bba

Browse files
Make the implementation better
1 parent 3ee780b commit bb80bba

15 files changed

+325
-35
lines changed

compiler/rustc_middle/src/query/keys.rs

+8
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,14 @@ impl Key for (DefId, SimplifiedType) {
319319
}
320320
}
321321

322+
impl Key for (DefId, Option<DefId>) {
323+
type Cache<V> = DefaultCache<Self, V>;
324+
325+
fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
326+
self.0.default_span(tcx)
327+
}
328+
}
329+
322330
impl<'tcx> Key for GenericArgsRef<'tcx> {
323331
type Cache<V> = DefaultCache<Self, V>;
324332

compiler/rustc_middle/src/query/mod.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -1371,11 +1371,12 @@ rustc_queries! {
13711371
desc { |tcx| "checking if trait `{}` is dyn-compatible", tcx.def_path_str(trait_id) }
13721372
}
13731373

1374-
query trait_has_impl_which_may_shadow_dyn(trait_def_id: DefId) -> bool {
1374+
query trait_has_impl_which_may_shadow_dyn(key: (DefId, Option<DefId>)) -> bool {
13751375
desc {
13761376
|tcx| "checking if trait `{}` has an impl which may overlap with \
1377-
the built-in impl for trait objects",
1378-
tcx.def_path_str(trait_def_id)
1377+
the built-in impl for `dyn {}`",
1378+
tcx.def_path_str(key.0),
1379+
key.1.map_or(String::from("..."), |def_id| tcx.def_path_str(def_id)),
13791380
}
13801381
}
13811382

compiler/rustc_middle/src/ty/context.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -581,8 +581,12 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
581581
self.trait_def(trait_def_id).implement_via_object
582582
}
583583

584-
fn trait_has_impl_which_may_shadow_dyn(self, trait_def_id: DefId) -> bool {
585-
self.trait_has_impl_which_may_shadow_dyn(trait_def_id)
584+
fn trait_has_impl_which_may_shadow_dyn(
585+
self,
586+
trait_def_id: DefId,
587+
principal_def_id: Option<DefId>,
588+
) -> bool {
589+
self.trait_has_impl_which_may_shadow_dyn((trait_def_id, principal_def_id))
586590
}
587591

588592
fn is_impl_trait_in_trait(self, def_id: DefId) -> bool {

compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,14 @@ where
8282
goal: Goal<I, Self>,
8383
assumption: I::Clause,
8484
) -> Result<Candidate<I>, NoSolution> {
85-
if ecx.cx().trait_has_impl_which_may_shadow_dyn(goal.predicate.trait_def_id(ecx.cx())) {
85+
let ty::Dynamic(data, _, _) = goal.predicate.self_ty().kind() else {
86+
unreachable!();
87+
};
88+
89+
if ecx.cx().trait_has_impl_which_may_shadow_dyn(
90+
goal.predicate.trait_def_id(ecx.cx()),
91+
data.principal_def_id(),
92+
) {
8693
return Err(NoSolution);
8794
}
8895

compiler/rustc_trait_selection/src/traits/project.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -864,7 +864,12 @@ fn assemble_candidates_from_object_ty<'cx, 'tcx>(
864864
let env_predicates = data
865865
.projection_bounds()
866866
.filter(|bound| bound.item_def_id() == obligation.predicate.def_id)
867-
.filter(|bound| !tcx.trait_has_impl_which_may_shadow_dyn(bound.trait_def_id(tcx)))
867+
.filter(|bound| {
868+
!tcx.trait_has_impl_which_may_shadow_dyn((
869+
bound.trait_def_id(tcx),
870+
data.principal_def_id(),
871+
))
872+
})
868873
.map(|p| p.with_self_ty(tcx, object_ty).upcast(tcx));
869874

870875
assemble_candidates_from_predicates(

compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -916,7 +916,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
916916
})
917917
})
918918
.filter(|(_, trait_ref)| {
919-
!tcx.trait_has_impl_which_may_shadow_dyn(trait_ref.def_id())
919+
!tcx.trait_has_impl_which_may_shadow_dyn((
920+
trait_ref.def_id(),
921+
Some(principal_trait_ref.def_id()),
922+
))
920923
})
921924
.map(|(idx, _)| ObjectCandidate(idx));
922925

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

+87-25
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
1212
pub mod specialization_graph;
1313

14-
use rustc_data_structures::fx::FxIndexSet;
14+
use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
1515
use rustc_errors::codes::*;
1616
use rustc_errors::{Diag, EmissionGuarantee};
1717
use rustc_hir::LangItem;
@@ -23,6 +23,8 @@ use rustc_middle::ty::print::PrintTraitRefExt as _;
2323
use rustc_middle::ty::{self, GenericArgsRef, ImplSubject, Ty, TyCtxt, TypeVisitableExt};
2424
use rustc_session::lint::builtin::{COHERENCE_LEAK_CHECK, ORDER_DEPENDENT_TRAIT_OBJECTS};
2525
use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, sym};
26+
use rustc_type_ir::elaborate;
27+
use rustc_type_ir::fast_reject::{SimplifiedType, TreatParams, simplify_type};
2628
use specialization_graph::GraphExt;
2729
use tracing::{debug, instrument};
2830

@@ -482,20 +484,62 @@ fn report_conflicting_impls<'tcx>(
482484

483485
pub(super) fn trait_has_impl_which_may_shadow_dyn<'tcx>(
484486
tcx: TyCtxt<'tcx>,
485-
trait_def_id: DefId,
487+
(target_trait_def_id, principal_def_id): (DefId, Option<DefId>),
486488
) -> bool {
487489
// We only care about trait objects which have associated types.
488490
if !tcx
489-
.associated_items(trait_def_id)
491+
.associated_items(target_trait_def_id)
490492
.in_definition_order()
491493
.any(|item| item.kind == ty::AssocKind::Type)
492494
{
493495
return false;
494496
}
495497

496-
let mut has_impl = false;
497-
tcx.for_each_impl(trait_def_id, |impl_def_id| {
498-
if has_impl {
498+
let target_self_ty =
499+
principal_def_id.map_or(SimplifiedType::MarkerTraitObject, SimplifiedType::Trait);
500+
501+
let elaborated_supertraits =
502+
principal_def_id.into_iter().flat_map(|def_id| tcx.supertrait_def_ids(def_id)).collect();
503+
504+
trait_has_impl_inner(
505+
tcx,
506+
target_trait_def_id,
507+
target_self_ty,
508+
&elaborated_supertraits,
509+
&mut Default::default(),
510+
true,
511+
)
512+
}
513+
514+
fn trait_has_impl_inner<'tcx>(
515+
tcx: TyCtxt<'tcx>,
516+
target_trait_def_id: DefId,
517+
target_self_ty: SimplifiedType<DefId>,
518+
elaborated_supertraits: &FxHashSet<DefId>,
519+
seen_traits: &mut FxHashSet<DefId>,
520+
first_generation: bool,
521+
) -> bool {
522+
if tcx.is_lang_item(target_trait_def_id, LangItem::Sized) {
523+
return false;
524+
}
525+
526+
// If we've encountered a trait in a cycle, then let's just
527+
// consider it to be implemented defensively.
528+
if !seen_traits.insert(target_trait_def_id) {
529+
return true;
530+
}
531+
// Since we don't pass in the set of auto traits, and just the principal,
532+
// consider all auto traits implemented.
533+
if tcx.trait_is_auto(target_trait_def_id) {
534+
return true;
535+
}
536+
if !first_generation && elaborated_supertraits.contains(&target_trait_def_id) {
537+
return true;
538+
}
539+
540+
let mut has_offending_impl = false;
541+
tcx.for_each_impl(target_trait_def_id, |impl_def_id| {
542+
if has_offending_impl {
499543
return;
500544
}
501545

@@ -504,33 +548,51 @@ pub(super) fn trait_has_impl_which_may_shadow_dyn<'tcx>(
504548
.expect("impl must have trait ref")
505549
.instantiate_identity()
506550
.self_ty();
507-
if self_ty.is_known_rigid() {
508-
return;
509-
}
510551

511-
let sized_trait = tcx.require_lang_item(LangItem::Sized, None);
512-
if tcx
513-
.param_env(impl_def_id)
514-
.caller_bounds()
515-
.iter()
516-
.filter_map(|clause| clause.as_trait_clause())
517-
.any(|bound| bound.def_id() == sized_trait && bound.self_ty().skip_binder() == self_ty)
552+
if simplify_type(tcx, self_ty, TreatParams::InstantiateWithInfer)
553+
.is_some_and(|simp| simp != target_self_ty)
518554
{
519555
return;
520556
}
521557

522-
if let ty::Alias(ty::Projection, alias_ty) = self_ty.kind()
523-
&& tcx
524-
.item_super_predicates(alias_ty.def_id)
525-
.iter_identity()
526-
.filter_map(|clause| clause.as_trait_clause())
527-
.any(|bound| bound.def_id() == sized_trait)
558+
for (pred, _) in
559+
elaborate::elaborate(tcx, tcx.predicates_of(impl_def_id).instantiate_identity(tcx))
528560
{
529-
return;
561+
if let ty::ClauseKind::Trait(trait_pred) = pred.kind().skip_binder()
562+
&& trait_pred.self_ty() == self_ty
563+
&& !trait_has_impl_inner(
564+
tcx,
565+
trait_pred.def_id(),
566+
target_self_ty,
567+
elaborated_supertraits,
568+
seen_traits,
569+
false,
570+
)
571+
{
572+
return;
573+
}
574+
}
575+
576+
if let ty::Alias(ty::Projection, alias_ty) = self_ty.kind() {
577+
for pred in tcx.item_super_predicates(alias_ty.def_id).iter_identity() {
578+
if let ty::ClauseKind::Trait(trait_pred) = pred.kind().skip_binder()
579+
&& trait_pred.self_ty() == self_ty
580+
&& !trait_has_impl_inner(
581+
tcx,
582+
trait_pred.def_id(),
583+
target_self_ty,
584+
elaborated_supertraits,
585+
seen_traits,
586+
false,
587+
)
588+
{
589+
return;
590+
}
591+
}
530592
}
531593

532-
has_impl = true;
594+
has_offending_impl = true;
533595
});
534596

535-
has_impl
597+
has_offending_impl
536598
}

compiler/rustc_type_ir/src/interner.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,11 @@ pub trait Interner:
274274

275275
fn trait_may_be_implemented_via_object(self, trait_def_id: Self::DefId) -> bool;
276276

277-
fn trait_has_impl_which_may_shadow_dyn(self, trait_def_id: Self::DefId) -> bool;
277+
fn trait_has_impl_which_may_shadow_dyn(
278+
self,
279+
trait_def_id: Self::DefId,
280+
principal_def_id: Option<Self::DefId>,
281+
) -> bool;
278282

279283
fn is_impl_trait_in_trait(self, def_id: Self::DefId) -> bool;
280284

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
//@ check-pass
2+
3+
// Make sure that if we don't disqualify a built-in object impl
4+
// due to a blanket with a trait bound that will never apply to
5+
// the object.
6+
7+
pub trait SimpleService {
8+
type Resp;
9+
}
10+
11+
trait Service {
12+
type Resp;
13+
}
14+
15+
impl<S> Service for S where S: SimpleService + ?Sized {
16+
type Resp = <S as SimpleService>::Resp;
17+
}
18+
19+
fn implements_service(x: &(impl Service<Resp = ()> + ?Sized)) {}
20+
21+
fn test(x: &dyn Service<Resp = ()>) {
22+
implements_service(x);
23+
}
24+
25+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
trait Trait {
2+
type Assoc;
3+
fn generate(&self) -> Self::Assoc;
4+
}
5+
6+
trait Other {}
7+
8+
impl<S> Trait for S where S: Other + ?Sized {
9+
type Assoc = &'static str;
10+
fn generate(&self) -> Self::Assoc { "hi" }
11+
}
12+
13+
trait Downstream: Trait<Assoc = usize> {}
14+
impl<T> Other for T where T: ?Sized + Downstream + OnlyDyn {}
15+
16+
trait OnlyDyn {}
17+
impl OnlyDyn for dyn Downstream {}
18+
19+
struct Concrete;
20+
impl Trait for Concrete {
21+
type Assoc = usize;
22+
fn generate(&self) -> Self::Assoc { 42 }
23+
}
24+
impl Downstream for Concrete {}
25+
26+
fn test<T: ?Sized + Other>(x: &T) {
27+
let s: &str = x.generate();
28+
println!("{s}");
29+
}
30+
31+
fn impl_downstream<T: ?Sized + Downstream>(x: &T) {}
32+
33+
fn main() {
34+
let x: &dyn Downstream = &Concrete;
35+
36+
test(x); // This call used to segfault.
37+
//~^ ERROR type mismatch resolving
38+
39+
// This no longer holds since `Downstream: Trait<Assoc = usize>`,
40+
// but the `Trait<Assoc = &'static str>` blanket impl now shadows.
41+
impl_downstream(x);
42+
//~^ ERROR type mismatch resolving
43+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
error[E0271]: type mismatch resolving `<dyn Downstream as Trait>::Assoc == usize`
2+
--> $DIR/indirect-impl-blanket-downstream-trait-2.rs:36:10
3+
|
4+
LL | test(x); // This call used to segfault.
5+
| ---- ^ type mismatch resolving `<dyn Downstream as Trait>::Assoc == usize`
6+
| |
7+
| required by a bound introduced by this call
8+
|
9+
note: expected this to be `usize`
10+
--> $DIR/indirect-impl-blanket-downstream-trait-2.rs:9:18
11+
|
12+
LL | type Assoc = &'static str;
13+
| ^^^^^^^^^^^^
14+
note: required for `dyn Downstream` to implement `Other`
15+
--> $DIR/indirect-impl-blanket-downstream-trait-2.rs:14:9
16+
|
17+
LL | impl<T> Other for T where T: ?Sized + Downstream + OnlyDyn {}
18+
| ^^^^^ ^ ---------- unsatisfied trait bound introduced here
19+
= note: associated types for the current `impl` cannot be restricted in `where` clauses
20+
note: required by a bound in `test`
21+
--> $DIR/indirect-impl-blanket-downstream-trait-2.rs:26:21
22+
|
23+
LL | fn test<T: ?Sized + Other>(x: &T) {
24+
| ^^^^^ required by this bound in `test`
25+
26+
error[E0271]: type mismatch resolving `<dyn Downstream as Trait>::Assoc == usize`
27+
--> $DIR/indirect-impl-blanket-downstream-trait-2.rs:41:21
28+
|
29+
LL | impl_downstream(x);
30+
| --------------- ^ type mismatch resolving `<dyn Downstream as Trait>::Assoc == usize`
31+
| |
32+
| required by a bound introduced by this call
33+
|
34+
note: expected this to be `usize`
35+
--> $DIR/indirect-impl-blanket-downstream-trait-2.rs:9:18
36+
|
37+
LL | type Assoc = &'static str;
38+
| ^^^^^^^^^^^^
39+
note: required by a bound in `impl_downstream`
40+
--> $DIR/indirect-impl-blanket-downstream-trait-2.rs:31:32
41+
|
42+
LL | fn impl_downstream<T: ?Sized + Downstream>(x: &T) {}
43+
| ^^^^^^^^^^ required by this bound in `impl_downstream`
44+
45+
error: aborting due to 2 previous errors
46+
47+
For more information about this error, try `rustc --explain E0271`.

0 commit comments

Comments
 (0)