about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-04-07 04:45:41 +0000
committerbors <bors@rust-lang.org>2023-04-07 04:45:41 +0000
commit937ef97bc566d5b7ceac2c7a7711ef7a734b1614 (patch)
treeaf1878349e1f7211b083cd7f12d3ded117ff6c8f
parente739c999cd23e3114187d889755eb897e02989ea (diff)
parent0241b52dad7ca63738a3495830e25b71780d3797 (diff)
downloadrust-937ef97bc566d5b7ceac2c7a7711ef7a734b1614.tar.gz
rust-937ef97bc566d5b7ceac2c7a7711ef7a734b1614.zip
Auto merge of #14521 - HKalbasi:dev, r=Veykril
Add bounds for fields in derive macro

Dependency of #14470
-rw-r--r--crates/hir-def/src/macro_expansion_tests/builtin_derive_macro.rs12
-rw-r--r--crates/hir-expand/src/builtin_derive_macro.rs73
-rw-r--r--crates/ide/src/expand_macro.rs8
3 files changed, 66 insertions, 27 deletions
diff --git a/crates/hir-def/src/macro_expansion_tests/builtin_derive_macro.rs b/crates/hir-def/src/macro_expansion_tests/builtin_derive_macro.rs
index fafcde25ae7..b7932f550e2 100644
--- a/crates/hir-def/src/macro_expansion_tests/builtin_derive_macro.rs
+++ b/crates/hir-def/src/macro_expansion_tests/builtin_derive_macro.rs
@@ -16,7 +16,7 @@ struct Foo;
 #[derive(Copy)]
 struct Foo;
 
-impl < > core::marker::Copy for Foo< > {}"#]],
+impl < > core::marker::Copy for Foo< > where {}"#]],
     );
 }
 
@@ -41,7 +41,7 @@ macro Copy {}
 #[derive(Copy)]
 struct Foo;
 
-impl < > crate ::marker::Copy for Foo< > {}"#]],
+impl < > crate ::marker::Copy for Foo< > where {}"#]],
     );
 }
 
@@ -57,7 +57,7 @@ struct Foo<A, B>;
 #[derive(Copy)]
 struct Foo<A, B>;
 
-impl <T0: core::marker::Copy, T1: core::marker::Copy, > core::marker::Copy for Foo<T0, T1, > {}"#]],
+impl <A: core::marker::Copy, B: core::marker::Copy, > core::marker::Copy for Foo<A, B, > where {}"#]],
     );
 }
 
@@ -74,7 +74,7 @@ struct Foo<A, B, 'a, 'b>;
 #[derive(Copy)]
 struct Foo<A, B, 'a, 'b>;
 
-impl <T0: core::marker::Copy, T1: core::marker::Copy, > core::marker::Copy for Foo<T0, T1, > {}"#]],
+impl <A: core::marker::Copy, B: core::marker::Copy, > core::marker::Copy for Foo<A, B, > where {}"#]],
     );
 }
 
@@ -90,7 +90,7 @@ struct Foo<A, B>;
 #[derive(Clone)]
 struct Foo<A, B>;
 
-impl <T0: core::clone::Clone, T1: core::clone::Clone, > core::clone::Clone for Foo<T0, T1, > {}"#]],
+impl <A: core::clone::Clone, B: core::clone::Clone, > core::clone::Clone for Foo<A, B, > where {}"#]],
     );
 }
 
@@ -106,6 +106,6 @@ struct Foo<const X: usize, T>(u32);
 #[derive(Clone)]
 struct Foo<const X: usize, T>(u32);
 
-impl <const T0: usize, T1: core::clone::Clone, > core::clone::Clone for Foo<T0, T1, > {}"#]],
+impl <const X: usize, T: core::clone::Clone, > core::clone::Clone for Foo<X, T, > where u32: core::clone::Clone, {}"#]],
     );
 }
