diff --git a/src/bindgen/builder.rs b/src/bindgen/builder.rs index d47919b9..c1ff074c 100644 --- a/src/bindgen/builder.rs +++ b/src/bindgen/builder.rs @@ -395,6 +395,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, @@ -407,6 +421,7 @@ impl Builder { result.functions, result.source_files, result.package_version, + assoc_types, ) .generate() } diff --git a/src/bindgen/ir/constant.rs b/src/bindgen/ir/constant.rs index 2f1d3bff..8f54f238 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::language_backend::LanguageBackend; use crate::bindgen::library::Library; @@ -238,6 +238,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.values_mut() { + literal.resolve_assoc_types(resolver); + } + } + Literal::Cast { ty, value } => { + value.resolve_assoc_types(resolver); + ty.resolve_assoc_types(resolver); + } + _ => {} + } + } } impl Literal { @@ -603,6 +628,11 @@ impl Item for Constant { fn generic_params(&self) -> &GenericParams { GenericParams::empty() } + + 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 2e633a7d..3997dbef 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::language_backend::LanguageBackend; use crate::bindgen::library::Library; @@ -636,6 +636,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 Enum { diff --git a/src/bindgen/ir/function.rs b/src/bindgen/ir/function.rs index 79adfce9..d51205b5 100644 --- a/src/bindgen/ir/function.rs +++ b/src/bindgen/ir/function.rs @@ -9,7 +9,9 @@ use syn::ext::IdentExt; use crate::bindgen::config::{Config, Language}; use crate::bindgen::declarationtyperesolver::DeclarationTypeResolver; use crate::bindgen::dependencies::Dependencies; -use crate::bindgen::ir::{AnnotationSet, Cfg, Documentation, GenericPath, Path, Type}; +use crate::bindgen::ir::{ + AnnotationSet, AssocTypeResolver, Cfg, Documentation, GenericPath, Path, Type, +}; use crate::bindgen::library::Library; use crate::bindgen::monomorph::Monomorphs; use crate::bindgen::rename::{IdentifierType, RenameRule}; @@ -219,6 +221,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); + } + } } trait SynFnArgHelpers { diff --git a/src/bindgen/ir/generic_path.rs b/src/bindgen/ir/generic_path.rs index 4610641c..5756f59e 100644 --- a/src/bindgen/ir/generic_path.rs +++ b/src/bindgen/ir/generic_path.rs @@ -6,11 +6,43 @@ 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::language_backend::LanguageBackend; use crate::bindgen::utilities::IterHelpers; use crate::bindgen::writer::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: &syn::QSelf) -> Result { + let self_type = &qself.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, @@ -184,6 +216,14 @@ impl GenericParams { ) { self.write_internal(language_backend, 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 { @@ -240,6 +280,7 @@ pub struct GenericPath { export_name: String, generics: Vec, ctype: Option, + assoc: Option, } impl GenericPath { @@ -250,6 +291,7 @@ impl GenericPath { export_name, generics, ctype: None, + assoc: None, } } @@ -288,6 +330,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() } @@ -305,7 +351,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<&syn::QSelf>) -> Result { assert!( !path.segments.is_empty(), "{:?} doesn't have any segments", @@ -314,6 +360,10 @@ impl GenericPath { let last_segment = path.segments.last().unwrap(); let name = last_segment.ident.unraw().to_string(); + let assoc = qself + .map(|qself| AssocTypeId::load(path, qself)) + .transpose()?; + let path = Path::new(name); let phantom_data_path = Path::new("PhantomData"); if path == phantom_data_path { @@ -338,6 +388,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 7816a294..3f8660d9 100644 --- a/src/bindgen/ir/global.rs +++ b/src/bindgen/ir/global.rs @@ -6,7 +6,8 @@ use crate::bindgen::config::Config; use crate::bindgen::declarationtyperesolver::DeclarationTypeResolver; use crate::bindgen::dependencies::Dependencies; use crate::bindgen::ir::{ - AnnotationSet, Cfg, Documentation, GenericParams, Item, ItemContainer, Path, Type, + AnnotationSet, AssocTypeResolver, Cfg, Documentation, GenericParams, Item, ItemContainer, Path, + Type, }; use crate::bindgen::library::Library; @@ -112,4 +113,8 @@ 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); + } } diff --git a/src/bindgen/ir/item.rs b/src/bindgen/ir/item.rs index 03e1c153..0c231842 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, Documentation, Enum, GenericArgument, GenericParams, OpaqueItem, - Path, Static, Struct, Typedef, Union, + AnnotationSet, AssocTypeResolver, Cfg, Constant, Documentation, Enum, GenericArgument, + GenericParams, OpaqueItem, Path, Static, Struct, Typedef, Union, }; use crate::bindgen::library::Library; use crate::bindgen::monomorph::Monomorphs; @@ -53,6 +53,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 4527e3ca..d423bd39 100644 --- a/src/bindgen/ir/opaque.rs +++ b/src/bindgen/ir/opaque.rs @@ -6,7 +6,8 @@ use crate::bindgen::config::Config; use crate::bindgen::declarationtyperesolver::DeclarationTypeResolver; use crate::bindgen::dependencies::Dependencies; use crate::bindgen::ir::{ - AnnotationSet, Cfg, Documentation, GenericArgument, GenericParams, Item, ItemContainer, Path, + AnnotationSet, AssocTypeResolver, Cfg, Documentation, GenericArgument, GenericParams, Item, + ItemContainer, Path, }; use crate::bindgen::library::Library; use crate::bindgen::mangle; @@ -135,4 +136,8 @@ 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); + } } diff --git a/src/bindgen/ir/structure.rs b/src/bindgen/ir/structure.rs index 49ae5da8..4c4d3466 100644 --- a/src/bindgen/ir/structure.rs +++ b/src/bindgen/ir/structure.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, Constant, Documentation, Field, GenericArgument, GenericParams, Item, - ItemContainer, Path, Repr, ReprAlign, ReprStyle, Type, + AnnotationSet, AssocTypeResolver, Cfg, Constant, Documentation, Field, GenericArgument, + GenericParams, Item, ItemContainer, Path, Repr, ReprAlign, ReprStyle, Type, }; use crate::bindgen::library::Library; use crate::bindgen::mangle; @@ -377,4 +377,14 @@ 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); + } + } } diff --git a/src/bindgen/ir/ty.rs b/src/bindgen/ir/ty.rs index e111559d..c4bfaae8 100644 --- a/src/bindgen/ir/ty.rs +++ b/src/bindgen/ir/ty.rs @@ -3,13 +3,14 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use std::borrow::Cow; +use std::collections::HashMap; use syn::ext::IdentExt; 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; @@ -267,7 +268,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.as_ref())?; Ok(ConstExpr::Name(generic_path.export_name().to_owned())) } _ => Err(format!("can't handle const expression {:?}", expr)), @@ -325,6 +326,8 @@ pub enum Type { }, } +pub type AssocTypeResolver = HashMap; + impl Type { pub fn const_ref_to(ty: &Self) -> Self { Type::Ptr { @@ -387,7 +390,7 @@ impl Type { } } syn::Type::Path(ref path) => { - let generic_path = GenericPath::load(&path.path)?; + let generic_path = GenericPath::load(&path.path, path.qself.as_ref())?; if generic_path.name() == "PhantomData" || generic_path.name() == "PhantomPinned" { return Ok(None); @@ -876,4 +879,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(); + } else { + warn!("{id:?}: Unknown associated type"); + } + } + } + Type::Primitive(_) => {} + } + } } diff --git a/src/bindgen/ir/typedef.rs b/src/bindgen/ir/typedef.rs index 58095878..426bfea3 100644 --- a/src/bindgen/ir/typedef.rs +++ b/src/bindgen/ir/typedef.rs @@ -10,8 +10,8 @@ use crate::bindgen::config::Config; use crate::bindgen::declarationtyperesolver::DeclarationTypeResolver; use crate::bindgen::dependencies::Dependencies; use crate::bindgen::ir::{ - AnnotationSet, Cfg, Documentation, GenericArgument, GenericParams, Item, ItemContainer, Path, - Type, + AnnotationSet, AssocTypeResolver, Cfg, Documentation, GenericArgument, GenericParams, Item, + ItemContainer, Path, Type, }; use crate::bindgen::library::Library; use crate::bindgen::mangle; @@ -178,4 +178,9 @@ 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); + } } diff --git a/src/bindgen/ir/union.rs b/src/bindgen/ir/union.rs index 410e21a2..3027fc64 100644 --- a/src/bindgen/ir/union.rs +++ b/src/bindgen/ir/union.rs @@ -8,8 +8,8 @@ use crate::bindgen::config::{Config, LayoutConfig}; use crate::bindgen::declarationtyperesolver::DeclarationTypeResolver; use crate::bindgen::dependencies::Dependencies; use crate::bindgen::ir::{ - AnnotationSet, Cfg, Documentation, Field, GenericArgument, GenericParams, Item, ItemContainer, - Path, Repr, ReprAlign, ReprStyle, + AnnotationSet, AssocTypeResolver, Cfg, Documentation, Field, GenericArgument, GenericParams, + Item, ItemContainer, Path, Repr, ReprAlign, ReprStyle, }; use crate::bindgen::library::Library; use crate::bindgen::mangle; @@ -258,4 +258,11 @@ 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); + } + } } diff --git a/src/bindgen/library.rs b/src/bindgen/library.rs index 9d61257f..d159ae68 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; @@ -28,6 +30,7 @@ pub struct Library { functions: Vec, source_files: Vec, package_version: String, + assoc_types: HashMap, } impl Library { @@ -44,6 +47,7 @@ impl Library { functions: Vec, source_files: Vec, package_version: String, + assoc_types: HashMap, ) -> Library { Library { config, @@ -57,10 +61,13 @@ impl Library { functions, source_files, package_version, + assoc_types, } } pub fn generate(mut self) -> Result { + self.replace_assoc_types(); + self.transfer_annotations(); self.simplify_standard_types(); @@ -447,4 +454,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 7f35d2a0..5c777c5d 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}; @@ -420,6 +420,10 @@ pub struct Parse { pub functions: Vec, pub source_files: Vec, pub package_version: String, + 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 { @@ -435,6 +439,8 @@ impl Parse { functions: Vec::new(), source_files: Vec::new(), package_version: String::new(), + assoc_types: HashMap::new(), + pending_assoc_types: HashMap::new(), } } @@ -484,6 +490,7 @@ impl Parse { self.functions.extend_from_slice(&other.functions); self.source_files.extend_from_slice(&other.source_files); self.package_version.clone_from(&other.package_version); + self.assoc_types.clone_from(&other.assoc_types); } fn load_syn_crate_mod<'a>( @@ -560,6 +567,8 @@ impl Parse { } } } + + self.load_syn_impl(item_impl); } syn::Item::Macro(ref item) => { self.load_builtin_macro(config, crate_name, mod_cfg, item); @@ -578,6 +587,164 @@ 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; + }; + + // Check if concrete type is another associated type + let output = Parse::find_dependings_assoc_types(&self.assoc_types, &mut conc_type); + let count = output.len(); + + for id in output { + self.pending_assoc_types + .entry(id) + .or_default() + .push(key.clone()); + } + + self.assoc_types + .insert(key.clone(), (conc_type.clone(), count as u8)); + + // Check if fully resolved, if so, check whether other types depend on this key + if count == 0 { + Parse::resolve_dependent_assoc_types( + &mut self.pending_assoc_types, + &mut self.assoc_types, + &key, + &conc_type, + ); + } + } + } + } + + // Find all types that `concrete_type` depends on to be fully resolved + fn find_dependings_assoc_types( + assoc_types: &HashMap, + concrete_type: &mut Type, + ) -> Vec { + match concrete_type { + Type::Ptr { ty: ty_, .. } => Parse::find_dependings_assoc_types(assoc_types, ty_), + Type::Array(ty_, _) => Parse::find_dependings_assoc_types(assoc_types, ty_), + Type::FuncPtr { ret, args, .. } => args + .iter_mut() + .flat_map(|(_, ty_)| Parse::find_dependings_assoc_types(assoc_types, ty_)) + .chain(Parse::find_dependings_assoc_types(assoc_types, ret)) + .collect(), + Type::Path(generic_path) => { + if let Some(id) = generic_path.assoc() { + if let Some((ty, 0)) = assoc_types.get(id) { + *concrete_type = ty.clone(); + } else { + return vec![id.clone()]; + } + } + vec![] + } + Type::Primitive(_) => vec![], + } + } + + // Given key k that is fully resolved, check what depends on k and resolve those + fn resolve_dependent_assoc_types( + pending_types: &mut HashMap>, + assoc_types: &mut HashMap, + key: &AssocTypeId, + resolved_ty: &Type, + ) { + let mut to_resolve = Vec::new(); + if let Some(id_vec) = pending_types.remove(key) { + for id in id_vec { + if let Some((curr_ty, count)) = assoc_types.get_mut(&id) { + Parse::check_satisfy_id(key, resolved_ty, 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::resolve_dependent_assoc_types(pending_types, assoc_types, &id, &curr_ty); + } + } + + fn check_satisfy_id( + resolved_key: &AssocTypeId, + resolved_ty: &Type, + curr_ty: &mut Type, + count: &mut u8, + ) { + match curr_ty { + Type::Ptr { ty: ty_, .. } => { + Parse::check_satisfy_id(resolved_key, resolved_ty, ty_, count); + } + Type::Array(ty_, _) => { + Parse::check_satisfy_id(resolved_key, resolved_ty, ty_, count); + } + Type::FuncPtr { ret, args, .. } => { + Parse::check_satisfy_id(resolved_key, resolved_ty, ret, count); + for (_, ty_) in args { + Parse::check_satisfy_id(resolved_key, resolved_ty, ty_, count) + } + } + Type::Path(generic_path) => { + if let Some(id) = generic_path.assoc() { + if id == resolved_key { + *curr_ty = resolved_ty.clone(); + *count -= 1; + } + } + } + Type::Primitive(_) => {} + } + } + 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 00000000..57c472d1 --- /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 00000000..40d5b89e --- /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 00000000..f399dbe4 --- /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 00000000..e639c5b3 --- /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 00000000..931f3373 --- /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 00000000..bf1ff8d9 --- /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 00000000..36adc89b --- /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 00000000..47fa58cb --- /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 00000000..df678a65 --- /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 00000000..fe327d7c --- /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 00000000..02680c2f --- /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 00000000..b30f0efc --- /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 00000000..1fbdf149 --- /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 00000000..097ecf6c --- /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 00000000..e64161c1 --- /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 00000000..1e5d751e Binary files /dev/null and b/tests/rust/libassoc_types.rlib differ