Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ensure only static lifetimes appear in derived types #39

Merged
merged 34 commits into from
Jan 18, 2021
Merged
Show file tree
Hide file tree
Changes from 30 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
e77fd47
Add bounds for generic type param
ascjones Sep 8, 2020
506da3f
Fmt
ascjones Sep 9, 2020
08e267b
Remove redundant clone
ascjones Sep 9, 2020
62a28e3
Make clippy happy
ascjones Sep 9, 2020
44718bc
Merge branch 'master' into aj-bounds
ascjones Nov 27, 2020
4bd32a3
Fmt
ascjones Nov 27, 2020
97fa4ac
Remove readding of type to bounds
ascjones Nov 27, 2020
41f73bc
Unused imports
ascjones Nov 27, 2020
549a806
Merge branch 'master' into aj-bounds
ascjones Nov 30, 2020
ae244d1
Merge branch 'master' into aj-bounds
ascjones Dec 3, 2020
af1541c
Merge branch 'master' into aj-bounds
ascjones Dec 4, 2020
91a49a4
Merge branch 'master' into aj-bounds
ascjones Dec 8, 2020
1183560
Doc tweaks (#37)
dvdplm Dec 8, 2020
0eef2d3
Adapt and simplify code to scale-info's needs
dvdplm Dec 9, 2020
b5195ff
Resolve todo
dvdplm Dec 9, 2020
e47a056
Fmt
dvdplm Dec 9, 2020
c877f21
Add ui test for Unions
dvdplm Dec 9, 2020
2b3274c
Only run trybuild-tests on nightly
dvdplm Dec 9, 2020
89a2b8c
Unify and simply collect_types_to_bind()
dvdplm Dec 10, 2020
9060b1a
Move a few trivial tests to trybuild tests instead
dvdplm Dec 10, 2020
f9d3a33
Add more trybuild tests
dvdplm Dec 10, 2020
81525b9
remove trivial test
dvdplm Dec 10, 2020
df26405
Make type_contains_idents more self-contained
dvdplm Dec 10, 2020
cc3bc31
Obey the fmt
dvdplm Dec 10, 2020
597ca3b
WIP
dvdplm Dec 14, 2020
d80c9e4
Cleanup
dvdplm Dec 14, 2020
dba5e2f
cleanup
dvdplm Dec 14, 2020
3d84505
Merge branch 'master' into dp-make-lifetimes-static
dvdplm Dec 14, 2020
a01f6b6
cleanup
dvdplm Dec 14, 2020
a110903
Merge branch 'master' into dp-make-lifetimes-static
dvdplm Jan 4, 2021
ca66eaf
Merge remote-tracking branch 'origin/master' into dp-make-lifetimes-s…
dvdplm Jan 18, 2021
47e6de1
Sort out funny whitespace in type names with lifetimes, `& \'static` …
dvdplm Jan 18, 2021
c20e1c4
Impl review feedback
dvdplm Jan 18, 2021
8323fc8
Avoid clones
dvdplm Jan 18, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion derive/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,5 @@ proc-macro = true

[dependencies]
quote = "1.0"
syn = { version = "1.0", features = ["derive"] }
syn = { version = "1.0", features = ["derive", "visit-mut"] }
proc-macro2 = "1.0"
24 changes: 21 additions & 3 deletions derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,10 @@ use syn::{
Error,
Result,
},
parse_quote,
punctuated::Punctuated,
token::Comma,
visit_mut::VisitMut,
Data,
DataEnum,
DataStruct,
Expand All @@ -45,6 +47,7 @@ use syn::{
ExprLit,
Field,
Fields,
Lifetime,
Lit,
Variant,
};
Expand All @@ -69,7 +72,11 @@ fn generate_type(input: TokenStream2) -> Result<TokenStream2> {
let ident = &ast.ident;
trait_bounds::add(ident, &mut ast.generics, &ast.data)?;

let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
ast.generics
.lifetimes_mut()
.for_each(|l| *l = parse_quote!('static));

let (_, ty_generics, where_clause) = ast.generics.split_for_impl();
let generic_type_ids = ast.generics.type_params().map(|ty| {
let ty_ident = &ty.ident;
quote! {
Expand All @@ -83,9 +90,9 @@ fn generate_type(input: TokenStream2) -> Result<TokenStream2> {
Data::Enum(ref e) => generate_variant_type(e),
Data::Union(_) => return Err(Error::new_spanned(input, "Unions not supported")),
};

let generic_types = ast.generics.type_params();
let type_info_impl = quote! {
impl #impl_generics ::scale_info::TypeInfo for #ident #ty_generics #where_clause {
impl <#( #generic_types ),*> ::scale_info::TypeInfo for #ident #ty_generics #where_clause {
type Identity = Self;
fn type_info() -> ::scale_info::Type {
::scale_info::Type::builder()
Expand All @@ -107,6 +114,17 @@ fn generate_fields(fields: &FieldsList) -> Vec<TokenStream2> {
.iter()
.map(|f| {
let (ty, ident) = (&f.ty, &f.ident);
// Replace any field lifetime params with `static to prevent "unnecessary lifetime parameter"
// warning. Any lifetime parameters are specified as 'static in the type of the impl.
struct StaticLifetimesReplace;
impl VisitMut for StaticLifetimesReplace {
fn visit_lifetime_mut(&mut self, lifetime: &mut Lifetime) {
*lifetime = parse_quote!('static)
}
}
let mut ty = ty.clone();
StaticLifetimesReplace.visit_type_mut(&mut ty);

let type_name = clean_type_string(&quote!(#ty).to_string());

if let Some(i) = ident {
Expand Down
39 changes: 22 additions & 17 deletions derive/src/trait_bounds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,29 +28,34 @@ use syn::{
/// associated types (e.g. `T::A: TypeInfo`), correctly dealing with
/// self-referential types.
pub fn add(input_ident: &Ident, generics: &mut Generics, data: &syn::Data) -> Result<()> {
let ty_params = generics.type_params_mut().fold(Vec::new(), |mut acc, p| {
p.bounds.push(parse_quote!(::scale_info::TypeInfo));
p.bounds.push(parse_quote!('static));
acc.push(p.ident.clone());
acc
});
let ty_params_ids = generics
.type_params()
.map(|type_param| type_param.ident.clone())
.collect::<Vec<Ident>>();

if ty_params.is_empty() {
if ty_params_ids.is_empty() {
return Ok(())
}

let types = collect_types_to_bind(input_ident, data, &ty_params)?;

if !types.is_empty() {
let where_clause = generics.make_where_clause();
let types = collect_types_to_bind(input_ident, data, &ty_params_ids)?;
let generics_clone = generics.clone();
dvdplm marked this conversation as resolved.
Show resolved Hide resolved
let where_clause = generics.make_where_clause();

types.into_iter().for_each(|ty| {
where_clause
.predicates
.push(parse_quote!(#ty : ::scale_info::TypeInfo + 'static))
});
}
types.into_iter().for_each(|ty| {
where_clause
.predicates
.push(parse_quote!(#ty : ::scale_info::TypeInfo + 'static))
});

generics_clone.type_params().for_each(|type_param| {
let ident = type_param.ident.clone();
dvdplm marked this conversation as resolved.
Show resolved Hide resolved
let mut bounds = type_param.bounds.clone();
bounds.push(parse_quote!(::scale_info::TypeInfo));
bounds.push(parse_quote!('static));
where_clause
.predicates
.push(parse_quote!( #ident : #bounds));
});
Ok(())
}

Expand Down
11 changes: 8 additions & 3 deletions test_suite/tests/derive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -186,8 +186,9 @@ fn associated_types_derive_without_bounds() {
}
#[allow(unused)]
#[derive(TypeInfo)]
struct Assoc<T: Types> {
struct Assoc<'bar, T: Types> {
a: T::A,
b: &'bar u64,
}

#[derive(TypeInfo)]
Expand All @@ -199,7 +200,11 @@ fn associated_types_derive_without_bounds() {
let struct_type = Type::builder()
.path(Path::new("Assoc", "derive"))
.type_params(tuple_meta_type!(ConcreteTypes))
.composite(Fields::named().field_of::<bool>("a", "T::A"));
.composite(
Fields::named()
.field_of::<bool>("a", "T::A")
.field_of::<u64>("b", "& \'static u64"),
dvdplm marked this conversation as resolved.
Show resolved Hide resolved
);

assert_type!(Assoc<ConcreteTypes>, struct_type);
}
Expand All @@ -209,8 +214,8 @@ fn associated_types_derive_without_bounds() {
fn ui_tests() {
let t = trybuild::TestCases::new();
t.compile_fail("tests/ui/fail_missing_derive.rs");
t.compile_fail("tests/ui/fail_non_static_lifetime.rs");
t.compile_fail("tests/ui/fail_unions.rs");
t.pass("tests/ui/pass_non_static_lifetime.rs");
t.pass("tests/ui/pass_self_referential.rs");
t.pass("tests/ui/pass_basic_generic_type.rs");
t.pass("tests/ui/pass_complex_generic_self_referential_type.rs");
Expand Down
12 changes: 12 additions & 0 deletions test_suite/tests/ui/pass_non_static_lifetime.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
use scale_info::TypeInfo;

#[derive(TypeInfo)]
struct Me<'a> {
_me: &'a Me<'a>,
}

fn assert_type_info<T: TypeInfo + 'static>() {}

fn main() {
assert_type_info::<Me>();
}