[K/JS] Fix problem with saving of parameter's default values after overriding ^KT-63907 Fixed

This commit is contained in:
Artem Kobzar
2024-03-01 13:20:33 +00:00
committed by Space Team
parent 807d352ed4
commit 35acade031
7 changed files with 81 additions and 5 deletions
@@ -85,6 +85,7 @@ class ExportModelGenerator(val context: JsIrBackendContext, val generateNamespac
is Exportability.Prohibited -> ErrorDeclaration(exportability.reason)
is Exportability.Allowed -> {
val parent = function.parent
val realOverrideTarget = function.realOverrideTarget
ExportedFunction(
function.getExportedIdentifier(),
returnType = exportType(function.returnType),
@@ -96,7 +97,13 @@ class ExportModelGenerator(val context: JsIrBackendContext, val generateNamespac
ir = function,
parameters = (listOfNotNull(function.extensionReceiverParameter) + function.valueParameters)
.filter { it.shouldBeExported() }
.memoryOptimizedMap { exportParameter(it) },
.memoryOptimizedMapIndexed { i, it ->
exportParameter(
it,
it.hasDefaultValue
|| realOverrideTarget.valueParameters.getOrNull(i)?.hasDefaultValue == true
)
}
)
}
}
@@ -106,12 +113,14 @@ class ExportModelGenerator(val context: JsIrBackendContext, val generateNamespac
if (!constructor.isPrimary) return null
val allValueParameters = listOfNotNull(constructor.extensionReceiverParameter) + constructor.valueParameters
return ExportedConstructor(
parameters = allValueParameters.filterNot { it.isBoxParameter }.memoryOptimizedMap { exportParameter(it) },
parameters = allValueParameters
.filterNot { it.isBoxParameter }
.memoryOptimizedMap { exportParameter(it, it.hasDefaultValue) },
visibility = constructor.visibility.toExportedVisibility()
)
}
private fun exportParameter(parameter: IrValueParameter): ExportedParameter {
private fun exportParameter(parameter: IrValueParameter, hasDefaultValue: Boolean): ExportedParameter {
// Parameter names do not matter in d.ts files. They can be renamed as we like
var parameterName = sanitizeName(parameter.name.asString(), withHash = false)
if (parameterName in allReservedWords)
@@ -120,10 +129,13 @@ class ExportModelGenerator(val context: JsIrBackendContext, val generateNamespac
return ExportedParameter(
parameterName,
exportType(parameter.type),
parameter.origin == JsLoweredDeclarationOrigin.JS_SHADOWED_DEFAULT_PARAMETER
hasDefaultValue
)
}
private val IrValueParameter.hasDefaultValue: Boolean
get() = origin == JsLoweredDeclarationOrigin.JS_SHADOWED_DEFAULT_PARAMETER
private fun exportProperty(property: IrProperty): ExportedDeclaration? {
for (accessor in listOfNotNull(property.getter, property.setter)) {
// TODO: Report a frontend error
@@ -53,5 +53,18 @@ declare namespace JS_TESTS {
readonly "foo.ExportedChildInterface": unique symbol;
};
}
interface InterfaceWithDefaultArguments {
foo(x?: number): number;
bar(x?: number): number;
readonly __doNotUseOrImplementIt: {
readonly "foo.InterfaceWithDefaultArguments": unique symbol;
};
}
class ImplementorOfInterfaceWithDefaultArguments implements foo.InterfaceWithDefaultArguments {
constructor();
bar(x?: number): number;
foo(x?: number): number;
readonly __doNotUseOrImplementIt: foo.InterfaceWithDefaultArguments["__doNotUseOrImplementIt"];
}
}
}
@@ -68,9 +68,20 @@ interface InterfaceWithCompanion {
}
// KT-64708
external interface ExportedParentInterface
interface ExportedChildInterface : ExportedParentInterface {
fun bar()
}
// KT-63907
interface InterfaceWithDefaultArguments {
fun foo(x: Int = 0) = x
fun bar(x: Int = 0) = x
}
class ImplementorOfInterfaceWithDefaultArguments : InterfaceWithDefaultArguments {
override fun bar(x: Int) = x + 1
}
@@ -3,6 +3,7 @@ import ChildTestInterfaceImpl = JS_TESTS.foo.ChildTestInterfaceImpl;
import processInterface = JS_TESTS.foo.processInterface;
import processOptionalInterface = JS_TESTS.foo.processOptionalInterface;
import WithTheCompanion = JS_TESTS.foo.WithTheCompanion;
import ImplementorOfInterfaceWithDefaultArguments = JS_TESTS.foo.ImplementorOfInterfaceWithDefaultArguments;
function assert(condition: boolean) {
if (!condition) {
@@ -23,5 +24,11 @@ function box(): string {
assert(WithTheCompanion.companionFunction() == "FUNCTION")
const instance = new ImplementorOfInterfaceWithDefaultArguments()
assert(instance.foo() === 0);
assert(instance.foo(2) === 2);
assert(instance.bar() === 1);
assert(instance.bar(2) === 3);
return "OK";
}
@@ -53,5 +53,18 @@ declare namespace JS_TESTS {
readonly "foo.ExportedChildInterface": unique symbol;
};
}
interface InterfaceWithDefaultArguments {
foo(x?: number): number;
bar(x?: number): number;
readonly __doNotUseOrImplementIt: {
readonly "foo.InterfaceWithDefaultArguments": unique symbol;
};
}
class ImplementorOfInterfaceWithDefaultArguments implements foo.InterfaceWithDefaultArguments {
constructor();
bar(x?: number): number;
foo(x?: number): number;
readonly __doNotUseOrImplementIt: foo.InterfaceWithDefaultArguments["__doNotUseOrImplementIt"];
}
}
}
@@ -63,10 +63,23 @@ interface InterfaceWithCompanion {
}
}
// KT-64708
@JsExport
external interface ExportedParentInterface
@JsExport
interface ExportedChildInterface : ExportedParentInterface {
fun bar()
}
// KT-63907
@JsExport
interface InterfaceWithDefaultArguments {
fun foo(x: Int = 0) = x
fun bar(x: Int = 0) = x
}
@JsExport
class ImplementorOfInterfaceWithDefaultArguments : InterfaceWithDefaultArguments {
override fun bar(x: Int) = x + 1
}
@@ -3,6 +3,7 @@ import ChildTestInterfaceImpl = JS_TESTS.foo.ChildTestInterfaceImpl;
import processInterface = JS_TESTS.foo.processInterface;
import processOptionalInterface = JS_TESTS.foo.processOptionalInterface;
import WithTheCompanion = JS_TESTS.foo.WithTheCompanion;
import ImplementorOfInterfaceWithDefaultArguments = JS_TESTS.foo.ImplementorOfInterfaceWithDefaultArguments;
function assert(condition: boolean) {
if (!condition) {
@@ -23,5 +24,11 @@ function box(): string {
assert(WithTheCompanion.companionFunction() == "FUNCTION")
const instance = new ImplementorOfInterfaceWithDefaultArguments()
assert(instance.foo() === 0);
assert(instance.foo(2) === 2);
assert(instance.bar() === 1);
assert(instance.bar(2) === 3);
return "OK";
}