diff --git a/crates/hir-expand/src/builtin_derive_macro.rs b/crates/hir-expand/src/builtin_derive_macro.rs
index 5c1a75132ee..2b874bffff6 100644
--- a/crates/hir-expand/src/builtin_derive_macro.rs
+++ b/crates/hir-expand/src/builtin_derive_macro.rs
@@ -1,11 +1,12 @@
 //! Builtin derives.
 
 use base_db::{CrateOrigin, LangCrateOrigin};
+use either::Either;
 use tracing::debug;
 
 use crate::tt::{self, TokenId};
 use syntax::{
-    ast::{self, AstNode, HasGenericParams, HasModuleItem, HasName},
+    ast::{self, AstNode, HasGenericParams, HasModuleItem, HasName, HasTypeBounds},
     match_ast,
 };
 
@@ -60,8 +61,11 @@ pub fn find_builtin_derive(ident: &name::Name) -> Option<BuiltinDeriveExpander>
 
 struct BasicAdtInfo {
     name: tt::Ident,
-    /// `Some(ty)` if it's a const param of type `ty`, `None` if it's a type param.
-    param_types: Vec<Option<tt::Subtree>>,
+    /// first field is the name, and
+    /// second field is `Some(ty)` if it's a const param of type `ty`, `None` if it's a type param.
+    /// third fields is where bounds, if any
+    param_types: Vec<(tt::Subtree, Option<tt::Subtree>, Option<tt::Subtree>)>,
+    field_types: Vec<tt::Subtree>,
 }
 
 fn parse_adt(tt: &tt::Subtree) -> Result<BasicAdtInfo, ExpandError> {
@@ -75,17 +79,34 @@ fn parse_adt(tt: &tt::Subtree) -> Result<BasicAdtInfo, ExpandError> {
         ExpandError::Other("no item found".into())
     })?;
     let node = item.syntax();
