Auto merge of #13463 - lowr:fix/builtin-derive-with-const-generics, r=Veykril
Support const generics for builtin derive macro Fixes #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.
This commit is contained in:
commit
19efa0b110
@ -12,11 +12,11 @@ fn test_copy_expand_simple() {
|
||||
#[derive(Copy)]
|
||||
struct Foo;
|
||||
"#,
|
||||
expect![[r##"
|
||||
expect![[r#"
|
||||
#[derive(Copy)]
|
||||
struct Foo;
|
||||
|
||||
impl < > core::marker::Copy for Foo< > {}"##]],
|
||||
impl < > core::marker::Copy for Foo< > {}"#]],
|
||||
);
|
||||
}
|
||||
|
||||
@ -33,7 +33,7 @@ macro Copy {}
|
||||
#[derive(Copy)]
|
||||
struct Foo;
|
||||
"#,
|
||||
expect![[r##"
|
||||
expect![[r#"
|
||||
#[rustc_builtin_macro]
|
||||
macro derive {}
|
||||
#[rustc_builtin_macro]
|
||||
@ -41,7 +41,7 @@ macro Copy {}
|
||||
#[derive(Copy)]
|
||||
struct Foo;
|
||||
|
||||
impl < > crate ::marker::Copy for Foo< > {}"##]],
|
||||
impl < > crate ::marker::Copy for Foo< > {}"#]],
|
||||
);
|
||||
}
|
||||
|
||||
@ -53,11 +53,11 @@ fn test_copy_expand_with_type_params() {
|
||||
#[derive(Copy)]
|
||||
struct Foo<A, B>;
|
||||
"#,
|
||||
expect![[r##"
|
||||
expect![[r#"
|
||||
#[derive(Copy)]
|
||||
struct Foo<A, B>;
|
||||
|
||||
impl <T0: core::marker::Copy, T1: core::marker::Copy> core::marker::Copy for Foo<T0, T1> {}"##]],
|
||||
impl <T0: core::marker::Copy, T1: core::marker::Copy, > core::marker::Copy for Foo<T0, T1, > {}"#]],
|
||||
);
|
||||
}
|
||||
|
||||
@ -70,11 +70,11 @@ fn test_copy_expand_with_lifetimes() {
|
||||
#[derive(Copy)]
|
||||
struct Foo<A, B, 'a, 'b>;
|
||||
"#,
|
||||
expect![[r##"
|
||||
expect![[r#"
|
||||
#[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 <T0: core::marker::Copy, T1: core::marker::Copy, > core::marker::Copy for Foo<T0, T1, > {}"#]],
|
||||
);
|
||||
}
|
||||
|
||||
@ -86,10 +86,26 @@ fn test_clone_expand() {
|
||||
#[derive(Clone)]
|
||||
struct Foo<A, B>;
|
||||
"#,
|
||||
expect![[r##"
|
||||
expect![[r#"
|
||||
#[derive(Clone)]
|
||||
struct Foo<A, B>;
|
||||
|
||||
impl <T0: core::clone::Clone, T1: core::clone::Clone> core::clone::Clone for Foo<T0, T1> {}"##]],
|
||||
impl <T0: core::clone::Clone, T1: core::clone::Clone, > core::clone::Clone for Foo<T0, T1, > {}"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_clone_expand_with_const_generics() {
|
||||
check(
|
||||
r#"
|
||||
//- minicore: derive, clone
|
||||
#[derive(Clone)]
|
||||
struct Foo<const X: usize, T>(u32);
|
||||
"#,
|
||||
expect![[r#"
|
||||
#[derive(Clone)]
|
||||
struct Foo<const X: usize, T>(u32);
|
||||
|
||||
impl <const T0: usize, T1: core::clone::Clone, > core::clone::Clone for Foo<T0, T1, > {}"#]],
|
||||
);
|
||||
}
|
||||
|
@ -60,7 +60,8 @@ pub fn find_builtin_derive(ident: &name::Name) -> Option<BuiltinDeriveExpander>
|
||||
|
||||
struct BasicAdtInfo {
|
||||
name: tt::Ident,
|
||||
type_or_const_params: usize,
|
||||
/// `Some(ty)` if it's a const param of type `ty`, `None` if it's a type param.
|
||||
param_types: Vec<Option<tt::Subtree>>,
|
||||
}
|
||||
|
||||
fn parse_adt(tt: &tt::Subtree) -> Result<BasicAdtInfo, ExpandError> {
|
||||
@ -92,50 +93,22 @@ fn parse_adt(tt: &tt::Subtree) -> Result<BasicAdtInfo, ExpandError> {
|
||||
let name_token_id =
|
||||
token_map.token_by_range(name.syntax().text_range()).unwrap_or_else(TokenId::unspecified);
|
||||
let name_token = tt::Ident { id: name_token_id, text: name.text().into() };
|
||||
let type_or_const_params =
|
||||
params.map_or(0, |type_param_list| type_param_list.type_or_const_params().count());
|
||||
Ok(BasicAdtInfo { name: name_token, type_or_const_params })
|
||||
}
|
||||
|
||||
fn make_type_args(n: usize, bound: Vec<tt::TokenTree>) -> Vec<tt::TokenTree> {
|
||||
let mut result = Vec::<tt::TokenTree>::with_capacity(n * 2);
|
||||
result.push(
|
||||
tt::Leaf::Punct(tt::Punct {
|
||||
char: '<',
|
||||
spacing: tt::Spacing::Alone,
|
||||
id: tt::TokenId::unspecified(),
|
||||
let param_types = params
|
||||
.into_iter()
|
||||
.flat_map(|param_list| param_list.type_or_const_params())
|
||||
.map(|param| {
|
||||
if let ast::TypeOrConstParam::Const(param) = param {
|
||||
let ty = param
|
||||
.ty()
|
||||
.map(|ty| mbe::syntax_node_to_token_tree(ty.syntax()).0)
|
||||
.unwrap_or_default();
|
||||
Some(ty)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.into(),
|
||||
);
|
||||
for i in 0..n {
|
||||
if i > 0 {
|
||||
result.push(
|
||||
tt::Leaf::Punct(tt::Punct {
|
||||
char: ',',
|
||||
spacing: tt::Spacing::Alone,
|
||||
id: tt::TokenId::unspecified(),
|
||||
})
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
result.push(
|
||||
tt::Leaf::Ident(tt::Ident {
|
||||
id: tt::TokenId::unspecified(),
|
||||
text: format!("T{}", i).into(),
|
||||
})
|
||||
.into(),
|
||||
);
|
||||
result.extend(bound.iter().cloned());
|
||||
}
|
||||
result.push(
|
||||
tt::Leaf::Punct(tt::Punct {
|
||||
char: '>',
|
||||
spacing: tt::Spacing::Alone,
|
||||
id: tt::TokenId::unspecified(),
|
||||
})
|
||||
.into(),
|
||||
);
|
||||
result
|
||||
.collect();
|
||||
Ok(BasicAdtInfo { name: name_token, param_types })
|
||||
}
|
||||
|
||||
fn expand_simple_derive(tt: &tt::Subtree, trait_path: tt::Subtree) -> ExpandResult<tt::Subtree> {
|
||||
@ -143,14 +116,27 @@ fn expand_simple_derive(tt: &tt::Subtree, trait_path: tt::Subtree) -> ExpandResu
|
||||
Ok(info) => info,
|
||||
Err(e) => return ExpandResult::only_err(e),
|
||||
};
|
||||
let (params, args): (Vec<_>, Vec<_>) = info
|
||||
.param_types
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(idx, param_ty)| {
|
||||
let ident = tt::Leaf::Ident(tt::Ident {
|
||||
id: tt::TokenId::unspecified(),
|
||||
text: format!("T{idx}").into(),
|
||||
});
|
||||
let ident_ = ident.clone();
|
||||
if let Some(ty) = param_ty {
|
||||
(quote! { const #ident : #ty , }, quote! { #ident_ , })
|
||||
} else {
|
||||
let bound = trait_path.clone();
|
||||
(quote! { #ident : #bound , }, quote! { #ident_ , })
|
||||
}
|
||||
})
|
||||
.unzip();
|
||||
let name = info.name;
|
||||
let trait_path_clone = trait_path.token_trees.clone();
|
||||
let bound = (quote! { : ##trait_path_clone }).token_trees;
|
||||
let type_params = make_type_args(info.type_or_const_params, bound);
|
||||
let type_args = make_type_args(info.type_or_const_params, Vec::new());
|
||||
let trait_path = trait_path.token_trees;
|
||||
let expanded = quote! {
|
||||
impl ##type_params ##trait_path for #name ##type_args {}
|
||||
impl < ##params > #trait_path for #name < ##args > {}
|
||||
};
|
||||
ExpandResult::ok(expanded)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user