-
Notifications
You must be signed in to change notification settings - Fork 717
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Objective-c inheritance support #1750
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm ok with the unsafe change I think.
I think looping over all the items to find the base class is not the way to go though. Does objective-c allow for multiple interfaces with the same name under different C++ namespaces? If so it seems this would break.
Is there any chance this could look more similar to the C++ case?
src/ir/objc.rs
Outdated
@@ -179,6 +183,35 @@ impl ObjCInterface { | |||
let name = c.spelling(); | |||
interface.template_names.push(name); | |||
} | |||
CXCursor_ObjCSuperClassRef => { | |||
let items_map = ctx.items(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looping over all the items means that this has really really bad performance characteristics. Which is pretty unfortunate... Do you really need to do a name lookup? I think Item::from_ty_or_ref
would do the right thing if you give it the cursor? See the handling of CXCursor_CXXBaseSpecifier
and such.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried to get around the need for the name lookup. After a bit of thought and reading through the Base
stuff in the handling of CXCursor_CXXBaseSpecifier
, I think the thing that would be similar would be something like:
struct Inheritance {
inheritance_type: InheritanceType,
parent_name: String,
}
enum InheritanceType {
Protocol,
Class,
}
The part about Class
and Protocol
in InheritanceType
is because the logic from the needle, haystack stuff I took from the protocol logic so it would make sense to fix both of those handlers. I'll think about it more and maybe implement it if it's not too gross. I'm not sure what goes on when you iterate through ctx.items()
but I kinda assume it's the whole syntax tree... 🤢
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bleh, I tried this a couple different ways based on the above idea similar to how
CXCursor_CXXBaseSpecifier
handling works. The issue is the templates. If we don't need to know if the parent is a template, then we can just use format!("I{}", c.spelling())
stored in the ir for the objc codegen.
I propose that we do one of the two options:
- take out template tags. I don't know how you'd use the template things with with the generated bindings anyway so why do we have them?
- Deal with the current bad performance - I've tested it with uikit-sys, it takes ~2.5 minutes to build so it's not the end of the world but people will definitely dislike that crate :/
I'm a bit up for doing option 1 and excluding generics support as a whole. @scoopr, do you have opinions on that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just to clarify, are you talking generally about generics support for objc code or just when there is a parent class that has generic params?
I would really like that NSArray<Foo>
works, but I guess I could be convinced that it is not critical with parent classes. Perhaps stuff like NSMutableArray
would look a bit odd?
Yes, the generics desugar to id
, so of course everything works without them, so if you must remove them completely, so be it. But I would find that kind of a missed opportunity.
If I had to choose, I would really try to live with bad performance, and perhaps try to optimize it separately if it indeed is that bad. But in the end I guess it is more important to be useful than idealistic.
I tried to understand the code here, but it would take a bit too long to actually ingest what happens here, and why other approaches don't work. Just as random idea, can the iterating of the items be done as a separate pass later, when you know all the needles to search for, so you could do only a single iteration of the items?
Also the objc_template.rs expectation tests shows some method generic params as u64
under libclang-9, though not in libclang-5, so are these types already being dropped from methods (by accident or something else)? The trait has then nevertheless
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just to clarify, are you talking generally about generics support for objc code or just when there is a parent class that has generic params?
Yeah.
Just as random idea, can the iterating of the items be done as a separate pass later, when you know all the needles to search for, so you could do only a single iteration of the items?
Also the objc_template.rs expectation tests shows some method generic params as u64 under libclang-9, though not in libclang-5, so are these types already being dropped from methods (by accident or something else)? The trait has then nevertheless
Yeah, that seems to be an issue with just libclang-9 that probably got merged in #1702. I'm not really sure why that is though. We should file that as a bug and investigate more.
If I had to choose, I would really try to live with bad performance, and perhaps try to optimize it separately if it indeed is that bad. But in the end I guess it is more important to be useful than idealistic.
That's good with me.
@emilio Is there anything else I can do other than fix the tests for this PR to get merged?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I still think looping through all the items here is not acceptable. Can you explain why the partial type approach (what the base classes / pointers / etc does) doesn't work?
57ec0d8
to
26db1e7
Compare
src/ir/objc.rs
Outdated
@@ -179,6 +183,35 @@ impl ObjCInterface { | |||
let name = c.spelling(); | |||
interface.template_names.push(name); | |||
} | |||
CXCursor_ObjCSuperClassRef => { | |||
let items_map = ctx.items(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I still think looping through all the items here is not acceptable. Can you explain why the partial type approach (what the base classes / pointers / etc does) doesn't work?
src/ir/objc.rs
Outdated
if Some(needle.as_ref()) == ty.name() { | ||
debug!("Found parent class {:?}", item); | ||
interface.parent_classes.push(id); | ||
for i in class.parent_classes.clone() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This clones the whole vector unnecessarily.
I managed to get I think a similar thing could be done for the CXCursor_ObjCProtocolRef handling. I wouldn't mind adding that as well. I'm not really sure how I feel about the solution but I really couldn't figure out how to get a parent's parent all the way up the tree. I also updated the unit tests to be more useful. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, this looks much better! Just need to resolve through type refs in codegen to simplify a bit and not have to manually write that loop.
Doing the same for protocols seems fine, but probably separate patch?
0594d09
to
b874115
Compare
Thanks for bearing with me! |
This PR adds objective-c inheritance support by generating the
impl IFoo for Foo { }
andimpl IBar for Foo { }
(see the unit test) which generally match the objective-c inheritance patterns.I also changed all the
unsafe fn
s do be internalunsafe
blocks to mimic that of @SSheldon's objc-foundation crate. I'm actually not sure this is the best way to do it. Would love some comments as to why not.I've got a branch of the bindgen book that I'm working on as well. I'm just gonna make it a separate PR and link to a uikit-sys crate.
Similar to #1722 I did, I don't have all the versions of clang so I'll fix CI once we discuss this more.