-    let (name, params) = match_ast! {
+    let (name, params, fields) = match_ast! {
         match node {
-            ast::Struct(it) => (it.name(), it.generic_param_list()),
-            ast::Enum(it) => (it.name(), it.generic_param_list()),
-            ast::Union(it) => (it.name(), it.generic_param_list()),
+            ast::Struct(it) => {
+                (it.name(), it.generic_param_list(), it.field_list().into_iter().collect::<Vec<_>>())
+            },
+            ast::Enum(it) => (it.name(), it.generic_param_list(), it.variant_list().into_iter().flat_map(|x| x.variants()).filter_map(|x| x.field_list()).collect()),
+            ast::Union(it) => (it.name(), it.generic_param_list(), it.record_field_list().into_iter().map(|x| ast::FieldList::RecordFieldList(x)).collect()),
             _ => {
                 debug!("unexpected node is {:?}", node);
                 return Err(ExpandError::Other("expected struct, enum or union".into()))
             },
         }
     };
+    let field_types = fields
+        .into_iter()
+        .flat_map(|f| match f {
+            ast::FieldList::RecordFieldList(x) => Either::Left(
+                x.fields()
+                    .filter_map(|x| x.ty())
+                    .map(|x| mbe::syntax_node_to_token_tree(x.syntax()).0),
+            ),
+            ast::FieldList::TupleFieldList(x) => Either::Right(
+                x.fields()
+                    .filter_map(|x| x.ty())
+                    .map(|x| mbe::syntax_node_to_token_tree(x.syntax()).0),
+            ),
+        })
+        .collect::<Vec<_>>();
     let name = name.ok_or_else(|| {
         debug!("parsed item has no name");
         ExpandError::Other("missing name".into())
@@ -97,7 +118,17 @@ fn parse_adt(tt: &tt::Subtree) -> Result<BasicAdtInfo, ExpandError> {
         .into_iter()
         .flat_map(|param_list| param_list.type_or_const_params())
         .map(|param| {
-            if let ast::TypeOrConstParam::Const(param) = param {
+            let name = param
+                .name()
+                .map(|x| mbe::syntax_node_to_token_tree(x.syntax()).0)
+                .unwrap_or_else(tt::Subtree::empty);
+            let bounds = match &param {
+                ast::TypeOrConstParam::Type(x) => {
+                    x.type_bound_list().map(|x| mbe::syntax_node_to_token_tree(x.syntax()).0)
+                }
+                ast::TypeOrConstParam::Const(_) => None,
+            };
+            let ty = if let ast::TypeOrConstParam::Const(param) = param {
                 let ty = param
                     .ty()
                     .map(|ty| mbe::syntax_node_to_token_tree(ty.syntax()).0)
@@ -105,10 +136,11 @@ fn parse_adt(tt: &tt::Subtree) -> Result<BasicAdtInfo, ExpandError> {
                 Some(ty)
             } else {
                 None
-            }
+            };
+            (name, ty, bounds)
         })
         .collect();
-    Ok(BasicAdtInfo { name: name_token, param_types })
+    Ok(BasicAdtInfo { name: name_token, param_types, field_types })
 }
 
 fn expand_simple_derive(tt: &tt::Subtree, trait_path: tt::Subtree) -> ExpandResult<tt::Subtree> {
@@ -116,16 +148,16 @@ fn expand_simple_derive(tt: &tt::Subtree, trait_path: tt::Subtree) -> ExpandResu
         Ok(info) => info,
         Err(e) => return ExpandResult::with_err(tt::Subtree::empty(), e),
     };
+    let mut where_block = vec![];
     let (params, args): (Vec<_>, Vec<_>) = info
         .param_types
         .into_iter()
-        .enumerate()
-        .map(|(idx, param_ty)| {
-            let ident = tt::Leaf::Ident(tt::Ident {
-                span: tt::TokenId::unspecified(),
-                text: format!("T{idx}").into(),
-            });
+        .map(|(ident, param_ty, bound)| {
             let ident_ = ident.clone();
+            if let Some(b) = bound {
+                let ident = ident.clone();
+                where_block.push(quote! { #ident : #b , });
+            }
             if let Some(ty) = param_ty {
                 (quote! { const #ident : #ty , }, quote! { #ident_ , })
             } else {
@@ -134,9 +166,16 @@ fn expand_simple_derive(tt: &tt::Subtree, trait_path: tt::Subtree) -> ExpandResu
             }
         })
         .unzip();
+
+    where_block.extend(info.field_types.iter().map(|x| {
+        let x = x.clone();
+        let bound = trait_path.clone();
+        quote! { #x : #bound , }
+    }));
+
     let name = info.name;
     let expanded = quote! {
-        impl < ##params > #trait_path for #name < ##args > {}
+        impl < ##params > #trait_path for #name < ##args > where ##where_block {}
     };
     ExpandResult::ok(expanded)
 }
diff --git a/crates/ide/src/expand_macro.rs b/crates/ide/src/expand_macro.rs
index 4382af43438..91af5716ca5 100644
--- a/crates/ide/src/expand_macro.rs
+++ b/crates/ide/src/expand_macro.rs
@@ -471,7 +471,7 @@ struct Foo {}
 "#,
             expect![[r#"
                 Clone
-                impl < >core::clone::Clone for Foo< >{}
+                impl < >core::clone::Clone for Foo< >where{}
             "#]],
         );
     }
@@ -488,7 +488,7 @@ struct Foo {}
 "#,
             expect![[r#"
                 Copy
-                impl < >core::marker::Copy for Foo< >{}
+                impl < >core::marker::Copy for Foo< >where{}
             "#]],
         );
     }
@@ -504,7 +504,7 @@ struct Foo {}
 "#,
             expect![[r#"
                 Copy
-                impl < >core::marker::Copy for Foo< >{}
+                impl < >core::marker::Copy for Foo< >where{}
             "#]],
         );
         check(
@@ -516,7 +516,7 @@ struct Foo {}
 "#,
             expect![[r#"
                 Clone
-                impl < >core::clone::Clone for Foo< >{}
+                impl < >core::clone::Clone for Foo< >where{}
             "#]],
         );
     }