about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2023-06-14 18:08:47 +0000
committerMichael Goulet <michael@errs.io>2023-06-27 18:28:07 +0000
commit858a861fff3c054f5eccb74c22d061f1765e9cbd (patch)
treeaddf805fb386c058c8755a0938f1b41fe972069f /compiler
parent3c554f5cb4965a08f2a2b45ab4bba321a5f249fa (diff)
downloadrust-858a861fff3c054f5eccb74c22d061f1765e9cbd.tar.gz
rust-858a861fff3c054f5eccb74c22d061f1765e9cbd.zip
Make associated type bounds in supertrait position implied
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_hir_analysis/src/collect/predicates_of.rs104
1 files changed, 54 insertions, 50 deletions
diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
index edb6a4cace3..5605901fbcb 100644
--- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
@@ -532,15 +532,20 @@ pub(super) fn explicit_predicates_of<'tcx>(
 
 #[derive(Copy, Clone, Debug)]
 pub enum PredicateFilter {
-    /// All predicates may be implied by the trait
+    /// All predicates may be implied by the trait.
     All,
 
-    /// Only traits that reference `Self: ..` are implied by the trait
+    /// Only traits that reference `Self: ..` are implied by the trait.
     SelfOnly,
 
     /// Only traits that reference `Self: ..` and define an associated type
-    /// with the given ident are implied by the trait
+    /// with the given ident are implied by the trait.
     SelfThatDefines(Ident),
+
+    /// Only traits that reference `Self: ..` and their associated type bounds.
+    /// For example, given `Self: Tr<A: B>`, this would expand to `Self: Tr`
+    /// and `<Self as Tr>::A: B`.
+    SelfAndAssociatedTypeBounds,
 }
 
 /// Ensures that the super-predicates of the trait with a `DefId`
@@ -564,11 +569,15 @@ pub(super) fn implied_predicates_of(
     tcx: TyCtxt<'_>,
     trait_def_id: LocalDefId,
 ) -> ty::GenericPredicates<'_> {
-    if tcx.is_trait_alias(trait_def_id.to_def_id()) {
-        implied_predicates_with_filter(tcx, trait_def_id.to_def_id(), PredicateFilter::All)
-    } else {
-        tcx.super_predicates_of(trait_def_id)
-    }
+    implied_predicates_with_filter(
+        tcx,
+        trait_def_id.to_def_id(),
+        if tcx.is_trait_alias(trait_def_id.to_def_id()) {
+            PredicateFilter::All
+        } else {
+            PredicateFilter::SelfAndAssociatedTypeBounds
+        },
+    )
 }
 
 /// Ensures that the super-predicates of the trait with a `DefId`
@@ -601,45 +610,28 @@ pub(super) fn implied_predicates_with_filter(
     let icx = ItemCtxt::new(tcx, trait_def_id);
 
     let self_param_ty = tcx.types.self_param;
-    let (superbounds, where_bounds_that_match) = match filter {
-        PredicateFilter::All => (
-            // Convert the bounds that follow the colon (or equal in trait aliases)
-            icx.astconv().compute_bounds(self_param_ty, bounds, OnlySelfBounds(false)),
-            // Also include all where clause bounds
-            icx.type_parameter_bounds_in_generics(
-                generics,
-                item.owner_id.def_id,
-                self_param_ty,
-                OnlySelfBounds(false),
-                None,
-            ),
-        ),
-        PredicateFilter::SelfOnly => (
-            // Convert the bounds that follow the colon (or equal in trait aliases)
-            icx.astconv().compute_bounds(self_param_ty, bounds, OnlySelfBounds(true)),
-            // Include where clause bounds for `Self`
-            icx.type_parameter_bounds_in_generics(
-                generics,
-                item.owner_id.def_id,
-                self_param_ty,
-                OnlySelfBounds(true),
-                None,
-            ),
-        ),
-        PredicateFilter::SelfThatDefines(assoc_name) => (
-            // Convert the bounds that follow the colon (or equal) that reference the associated name
-            icx.astconv().compute_bounds_that_match_assoc_item(self_param_ty, bounds, assoc_name),
-            // Include where clause bounds for `Self` that reference the associated name
-            icx.type_parameter_bounds_in_generics(
-                generics,
-                item.owner_id.def_id,
-                self_param_ty,
-                OnlySelfBounds(true),
-                Some(assoc_name),
-            ),
-        ),
+    let superbounds = match filter {
+        // Should imply both "real" supertraits, and also associated type bounds
+        // from the supertraits position.
+        PredicateFilter::All | PredicateFilter::SelfAndAssociatedTypeBounds => {
+            icx.astconv().compute_bounds(self_param_ty, bounds, OnlySelfBounds(false))
+        }
+        // Should only imply "real" supertraits, i.e. predicates with the self type `Self`.
+        PredicateFilter::SelfOnly => {
+            icx.astconv().compute_bounds(self_param_ty, bounds, OnlySelfBounds(true))
+        }
+        PredicateFilter::SelfThatDefines(assoc_name) => {
+            icx.astconv().compute_bounds_that_match_assoc_item(self_param_ty, bounds, assoc_name)
+        }
     };
 
+    let where_bounds_that_match = icx.type_parameter_bounds_in_generics(
+        generics,
+        item.owner_id.def_id,
+        self_param_ty,
+        filter,
+    );
+
     // Combine the two lists to form the complete set of superbounds:
     let implied_bounds =
         &*tcx.arena.alloc_from_iter(superbounds.clauses().chain(where_bounds_that_match));
@@ -743,8 +735,7 @@ pub(super) fn type_param_predicates(
             ast_generics,
             def_id,
             ty,
-            OnlySelfBounds(true),
-            Some(assoc_name),
+            PredicateFilter::SelfThatDefines(assoc_name),
         )
         .into_iter()
         .filter(|(predicate, _)| match predicate.kind().skip_binder() {
@@ -768,8 +759,7 @@ impl<'tcx> ItemCtxt<'tcx> {
         ast_generics: &'tcx hir::Generics<'tcx>,
         param_def_id: LocalDefId,
         ty: Ty<'tcx>,
-        only_self_bounds: OnlySelfBounds,
-        assoc_name: Option<Ident>,
+        filter: PredicateFilter,
     ) -> Vec<(ty::Clause<'tcx>, Span)> {
         let mut bounds = Bounds::default();
 
@@ -778,9 +768,23 @@ impl<'tcx> ItemCtxt<'tcx> {
                 continue;
             };
 
+            let (only_self_bounds, assoc_name) = match filter {
+                PredicateFilter::All | PredicateFilter::SelfAndAssociatedTypeBounds => {
+                    (OnlySelfBounds(false), None)
+                }
+                PredicateFilter::SelfOnly => (OnlySelfBounds(true), None),
+                PredicateFilter::SelfThatDefines(assoc_name) => {
+                    (OnlySelfBounds(true), Some(assoc_name))
+                }
+            };
+
+            // Subtle: If we're collecting `SelfAndAssociatedTypeBounds`, then we
+            // want to only consider predicates with `Self: ...`, but we don't want
+            // `OnlySelfBounds(true)` since we want to collect the nested associated
+            // type bound as well.
             let bound_ty = if predicate.is_param_bound(param_def_id.to_def_id()) {
                 ty
-            } else if !only_self_bounds.0 {
+            } else if matches!(filter, PredicateFilter::All) {
                 self.to_ty(predicate.bounded_ty)
             } else {
                 continue;