mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-28 14:03:35 +00:00
Support const generics for builtin derive macro
This commit is contained in:
parent
8ee23f4f0a
commit
6459d7f817
2 changed files with 62 additions and 60 deletions
|
@ -12,11 +12,11 @@ fn test_copy_expand_simple() {
|
||||||
#[derive(Copy)]
|
#[derive(Copy)]
|
||||||
struct Foo;
|
struct Foo;
|
||||||
"#,
|
"#,
|
||||||
expect![[r##"
|
expect![[r#"
|
||||||
#[derive(Copy)]
|
#[derive(Copy)]
|
||||||
struct Foo;
|
struct Foo;
|
||||||
|
|
||||||
impl < > core::marker::Copy for Foo< > {}"##]],
|
impl < > core::marker::Copy for Foo< > {}"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ macro Copy {}
|
||||||
#[derive(Copy)]
|
#[derive(Copy)]
|
||||||
struct Foo;
|
struct Foo;
|
||||||
"#,
|
"#,
|
||||||
expect![[r##"
|
expect![[r#"
|
||||||
#[rustc_builtin_macro]
|
#[rustc_builtin_macro]
|
||||||
macro derive {}
|
macro derive {}
|
||||||
#[rustc_builtin_macro]
|
#[rustc_builtin_macro]
|
||||||
|
@ -41,7 +41,7 @@ macro Copy {}
|
||||||
#[derive(Copy)]
|
#[derive(Copy)]
|
||||||
struct Foo;
|
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)]
|
#[derive(Copy)]
|
||||||
struct Foo<A, B>;
|
struct Foo<A, B>;
|
||||||
"#,
|
"#,
|
||||||
expect![[r##"
|
expect![[r#"
|
||||||
#[derive(Copy)]
|
#[derive(Copy)]
|
||||||
struct Foo<A, B>;
|
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)]
|
#[derive(Copy)]
|
||||||
struct Foo<A, B, 'a, 'b>;
|
struct Foo<A, B, 'a, 'b>;
|
||||||
"#,
|
"#,
|
||||||
expect![[r##"
|
expect![[r#"
|
||||||
#[derive(Copy)]
|
#[derive(Copy)]
|
||||||
struct Foo<A, B, 'a, 'b>;
|
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)]
|
#[derive(Clone)]
|
||||||
struct Foo<A, B>;
|
struct Foo<A, B>;
|
||||||
"#,
|
"#,
|
||||||
expect![[r##"
|
expect![[r#"
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
struct Foo<A, B>;
|
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 {
|
struct BasicAdtInfo {
|
||||||
name: tt::Ident,
|
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> {
|
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 =
|
let name_token_id =
|
||||||
token_map.token_by_range(name.syntax().text_range()).unwrap_or_else(TokenId::unspecified);
|
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 name_token = tt::Ident { id: name_token_id, text: name.text().into() };
|
||||||
let type_or_const_params =
|
let param_types = params
|
||||||
params.map_or(0, |type_param_list| type_param_list.type_or_const_params().count());
|
.into_iter()
|
||||||
Ok(BasicAdtInfo { name: name_token, type_or_const_params })
|
.flat_map(|param_list| param_list.type_or_const_params())
|
||||||
}
|
.map(|param| {
|
||||||
|
if let ast::TypeOrConstParam::Const(param) = param {
|
||||||
fn make_type_args(n: usize, bound: Vec<tt::TokenTree>) -> Vec<tt::TokenTree> {
|
let ty = param
|
||||||
let mut result = Vec::<tt::TokenTree>::with_capacity(n * 2);
|
.ty()
|
||||||
result.push(
|
.map(|ty| mbe::syntax_node_to_token_tree(ty.syntax()).0)
|
||||||
tt::Leaf::Punct(tt::Punct {
|
.unwrap_or_default();
|
||||||
char: '<',
|
Some(ty)
|
||||||
spacing: tt::Spacing::Alone,
|
} else {
|
||||||
id: tt::TokenId::unspecified(),
|
None
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.into(),
|
.collect();
|
||||||
);
|
Ok(BasicAdtInfo { name: name_token, param_types })
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expand_simple_derive(tt: &tt::Subtree, trait_path: tt::Subtree) -> ExpandResult<tt::Subtree> {
|
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,
|
Ok(info) => info,
|
||||||
Err(e) => return ExpandResult::only_err(e),
|
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 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! {
|
let expanded = quote! {
|
||||||
impl ##type_params ##trait_path for #name ##type_args {}
|
impl < ##params > #trait_path for #name < ##args > {}
|
||||||
};
|
};
|
||||||
ExpandResult::ok(expanded)
|
ExpandResult::ok(expanded)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue