From cda3c70bf69a352639ab8c7b0463c70c57253bf8 Mon Sep 17 00:00:00 2001 From: orangeng Date: Tue, 10 Oct 2023 01:35:28 -0500 Subject: [PATCH] Squashed commits. Added functionality to resolve fully-qualified trait associated types in cbindgen Parsed associated types to map Parsed associated type on function signature. Replaced assoc type with concrete type Fixed unwraps. Changed storage of AssocTypeId in function Fixed unwraps in Parse::load_syn_impl() Moved AssocTypeId into GenericPath (Type::Path(GenericPath)) Minor changes Moved assoc type translation to Library. Added for consts and structs Added 1 test for assoc_types Automatic output from tests Minor fixes Fixed things from feedback Added recursive associated type replacements. Added test for array Added test for nested associated types in func ptr and raw ptr Added assoc type replacement for all types in Library. Added tests for each Minor fixes + cargo fmt WIP: Resolving nested associated types Added GenericParam parsing. Fixed nested associated types. Added fn for generic_params. Added OpaqueItem processing in library Added resolve_assoc for Literal. Moved resolve_assoc to individual ir types Moved resolve_assoc_types to Item trait. Added type alias for AssocTypeResolver Add docs for no-export --- src/bindgen/builder.rs | 15 ++ src/bindgen/ir/constant.rs | 34 +++- src/bindgen/ir/enumeration.rs | 19 +- src/bindgen/ir/field.rs | 6 +- src/bindgen/ir/function.rs | 12 +- src/bindgen/ir/generic_path.rs | 64 +++++- 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 | 35 +++- src/bindgen/ir/typedef.rs | 9 +- src/bindgen/ir/union.rs | 11 +- src/bindgen/library.rs | 54 +++++- src/bindgen/parser.rs | 182 +++++++++++++++++- 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 | 90 +++++++++ tests/rust/assoc_types_nested.rs | 37 ++++ tests/rust/libassoc_types.rlib | Bin 0 -> 10196 bytes 31 files changed, 1317 insertions(+), 29 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/field.rs b/src/bindgen/ir/field.rs index 6e132bfaf..25db15631 100644 --- a/src/bindgen/ir/field.rs +++ b/src/bindgen/ir/field.rs @@ -5,7 +5,7 @@ use syn::ext::IdentExt; use crate::bindgen::cdecl; use crate::bindgen::config::{Config, Language}; use crate::bindgen::ir::{AnnotationSet, Cfg, ConditionWrite}; -use crate::bindgen::ir::{Documentation, Path, ToCondition, Type}; +use crate::bindgen::ir::{AssocTypeResolver, Documentation, Path, ToCondition, Type}; use crate::bindgen::writer::{Source, SourceWriter}; #[derive(Debug, Clone)] @@ -47,6 +47,10 @@ impl Field { None }) } + + pub fn resolve_assoc_types(&mut self, resolver: &AssocTypeResolver) { + self.ty.resolve_assoc_types(resolver); + } } impl Source for Field { 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..3f99b4450 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, @@ -57,6 +92,10 @@ impl GenericParam { pub fn name(&self) -> &Path { &self.name } + + pub fn ty(&mut self) -> &mut GenericParamType { + &mut self.ty + } } #[derive(Default, Debug, Clone)] @@ -129,6 +168,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_) = generic_param.ty() { + ty_.resolve_assoc_types(resolver); + } + } + } } impl Deref for GenericParams { @@ -200,6 +247,7 @@ pub struct GenericPath { export_name: String, generics: Vec, ctype: Option, + assoc: Option, } impl GenericPath { @@ -210,6 +258,7 @@ impl GenericPath { export_name, generics, ctype: None, + assoc: None, } } @@ -248,6 +297,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 +318,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 +327,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 +353,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..7c8ff117d 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.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..688aa6eb8 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.resolve_assoc_types(resolver); + } + } } impl Source for Union { diff --git a/src/bindgen/library.rs b/src/bindgen/library.rs index cb4cfbd3a..d86e442af 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,49 @@ 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; + + // Replace associated types in constants + self.constants.for_all_items_mut(|const_| { + const_.resolve_assoc_types(assoc_map); + }); + + // Replace associated types in 'static's + self.globals.for_all_items_mut(|static_| { + static_.resolve_assoc_types(assoc_map); + }); + + // Replace associated types in enums + self.enums.for_all_items_mut(|enum_| { + enum_.resolve_assoc_types(assoc_map); + }); + + // Replace associated types in structs + self.structs.for_all_items_mut(|struct_| { + struct_.resolve_assoc_types(assoc_map); + }); + + // Replace associated types in unions + self.unions.for_all_items_mut(|union_| { + union_.resolve_assoc_types(assoc_map); + }); + + // Replace associated types in opaque items + self.opaque_items.for_all_items_mut(|opaque_item| { + opaque_item.resolve_assoc_types(assoc_map); + }); + + // Replace associated types in type aliases (C typedef) + self.typedefs.for_all_items_mut(|typedef| { + typedef.resolve_assoc_types(assoc_map); + }); + + // Replace associated types in function signatures + 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 0000000000000000000000000000000000000000..1e5d751e93043adf044cd100d5c8bce870a754d0 GIT binary patch literal 10196 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