-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Kotlin: Extract a no-arg constuctor whenever a Kotlin class has default values for all parameters #11553
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
Kotlin: Extract a no-arg constuctor whenever a Kotlin class has default values for all parameters #11553
Conversation
…s for all parameters
| if (f is IrConstructor && f.valueParameters.isNotEmpty() && f.valueParameters.all { it.defaultValue != null }) { | ||
| // Per https://kotlinlang.org/docs/classes.html#creating-instances-of-classes, a single default overload gets created specifically | ||
| // when we have all default parameters, regardless of `@JvmOverloads`. | ||
| extractGeneratedOverload(f.valueParameters.map { _ -> null }) | ||
| } | ||
| return |
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.
Are we only generating a single parameterless constructor in this case?
The following code:
public class AllDefaultsConstructor(val x: Int=1, val y: Int = 2)
shows up as the below in bytecode:
public <init>(II)V
public synthetic <init>(IIILkotlin/jvm/internal/DefaultConstructorMarker;)V
public <init>()V
Are we still generating the second overload?
In the below
fun fn() {
AllDefaultsConstructor()
AllDefaultsConstructor(1)
AllDefaultsConstructor(1,2)
}
The first two instances are created through public synthetic <init>(IIILkotlin/jvm/internal/DefaultConstructorMarker;)V, do I understand it correctly that the parameterless constructor is only added for interop with Java?
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.
Yes, that's right.
The rules:
| Scenario | Generated functions |
|---|---|
Constructor, all default params, no @JvmOverloads |
No-arg constructor, DefaultConstructorMarker constructor |
Constructor, some default params, no @JvmOverloads |
DefaultConstructorMarker constructor |
Constructor, @JvmOverloads annotation |
A constructor that omits all default parameters ... one that omits only the rightmost default parameter, plus the DefaultConstructorMarker constructor |
Method, some/all default params, no @JvmOverloads |
A $default method |
Method, some/all default params, has @JvmOverloads |
A method that omits all default parameters ... one that omits only the rightmost default parameter, plus a $default method |
extractGeneratedOverloads is responsible for producing the @JvmOverloads variants + the no-arg constructor; extractDefaultsFunction produces the $defaults method or DefaultConstructorMarker constructor.
AFAICT Kotlin will always call via the $defaults / DefaultConstructorMarker variant even if a more "natural" Java interop version is available.
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.
Thanks, this table is super useful. Are there tests that cover all use cases? I think there might be no unit tests that cover the Constructor, all default params, no @JvmOverloads scenario, which is introduced in this PR, but hopefully the integration test would report an issue if the constructor was not added by the kotlin extractor.
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.
Yes, I figured the integration test could be more direct since Java can actually use the generated constructor -- if it was missing, we'd see a database inconsistency because callableBinding would point at a non-existent symbol. Test coverage: yes I think we've got all those cases; the missing one was the top one, for which this PR introduces coverage.
…xplicitly declare a no-arg constructor.
No description provided.