Skip to content

Commit 19efa0b

Browse files
committed
Auto merge of rust-lang#13463 - lowr:fix/builtin-derive-with-const-generics, r=Veykril
Support const generics for builtin derive macro Fixes rust-lang#13121 We have been treating every generic parameter as type parameter during builtin derive macro expansion. This patch adds support for const generics in such expansions.
2 parents d3b7e94 + 6459d7f commit 19efa0b

File tree

2 files changed

+62
-60
lines changed

2 files changed

+62
-60
lines changed

crates/hir-def/src/macro_expansion_tests/builtin_derive_macro.rs

+26-10
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@ fn test_copy_expand_simple() {
1212
#[derive(Copy)]
1313
struct Foo;
1414
"#,
15-
expect![[r##"
15+
expect![[r#"
1616
#[derive(Copy)]
1717
struct Foo;
1818
19-
impl < > core::marker::Copy for Foo< > {}"##]],
19+
impl < > core::marker::Copy for Foo< > {}"#]],
2020
);
2121
}
2222

@@ -33,15 +33,15 @@ macro Copy {}
3333
#[derive(Copy)]
3434
struct Foo;
3535
"#,
36-
expect![[r##"
36+
expect![[r#"
3737
#[rustc_builtin_macro]
3838
macro derive {}
3939
#[rustc_builtin_macro]
4040
macro Copy {}
4141
#[derive(Copy)]
4242
struct Foo;
4343
44-
impl < > crate ::marker::Copy for Foo< > {}"##]],
44+
impl < > crate ::marker::Copy for Foo< > {}"#]],
4545
);
4646
}
4747

@@ -53,11 +53,11 @@ fn test_copy_expand_with_type_params() {
5353
#[derive(Copy)]
5454
struct Foo<A, B>;
5555
"#,
56-
expect![[r##"
56+
expect![[r#"
5757
#[derive(Copy)]
5858
struct Foo<A, B>;
5959
60-
impl <T0: core::marker::Copy, T1: core::marker::Copy> core::marker::Copy for Foo<T0, T1> {}"##]],
60+
impl <T0: core::marker::Copy, T1: core::marker::Copy, > core::marker::Copy for Foo<T0, T1, > {}"#]],
6161
);
6262
}
6363

@@ -70,11 +70,11 @@ fn test_copy_expand_with_lifetimes() {
7070
#[derive(Copy)]
7171
struct Foo<A, B, 'a, 'b>;
7272
"#,
73-
expect![[r##"
73+
expect![[r#"
7474
#[derive(Copy)]
7575
struct Foo<A, B, 'a, 'b>;
7676
77-
impl <T0: core::marker::Copy, T1: core::marker::Copy> core::marker::Copy for Foo<T0, T1> {}"##]],
77+
impl <T0: core::marker::Copy, T1: core::marker::Copy, > core::marker::Copy for Foo<T0, T1, > {}"#]],
7878
);
7979
}
8080

@@ -86,10 +86,26 @@ fn test_clone_expand() {
8686
#[derive(Clone)]
8787
struct Foo<A, B>;
8888
"#,
89-
expect![[r##"
89+
expect![[r#"
9090
#[derive(Clone)]
9191
struct Foo<A, B>;
9292
93-
impl <T0: core::clone::Clone, T1: core::clone::Clone> core::clone::Clone for Foo<T0, T1> {}"##]],
93+
impl <T0: core::clone::Clone, T1: core::clone::Clone, > core::clone::Clone for Foo<T0, T1, > {}"#]],
94+
);
95+
}
96+
97+
#[test]
98+
fn test_clone_expand_with_const_generics() {
99+
check(
100+
r#"
101+
//- minicore: derive, clone
102+
#[derive(Clone)]
103+
struct Foo<const X: usize, T>(u32);
104+
"#,
105+
expect![[r#"
106+
#[derive(Clone)]
107+
struct Foo<const X: usize, T>(u32);
108+
109+
impl <const T0: usize, T1: core::clone::Clone, > core::clone::Clone for Foo<T0, T1, > {}"#]],
94110
);
95111
}

crates/hir-expand/src/builtin_derive_macro.rs

+36-50
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,8 @@ pub fn find_builtin_derive(ident: &name::Name) -> Option<BuiltinDeriveExpander>
6060

6161
struct BasicAdtInfo {
6262
name: tt::Ident,
63-
type_or_const_params: usize,
63+
/// `Some(ty)` if it's a const param of type `ty`, `None` if it's a type param.
64+
param_types: Vec<Option<tt::Subtree>>,
6465
}
6566

6667
fn parse_adt(tt: &tt::Subtree) -> Result<BasicAdtInfo, ExpandError> {
@@ -92,65 +93,50 @@ fn parse_adt(tt: &tt::Subtree) -> Result<BasicAdtInfo, ExpandError> {
9293
let name_token_id =
9394
token_map.token_by_range(name.syntax().text_range()).unwrap_or_else(TokenId::unspecified);
9495
let name_token = tt::Ident { id: name_token_id, text: name.text().into() };
95-
let type_or_const_params =
96-
params.map_or(0, |type_param_list| type_param_list.type_or_const_params().count());
97-
Ok(BasicAdtInfo { name: name_token, type_or_const_params })
98-
}
99-
100-
fn make_type_args(n: usize, bound: Vec<tt::TokenTree>) -> Vec<tt::TokenTree> {
101-
let mut result = Vec::<tt::TokenTree>::with_capacity(n * 2);
102-
result.push(
103-
tt::Leaf::Punct(tt::Punct {
104-
char: '<',
105-
spacing: tt::Spacing::Alone,
106-
id: tt::TokenId::unspecified(),
107-
})
108-
.into(),
109-
);
110-
for i in 0..n {
111-
if i > 0 {
112-
result.push(
113-
tt::Leaf::Punct(tt::Punct {
114-
char: ',',
115-
spacing: tt::Spacing::Alone,
116-
id: tt::TokenId::unspecified(),
117-
})
118-
.into(),
119-
);
120-
}
121-
result.push(
122-
tt::Leaf::Ident(tt::Ident {
123-
id: tt::TokenId::unspecified(),
124-
text: format!("T{}", i).into(),
125-
})
126-
.into(),
127-
);
128-
result.extend(bound.iter().cloned());
129-
}
130-
result.push(
131-
tt::Leaf::Punct(tt::Punct {
132-
char: '>',
133-
spacing: tt::Spacing::Alone,
134-
id: tt::TokenId::unspecified(),
96+
let param_types = params
97+
.into_iter()
98+
.flat_map(|param_list| param_list.type_or_const_params())
99+
.map(|param| {
100+
if let ast::TypeOrConstParam::Const(param) = param {
101+
let ty = param
102+
.ty()
103+
.map(|ty| mbe::syntax_node_to_token_tree(ty.syntax()).0)
104+
.unwrap_or_default();
105+
Some(ty)
106+
} else {
107+
None
108+
}
135109
})
136-
.into(),
137-
);
138-
result
110+
.collect();
111+
Ok(BasicAdtInfo { name: name_token, param_types })
139112
}
140113

141114
fn expand_simple_derive(tt: &tt::Subtree, trait_path: tt::Subtree) -> ExpandResult<tt::Subtree> {
142115
let info = match parse_adt(tt) {
143116
Ok(info) => info,
144117
Err(e) => return ExpandResult::only_err(e),
145118
};
119+
let (params, args): (Vec<_>, Vec<_>) = info
120+
.param_types
121+
.into_iter()
122+
.enumerate()
123+
.map(|(idx, param_ty)| {
124+
let ident = tt::Leaf::Ident(tt::Ident {
125+
id: tt::TokenId::unspecified(),
126+
text: format!("T{idx}").into(),
127+
});
128+
let ident_ = ident.clone();
129+
if let Some(ty) = param_ty {
130+
(quote! { const #ident : #ty , }, quote! { #ident_ , })
131+
} else {
132+
let bound = trait_path.clone();
133+
(quote! { #ident : #bound , }, quote! { #ident_ , })
134+
}
135+
})
136+
.unzip();
146137
let name = info.name;
147-
let trait_path_clone = trait_path.token_trees.clone();
148-
let bound = (quote! { : ##trait_path_clone }).token_trees;
149-
let type_params = make_type_args(info.type_or_const_params, bound);
150-
let type_args = make_type_args(info.type_or_const_params, Vec::new());
151-
let trait_path = trait_path.token_trees;
152138
let expanded = quote! {
153-
impl ##type_params ##trait_path for #name ##type_args {}
139+
impl < ##params > #trait_path for #name < ##args > {}
154140
};
155141
ExpandResult::ok(expanded)
156142
}

0 commit comments

Comments
 (0)