Skip to content

Commit 1a961a0

Browse files
committed
Auto merge of rust-lang#132289 - compiler-errors:vanquish-dyn-incompleteness, r=<try>
Disqualify built-in trait impl if it seems likely to overlap in an unsound way with a blanket impl cc rust-lang#57893 r? lcnr
2 parents 2d0ea79 + bb80bba commit 1a961a0

22 files changed

+453
-20
lines changed

compiler/rustc_middle/src/query/keys.rs

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

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

compiler/rustc_middle/src/query/mod.rs

+9
Original file line numberDiff line numberDiff line change
@@ -1370,6 +1370,15 @@ rustc_queries! {
13701370
desc { |tcx| "checking if trait `{}` is dyn-compatible", tcx.def_path_str(trait_id) }
13711371
}
13721372

1373+
query trait_has_impl_which_may_shadow_dyn(key: (DefId, Option<DefId>)) -> bool {
1374+
desc {
1375+
|tcx| "checking if trait `{}` has an impl which may overlap with \
1376+
the built-in impl for `dyn {}`",
1377+
tcx.def_path_str(key.0),
1378+
key.1.map_or(String::from("..."), |def_id| tcx.def_path_str(def_id)),
1379+
}
1380+
}
1381+
13731382
/// Gets the ParameterEnvironment for a given item; this environment
13741383
/// will be in "user-facing" mode, meaning that it is suitable for
13751384
/// type-checking etc, and it does not normalize specializable

compiler/rustc_middle/src/ty/context.rs

+8
Original file line numberDiff line numberDiff line change
@@ -578,6 +578,14 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
578578
self.trait_def(trait_def_id).implement_via_object
579579
}
580580

581+
fn trait_has_impl_which_may_shadow_dyn(
582+
self,
583+
trait_def_id: DefId,
584+
principal_def_id: Option<DefId>,
585+
) -> bool {
586+
self.trait_has_impl_which_may_shadow_dyn((trait_def_id, principal_def_id))
587+
}
588+
581589
fn is_impl_trait_in_trait(self, def_id: DefId) -> bool {
582590
self.is_impl_trait_in_trait(def_id)
583591
}

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

