Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 264a7c4

Browse files
committedOct 28, 2024·
Auto merge of rust-lang#132289 - compiler-errors:vanquish-dyn-incompleteness, r=<try>
Disqualify built-in trait impl if it seems likely to be overlap in an unsound way with a blanket impl r? lcnr
2 parents 3f1be1e + 3ee780b commit 264a7c4

File tree

14 files changed

+161
-18
lines changed

14 files changed

+161
-18
lines changed
 

‎compiler/rustc_middle/src/query/mod.rs

+8
Original file line numberDiff line numberDiff line change
@@ -1371,6 +1371,14 @@ 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 {
1375+
desc {
1376+
|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)
1379+
}
1380+
}
1381+
13741382
/// Gets the ParameterEnvironment for a given item; this environment
13751383
/// will be in "user-facing" mode, meaning that it is suitable for
13761384
/// type-checking etc, and it does not normalize specializable

‎compiler/rustc_middle/src/ty/context.rs

+4
Original file line numberDiff line numberDiff line change
@@ -581,6 +581,10 @@ 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)
586+
}
587+
584588
fn is_impl_trait_in_trait(self, def_id: DefId) -> bool {
585589
self.is_impl_trait_in_trait(def_id)
586590
}

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

+4
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,10 @@ 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())) {
86+
return Err(NoSolution);
87+
}
88+
8589
Self::probe_and_match_goal_against_assumption(ecx, source, goal, assumption, |ecx| {
8690
let cx = ecx.cx();
8791
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
@@ -601,6 +601,7 @@ pub fn provide(providers: &mut Providers) {
601601
specialization_graph_of: specialize::specialization_graph_provider,
602602
specializes: specialize::specializes,
603603
specialization_enabled_in: specialize::specialization_enabled_in,
604+
trait_has_impl_which_may_shadow_dyn: specialize::trait_has_impl_which_may_shadow_dyn,
604605
instantiate_and_check_impossible_predicates,
605606
is_impossible_associated_item,
606607
..*providers

‎compiler/rustc_trait_selection/src/traits/project.rs

+1
Original file line numberDiff line numberDiff line change
@@ -864,6 +864,7 @@ 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)))
867868
.map(|p| p.with_self_ty(tcx, object_ty).upcast(tcx));
868869

869870
assemble_candidates_from_predicates(

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

+9-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,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
914915
.is_ok()
915916
})
916917
})
918+
.filter(|(_, trait_ref)| {
919+
!tcx.trait_has_impl_which_may_shadow_dyn(trait_ref.def_id())
920+
})
917921
.map(|(idx, _)| ObjectCandidate(idx));
918922

919923
candidates.vec.extend(candidate_supertraits);

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

+56
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ pub mod specialization_graph;
1414
use rustc_data_structures::fx::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;
@@ -478,3 +479,58 @@ fn report_conflicting_impls<'tcx>(
478479
}
479480
}
480481
}
482+
483+
pub(super) fn trait_has_impl_which_may_shadow_dyn<'tcx>(
484+
tcx: TyCtxt<'tcx>,
485+
trait_def_id: DefId,
486+
) -> bool {
487+
// We only care about trait objects which have associated types.
488+
if !tcx
489+
.associated_items(trait_def_id)
490+
.in_definition_order()
491+
.any(|item| item.kind == ty::AssocKind::Type)
492+
{
493+
return false;
494+
}
495+
496+
let mut has_impl = false;
497+
tcx.for_each_impl(trait_def_id, |impl_def_id| {
498+
if has_impl {
499+
return;
500+
}
501+
502+
let self_ty = tcx
503+
.impl_trait_ref(impl_def_id)
504+
.expect("impl must have trait ref")
505+
.instantiate_identity()
506+
.self_ty();
507+
if self_ty.is_known_rigid() {
508+
return;
509+
}
510+
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)
518+
{
519+
return;
520+
}
521+
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)
528+
{
529+
return;
530+
}
531+
532+
has_impl = true;
533+
});
534+
535+
has_impl
536+
}

‎compiler/rustc_type_ir/src/interner.rs

+2
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,8 @@ 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;
278+
277279
fn is_impl_trait_in_trait(self, def_id: Self::DefId) -> bool;
278280

