-
Notifications
You must be signed in to change notification settings - Fork 51
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
Code generation for trait support in Kotlin #689
Conversation
@jcrist1 |
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.
Had a look at the destructor code and it makes sense. I just want to check that I understand it:
Scenario 1
- We create an obj in kotlin that implments
TesterTrait
,t
- We pass that to
fromTraitObj
to instantiate the native struct which I'll calltVTable
- This increments a global ref for the and
tVTable
holds a reference tot
in its methods - We pass
tVTable
into a native method which immediately returns say an int, - this method consumes
tVTable
and drops it - this calls the
dtor
and the global jni reference is removed / decremented - this means GC can also clean up
t
(if nothing else is pointing to it)
Scenario 2
Can we do the following?
- We create an obj in kotlin that implments
TesterTrait
,t
- We pass that to
fromTraitObj
to instantiate the native struct which I'll calltVTable
- This increments a global ref for the and
tVTable
holds a reference tot
in its methods - We pass
tVTable
into a native method which immediately returns say an int, - this method boxes the trait internally and returns an opaque wrapper around it (say
OpaqueTesterTrait(Box<dyn TesterTrait>)
) - the reference stays around until the returned opaque is cleaned up.
- when
OpaqueTesterTrait
is cleaned up by the JVM it calls the drop method on the opaque which calls drop on the internal boxed dyn trait (I'm a little uncertain of how cleanup runs on trait objects). This I assume would call the dtor and decrement/remove the global reference totVTable
in the JVM, allowing cleanup oft
as well
That sounds good to me 😄
Then I think we could make it much more ergonomic by making kotlin methods take the TesterTrait
directly insteat of DiplomatTrait_TesterTrait_Wrapper
Finally I've got some style comments. In general it would be nice if the generated public api followed the kotlin style convention of camel case. I feel like it would make adoption more likely for kotlin users.
tool/src/kotlin/snapshots/diplomat_tool__kotlin__test__trait_gen.snap
Outdated
Show resolved
Hide resolved
.enumerate() | ||
.map(|(index, param)| { | ||
if let Some(param_name) = ¶m.name { | ||
param_name.to_string() |
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.
ditto (can probably use the formatter)
Type::ImplTrait(ref trt) => { | ||
let trait_id = trt.id(); | ||
let resolved = self.tcx.resolve_trait(trait_id); | ||
format!("DiplomatTrait_{}_Wrapper_Native", resolved.name).into() |
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.
Can we have the kotlin traits
format!("DiplomatTrait_{}_Wrapper_Native", resolved.name).into() | |
format!("DiplomatTrait{}WrapperNative", resolved.name).into() |
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've left them as-is because now these types are internal, and the user would only interact with the trait itself, which just has the original name from rust (TesterTrait
in this example)
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 I'm still not a fan of breaking naming conventions
@jcrist1 if you would like to do some uniform renaming I think that would be welcome.
feature_tests/kotlin/somelib/src/main/kotlin/dev/diplomattest/somelib/TesterTrait.kt
Show resolved
Hide resolved
feature_tests/kotlin/somelib/src/main/kotlin/dev/diplomattest/somelib/TraitWrapper.kt
Outdated
Show resolved
Hide resolved
Thanks for the comments -- yes, that is how the destructors work! A trait object I'll go through and fix your code change suggestions now! |
tool/src/kotlin/snapshots/diplomat_tool__kotlin__test__trait_gen.snap
Outdated
Show resolved
Hide resolved
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.
Really nice!
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.
we should also have a runnable test for this
Type::ImplTrait(ref trt) => { | ||
let trait_id = trt.id(); | ||
let resolved = self.tcx.resolve_trait(trait_id); | ||
format!("DiplomatTrait_{}_Wrapper_Native", resolved.name).into() |
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 I'm still not a fan of breaking naming conventions
@jcrist1 if you would like to do some uniform renaming I think that would be welcome.
Code generation for trait support in the Kotlin backend.
We added trait support to Diplomat's internal representation and the C backend in this PR. The trait design is described in our design doc.