+11
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,17 @@ where
8282
goal: Goal<I, Self>,
8383
assumption: I::Clause,
8484
) -> Result<Candidate<I>, NoSolution> {
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+
) {
93+
return Err(NoSolution);
94+
}
95+
8596
Self::probe_and_match_goal_against_assumption(ecx, source, goal, assumption, |ecx| {
8697
let cx = ecx.cx();
8798
let ty::Dynamic(bounds, _, _) = goal.predicate.self_ty().kind() else {

compiler/rustc_trait_selection/src/traits/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -824,6 +824,7 @@ pub fn provide(providers: &mut Providers) {
824824
specialization_graph_of: specialize::specialization_graph_provider,
825825
specializes: specialize::specializes,
826826
specialization_enabled_in: specialize::specialization_enabled_in,
827+
trait_has_impl_which_may_shadow_dyn: specialize::trait_has_impl_which_may_shadow_dyn,
827828
instantiate_and_check_impossible_predicates,
828829
is_impossible_associated_item,
829830
..*providers

compiler/rustc_trait_selection/src/traits/project.rs

+6
Original file line numberDiff line numberDiff line change
@@ -842,6 +842,12 @@ fn assemble_candidates_from_object_ty<'cx, 'tcx>(
842842
let env_predicates = data
843843
.projection_bounds()
844844
.filter(|bound| bound.item_def_id() == obligation.predicate.def_id)
845+
.filter(|bound| {
846+
!tcx.trait_has_impl_which_may_shadow_dyn((
847+
bound.trait_def_id(tcx),
848+
data.principal_def_id(),
849+
))
850+
})
845851
.map(|p| p.with_self_ty(tcx, object_ty).upcast(tcx));
846852

847853
assemble_candidates_from_predicates(

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

+12-5
Original file line numberDiff line numberDiff line change
@@ -855,7 +855,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
855855
"assemble_candidates_from_object_ty",
856856
);
857857

858-
if !self.tcx().trait_def(obligation.predicate.def_id()).implement_via_object {
858+
let tcx = self.tcx();
859+
if !tcx.trait_def(obligation.predicate.def_id()).implement_via_object {
859860
return;
860861
}
861862

@@ -876,9 +877,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
876877

877878
if let Some(principal) = data.principal() {
878879
if !self.infcx.tcx.features().dyn_compatible_for_dispatch() {
879-
principal.with_self_ty(self.tcx(), self_ty)
880-
} else if self.tcx().is_dyn_compatible(principal.def_id()) {
881-
principal.with_self_ty(self.tcx(), self_ty)
880+
principal.with_self_ty(tcx, self_ty)
881+
} else if tcx.is_dyn_compatible(principal.def_id()) {
882+
principal.with_self_ty(tcx, self_ty)
882883
} else {
883884
return;
884885
}
@@ -902,7 +903,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
902903
// correct trait, but also the correct type parameters.
903904
// For example, we may be trying to upcast `Foo` to `Bar<i32>`,
904905
// but `Foo` is declared as `trait Foo: Bar<u32>`.
905-
let candidate_supertraits = util::supertraits(self.tcx(), principal_trait_ref)
906+
let candidate_supertraits = util::supertraits(tcx, principal_trait_ref)
906907
.enumerate()
907908
.filter(|&(_, upcast_trait_ref)| {
908909
self.infcx.probe(|_| {
@@ -914,6 +915,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
914915
.is_ok()
915916
})
916917
})
918+
.filter(|(_, trait_ref)| {
919+
!tcx.trait_has_impl_which_may_shadow_dyn((
920+
trait_ref.def_id(),
921+
Some(principal_trait_ref.def_id()),
922+
))
923+
})
917924
.map(|(idx, _)| ObjectCandidate(idx));
918925

919926
candidates.vec.extend(candidate_supertraits);

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

+119-1
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,10 @@
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};
17+
use rustc_hir::LangItem;
1718
use rustc_hir::def_id::{DefId, LocalDefId};
1819
use rustc_infer::infer::DefineOpaqueTypes;
1920
use rustc_middle::bug;
@@ -24,6 +25,8 @@ use rustc_middle::ty::{
2425
};
2526
use rustc_session::lint::builtin::{COHERENCE_LEAK_CHECK, ORDER_DEPENDENT_TRAIT_OBJECTS};
2627
use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, sym};
28+
use rustc_type_ir::elaborate;
29+
use rustc_type_ir::fast_reject::{SimplifiedType, TreatParams, simplify_type};
2730
use specialization_graph::GraphExt;
2831
use tracing::{debug, instrument};
2932

@@ -480,3 +483,118 @@ fn report_conflicting_impls<'tcx>(
480483
}
481484
}
482485
}
486+
487+
pub(super) fn trait_has_impl_which_may_shadow_dyn<'tcx>(
488+
tcx: TyCtxt<'tcx>,
489+
(target_trait_def_id, principal_def_id): (DefId, Option<DefId>),
490+
) -> bool {
491+
// We only care about trait objects which have associated types.
492+
if !tcx
493+
.associated_items(target_trait_def_id)
494+
.in_definition_order()
495+
.any(|item| item.kind == ty::AssocKind::Type)
496+
{
497+
return false;
498+
}
499+
500+
let target_self_ty =
501+
principal_def_id.map_or(SimplifiedType::MarkerTraitObject, SimplifiedType::Trait);
502+
503+
let elaborated_supertraits =
504+
principal_def_id.into_iter().flat_map(|def_id| tcx.supertrait_def_ids(def_id)).collect();
505+
506+
trait_has_impl_inner(
507+
tcx,
508+
target_trait_def_id,
509+
target_self_ty,
510+
&elaborated_supertraits,
511+
&mut Default::default(),
512+
true,
513+
)
514+
}
515+
516+
fn trait_has_impl_inner<'tcx>(
517+
tcx: TyCtxt<'tcx>,
518+
target_trait_def_id: DefId,
519+
target_self_ty: SimplifiedType<DefId>,
520+
elaborated_supertraits: &FxHashSet<DefId>,
521+
seen_traits: &mut FxHashSet<DefId>,
522+
first_generation: bool,
523+
) -> bool {
524+
if tcx.is_lang_item(target_trait_def_id, LangItem::Sized) {
525+
return false;
526+
}
527+
528+
// If we've encountered a trait in a cycle, then let's just
529+
// consider it to be implemented defensively.
530+
if !seen_traits.insert(target_trait_def_id) {
531+
return true;
532+
}
533+
// Since we don't pass in the set of auto traits, and just the principal,
534+
// consider all auto traits implemented.
535+
if tcx.trait_is_auto(target_trait_def_id) {
536+
return true;
537+
}
538+
if !first_generation && elaborated_supertraits.contains(&target_trait_def_id) {
539+
return true;
540+
}
541+
542+
let mut has_offending_impl = false;
543+
tcx.for_each_impl(target_trait_def_id, |impl_def_id| {
544+
if has_offending_impl {
545+
return;
546+
}
547+
548+
let self_ty = tcx
549+
.impl_trait_ref(impl_def_id)
550+
.expect("impl must have trait ref")
551+
.instantiate_identity()
552+
.self_ty();
553+
554+
if simplify_type(tcx, self_ty, TreatParams::InstantiateWithInfer)
555+
.is_some_and(|simp| simp != target_self_ty)
556+
{
557+
return;
558+
}
559+
560+
for (pred, _) in
561+
elaborate::elaborate(tcx, tcx.predicates_of(impl_def_id).instantiate_identity(tcx))
562+
{
563+
if let ty::ClauseKind::Trait(trait_pred) = pred.kind().skip_binder()
564+
&& trait_pred.self_ty() == self_ty
565+
&& !trait_has_impl_inner(
566+
tcx,
567+
trait_pred.def_id(),
568+
target_self_ty,
569+
elaborated_supertraits,
570+
seen_traits,
571+
false,
572+
)
573+
{
574+
return;
575+
}
576+
}
577+
578+
if let ty::Alias(ty::Projection, alias_ty) = self_ty.kind() {
579+
for pred in tcx.item_super_predicates(alias_ty.def_id).iter_identity() {
580+
if let ty::ClauseKind::Trait(trait_pred) = pred.kind().skip_binder()
581+
&& trait_pred.self_ty() == self_ty
582+
&& !trait_has_impl_inner(
583+
tcx,
584+
trait_pred.def_id(),
585+
target_self_ty,
586+
elaborated_supertraits,
587+
seen_traits,
588+
false,
589+
)
590+
{
591+
return;
592+
}
593+
}
594+
}
595+
596+
has_offending_impl = true;
597+
});
598+
599+
has_offending_impl
600+
}

compiler/rustc_type_ir/src/interner.rs

+6
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,12 @@ pub trait Interner:
269269

270270
fn trait_may_be_implemented_via_object(self, trait_def_id: Self::DefId) -> bool;
271271

272+
fn trait_has_impl_which_may_shadow_dyn(
273+
self,
274+
trait_def_id: Self::DefId,
275+
principal_def_id: Option<Self::DefId>,
276+
) -> bool;
277+
272278
fn is_impl_trait_in_trait(self, def_id: Self::DefId) -> bool;
273279

274280
fn delay_bug(self, msg: impl ToString) -> Self::ErrorGuaranteed;

compiler/rustc_type_ir/src/predicate.rs

+4
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,10 @@ impl<I: Interner> ty::Binder<I, ExistentialProjection<I>> {
433433
pub fn item_def_id(&self) -> I::DefId {
434434
self.skip_binder().def_id
435435
}
436+
437+
pub fn trait_def_id(self, interner: I) -> I::DefId {
438+
interner.parent(self.skip_binder().def_id)
439+
}
436440
}
437441

438442
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
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+
}

0 commit comments

Comments
 (0)