279281
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
@@ -434,6 +434,10 @@ impl<I: Interner> ty::Binder<I, ExistentialProjection<I>> {
434434
pub fn item_def_id(&self) -> I::DefId {
435435
self.skip_binder().def_id
436436
}
437+
438+
pub fn trait_def_id(self, interner: I) -> I::DefId {
439+
interner.parent(self.skip_binder().def_id)
440+
}
437441
}
438442

439443
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/indirect-impl-for-trait-obj-coherence.rs:23:41
3+
|
4+
LL | fn transmute<T, U>(x: T) -> U {
5+
| - - expected type parameter
6+
| |
7+
| found type parameter
8+
LL | foo::<dyn Object<U, Output = T>, U>(x)
9+
| ----------------------------------- ^ expected type parameter `U`, found type parameter `T`
10+
| |
11+
| arguments to this function are incorrect
12+
|
13+
= note: expected type parameter `U`
14+
found type parameter `T`
15+
= note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound
16+
= note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
17+
note: function defined here
18+
--> $DIR/indirect-impl-for-trait-obj-coherence.rs:17:4
19+
|
20+
LL | fn foo<T: ?Sized, U>(x: <T as Object<U>>::Output) -> U {
21+
| ^^^ ---------------------------
22+
23+
error: aborting due to 1 previous error
24+
25+
For more information about this error, try `rustc --explain E0308`.
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,25 @@
1-
error[E0284]: type annotations needed: cannot normalize `<dyn Object<U, Output = T> as Object<U>>::Output`
2-
--> $DIR/indirect-impl-for-trait-obj-coherence.rs:25:41
1+
error[E0308]: mismatched types
2+
--> $DIR/indirect-impl-for-trait-obj-coherence.rs:23:41
33
|
4+
LL | fn transmute<T, U>(x: T) -> U {
5+
| - - expected type parameter
6+
| |
7+
| found type parameter
48
LL | foo::<dyn Object<U, Output = T>, U>(x)
5-
| ^ cannot normalize `<dyn Object<U, Output = T> as Object<U>>::Output`
9+
| ----------------------------------- ^ expected type parameter `U`, found type parameter `T`
10+
| |
11+
| arguments to this function are incorrect
12+
|
13+
= note: expected type parameter `U`
14+
found type parameter `T`
15+
= note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound
16+
= note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
17+
note: function defined here
18+
--> $DIR/indirect-impl-for-trait-obj-coherence.rs:17:4
19+
|
20+
LL | fn foo<T: ?Sized, U>(x: <T as Object<U>>::Output) -> U {
21+
| ^^^ ---------------------------
622

723
error: aborting due to 1 previous error
824

9-
For more information about this error, try `rustc --explain E0284`.
25+
For more information about this error, try `rustc --explain E0308`.

‎tests/ui/coherence/indirect-impl-for-trait-obj-coherence.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
//@ revisions: current next
22
//@[next] compile-flags: -Znext-solver
33
//@ ignore-compare-mode-next-solver (explicit revisions)
4-
//@[current] check-pass
5-
//@[current] known-bug: #57893
64

75
// Should fail. Because we see an impl that uses a certain associated type, we
86
// type-check assuming that impl is used. However, this conflicts with the
@@ -23,7 +21,7 @@ fn foo<T: ?Sized, U>(x: <T as Object<U>>::Output) -> U {
2321
#[allow(dead_code)]
2422
fn transmute<T, U>(x: T) -> U {
2523
foo::<dyn Object<U, Output = T>, U>(x)
26-
//[next]~^ ERROR type annotations needed: cannot normalize `<dyn Object<U, Output = T> as Object<U>>::Output`
24+
//~^ ERROR mismatched types
2725
}
2826

2927
fn main() {}

‎tests/ui/dyn-compatibility/almost-supertrait-associated-type.rs

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ fn transmute<T, U>(t: T) -> U {
77
(&PhantomData::<T> as &dyn Foo<T, U>).transmute(t)
88
//~^ ERROR the trait `Foo` cannot be made into an object
99
//~| ERROR the trait `Foo` cannot be made into an object
10+
//~| ERROR the trait bound `dyn Foo<T, U>: Super<ActuallySuper>` is not satisfied
1011
}
1112

1213
struct ActuallySuper;

‎tests/ui/dyn-compatibility/almost-supertrait-associated-type.stderr

+25-6
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
error[E0038]: the trait `Foo` cannot be made into an object
2-
--> $DIR/almost-supertrait-associated-type.rs:21:20
2+
--> $DIR/almost-supertrait-associated-type.rs:22:20
33
|
44
LL | impl<T, U> Dyn for dyn Foo<T, U> + '_ {
55
| ^^^^^^^^^^^^^^^^^^ `Foo` cannot be made into an object
66
|
77
note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
8-
--> $DIR/almost-supertrait-associated-type.rs:33:34
8+
--> $DIR/almost-supertrait-associated-type.rs:34:34
99
|
1010
LL | trait Foo<T, U>: Super<ActuallySuper, Assoc = T>
1111
| --- this trait cannot be made into an object...
@@ -15,14 +15,32 @@ LL | fn transmute(&self, t: T) -> <Self as Super<NotActuallySuper>>::Assoc;
1515
= help: consider moving `transmute` to another trait
1616
= help: only type `std::marker::PhantomData<T>` implements the trait, consider using it directly instead
1717

18+
error[E0277]: the trait bound `dyn Foo<T, U>: Super<ActuallySuper>` is not satisfied
19+
--> $DIR/almost-supertrait-associated-type.rs:7:43
20+
|
21+
LL | (&PhantomData::<T> as &dyn Foo<T, U>).transmute(t)
22+
| ^^^^^^^^^ the trait `Super<ActuallySuper>` is not implemented for `dyn Foo<T, U>`
23+
|
24+
= help: the following other types implement trait `Super<Q>`:
25+
`PhantomData<T>` implements `Super<ActuallySuper>`
26+
`PhantomData<T>` implements `Super<NotActuallySuper>`
27+
note: required by a bound in `Foo::transmute`
28+
--> $DIR/almost-supertrait-associated-type.rs:30:18
29+
|
30+
LL | trait Foo<T, U>: Super<ActuallySuper, Assoc = T>
31+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Foo::transmute`
32+
...
33+
LL | fn transmute(&self, t: T) -> <Self as Super<NotActuallySuper>>::Assoc;
34+
| --------- required by a bound in this associated function
35+
1836
error[E0038]: the trait `Foo` cannot be made into an object
1937
--> $DIR/almost-supertrait-associated-type.rs:7:27
2038
|
2139
LL | (&PhantomData::<T> as &dyn Foo<T, U>).transmute(t)
2240
| ^^^^^^^^^^^^^^ `Foo` cannot be made into an object
2341
|
2442
note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
25-
--> $DIR/almost-supertrait-associated-type.rs:33:34
43+
--> $DIR/almost-supertrait-associated-type.rs:34:34
2644
|
2745
LL | trait Foo<T, U>: Super<ActuallySuper, Assoc = T>
2846
| --- this trait cannot be made into an object...
@@ -39,7 +57,7 @@ LL | (&PhantomData::<T> as &dyn Foo<T, U>).transmute(t)
3957
| ^^^^^^^^^^^^^^^^^ `Foo` cannot be made into an object
4058
|
4159
note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
42-
--> $DIR/almost-supertrait-associated-type.rs:33:34
60+
--> $DIR/almost-supertrait-associated-type.rs:34:34
4361
|
4462
LL | trait Foo<T, U>: Super<ActuallySuper, Assoc = T>
4563
| --- this trait cannot be made into an object...
@@ -50,6 +68,7 @@ LL | fn transmute(&self, t: T) -> <Self as Super<NotActuallySuper>>::Assoc;
5068
= help: only type `std::marker::PhantomData<T>` implements the trait, consider using it directly instead
5169
= note: required for the cast from `&PhantomData<T>` to `&dyn Foo<T, U>`
5270

53-
error: aborting due to 3 previous errors
71+
error: aborting due to 4 previous errors
5472

55-
For more information about this error, try `rustc --explain E0038`.
73+
Some errors have detailed explanations: E0038, E0277.
74+
For more information about an error, try `rustc --explain E0038`.

0 commit comments

Comments
 (0)
Please sign in to comment.