Open adetaylor opened 3 years ago
I am looking into solving this.
Here is my plan. I would appreciate any guidance: since this is my first potential bindgen
contribution, I feel this is quite ambitious and I could easily spend lots of time down blind alleys.
TL;DR: we generate a new trait
for each associated type.
Type
gains a new bool
(alongside is_const
) called is_associated_type
.ClangItemParser
for Item
, in the function from_ty_with_id
("one of the trickiest methods you'll find", terrific) there is a check for ty.is_associated_type()
where we currently generate an opaque type. Instead, we will call build_ty_wrapper
with a new parameter that indicates that this is an associated type. This is stored in the bool
.inner_types
member of the comp
, we will add these to a new list, associated_types
.impl CodeGenerator for CompInfo
, codegen
func, we already iterate through inner types. We will also iterate through associated_types
, but instead of simply generating those types we will generate:
pub trait __bindgen_has_associated_type_ASSOCIATED_TYPE_NAME {
type ASSOCIATED_TYPE_NAME;
};
(generated only once per ASSOCIATED_TYPE_NAME
) and
impl __bindgen_has_associated_type_ASSOCIATED_TYPE_NAME for TYPE {
type ASSOCIATED_TYPE_NAME = WHATEVER_THE_TYPEDEF_POINTED_TO;
}
BindgenContext::resolve_typerefs
, adjust the resolution so it ends up outputting something like <TYPE as __bindgen_has_associated_type_ASSOCIATED_TYPE_NAME>::ASSOCIATED_TYPE_NAME
Debug + Copy + Clone + __bindgen_has_associated_type_ASSOCIATED_TYPE_NAME
which is unpleasant but do-able.I anticipate Much Doom in attempting to implement this plan. Any pointers for how to avoid the most egregious pits of lava would be much appreciated.
OK, here's my progress so far (this is a branch 90% full of logging hacks, obviously much rebasing and cleaning would occur before PRing it). https://github.com/rust-lang/rust-bindgen/compare/master...adetaylor:associated-type-wip
A few differences from the above plan:
TypeKind::TypeParamAssociatedType(String)
rather than an extra bool
, which is nicer.inner_type
vec seemed fine.template <typename ContainedType> class Container {
public:
typedef typename ContainedType::related_type content_ty;
...
}
the typedef
becomes a plain old Alias
(clang doesn't feed us CXCursor_TypeAliasTemplateDecl
which we might have expected). That Alias
currently does not have any way to squeeze out an EdgeKind::TemplateArgument
and thus the UsedTemplateParameters
analysis does not think the typedef
refers to ContainedType
. As such we generate:
pub type Container_content_ty = ContainedType::related_type
instead of
pub type Container_content_ty<ContainedType> = ContainedType::related_type
Once I can make those edges appear properly, there's further work even on this specific line because it actually needs to be
pub type Container_content_ty<ContainedType> = <ContainedType as __bindgen_has_inner_type_related_type>::related_type;
but that's for later.
OK, I came back to this after a while and found I couldn't remember much :) Notes-to-self:
cargo build && ./tests/test-one.sh inner_type_simple
I have managed to make a suitable edge exist to the TypeParameterAssociatedType
. For the following header:
struct InnerType {
typedef int related_type;
long int foo;
};
template <typename ContainedType> class Container {
public:
typename ContainedType::related_type contents_;
};
typedef Container<InnerType> Concrete;
we now generate the following bindings (test code removed for clarity):
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
pub struct InnerType {
pub foo: ::std::os::raw::c_long,
}
pub type InnerType_related_type = ::std::os::raw::c_int;
pub trait __bindgen_has_inner_type_related_type {
type related_type: std::fmt::Debug + Copy + Clone + Default;
}
impl __bindgen_has_inner_type_related_type for InnerType {
type related_type = InnerType_related_type;
}
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
pub struct Container<ContainedType: __bindgen_has_inner_type_related_type> {
pub contents_: ContainedType::related_type,
pub _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell<ContainedType>>,
}
pub type Concrete = Container;
This is all correct except:
__bindgen_has_inner_type_related_type::related_type
should probably instead be applied to something later, per the example in tests/expectations/tests/inner_type.rs
in my branch-o-hacks.pub type Concrete = Container<InnerType>
. This is for just the reasons given in the previous comment - clang is giving us an Alias
not a TemplateAlias
.I'm hoping to:
Container<InnerType>
which doesn't run into the type alias bug above. e.g. as a function parameter or variable.bindgen
to generate working code for such a case.Alias
scenario.
Input C/C++ Header
Bindgen Invocation
Rust code
Actual Results
Expected Results
I'd expect the type of
contents_
to be ac_int
.Other notes
Perhaps this counts as the "traits templates" situation listed under the recorded C++ limitations but, as it doesn't involve any nasty SFINAE magic I am hoping this may be possible.
Thanks for bindgen, it's amazing! Apologies if this is a duplicate.