about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-05-10 00:40:57 +0000
committerbors <bors@rust-lang.org>2022-05-10 00:40:57 +0000
commit362010d6be0e551fa35c6e0488abb18686b2add4 (patch)
treeac3d6255176d0d119485e26d9b878cb685243511 /compiler
parentcb390735b03aa44229ff2858be8fedbd7b0ce7cb (diff)
parente947fad68cc7dce9285364984931dc1f286b9fa3 (diff)
Auto merge of #96715 - cjgillot:trait-alias-loop, r=compiler-errors
Fortify handing of where bounds on trait & trait alias definitions

Closes https://github.com/rust-lang/rust/issues/96664
Closes https://github.com/rust-lang/rust/issues/96665

Since https://github.com/rust-lang/rust/pull/93803, when listing all bounds and predicates we now need to account for the possible presence of predicates on any of the generic parameters.  Both bugs were hidden by the special handling of bounds at  the generic parameter declaration position.

Trait alias expansion used to confuse predicates on `Self` and where predicates.
Exiting too late when listing all the bounds caused a cycle error.
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_error_messages/locales/en-US/typeck.ftl1
-rw-r--r--compiler/rustc_trait_selection/src/traits/util.rs3
-rw-r--r--compiler/rustc_typeck/src/astconv/mod.rs14
-rw-r--r--compiler/rustc_typeck/src/collect.rs13
-rw-r--r--compiler/rustc_typeck/src/errors.rs2
5 files changed, 24 insertions, 9 deletions
diff --git a/compiler/rustc_error_messages/locales/en-US/typeck.ftl b/compiler/rustc_error_messages/locales/en-US/typeck.ftl
index aef18fcafaa..9195d7a2b8f 100644
--- a/compiler/rustc_error_messages/locales/en-US/typeck.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/typeck.ftl
@@ -45,6 +45,7 @@ typeck-copy-impl-on-non-adt =
 
 typeck-trait-object-declared-with-no-traits =
     at least one trait is required for an object type
+    .alias-span = this alias does not contain a trait
 
 typeck-ambiguous-lifetime-bound =
     ambiguous lifetime bound, explicit lifetime bound required
diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs
index 7543d1f9a7b..d101f69096f 100644
--- a/compiler/rustc_trait_selection/src/traits/util.rs
+++ b/compiler/rustc_trait_selection/src/traits/util.rs
@@ -118,13 +118,14 @@ impl<'tcx> TraitAliasExpander<'tcx> {
 
         // Get components of trait alias.
         let predicates = tcx.super_predicates_of(trait_ref.def_id());
+        debug!(?predicates);
 
         let items = predicates.predicates.iter().rev().filter_map(|(pred, span)| {
             pred.subst_supertrait(tcx, &trait_ref)
                 .to_opt_poly_trait_pred()
                 .map(|trait_ref| item.clone_and_push(trait_ref.map_bound(|t| t.trait_ref), *span))
         });
-        debug!("expand_trait_aliases: items={:?}", items.clone());
+        debug!("expand_trait_aliases: items={:?}", items.clone().collect::<Vec<_>>());
 
         self.stack.extend(items);
 
diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs
index 3c1676b1aac..e940d065a99 100644
--- a/compiler/rustc_typeck/src/astconv/mod.rs
+++ b/compiler/rustc_typeck/src/astconv/mod.rs
@@ -1064,6 +1064,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         let mut bounds = Bounds::default();
 
         self.add_bounds(param_ty, ast_bounds.iter(), &mut bounds, ty::List::empty());
+        debug!(?bounds);
 
         bounds
     }
@@ -1327,8 +1328,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         // is used and no 'maybe' bounds are used.
         let expanded_traits =
             traits::expand_trait_aliases(tcx, bounds.trait_bounds.iter().map(|&(a, b, _)| (a, b)));
