about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2025-05-07 16:55:21 +0000
committerPietro Albini <pietro@pietroalbini.org>2025-05-09 18:12:13 +0200
commitd800540c12f6da4f2006ff2b13ea64a6883857bf (patch)
tree1804e77836e03d19ee5c8e59530397e1a0674bc5
parent2f71d0a243f31f346f868808f8ff5892a8ff8279 (diff)
downloadrust-d800540c12f6da4f2006ff2b13ea64a6883857bf.tar.gz
rust-d800540c12f6da4f2006ff2b13ea64a6883857bf.zip
Review
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs25
-rw-r--r--tests/ui/traits/object/constrain-via-unnecessary-bound.rs2
2 files changed, 21 insertions, 6 deletions
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
index 19f80751d05..8be8ea1cc1c 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
@@ -146,7 +146,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
 
         let principal_trait = regular_traits.into_iter().next();
 
-        let mut needed_associated_types = vec![];
+        // A stable ordering of associated types from the principal trait and all its
+        // supertraits. We use this to ensure that different substitutions of a trait
+        // don't result in `dyn Trait` types with different projections lists, which
+        // can be unsound: <https://github.com/rust-lang/rust/pull/136458>.
+        // We achieve a stable ordering by walking over the unsubstituted principal
+        // trait ref.
+        let mut ordered_associated_types = vec![];
+
         if let Some((principal_trait, ref spans)) = principal_trait {
             let principal_trait = principal_trait.map_bound(|trait_pred| {
                 assert_eq!(trait_pred.polarity, ty::PredicatePolarity::Positive);
@@ -171,7 +178,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                         // FIXME(negative_bounds): Handle this correctly...
                         let trait_ref =
                             tcx.anonymize_bound_vars(bound_predicate.rebind(pred.trait_ref));
-                        needed_associated_types.extend(
+                        ordered_associated_types.extend(
                             tcx.associated_items(pred.trait_ref.def_id)
                                 .in_definition_order()
                                 // We only care about associated types.
@@ -249,15 +256,23 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             }
         }
 
+        // We compute the list of projection bounds taking the ordered associated types,
+        // and check if there was an entry in the collected `projection_bounds`. Those
+        // are computed by first taking the user-written associated types, then elaborating
+        // the principal trait ref, and only using those if there was no user-written.
+        // See note below about how we handle missing associated types with `Self: Sized`,
+        // which are not required to be provided, but are still used if they are provided.
         let mut missing_assoc_types = FxIndexSet::default();
-        let projection_bounds: Vec<_> = needed_associated_types
+        let projection_bounds: Vec<_> = ordered_associated_types
             .into_iter()
             .filter_map(|key| {
                 if let Some(assoc) = projection_bounds.get(&key) {
                     Some(*assoc)
                 } else {
-                    // If the associated type has a `where Self: Sized` bound,
-                    // we do not need to constrain the associated type.
+                    // If the associated type has a `where Self: Sized` bound, then
+                    // we do not need to provide the associated type. This results in
+                    // a `dyn Trait` type that has a different number of projection
+                    // bounds, which may lead to type mismatches.
                     if !tcx.generics_require_sized_self(key.0) {
                         missing_assoc_types.insert(key);
                     }
diff --git a/tests/ui/traits/object/constrain-via-unnecessary-bound.rs b/tests/ui/traits/object/constrain-via-unnecessary-bound.rs
index 5534471fb27..4640d6b3ed5 100644
--- a/tests/ui/traits/object/constrain-via-unnecessary-bound.rs
+++ b/tests/ui/traits/object/constrain-via-unnecessary-bound.rs
@@ -13,7 +13,7 @@ pub trait Trait {
 }
 
 impl Other for dyn Trait {}
-// `dyn Trait<Assoc = ()>` is a different "nominal type" than `dyn Traiat`.
+// `dyn Trait<Assoc = ()>` is a different "nominal type" than `dyn Trait`.
 impl Other for dyn Trait<Assoc = ()> {}
 //~^ WARN unnecessary associated type bound for dyn-incompatible associated type