Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
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
Next Next commit
Check first segment when looking for recursive types and ensure QSelf…
… is not there

Fixes #73
  • Loading branch information
dvdplm committed Mar 9, 2021
commit 3ba4478a4fcd44bbe898a8b4de966cbf87cd05c5
33 changes: 31 additions & 2 deletions derive/src/trait_bounds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@ use syn::{
parse_quote,
punctuated::Punctuated,
spanned::Spanned,
visit::Visit,
visit::{self, Visit},
Generics,
Result,
Type,
TypePath,
WhereClause,
};

Expand Down Expand Up @@ -112,6 +113,34 @@ fn type_contains_idents(ty: &Type, idents: &[Ident]) -> bool {
visitor.result
}

/// Checks if the given type or any containing type path starts with the given ident.
fn type_or_sub_type_path_starts_with_ident(ty: &Type, ident: &Ident) -> bool {
// Visits the ast and checks if the a type path starts with the given ident.
struct TypePathStartsWithIdent<'a> {
result: bool,
ident: &'a Ident
}

impl<'a, 'ast> Visit<'ast> for TypePathStartsWithIdent<'a> {
fn visit_type_path(&mut self, i: &'ast TypePath) {
if i.qself.is_none() {
if let Some(segment) = i.path.segments.first() {
if &segment.ident == self.ident {
self.result = true;
return;
}
}
}
visit::visit_type_path(self, i);
}
}

let mut visitor = TypePathStartsWithIdent { result: false, ident };
visitor.visit_type(ty);
visitor.result
}


/// Returns all types that must be added to the where clause with a boolean
/// indicating if the field is [`scale::Compact`] or not.
fn collect_types_to_bind(
Expand All @@ -128,7 +157,7 @@ fn collect_types_to_bind(
&&
// Remove all remaining types that start/contain the input ident
// to not have them in the where clause.
!type_contains_idents(&field.ty, &[input_ident.clone()])
!type_or_sub_type_path_starts_with_ident(&field.ty, &input_ident)
})
.map(|f| (f.ty.clone(), super::is_compact(f)))
.collect()
Expand Down
35 changes: 35 additions & 0 deletions test_suite/tests/derive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ use scale_info::{
prelude::{
boxed::Box,
marker::PhantomData,
vec::Vec,
},
tuple_meta_type,
Path,
Expand Down Expand Up @@ -234,6 +235,40 @@ fn associated_types_derive_without_bounds() {
assert_type!(Assoc<ConcreteTypes>, struct_type);
}

#[test]
fn associated_types_named_like_the_derived_type_works() {
trait Types {
type Assoc;
}
#[allow(unused)]
#[derive(TypeInfo)]
struct Assoc<T: Types> {
a: Vec<T::Assoc>,
b: Vec<<T>::Assoc>,
c: T::Assoc,
d: <T>::Assoc,
}

#[derive(TypeInfo)]
enum ConcreteTypes {}
impl Types for ConcreteTypes {
type Assoc = bool;
}

let struct_type = Type::builder()
.path(Path::new("Assoc", "derive"))
.type_params(tuple_meta_type!(ConcreteTypes))
.composite(
Fields::named()
.field_of::<Vec<bool>>("a", "Vec<T::Assoc>")
.field_of::<Vec<bool>>("b", "Vec<<T>::Assoc>")
.field_of::<bool>("c", "T::Assoc")
.field_of::<bool>("d", "<T>::Assoc")
);

assert_type!(Assoc<ConcreteTypes>, struct_type);
}

#[test]
fn scale_compact_types_work_in_structs() {
#[allow(unused)]
Expand Down