-        let (mut auto_traits, regular_traits): (Vec<_>, Vec<_>) =
-            expanded_traits.partition(|i| tcx.trait_is_auto(i.trait_ref().def_id()));
+        let (mut auto_traits, regular_traits): (Vec<_>, Vec<_>) = expanded_traits
+            .filter(|i| i.trait_ref().self_ty().skip_binder() == dummy_self)
+            .partition(|i| tcx.trait_is_auto(i.trait_ref().def_id()));
         if regular_traits.len() > 1 {
             let first_trait = &regular_traits[0];
             let additional_trait = &regular_traits[1];
@@ -1362,7 +1364,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         }
 
         if regular_traits.is_empty() && auto_traits.is_empty() {
-            tcx.sess.emit_err(TraitObjectDeclaredWithNoTraits { span });
+            let trait_alias_span = bounds
+                .trait_bounds
+                .iter()
+                .map(|&(trait_ref, _, _)| trait_ref.def_id())
+                .find(|&trait_ref| tcx.is_trait_alias(trait_ref))
+                .map(|trait_ref| tcx.def_span(trait_ref));
+            tcx.sess.emit_err(TraitObjectDeclaredWithNoTraits { span, trait_alias_span });
             return tcx.ty_error();
         }
 
diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs
index 74714d75fa0..2e0e026631b 100644
--- a/compiler/rustc_typeck/src/collect.rs
+++ b/compiler/rustc_typeck/src/collect.rs
@@ -52,6 +52,7 @@ use std::iter;
 mod item_bounds;
 mod type_of;
 
+#[derive(Debug)]
 struct OnlySelfBounds(bool);
 
 ///////////////////////////////////////////////////////////////////////////
@@ -650,6 +651,7 @@ impl<'tcx> ItemCtxt<'tcx> {
     /// AST. We do this to avoid having to convert *all* the bounds, which
     /// would create artificial cycles. Instead, we can only convert the
     /// bounds for a type parameter `X` if `X::Foo` is used.
+    #[instrument(level = "trace", skip(self, ast_generics))]
     fn type_parameter_bounds_in_generics(
         &self,
         ast_generics: &'tcx hir::Generics<'tcx>,
@@ -659,6 +661,7 @@ impl<'tcx> ItemCtxt<'tcx> {
         assoc_name: Option<Ident>,
     ) -> Vec<(ty::Predicate<'tcx>, Span)> {
         let param_def_id = self.tcx.hir().local_def_id(param_id).to_def_id();
+        debug!(?param_def_id);
         ast_generics
             .predicates
             .iter()
@@ -676,13 +679,12 @@ impl<'tcx> ItemCtxt<'tcx> {
                 };
                 let bvars = self.tcx.late_bound_vars(bp.bounded_ty.hir_id);
 
-                bp.bounds
-                    .iter()
-                    .filter(|b| match assoc_name {
+                bp.bounds.iter().filter_map(move |b| bt.map(|bt| (bt, b, bvars))).filter(
+                    |(_, b, _)| match assoc_name {
                         Some(assoc_name) => self.bound_defines_assoc_item(b, assoc_name),
                         None => true,
-                    })
-                    .filter_map(move |b| bt.map(|bt| (bt, b, bvars)))
+                    },
+                )
             })
             .flat_map(|(bt, b, bvars)| predicates_from_bound(self, bt, b, bvars))
             .collect()
@@ -1140,6 +1142,7 @@ fn super_predicates_that_define_assoc_type(
 
         // Combine the two lists to form the complete set of superbounds:
         let superbounds = &*tcx.arena.alloc_from_iter(superbounds1.into_iter().chain(superbounds2));
+        debug!(?superbounds);
 
         // Now require that immediate supertraits are converted,
         // which will, in turn, reach indirect supertraits.
diff --git a/compiler/rustc_typeck/src/errors.rs b/compiler/rustc_typeck/src/errors.rs
index a3e7108caae..81d4c9135ef 100644
--- a/compiler/rustc_typeck/src/errors.rs
+++ b/compiler/rustc_typeck/src/errors.rs
@@ -103,6 +103,8 @@ pub struct CopyImplOnNonAdt {
 pub struct TraitObjectDeclaredWithNoTraits {
     #[primary_span]
     pub span: Span,
+    #[label = "alias-span"]
+    pub trait_alias_span: Option<Span>,
 }
 
 #[derive(SessionDiagnostic)]