From a76a4e863b1873e605d5e5c5dd9ac50e38b0ebef Mon Sep 17 00:00:00 2001 From: orangeng Date: Tue, 10 Oct 2023 01:35:28 -0500 Subject: [PATCH] Resolve fully-qualified associated types In the parsing stage, the functionality of the syn::Impl parsing is extended to keep track of associated type implementations in trait Impls. This info is kept in a hash-map, where the key is a combination of (self type, trait name, associated type name) and the value is the concrete type itself. In the library/transformation stage, this populated hashmap is then referenced to resolve associated types found. --- src/bindgen/builder.rs | 15 ++ src/bindgen/ir/constant.rs | 34 +++- src/bindgen/ir/enumeration.rs | 19 +- src/bindgen/ir/function.rs | 12 +- src/bindgen/ir/generic_path.rs | 59 +++++- src/bindgen/ir/global.rs | 8 +- src/bindgen/ir/item.rs | 5 +- src/bindgen/ir/opaque.rs | 8 +- src/bindgen/ir/structure.rs | 16 +- src/bindgen/ir/ty.rs | 37 +++- src/bindgen/ir/typedef.rs | 9 +- src/bindgen/ir/union.rs | 11 +- src/bindgen/library.rs | 46 ++++- src/bindgen/parser.rs | 175 +++++++++++++++++- tests/expectations/assoc_types.c | 76 ++++++++ tests/expectations/assoc_types.compat.c | 84 +++++++++ tests/expectations/assoc_types.cpp | 85 +++++++++ tests/expectations/assoc_types.pyx | 64 +++++++ tests/expectations/assoc_types_both.c | 76 ++++++++ tests/expectations/assoc_types_both.compat.c | 84 +++++++++ tests/expectations/assoc_types_nested.c | 8 + .../expectations/assoc_types_nested.compat.c | 16 ++ tests/expectations/assoc_types_nested.cpp | 13 ++ tests/expectations/assoc_types_nested.pyx | 11 ++ tests/expectations/assoc_types_tag.c | 76 ++++++++ tests/expectations/assoc_types_tag.compat.c | 84 +++++++++ tests/expectations/assoc_types_tag.pyx | 64 +++++++ tests/rust/assoc_types.rs | 100 ++++++++++ tests/rust/assoc_types_nested.rs | 41 ++++ tests/rust/libassoc_types.rlib | Bin 0 -> 10196 bytes 30 files changed, 1308 insertions(+), 28 deletions(-) create mode 100644 tests/expectations/assoc_types.c create mode 100644 tests/expectations/assoc_types.compat.c create mode 100644 tests/expectations/assoc_types.cpp create mode 100644 tests/expectations/assoc_types.pyx create mode 100644 tests/expectations/assoc_types_both.c create mode 100644 tests/expectations/assoc_types_both.compat.c create mode 100644 tests/expectations/assoc_types_nested.c create mode 100644 tests/expectations/assoc_types_nested.compat.c create mode 100644 tests/expectations/assoc_types_nested.cpp create mode 100644 tests/expectations/assoc_types_nested.pyx create mode 100644 tests/expectations/assoc_types_tag.c create mode 100644 tests/expectations/assoc_types_tag.compat.c create mode 100644 tests/expectations/assoc_types_tag.pyx create mode 100644 tests/rust/assoc_types.rs create mode 100644 tests/rust/assoc_types_nested.rs create mode 100644 tests/rust/libassoc_types.rlib 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..56394a4eb 100644 --- a/src/bindgen/ir/generic_path.rs +++ b/src/bindgen/ir/generic_path.rs @@ -6,10 +6,42 @@ 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: &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, @@ -129,6 +161,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 +240,7 @@ pub struct GenericPath { export_name: String, generics: Vec, ctype: Option, + assoc: Option, } impl GenericPath { @@ -210,6 +251,7 @@ impl GenericPath { export_name, generics, ctype: None, + assoc: None, } } @@ -248,6 +290,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 +311,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", @@ -274,6 +320,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 { @@ -298,6 +348,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..c89071628 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.as_ref())?; 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.as_ref())?; if generic_path.name() == "PhantomData" || generic_path.name() == "PhantomPinned" { return Ok(None); @@ -1002,6 +1005,34 @@ 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(_) => {} + } + } } 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..febf408f6 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,168 @@ 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(&mut 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, &mut **ty_) + } + Type::Array(ty_, _) => Parse::find_dependings_assoc_types(assoc_types, &mut **ty_), + Type::FuncPtr { ret, args, .. } => args + .iter_mut() + .map(|(_, ty_)| Parse::find_dependings_assoc_types(assoc_types, ty_)) + .flatten() + .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 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..7f5f34a28 --- /dev/null +++ b/tests/rust/assoc_types.rs @@ -0,0 +1,100 @@ +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 "C" fn test_enum(enum_: EnumTest) {} + +#[no_mangle] +pub extern "C" fn test_struct_gen(struct_: AnotherStruct) {} + +#[no_mangle] +pub extern "C" fn test_union(union_: UnionTest) {} + +#[no_mangle] +pub extern "C" fn test_typedefs(typedef: typedef_test) {} + +#[no_mangle] +pub extern "C" fn test_fn( + struct_: &::SomeType, +) -> ::SomeType { + struct_ +} + +#[no_mangle] +pub extern "C" fn test_func_ptr( + fn_ptr: extern "C" fn( + ::AnotherType, + bool, + ) -> ::SomeType, +) { +} + +#[no_mangle] +pub extern "C" fn test_raw_ptr( + a: *const ::SomeType, + b: *mut ::AnotherType, +) { +} diff --git a/tests/rust/assoc_types_nested.rs b/tests/rust/assoc_types_nested.rs new file mode 100644 index 000000000..b442b981a --- /dev/null +++ b/tests/rust/assoc_types_nested.rs @@ -0,0 +1,41 @@ +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 "C" fn test_nested_assoc( + out: ::outer, + mid: ::middle, +) -> ::inner { +} + +#[no_mangle] +extern "C" 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 0000000000000000000000000000000000000000..1e5d751e93043adf044cd100d5c8bce870a754d0 GIT binary patch literal 10196 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