diff --git a/src/bindgen/builder.rs b/src/bindgen/builder.rs index a0328b409..a3986a147 100644 --- a/src/bindgen/builder.rs +++ b/src/bindgen/builder.rs @@ -394,6 +394,20 @@ impl Builder { result.source_files.extend_from_slice(self.srcs.as_slice()); + let assoc_types = result + .assoc_types + .into_iter() + .filter_map( + |(id, (ty_, count))| { + if count == 0 { + Some((id, ty_)) + } else { + None + } + }, + ) + .collect(); + Library::new( self.config, result.constants, @@ -405,6 +419,7 @@ impl Builder { result.typedefs, result.functions, result.source_files, + assoc_types, ) .generate() } diff --git a/src/bindgen/ir/constant.rs b/src/bindgen/ir/constant.rs index d3b9bd443..7345e5ea5 100644 --- a/src/bindgen/ir/constant.rs +++ b/src/bindgen/ir/constant.rs @@ -13,8 +13,8 @@ use crate::bindgen::config::{Config, Language}; use crate::bindgen::declarationtyperesolver::DeclarationTypeResolver; use crate::bindgen::dependencies::Dependencies; use crate::bindgen::ir::{ - AnnotationSet, Cfg, ConditionWrite, Documentation, GenericParams, Item, ItemContainer, Path, - Struct, ToCondition, Type, + AnnotationSet, AssocTypeResolver, Cfg, ConditionWrite, Documentation, GenericParams, Item, + ItemContainer, Path, Struct, ToCondition, Type, }; use crate::bindgen::library::Library; use crate::bindgen::writer::{Source, SourceWriter}; @@ -237,6 +237,31 @@ impl Literal { }); uses_only_primitive_types } + + pub fn resolve_assoc_types(&mut self, resolver: &AssocTypeResolver) { + match self { + Literal::PostfixUnaryOp { value, .. } => { + value.resolve_assoc_types(resolver); + } + Literal::BinOp { left, right, .. } => { + left.resolve_assoc_types(resolver); + right.resolve_assoc_types(resolver); + } + Literal::FieldAccess { base, .. } => { + base.resolve_assoc_types(resolver); + } + Literal::Struct { fields, .. } => { + for (_, literal) in fields { + literal.resolve_assoc_types(resolver); + } + } + Literal::Cast { ty, value } => { + value.resolve_assoc_types(resolver); + ty.resolve_assoc_types(resolver); + } + _ => {} + } + } } impl Literal { @@ -689,6 +714,11 @@ impl Item for Constant { fn resolve_declaration_types(&mut self, resolver: &DeclarationTypeResolver) { self.ty.resolve_declaration_types(resolver); } + + fn resolve_assoc_types(&mut self, resolver: &AssocTypeResolver) { + self.ty.resolve_assoc_types(resolver); + self.value.resolve_assoc_types(resolver); + } } impl Constant { diff --git a/src/bindgen/ir/enumeration.rs b/src/bindgen/ir/enumeration.rs index a456b761a..ff832c661 100644 --- a/src/bindgen/ir/enumeration.rs +++ b/src/bindgen/ir/enumeration.rs @@ -10,9 +10,9 @@ use crate::bindgen::config::{Config, Language}; use crate::bindgen::declarationtyperesolver::DeclarationTypeResolver; use crate::bindgen::dependencies::Dependencies; use crate::bindgen::ir::{ - AnnotationSet, AnnotationValue, Cfg, ConditionWrite, DeprecatedNoteKind, Documentation, Field, - GenericArgument, GenericParams, GenericPath, Item, ItemContainer, Literal, Path, Repr, - ReprStyle, Struct, ToCondition, Type, + AnnotationSet, AnnotationValue, AssocTypeResolver, Cfg, ConditionWrite, DeprecatedNoteKind, + Documentation, Field, GenericArgument, GenericParams, GenericPath, Item, ItemContainer, + Literal, Path, Repr, ReprStyle, Struct, ToCondition, Type, }; use crate::bindgen::library::Library; use crate::bindgen::mangle; @@ -652,6 +652,19 @@ impl Item for Enum { variant.add_dependencies(library, out); } } + + fn resolve_assoc_types(&mut self, resolver: &AssocTypeResolver) { + for variant in self.variants.iter_mut() { + if let Some(literal) = variant.discriminant.as_mut() { + literal.resolve_assoc_types(resolver); + } + if let VariantBody::Body { body, .. } = &mut variant.body { + body.resolve_assoc_types(resolver); + } + } + + self.generic_params.resolve_assoc_types(resolver); + } } impl Source for Enum { diff --git a/src/bindgen/ir/function.rs b/src/bindgen/ir/function.rs index 8c65f2f9e..5017f3fa5 100644 --- a/src/bindgen/ir/function.rs +++ b/src/bindgen/ir/function.rs @@ -12,8 +12,8 @@ use crate::bindgen::config::{Config, Language, Layout}; use crate::bindgen::declarationtyperesolver::DeclarationTypeResolver; use crate::bindgen::dependencies::Dependencies; use crate::bindgen::ir::{ - AnnotationSet, Cfg, ConditionWrite, DeprecatedNoteKind, Documentation, GenericPath, Path, - ToCondition, Type, + AnnotationSet, AssocTypeResolver, Cfg, ConditionWrite, DeprecatedNoteKind, Documentation, + GenericPath, Path, ToCondition, Type, }; use crate::bindgen::library::Library; use crate::bindgen::monomorph::Monomorphs; @@ -218,6 +218,14 @@ impl Function { } } } + + pub fn resolve_assoc_types(&mut self, resolver: &AssocTypeResolver) { + self.ret.resolve_assoc_types(resolver); + + for arg in self.args.iter_mut() { + arg.ty.resolve_assoc_types(resolver); + } + } } impl Source for Function { diff --git a/src/bindgen/ir/generic_path.rs b/src/bindgen/ir/generic_path.rs index ef14890ab..6fe285b01 100644 --- a/src/bindgen/ir/generic_path.rs +++ b/src/bindgen/ir/generic_path.rs @@ -6,10 +6,45 @@ use syn::ext::IdentExt; use crate::bindgen::cdecl; use crate::bindgen::config::{Config, Language}; use crate::bindgen::declarationtyperesolver::{DeclarationType, DeclarationTypeResolver}; -use crate::bindgen::ir::{ConstExpr, Path, Type}; +use crate::bindgen::ir::{AssocTypeResolver, ConstExpr, Path, Type}; use crate::bindgen::utilities::IterHelpers; use crate::bindgen::writer::{Source, SourceWriter}; +// Struct that serves as key for resolving associated types +#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub struct AssocTypeId { + pub ty: Box, + pub trait_: Path, + pub ident: Path, +} + +impl AssocTypeId { + pub fn load(path: &syn::Path, qself: &Option) -> Result { + let self_type = &qself + .as_ref() + .ok_or(String::from("Type is not fully-qualified."))? + .ty; + + let ir_type_opt = Type::load(&self_type)?; + let ir_type = ir_type_opt.ok_or(String::from("Valid but empty type"))?; + + let path_len = path.segments.len(); + // Theoretically not possible if qself is present + if path_len < 2 { + return Err(String::from("Trait not found in type")); + } + + let ident = path.segments.last().unwrap().ident.to_string(); + let trait_ident = path.segments[path_len - 2].ident.to_string(); + + Ok(AssocTypeId { + ty: Box::new(ir_type), + trait_: Path::new(trait_ident), + ident: Path::new(ident), + }) + } +} + #[derive(Debug, Clone)] pub enum GenericParamType { Type, @@ -129,6 +164,14 @@ impl GenericParams { pub fn write_with_default(&self, config: &Config, out: &mut SourceWriter) { self.write_internal(config, out, true); } + + pub fn resolve_assoc_types(&mut self, resolver: &AssocTypeResolver) { + for generic_param in self.0.iter_mut() { + if let GenericParamType::Const(ty_) = &mut generic_param.ty { + ty_.resolve_assoc_types(resolver); + } + } + } } impl Deref for GenericParams { @@ -200,6 +243,7 @@ pub struct GenericPath { export_name: String, generics: Vec, ctype: Option, + assoc: Option, } impl GenericPath { @@ -210,6 +254,7 @@ impl GenericPath { export_name, generics, ctype: None, + assoc: None, } } @@ -248,6 +293,10 @@ impl GenericPath { &self.export_name } + pub fn assoc(&self) -> Option<&AssocTypeId> { + self.assoc.as_ref() + } + pub fn is_single_identifier(&self) -> bool { self.generics.is_empty() } @@ -265,7 +314,7 @@ impl GenericPath { self.ctype = resolver.type_for(&self.path); } - pub fn load(path: &syn::Path) -> Result { + pub fn load(path: &syn::Path, qself: &Option) -> Result { assert!( !path.segments.is_empty(), "{:?} doesn't have any segments", @@ -274,6 +323,8 @@ impl GenericPath { let last_segment = path.segments.last().unwrap(); let name = last_segment.ident.unraw().to_string(); + let assoc = AssocTypeId::load(path, qself).ok(); + let path = Path::new(name); let phantom_data_path = Path::new("PhantomData"); if path == phantom_data_path { @@ -298,6 +349,9 @@ impl GenericPath { _ => Vec::new(), }; - Ok(Self::new(path, generics)) + let mut ret = Self::new(path, generics); + ret.assoc = assoc; + + Ok(ret) } } diff --git a/src/bindgen/ir/global.rs b/src/bindgen/ir/global.rs index 82a1756e1..7afe88e91 100644 --- a/src/bindgen/ir/global.rs +++ b/src/bindgen/ir/global.rs @@ -8,7 +8,9 @@ use crate::bindgen::cdecl; use crate::bindgen::config::Config; use crate::bindgen::declarationtyperesolver::DeclarationTypeResolver; use crate::bindgen::dependencies::Dependencies; -use crate::bindgen::ir::{AnnotationSet, Cfg, Documentation, Item, ItemContainer, Path, Type}; +use crate::bindgen::ir::{ + AnnotationSet, AssocTypeResolver, Cfg, Documentation, Item, ItemContainer, Path, Type, +}; use crate::bindgen::library::Library; use crate::bindgen::writer::{Source, SourceWriter}; @@ -106,6 +108,10 @@ impl Item for Static { fn add_dependencies(&self, library: &Library, out: &mut Dependencies) { self.ty.add_dependencies(library, out); } + + fn resolve_assoc_types(&mut self, resolver: &AssocTypeResolver) { + self.ty.resolve_assoc_types(resolver); + } } impl Source for Static { diff --git a/src/bindgen/ir/item.rs b/src/bindgen/ir/item.rs index 16d98f55d..cdf9f76d5 100644 --- a/src/bindgen/ir/item.rs +++ b/src/bindgen/ir/item.rs @@ -9,8 +9,8 @@ use crate::bindgen::config::Config; use crate::bindgen::declarationtyperesolver::DeclarationTypeResolver; use crate::bindgen::dependencies::Dependencies; use crate::bindgen::ir::{ - AnnotationSet, Cfg, Constant, Enum, GenericArgument, OpaqueItem, Path, Static, Struct, Typedef, - Union, + AnnotationSet, AssocTypeResolver, Cfg, Constant, Enum, GenericArgument, OpaqueItem, Path, + Static, Struct, Typedef, Union, }; use crate::bindgen::library::Library; use crate::bindgen::monomorph::Monomorphs; @@ -46,6 +46,7 @@ pub trait Item { ) { unreachable!("Cannot instantiate {} as a generic.", self.name()) } + fn resolve_assoc_types(&mut self, resolver: &AssocTypeResolver); } #[derive(Debug, Clone)] diff --git a/src/bindgen/ir/opaque.rs b/src/bindgen/ir/opaque.rs index 4451d4a16..90a03dd2d 100644 --- a/src/bindgen/ir/opaque.rs +++ b/src/bindgen/ir/opaque.rs @@ -8,8 +8,8 @@ use crate::bindgen::config::{Config, Language}; use crate::bindgen::declarationtyperesolver::DeclarationTypeResolver; use crate::bindgen::dependencies::Dependencies; use crate::bindgen::ir::{ - AnnotationSet, Cfg, ConditionWrite, Documentation, GenericArgument, GenericParams, Item, - ItemContainer, Path, ToCondition, + AnnotationSet, AssocTypeResolver, Cfg, ConditionWrite, Documentation, GenericArgument, + GenericParams, Item, ItemContainer, Path, ToCondition, }; use crate::bindgen::library::Library; use crate::bindgen::mangle; @@ -135,6 +135,10 @@ impl Item for OpaqueItem { out.insert_opaque(self, monomorph, generic_values.to_owned()); } + + fn resolve_assoc_types(&mut self, resolver: &AssocTypeResolver) { + self.generic_params.resolve_assoc_types(resolver); + } } impl Source for OpaqueItem { diff --git a/src/bindgen/ir/structure.rs b/src/bindgen/ir/structure.rs index 2eefa953d..44d7e16b2 100644 --- a/src/bindgen/ir/structure.rs +++ b/src/bindgen/ir/structure.rs @@ -10,9 +10,9 @@ use crate::bindgen::config::{Config, Language, LayoutConfig}; use crate::bindgen::declarationtyperesolver::DeclarationTypeResolver; use crate::bindgen::dependencies::Dependencies; use crate::bindgen::ir::{ - AnnotationSet, Cfg, ConditionWrite, Constant, DeprecatedNoteKind, Documentation, Field, - GenericArgument, GenericParams, Item, ItemContainer, Path, Repr, ReprAlign, ReprStyle, - ToCondition, Type, Typedef, + AnnotationSet, AssocTypeResolver, Cfg, ConditionWrite, Constant, DeprecatedNoteKind, + Documentation, Field, GenericArgument, GenericParams, Item, ItemContainer, Path, Repr, + ReprAlign, ReprStyle, ToCondition, Type, Typedef, }; use crate::bindgen::library::Library; use crate::bindgen::mangle; @@ -374,6 +374,16 @@ impl Item for Struct { let monomorph = self.specialize(generic_values, &mappings, library.get_config()); out.insert_struct(library, self, monomorph, generic_values.to_owned()); } + + fn resolve_assoc_types(&mut self, resolver: &AssocTypeResolver) { + self.generic_params.resolve_assoc_types(resolver); + for field in self.fields.iter_mut() { + field.ty.resolve_assoc_types(resolver); + } + for const_ in self.associated_constants.iter_mut() { + const_.resolve_assoc_types(resolver); + } + } } impl Source for Struct { diff --git a/src/bindgen/ir/ty.rs b/src/bindgen/ir/ty.rs index 5a31fb646..411686cc1 100644 --- a/src/bindgen/ir/ty.rs +++ b/src/bindgen/ir/ty.rs @@ -3,6 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use std::borrow::Cow; +use std::collections::HashMap; use std::io::Write; use syn::ext::IdentExt; @@ -11,7 +12,7 @@ use crate::bindgen::cdecl; use crate::bindgen::config::{Config, Language}; use crate::bindgen::declarationtyperesolver::DeclarationTypeResolver; use crate::bindgen::dependencies::Dependencies; -use crate::bindgen::ir::{GenericArgument, GenericParams, GenericPath, Path}; +use crate::bindgen::ir::{AssocTypeId, GenericArgument, GenericParams, GenericPath, Path}; use crate::bindgen::library::Library; use crate::bindgen::monomorph::Monomorphs; use crate::bindgen::utilities::IterHelpers; @@ -344,7 +345,7 @@ impl ConstExpr { Ok(ConstExpr::Value(val)) } syn::Expr::Path(ref path) => { - let generic_path = GenericPath::load(&path.path)?; + let generic_path = GenericPath::load(&path.path, &path.qself)?; Ok(ConstExpr::Name(generic_path.export_name().to_owned())) } _ => Err(format!("can't handle const expression {:?}", expr)), @@ -408,6 +409,8 @@ pub enum Type { }, } +pub type AssocTypeResolver = HashMap; + impl Type { pub fn const_ref_to(ty: &Self) -> Self { Type::Ptr { @@ -470,7 +473,7 @@ impl Type { } } syn::Type::Path(ref path) => { - let generic_path = GenericPath::load(&path.path)?; + let generic_path = GenericPath::load(&path.path, &path.qself)?; if generic_path.name() == "PhantomData" || generic_path.name() == "PhantomPinned" { return Ok(None); @@ -1002,6 +1005,32 @@ impl Type { Type::FuncPtr { .. } => true, } } + + // Search and replace specific associated types with concrete types + pub fn resolve_assoc_types(&mut self, resolver: &AssocTypeResolver) { + match self { + Type::Ptr { ty: ty_, .. } => { + ty_.resolve_assoc_types(resolver); + } + Type::Array(ty_, _) => { + ty_.resolve_assoc_types(resolver); + } + Type::FuncPtr { ret, args, .. } => { + ret.resolve_assoc_types(resolver); + for (_, ty_) in args { + ty_.resolve_assoc_types(resolver); + } + } + Type::Path(generic_path) => { + if let Some(id) = generic_path.assoc() { + if let Some(concrete) = resolver.get(id) { + *self = concrete.clone(); + } + } + } + _ => {} + } + } } impl Source for String { diff --git a/src/bindgen/ir/typedef.rs b/src/bindgen/ir/typedef.rs index 626732e2a..9068a07ac 100644 --- a/src/bindgen/ir/typedef.rs +++ b/src/bindgen/ir/typedef.rs @@ -11,8 +11,8 @@ use crate::bindgen::config::{Config, Language}; use crate::bindgen::declarationtyperesolver::DeclarationTypeResolver; use crate::bindgen::dependencies::Dependencies; use crate::bindgen::ir::{ - AnnotationSet, Cfg, ConditionWrite, Documentation, Field, GenericArgument, GenericParams, Item, - ItemContainer, Path, ToCondition, Type, + AnnotationSet, AssocTypeResolver, Cfg, ConditionWrite, Documentation, Field, GenericArgument, + GenericParams, Item, ItemContainer, Path, ToCondition, Type, }; use crate::bindgen::library::Library; use crate::bindgen::mangle; @@ -178,6 +178,11 @@ impl Item for Typedef { out.insert_typedef(library, self, monomorph, generic_values.to_owned()); } + + fn resolve_assoc_types(&mut self, resolver: &AssocTypeResolver) { + self.generic_params.resolve_assoc_types(resolver); + self.aliased.resolve_assoc_types(resolver); + } } impl Source for Typedef { diff --git a/src/bindgen/ir/union.rs b/src/bindgen/ir/union.rs index 07bd16c58..d1d13b990 100644 --- a/src/bindgen/ir/union.rs +++ b/src/bindgen/ir/union.rs @@ -10,8 +10,8 @@ use crate::bindgen::config::{Config, Language, LayoutConfig}; use crate::bindgen::declarationtyperesolver::DeclarationTypeResolver; use crate::bindgen::dependencies::Dependencies; use crate::bindgen::ir::{ - AnnotationSet, Cfg, ConditionWrite, Documentation, Field, GenericArgument, GenericParams, Item, - ItemContainer, Path, Repr, ReprAlign, ReprStyle, ToCondition, + AnnotationSet, AssocTypeResolver, Cfg, ConditionWrite, Documentation, Field, GenericArgument, + GenericParams, Item, ItemContainer, Path, Repr, ReprAlign, ReprStyle, ToCondition, }; use crate::bindgen::library::Library; use crate::bindgen::mangle; @@ -257,6 +257,13 @@ impl Item for Union { out.insert_union(library, self, monomorph, generic_values.to_owned()); } + + fn resolve_assoc_types(&mut self, resolver: &AssocTypeResolver) { + self.generic_params.resolve_assoc_types(resolver); + for field in self.fields.iter_mut() { + field.ty.resolve_assoc_types(resolver); + } + } } impl Source for Union { diff --git a/src/bindgen/library.rs b/src/bindgen/library.rs index cb4cfbd3a..9696f20dc 100644 --- a/src/bindgen/library.rs +++ b/src/bindgen/library.rs @@ -10,7 +10,9 @@ use crate::bindgen::config::{Config, Language, SortKey}; use crate::bindgen::declarationtyperesolver::DeclarationTypeResolver; use crate::bindgen::dependencies::Dependencies; use crate::bindgen::error::Error; -use crate::bindgen::ir::{Constant, Enum, Function, Item, ItemContainer, ItemMap}; +use crate::bindgen::ir::{ + AssocTypeId, Constant, Enum, Function, Item, ItemContainer, ItemMap, Type, +}; use crate::bindgen::ir::{OpaqueItem, Path, Static, Struct, Typedef, Union}; use crate::bindgen::monomorph::Monomorphs; use crate::bindgen::ItemType; @@ -27,6 +29,7 @@ pub struct Library { typedefs: ItemMap, functions: Vec, source_files: Vec, + assoc_types: HashMap, } impl Library { @@ -42,6 +45,7 @@ impl Library { typedefs: ItemMap, functions: Vec, source_files: Vec, + assoc_types: HashMap, ) -> Library { Library { config, @@ -54,10 +58,13 @@ impl Library { typedefs, functions, source_files, + assoc_types, } } pub fn generate(mut self) -> Result { + self.replace_assoc_types(); + self.transfer_annotations(); self.simplify_standard_types(); @@ -443,4 +450,41 @@ impl Library { x.mangle_paths(&monomorphs); } } + + // Replace all associated types with concrete types + fn replace_assoc_types(&mut self) { + let assoc_map = &self.assoc_types; + + self.constants.for_all_items_mut(|const_| { + const_.resolve_assoc_types(assoc_map); + }); + + self.globals.for_all_items_mut(|static_| { + static_.resolve_assoc_types(assoc_map); + }); + + self.enums.for_all_items_mut(|enum_| { + enum_.resolve_assoc_types(assoc_map); + }); + + self.structs.for_all_items_mut(|struct_| { + struct_.resolve_assoc_types(assoc_map); + }); + + self.unions.for_all_items_mut(|union_| { + union_.resolve_assoc_types(assoc_map); + }); + + self.opaque_items.for_all_items_mut(|opaque_item| { + opaque_item.resolve_assoc_types(assoc_map); + }); + + self.typedefs.for_all_items_mut(|typedef| { + typedef.resolve_assoc_types(assoc_map); + }); + + for func in self.functions.iter_mut() { + func.resolve_assoc_types(assoc_map); + } + } } diff --git a/src/bindgen/parser.rs b/src/bindgen/parser.rs index b54c7fbbd..07e336438 100644 --- a/src/bindgen/parser.rs +++ b/src/bindgen/parser.rs @@ -15,8 +15,8 @@ use crate::bindgen::cargo::{Cargo, PackageRef}; use crate::bindgen::config::{Config, ParseConfig}; use crate::bindgen::error::Error; use crate::bindgen::ir::{ - AnnotationSet, AnnotationValue, Cfg, Constant, Documentation, Enum, Function, GenericParam, - GenericParams, ItemMap, OpaqueItem, Path, Static, Struct, Type, Typedef, Union, + AnnotationSet, AnnotationValue, AssocTypeId, Cfg, Constant, Documentation, Enum, Function, + GenericParam, GenericParams, ItemMap, OpaqueItem, Path, Static, Struct, Type, Typedef, Union, }; use crate::bindgen::utilities::{SynAbiHelpers, SynAttributeHelpers, SynItemHelpers}; @@ -409,6 +409,10 @@ pub struct Parse { pub typedefs: ItemMap, pub functions: Vec, pub source_files: Vec, + pub assoc_types: HashMap, + // If A depends on B e.g. impl trait for A{ type inner = B } + // Key is B, Value is all A's + pending_assoc_types: HashMap>, } impl Parse { @@ -423,6 +427,8 @@ impl Parse { typedefs: ItemMap::default(), functions: Vec::new(), source_files: Vec::new(), + assoc_types: HashMap::new(), + pending_assoc_types: HashMap::new(), } } @@ -471,6 +477,7 @@ impl Parse { self.typedefs.extend_with(&other.typedefs); self.functions.extend_from_slice(&other.functions); self.source_files.extend_from_slice(&other.source_files); + self.assoc_types = other.assoc_types.clone(); } fn load_syn_crate_mod<'a>( @@ -545,6 +552,8 @@ impl Parse { } } } + + self.load_syn_impl(item_impl); } syn::Item::Macro(ref item) => { self.load_builtin_macro(config, crate_name, mod_cfg, item); @@ -563,6 +572,175 @@ impl Parse { nested_modules } + fn load_syn_impl(&mut self, item_impl: &syn::ItemImpl) { + let trait_ = if let Some((_, path, _)) = &item_impl.trait_ { + Path::new(path.segments.last().unwrap().ident.to_string()) + } else { + return; + }; + + fn try_type_load(ty: &syn::Type) -> Result { + match Type::load(ty) { + Ok(opt) => match opt { + Some(output) => return Ok(output), + None => { + warn!("Err parsing assoc type in impl: Valid but empty type"); + } + }, + Err(msg) => { + warn!("Err parsing assoc type in impl: {}", msg); + } + } + + Err(()) + } + + for impl_item in &item_impl.items { + if let syn::ImplItem::Type(impl_item_type) = impl_item { + let ty = if let Ok(ty) = try_type_load(&item_impl.self_ty) { + ty + } else { + continue; + }; + + let ident = impl_item_type.ident.to_string(); + let ident = Path::new(ident); + + let key = AssocTypeId { + ty: Box::new(ty), + trait_: trait_.clone(), + ident, + }; + + let syn_type = &impl_item_type.ty; + + let mut conc_type = if let Ok(ty) = try_type_load(syn_type) { + ty + } else { + continue; + }; + let mut count: u8 = 0; + + // Check if concrete type is another associated type + Parse::check_nested_assoc_types( + &mut self.pending_assoc_types, + &mut self.assoc_types, + &key, + &mut conc_type, + &mut count, + ); + + self.assoc_types + .insert(key.clone(), (conc_type.clone(), count)); + + // Check if fully resolved, if so, check whether other types depend on this key + if count == 0 { + Parse::check_satisfy( + &mut self.pending_assoc_types, + &mut self.assoc_types, + &key, + &conc_type, + ); + } + } + } + } + + // Recursive function, marks all nested associated types and count dependencies + fn check_nested_assoc_types( + pending_types: &mut HashMap>, + assoc_types: &mut HashMap, + key: &AssocTypeId, + conc_type: &mut Type, + count: &mut u8, + ) { + match conc_type { + Type::Ptr { ty: ty_, .. } => { + Parse::check_nested_assoc_types(pending_types, assoc_types, key, &mut **ty_, count); + } + Type::Array(ty_, _) => { + Parse::check_nested_assoc_types(pending_types, assoc_types, key, &mut **ty_, count); + } + Type::FuncPtr { ret, args, .. } => { + Parse::check_nested_assoc_types(pending_types, assoc_types, key, &mut **ret, count); + for (_, ty_) in args { + Parse::check_nested_assoc_types(pending_types, assoc_types, key, ty_, count); + } + } + Type::Path(generic_path) => { + if let Some(id) = generic_path.assoc() { + if let Some((ty, 0)) = assoc_types.get(id) { + *conc_type = ty.clone(); + } else { + pending_types + .entry(id.clone()) + .or_default() + .push(key.clone()); + + *count += 1; + } + } + } + _ => {} + } + } + + // Given key k that is fully resolved, check what depends on k and resolve those + fn check_satisfy( + pending_types: &mut HashMap>, + assoc_types: &mut HashMap, + key: &AssocTypeId, + resolved_ty: &Type, + ) { + let mut to_resolve: Vec = Vec::new(); + if let Some(id_vec) = pending_types.remove(key) { + for id in id_vec { + let (curr_ty, count) = assoc_types.get_mut(&id).unwrap(); + Parse::check_satisfy_id(key, resolved_ty, &id, curr_ty, count); + if *count == 0 { + to_resolve.push(id.clone()); + } + } + } + + for id in to_resolve { + let curr_ty = assoc_types.get(&id).unwrap().0.clone(); + Parse::check_satisfy(pending_types, assoc_types, &id, &curr_ty); + } + } + + fn check_satisfy_id( + resolved_key: &AssocTypeId, + resolved_ty: &Type, + curr_key: &AssocTypeId, + curr_ty: &mut Type, + count: &mut u8, + ) { + match curr_ty { + Type::Ptr { ty: ty_, .. } => { + Parse::check_satisfy_id(resolved_key, resolved_ty, curr_key, ty_, count); + } + Type::Array(ty_, _) => { + Parse::check_satisfy_id(resolved_key, resolved_ty, curr_key, ty_, count); + } + Type::FuncPtr { ret, args, .. } => { + Parse::check_satisfy_id(resolved_key, resolved_ty, curr_key, ret, count); + for (_, ty_) in args { + Parse::check_satisfy_id(resolved_key, resolved_ty, curr_key, ty_, count) + } + } + Type::Path(generic_path) => { + if let Some(id) = generic_path.assoc() { + if id == resolved_key { + *curr_ty = resolved_ty.clone(); + *count -= 1; + } + } + } + _ => {} + } + } + fn load_syn_assoc_consts_from_impl( &mut self, crate_name: &str, diff --git a/tests/expectations/assoc_types.c b/tests/expectations/assoc_types.c new file mode 100644 index 000000000..57c472d1b --- /dev/null +++ b/tests/expectations/assoc_types.c @@ -0,0 +1,76 @@ +#include +#include +#include +#include + +#define CONST_TEST_1 50 + +#define CONST_TEST_2 100 + +typedef enum { + enum_var1, + enum_var2, + enum_var3, +} EnumTest_Tag; + +typedef struct { + bool a; + uint64_t b; +} enum_var3_Body; + +typedef struct { + EnumTest_Tag tag; + union { + struct { + uint8_t enum_var2[5]; + }; + enum_var3_Body enum_var3; + }; +} EnumTest; + +typedef struct { + uint8_t a; + int64_t b; + bool c[36]; +} AnotherStruct; + +typedef enum { + union_var1, + union_var2, + union_var3, +} UnionTest_Tag; + +typedef struct { + bool a; + uint64_t b; +} union_var3_Body; + +typedef struct { + UnionTest_Tag tag; + union { + struct { + uint8_t union_var2[5]; + }; + union_var3_Body union_var3; + }; +} UnionTest; + +typedef int64_t typedef_test; + +extern const uint64_t STATIC_TEST_1[5]; + +extern const bool STATIC_TEST_2; + +void test_enum(EnumTest enum_); + +void test_struct_gen(AnotherStruct struct_); + +void test_union(UnionTest union_); + +void test_typedefs(typedef_test typedef_); + +int64_t test_fn(const int64_t *struct_); + +void test_func_ptr(bool (*fn_ptr)(uint64_t, bool)); + +void test_raw_ptr(const bool *a, uint64_t *b); diff --git a/tests/expectations/assoc_types.compat.c b/tests/expectations/assoc_types.compat.c new file mode 100644 index 000000000..286747f29 --- /dev/null +++ b/tests/expectations/assoc_types.compat.c @@ -0,0 +1,84 @@ +#include +#include +#include +#include + +#define CONST_TEST_1 50 + +#define CONST_TEST_2 100 + +typedef enum { + enum_var1, + enum_var2, + enum_var3, +} EnumTest_Tag; + +typedef struct { + bool a; + uint64_t b; +} enum_var3_Body; + +typedef struct { + EnumTest_Tag tag; + union { + struct { + uint8_t enum_var2[5]; + }; + enum_var3_Body enum_var3; + }; +} EnumTest; + +typedef struct { + uint8_t a; + int64_t b; + bool c[36]; +} AnotherStruct; + +typedef enum { + union_var1, + union_var2, + union_var3, +} UnionTest_Tag; + +typedef struct { + bool a; + uint64_t b; +} union_var3_Body; + +typedef struct { + UnionTest_Tag tag; + union { + struct { + uint8_t union_var2[5]; + }; + union_var3_Body union_var3; + }; +} UnionTest; + +typedef int64_t typedef_test; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +extern const uint64_t STATIC_TEST_1[5]; + +extern const bool STATIC_TEST_2; + +void test_enum(EnumTest enum_); + +void test_struct_gen(AnotherStruct struct_); + +void test_union(UnionTest union_); + +void test_typedefs(typedef_test typedef_); + +int64_t test_fn(const int64_t *struct_); + +void test_func_ptr(bool (*fn_ptr)(uint64_t, bool)); + +void test_raw_ptr(const bool *a, uint64_t *b); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/expectations/assoc_types.cpp b/tests/expectations/assoc_types.cpp new file mode 100644 index 000000000..8b4fedd3d --- /dev/null +++ b/tests/expectations/assoc_types.cpp @@ -0,0 +1,85 @@ +#include +#include +#include +#include +#include + +constexpr static const int64_t CONST_TEST_1 = 50; + +constexpr static const uint64_t CONST_TEST_2 = 100; + +struct EnumTest { + enum class Tag { + enum_var1, + enum_var2, + enum_var3, + }; + + struct enum_var2_Body { + uint8_t _0[5]; + }; + + struct enum_var3_Body { + bool a; + uint64_t b; + }; + + Tag tag; + union { + enum_var2_Body enum_var2; + enum_var3_Body enum_var3; + }; +}; + +struct AnotherStruct { + uint8_t a; + int64_t b; + bool c[36]; +}; + +struct UnionTest { + enum class Tag { + union_var1, + union_var2, + union_var3, + }; + + struct union_var2_Body { + uint8_t _0[5]; + }; + + struct union_var3_Body { + bool a; + uint64_t b; + }; + + Tag tag; + union { + union_var2_Body union_var2; + union_var3_Body union_var3; + }; +}; + +using typedef_test = int64_t; + +extern "C" { + +extern const uint64_t STATIC_TEST_1[5]; + +extern const bool STATIC_TEST_2; + +void test_enum(EnumTest enum_); + +void test_struct_gen(AnotherStruct struct_); + +void test_union(UnionTest union_); + +void test_typedefs(typedef_test typedef_); + +int64_t test_fn(const int64_t *struct_); + +void test_func_ptr(bool (*fn_ptr)(uint64_t, bool)); + +void test_raw_ptr(const bool *a, uint64_t *b); + +} // extern "C" diff --git a/tests/expectations/assoc_types.pyx b/tests/expectations/assoc_types.pyx new file mode 100644 index 000000000..e639c5b3b --- /dev/null +++ b/tests/expectations/assoc_types.pyx @@ -0,0 +1,64 @@ +from libc.stdint cimport int8_t, int16_t, int32_t, int64_t, intptr_t +from libc.stdint cimport uint8_t, uint16_t, uint32_t, uint64_t, uintptr_t +cdef extern from *: + ctypedef bint bool + ctypedef struct va_list + +cdef extern from *: + + const int64_t CONST_TEST_1 # = 50 + + const uint64_t CONST_TEST_2 # = 100 + + ctypedef enum EnumTest_Tag: + enum_var1, + enum_var2, + enum_var3, + + ctypedef struct enum_var3_Body: + bool a; + uint64_t b; + + ctypedef struct EnumTest: + EnumTest_Tag tag; + uint8_t enum_var2[5]; + enum_var3_Body enum_var3; + + ctypedef struct AnotherStruct: + uint8_t a; + int64_t b; + bool c[36]; + + ctypedef enum UnionTest_Tag: + union_var1, + union_var2, + union_var3, + + ctypedef struct union_var3_Body: + bool a; + uint64_t b; + + ctypedef struct UnionTest: + UnionTest_Tag tag; + uint8_t union_var2[5]; + union_var3_Body union_var3; + + ctypedef int64_t typedef_test; + + extern const uint64_t STATIC_TEST_1[5]; + + extern const bool STATIC_TEST_2; + + void test_enum(EnumTest enum_); + + void test_struct_gen(AnotherStruct struct_); + + void test_union(UnionTest union_); + + void test_typedefs(typedef_test typedef_); + + int64_t test_fn(const int64_t *struct_); + + void test_func_ptr(bool (*fn_ptr)(uint64_t, bool)); + + void test_raw_ptr(const bool *a, uint64_t *b); diff --git a/tests/expectations/assoc_types_both.c b/tests/expectations/assoc_types_both.c new file mode 100644 index 000000000..931f3373a --- /dev/null +++ b/tests/expectations/assoc_types_both.c @@ -0,0 +1,76 @@ +#include +#include +#include +#include + +#define CONST_TEST_1 50 + +#define CONST_TEST_2 100 + +typedef enum EnumTest_Tag { + enum_var1, + enum_var2, + enum_var3, +} EnumTest_Tag; + +typedef struct enum_var3_Body { + bool a; + uint64_t b; +} enum_var3_Body; + +typedef struct EnumTest { + EnumTest_Tag tag; + union { + struct { + uint8_t enum_var2[5]; + }; + enum_var3_Body enum_var3; + }; +} EnumTest; + +typedef struct AnotherStruct { + uint8_t a; + int64_t b; + bool c[36]; +} AnotherStruct; + +typedef enum UnionTest_Tag { + union_var1, + union_var2, + union_var3, +} UnionTest_Tag; + +typedef struct union_var3_Body { + bool a; + uint64_t b; +} union_var3_Body; + +typedef struct UnionTest { + UnionTest_Tag tag; + union { + struct { + uint8_t union_var2[5]; + }; + union_var3_Body union_var3; + }; +} UnionTest; + +typedef int64_t typedef_test; + +extern const uint64_t STATIC_TEST_1[5]; + +extern const bool STATIC_TEST_2; + +void test_enum(struct EnumTest enum_); + +void test_struct_gen(struct AnotherStruct struct_); + +void test_union(struct UnionTest union_); + +void test_typedefs(typedef_test typedef_); + +int64_t test_fn(const int64_t *struct_); + +void test_func_ptr(bool (*fn_ptr)(uint64_t, bool)); + +void test_raw_ptr(const bool *a, uint64_t *b); diff --git a/tests/expectations/assoc_types_both.compat.c b/tests/expectations/assoc_types_both.compat.c new file mode 100644 index 000000000..28460104d --- /dev/null +++ b/tests/expectations/assoc_types_both.compat.c @@ -0,0 +1,84 @@ +#include +#include +#include +#include + +#define CONST_TEST_1 50 + +#define CONST_TEST_2 100 + +typedef enum EnumTest_Tag { + enum_var1, + enum_var2, + enum_var3, +} EnumTest_Tag; + +typedef struct enum_var3_Body { + bool a; + uint64_t b; +} enum_var3_Body; + +typedef struct EnumTest { + EnumTest_Tag tag; + union { + struct { + uint8_t enum_var2[5]; + }; + enum_var3_Body enum_var3; + }; +} EnumTest; + +typedef struct AnotherStruct { + uint8_t a; + int64_t b; + bool c[36]; +} AnotherStruct; + +typedef enum UnionTest_Tag { + union_var1, + union_var2, + union_var3, +} UnionTest_Tag; + +typedef struct union_var3_Body { + bool a; + uint64_t b; +} union_var3_Body; + +typedef struct UnionTest { + UnionTest_Tag tag; + union { + struct { + uint8_t union_var2[5]; + }; + union_var3_Body union_var3; + }; +} UnionTest; + +typedef int64_t typedef_test; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +extern const uint64_t STATIC_TEST_1[5]; + +extern const bool STATIC_TEST_2; + +void test_enum(struct EnumTest enum_); + +void test_struct_gen(struct AnotherStruct struct_); + +void test_union(struct UnionTest union_); + +void test_typedefs(typedef_test typedef_); + +int64_t test_fn(const int64_t *struct_); + +void test_func_ptr(bool (*fn_ptr)(uint64_t, bool)); + +void test_raw_ptr(const bool *a, uint64_t *b); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/expectations/assoc_types_nested.c b/tests/expectations/assoc_types_nested.c new file mode 100644 index 000000000..36adc89b3 --- /dev/null +++ b/tests/expectations/assoc_types_nested.c @@ -0,0 +1,8 @@ +#include +#include +#include +#include + +bool test_nested_assoc(bool out, bool mid); + +void test_double_assoc(bool double_[10]); diff --git a/tests/expectations/assoc_types_nested.compat.c b/tests/expectations/assoc_types_nested.compat.c new file mode 100644 index 000000000..515d11e07 --- /dev/null +++ b/tests/expectations/assoc_types_nested.compat.c @@ -0,0 +1,16 @@ +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +bool test_nested_assoc(bool out, bool mid); + +void test_double_assoc(bool double_[10]); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/expectations/assoc_types_nested.cpp b/tests/expectations/assoc_types_nested.cpp new file mode 100644 index 000000000..bd5c1d5ec --- /dev/null +++ b/tests/expectations/assoc_types_nested.cpp @@ -0,0 +1,13 @@ +#include +#include +#include +#include +#include + +extern "C" { + +bool test_nested_assoc(bool out, bool mid); + +void test_double_assoc(bool double_[10]); + +} // extern "C" diff --git a/tests/expectations/assoc_types_nested.pyx b/tests/expectations/assoc_types_nested.pyx new file mode 100644 index 000000000..fe327d7cf --- /dev/null +++ b/tests/expectations/assoc_types_nested.pyx @@ -0,0 +1,11 @@ +from libc.stdint cimport int8_t, int16_t, int32_t, int64_t, intptr_t +from libc.stdint cimport uint8_t, uint16_t, uint32_t, uint64_t, uintptr_t +cdef extern from *: + ctypedef bint bool + ctypedef struct va_list + +cdef extern from *: + + bool test_nested_assoc(bool out, bool mid); + + void test_double_assoc(bool double_[10]); diff --git a/tests/expectations/assoc_types_tag.c b/tests/expectations/assoc_types_tag.c new file mode 100644 index 000000000..02680c2fb --- /dev/null +++ b/tests/expectations/assoc_types_tag.c @@ -0,0 +1,76 @@ +#include +#include +#include +#include + +#define CONST_TEST_1 50 + +#define CONST_TEST_2 100 + +enum EnumTest_Tag { + enum_var1, + enum_var2, + enum_var3, +}; + +struct enum_var3_Body { + bool a; + uint64_t b; +}; + +struct EnumTest { + enum EnumTest_Tag tag; + union { + struct { + uint8_t enum_var2[5]; + }; + struct enum_var3_Body enum_var3; + }; +}; + +struct AnotherStruct { + uint8_t a; + int64_t b; + bool c[36]; +}; + +enum UnionTest_Tag { + union_var1, + union_var2, + union_var3, +}; + +struct union_var3_Body { + bool a; + uint64_t b; +}; + +struct UnionTest { + enum UnionTest_Tag tag; + union { + struct { + uint8_t union_var2[5]; + }; + struct union_var3_Body union_var3; + }; +}; + +typedef int64_t typedef_test; + +extern const uint64_t STATIC_TEST_1[5]; + +extern const bool STATIC_TEST_2; + +void test_enum(struct EnumTest enum_); + +void test_struct_gen(struct AnotherStruct struct_); + +void test_union(struct UnionTest union_); + +void test_typedefs(typedef_test typedef_); + +int64_t test_fn(const int64_t *struct_); + +void test_func_ptr(bool (*fn_ptr)(uint64_t, bool)); + +void test_raw_ptr(const bool *a, uint64_t *b); diff --git a/tests/expectations/assoc_types_tag.compat.c b/tests/expectations/assoc_types_tag.compat.c new file mode 100644 index 000000000..695712228 --- /dev/null +++ b/tests/expectations/assoc_types_tag.compat.c @@ -0,0 +1,84 @@ +#include +#include +#include +#include + +#define CONST_TEST_1 50 + +#define CONST_TEST_2 100 + +enum EnumTest_Tag { + enum_var1, + enum_var2, + enum_var3, +}; + +struct enum_var3_Body { + bool a; + uint64_t b; +}; + +struct EnumTest { + enum EnumTest_Tag tag; + union { + struct { + uint8_t enum_var2[5]; + }; + struct enum_var3_Body enum_var3; + }; +}; + +struct AnotherStruct { + uint8_t a; + int64_t b; + bool c[36]; +}; + +enum UnionTest_Tag { + union_var1, + union_var2, + union_var3, +}; + +struct union_var3_Body { + bool a; + uint64_t b; +}; + +struct UnionTest { + enum UnionTest_Tag tag; + union { + struct { + uint8_t union_var2[5]; + }; + struct union_var3_Body union_var3; + }; +}; + +typedef int64_t typedef_test; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +extern const uint64_t STATIC_TEST_1[5]; + +extern const bool STATIC_TEST_2; + +void test_enum(struct EnumTest enum_); + +void test_struct_gen(struct AnotherStruct struct_); + +void test_union(struct UnionTest union_); + +void test_typedefs(typedef_test typedef_); + +int64_t test_fn(const int64_t *struct_); + +void test_func_ptr(bool (*fn_ptr)(uint64_t, bool)); + +void test_raw_ptr(const bool *a, uint64_t *b); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/expectations/assoc_types_tag.pyx b/tests/expectations/assoc_types_tag.pyx new file mode 100644 index 000000000..1fbdf1492 --- /dev/null +++ b/tests/expectations/assoc_types_tag.pyx @@ -0,0 +1,64 @@ +from libc.stdint cimport int8_t, int16_t, int32_t, int64_t, intptr_t +from libc.stdint cimport uint8_t, uint16_t, uint32_t, uint64_t, uintptr_t +cdef extern from *: + ctypedef bint bool + ctypedef struct va_list + +cdef extern from *: + + const int64_t CONST_TEST_1 # = 50 + + const uint64_t CONST_TEST_2 # = 100 + + cdef enum EnumTest_Tag: + enum_var1, + enum_var2, + enum_var3, + + cdef struct enum_var3_Body: + bool a; + uint64_t b; + + cdef struct EnumTest: + EnumTest_Tag tag; + uint8_t enum_var2[5]; + enum_var3_Body enum_var3; + + cdef struct AnotherStruct: + uint8_t a; + int64_t b; + bool c[36]; + + cdef enum UnionTest_Tag: + union_var1, + union_var2, + union_var3, + + cdef struct union_var3_Body: + bool a; + uint64_t b; + + cdef struct UnionTest: + UnionTest_Tag tag; + uint8_t union_var2[5]; + union_var3_Body union_var3; + + ctypedef int64_t typedef_test; + + extern const uint64_t STATIC_TEST_1[5]; + + extern const bool STATIC_TEST_2; + + void test_enum(EnumTest enum_); + + void test_struct_gen(AnotherStruct struct_); + + void test_union(UnionTest union_); + + void test_typedefs(typedef_test typedef_); + + int64_t test_fn(const int64_t *struct_); + + void test_func_ptr(bool (*fn_ptr)(uint64_t, bool)); + + void test_raw_ptr(const bool *a, uint64_t *b); diff --git a/tests/rust/assoc_types.rs b/tests/rust/assoc_types.rs new file mode 100644 index 000000000..097ecf6c7 --- /dev/null +++ b/tests/rust/assoc_types.rs @@ -0,0 +1,90 @@ +pub trait MyTrait{ + type SomeType; +} + +pub trait AnotherTrait{ + type AnotherType; +} + +#[repr(C)] +pub struct MyStruct{ + a: u8, +} + +impl MyTrait for MyStruct{ + type SomeType = i64; +} + +impl AnotherTrait for MyStruct{ + type AnotherType = [u8; 5]; +} + +impl MyTrait for i32{ + type SomeType = bool; +} + +impl AnotherTrait for i32{ + type AnotherType = u64; +} + +pub const CONST_TEST_1: ::SomeType = 50; +pub const CONST_TEST_2: ::AnotherType = 100; + +#[no_mangle] +pub static STATIC_TEST_1: [::AnotherType; 5] = [1, 2, 3, 4, 5]; +#[no_mangle] +pub static STATIC_TEST_2: ::SomeType = false; + +#[repr(C)] +pub enum EnumTest{ + enum_var1, + enum_var2(::AnotherType), + enum_var3{ + a: ::SomeType, + b: ::AnotherType, + } +} + +#[repr(C)] +pub struct AnotherStruct{ + a: u8, + b: ::SomeType, + c: [::SomeType; 36], +} + +#[repr(C)] +pub enum UnionTest{ + union_var1, + union_var2(::AnotherType), + union_var3{ + a: ::SomeType, + b: ::AnotherType, + } +} + +pub type typedef_test = ::SomeType; + +#[no_mangle] +pub extern fn test_enum(enum_: EnumTest){} + +#[no_mangle] +pub extern fn test_struct_gen(struct_: AnotherStruct){} + +#[no_mangle] +pub extern fn test_union(union_: UnionTest){} + +#[no_mangle] +pub extern fn test_typedefs(typedef: typedef_test){} + +#[no_mangle] +pub extern fn test_fn(struct_: &::SomeType) -> ::SomeType { + struct_ +} + + +#[no_mangle] +pub extern fn test_func_ptr(fn_ptr: extern fn(::AnotherType, bool) -> ::SomeType){ +} + +#[no_mangle] +pub extern fn test_raw_ptr(a: *const ::SomeType, b: *mut ::AnotherType){} \ No newline at end of file diff --git a/tests/rust/assoc_types_nested.rs b/tests/rust/assoc_types_nested.rs new file mode 100644 index 000000000..e64161c1e --- /dev/null +++ b/tests/rust/assoc_types_nested.rs @@ -0,0 +1,37 @@ +pub trait Inner{ + type inner; +} + +pub trait Middle{ + type middle; +} + +pub trait Outer{ + type outer; +} + +pub trait Double{ + type double; +} + +impl Double for u32{ + type double = [::outer; 10]; +} + +impl Outer for u32{ + type outer = ::middle; +} + +impl Middle for u32{ + type middle = ::inner; +} + +impl Inner for u32{ + type inner = bool; +} + +#[no_mangle] +extern fn test_nested_assoc(out: ::outer, mid: ::middle) -> ::inner {} + +#[no_mangle] +extern fn test_double_assoc(double: ::double){} diff --git a/tests/rust/libassoc_types.rlib b/tests/rust/libassoc_types.rlib new file mode 100644 index 000000000..1e5d751e9 Binary files /dev/null and b/tests/rust/libassoc_types.rlib differ