about summary refs log tree commit diff
diff options
context:
space:
mode:
authorStuart Cook <Zalathar@users.noreply.github.com>2025-04-08 20:55:09 +1000
committerGitHub <noreply@github.com>2025-04-08 20:55:09 +1000
commit056756c7c4db570f93f8586828648fe02480dcb4 (patch)
tree296476047e75fc891e2173ed9d278e81ca7da0b8
parentab80f575c485eccd57a86a92a7aabad5815270d7 (diff)
parent45afefa7c025f3847439822b053edf76ae62e561 (diff)
downloadrust-056756c7c4db570f93f8586828648fe02480dcb4.tar.gz
rust-056756c7c4db570f93f8586828648fe02480dcb4.zip
Rollup merge of #139421 - compiler-errors:upcast-no-principal-with-proj, r=oli-obk
Fix trait upcasting to dyn type with no principal when there are projections

#126660 (which I had originally authored, lol) had a subtle bug that is the moral equivalent of #114036, which is that when upcasting from `dyn Principal<Projection = Ty> + AutoTrait` to `dyn AutoTrait`, we were dropping the trait ref for `Principal` but not its projections (if there were any).

With debug assertions enabled, this triggers the assertion I luckily added in a2a0cfe82563146325674b8d437f9f9f6e703703, but even without debug assertions this is a logical bug since we had a dyn type with just a projection bound but no principal, so it caused a type mismatch.

This does not need an FCP because this should've been covered by the FCP in #126660, but we just weren't testing a case when casting from a `dyn` type with projections 😸

Fixes #139418

r? ````@oli-obk```` (or anyone)
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs38
-rw-r--r--tests/ui/traits/dyn-drop-principal-with-projections.rs13
2 files changed, 37 insertions, 14 deletions
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index 2cb7d2d8931..9d5eb551fe6 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -1090,26 +1090,36 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             {
                 // See `assemble_candidates_for_unsizing` for more info.
                 // We already checked the compatibility of auto traits within `assemble_candidates_for_unsizing`.
-                let iter = data_a
-                    .principal()
-                    .filter(|_| {
-                        // optionally drop the principal, if we're unsizing to no principal
-                        data_b.principal().is_some()
-                    })
-                    .map(|b| b.map_bound(ty::ExistentialPredicate::Trait))
-                    .into_iter()
-                    .chain(
+                let existential_predicates = if data_b.principal().is_some() {
+                    tcx.mk_poly_existential_predicates_from_iter(
                         data_a
-                            .projection_bounds()
-                            .map(|b| b.map_bound(ty::ExistentialPredicate::Projection)),
+                            .principal()
+                            .map(|b| b.map_bound(ty::ExistentialPredicate::Trait))
+                            .into_iter()
+                            .chain(
+                                data_a
+                                    .projection_bounds()
+                                    .map(|b| b.map_bound(ty::ExistentialPredicate::Projection)),
+                            )
+                            .chain(
+                                data_b
+                                    .auto_traits()
+                                    .map(ty::ExistentialPredicate::AutoTrait)
+                                    .map(ty::Binder::dummy),
+                            ),
                     )
-                    .chain(
+                } else {
+                    // If we're unsizing to a dyn type that has no principal, then drop
+                    // the principal and projections from the type. We use the auto traits
+                    // from the RHS type since as we noted that we've checked for auto
+                    // trait compatibility during unsizing.
+                    tcx.mk_poly_existential_predicates_from_iter(
                         data_b
                             .auto_traits()
                             .map(ty::ExistentialPredicate::AutoTrait)
                             .map(ty::Binder::dummy),
-                    );
-                let existential_predicates = tcx.mk_poly_existential_predicates_from_iter(iter);
+                    )
+                };
                 let source_trait = Ty::new_dynamic(tcx, existential_predicates, r_b, dyn_a);
 
                 // Require that the traits involved in this upcast are **equal**;
diff --git a/tests/ui/traits/dyn-drop-principal-with-projections.rs b/tests/ui/traits/dyn-drop-principal-with-projections.rs
new file mode 100644
index 00000000000..912061847c6
--- /dev/null
+++ b/tests/ui/traits/dyn-drop-principal-with-projections.rs
@@ -0,0 +1,13 @@
+//@ check-pass
+
+trait Tr {
+    type Assoc;
+}
+
+impl Tr for () {
+    type Assoc = ();
+}
+
+fn main() {
+    let x = &() as &(dyn Tr<Assoc = ()> + Send) as &dyn Send;
+}