about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2021-10-02 18:46:27 +0000
committerbors <bors@rust-lang.org>2021-10-02 18:46:27 +0000
commitf03eb6bef8ced8a243858b819e013b9caf83d757 (patch)
tree3d7a5598b782533000f0c026859f6a987a3d9041 /compiler
parentd14731cb3ced8318d7fc83cbe838f0e7f2fb3b40 (diff)
parent87241e909933b30bb31af4edf58d1a331589df3c (diff)
downloadrust-f03eb6bef8ced8a243858b819e013b9caf83d757.tar.gz
rust-f03eb6bef8ced8a243858b819e013b9caf83d757.zip
Auto merge of #89341 - audunhalland:derive-type-params-with-bound-generic-params, r=jackh726
Deriving: Include bound generic params in type parameters for where clause

Fixes #89188.

The `derive` macro ignored the `for<'s>` needed with the `Fn` trait in that code example.

edit: I'm unsure if this might cause regressions. I'm not an experienced compiler developer so I'm not used to thinking about unwanted side effects code changes like this might have.
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/generic/mod.rs50
1 files changed, 40 insertions, 10 deletions
diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
index 59f933d422d..0f88995846c 100644
--- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
@@ -332,20 +332,27 @@ pub fn combine_substructure(
     RefCell::new(f)
 }
 
+struct TypeParameter {
+    bound_generic_params: Vec<ast::GenericParam>,
+    ty: P<ast::Ty>,
+}
+
 /// This method helps to extract all the type parameters referenced from a
 /// type. For a type parameter `<T>`, it looks for either a `TyPath` that
 /// is not global and starts with `T`, or a `TyQPath`.
+/// Also include bound generic params from the input type.
 fn find_type_parameters(
     ty: &ast::Ty,
     ty_param_names: &[Symbol],
     cx: &ExtCtxt<'_>,
-) -> Vec<P<ast::Ty>> {
+) -> Vec<TypeParameter> {
     use rustc_ast::visit;
 
     struct Visitor<'a, 'b> {
         cx: &'a ExtCtxt<'b>,
         ty_param_names: &'a [Symbol],
-        types: Vec<P<ast::Ty>>,
+        bound_generic_params_stack: Vec<ast::GenericParam>,
+        type_params: Vec<TypeParameter>,
     }
 
     impl<'a, 'b> visit::Visitor<'a> for Visitor<'a, 'b> {
@@ -353,7 +360,10 @@ fn find_type_parameters(
             if let ast::TyKind::Path(_, ref path) = ty.kind {
                 if let Some(segment) = path.segments.first() {
                     if self.ty_param_names.contains(&segment.ident.name) {
-                        self.types.push(P(ty.clone()));
+                        self.type_params.push(TypeParameter {
+                            bound_generic_params: self.bound_generic_params_stack.clone(),
+                            ty: P(ty.clone()),
+                        });
                     }
                 }
             }
@@ -361,15 +371,35 @@ fn find_type_parameters(
             visit::walk_ty(self, ty)
         }
 
+        // Place bound generic params on a stack, to extract them when a type is encountered.
+        fn visit_poly_trait_ref(
+            &mut self,
+            trait_ref: &'a ast::PolyTraitRef,
+            modifier: &'a ast::TraitBoundModifier,
+        ) {
+            let stack_len = self.bound_generic_params_stack.len();
+            self.bound_generic_params_stack
+                .extend(trait_ref.bound_generic_params.clone().into_iter());
+
+            visit::walk_poly_trait_ref(self, trait_ref, modifier);
+
+            self.bound_generic_params_stack.truncate(stack_len);
+        }
+
         fn visit_mac_call(&mut self, mac: &ast::MacCall) {
             self.cx.span_err(mac.span(), "`derive` cannot be used on items with type macros");
         }
     }
 
-    let mut visitor = Visitor { cx, ty_param_names, types: Vec::new() };
+    let mut visitor = Visitor {
+        cx,
+        ty_param_names,
+        bound_generic_params_stack: Vec::new(),
+        type_params: Vec::new(),
+    };
     visit::Visitor::visit_ty(&mut visitor, ty);
 
-    visitor.types
+    visitor.type_params
 }
 
 impl<'a> TraitDef<'a> {
@@ -617,11 +647,11 @@ impl<'a> TraitDef<'a> {
                     ty_params.map(|ty_param| ty_param.ident.name).collect();
 
                 for field_ty in field_tys {
-                    let tys = find_type_parameters(&field_ty, &ty_param_names, cx);
+                    let field_ty_params = find_type_parameters(&field_ty, &ty_param_names, cx);
 
-                    for ty in tys {
+                    for field_ty_param in field_ty_params {
                         // if we have already handled this type, skip it
-                        if let ast::TyKind::Path(_, ref p) = ty.kind {
+                        if let ast::TyKind::Path(_, ref p) = field_ty_param.ty.kind {
                             if p.segments.len() == 1
                                 && ty_param_names.contains(&p.segments[0].ident.name)
                             {
@@ -639,8 +669,8 @@ impl<'a> TraitDef<'a> {
 
                         let predicate = ast::WhereBoundPredicate {
                             span: self.span,
-                            bound_generic_params: Vec::new(),
-                            bounded_ty: ty,
+                            bound_generic_params: field_ty_param.bound_generic_params,
+                            bounded_ty: field_ty_param.ty,
                             bounds,
                         };