JS: refactor generation of functions with optional parameters. Fix #KT-7302, #KT-13888
This commit is contained in:
@@ -125,7 +125,7 @@ val DeclarationDescriptorWithVisibility.isEffectivelyPrivateApi: Boolean
|
||||
|
||||
val DeclarationDescriptor.isInsidePrivateClass: Boolean
|
||||
get() {
|
||||
var parent = containingDeclaration as? ClassDescriptor
|
||||
val parent = containingDeclaration as? ClassDescriptor
|
||||
return parent != null && Visibilities.isPrivate(parent.visibility)
|
||||
}
|
||||
|
||||
@@ -197,6 +197,14 @@ fun ValueParameterDescriptor.hasDefaultValue(): Boolean {
|
||||
)
|
||||
}
|
||||
|
||||
fun FunctionDescriptor.hasOrInheritsParametersWithDefaultValue(): Boolean = DFS.ifAny(
|
||||
listOf(this),
|
||||
{ current -> current.overriddenDescriptors.map { it.original } },
|
||||
{ it.hasOwnParametersWithDefaultValue() }
|
||||
)
|
||||
|
||||
fun FunctionDescriptor.hasOwnParametersWithDefaultValue() = original.valueParameters.any { it.declaresDefaultValue() }
|
||||
|
||||
fun Annotated.isRepeatableAnnotation(): Boolean =
|
||||
annotations.findAnnotation(KotlinBuiltIns.FQ_NAMES.repeatable) != null
|
||||
|
||||
|
||||
@@ -923,12 +923,24 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("js/js.translator/testData/box/defaultArguments"), Pattern.compile("^([^_](.+))\\.kt$"), TargetBackend.JS, true);
|
||||
}
|
||||
|
||||
@TestMetadata("complexExpressionAsConstructorDefaultArgument.kt")
|
||||
public void testComplexExpressionAsConstructorDefaultArgument() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/defaultArguments/complexExpressionAsConstructorDefaultArgument.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("complexExpressionAsDefaultArgument.kt")
|
||||
public void testComplexExpressionAsDefaultArgument() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/defaultArguments/complexExpressionAsDefaultArgument.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("complexExpressionAsOverriddenDefaultArgument.kt")
|
||||
public void testComplexExpressionAsOverriddenDefaultArgument() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/defaultArguments/complexExpressionAsOverriddenDefaultArgument.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("constructorCallWithDefArg1.kt")
|
||||
public void testConstructorCallWithDefArg1() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/defaultArguments/constructorCallWithDefArg1.kt");
|
||||
@@ -1007,6 +1019,12 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("superCall.kt")
|
||||
public void testSuperCall() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/defaultArguments/superCall.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("virtualCallWithDefArg.kt")
|
||||
public void testVirtualCallWithDefArg() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/defaultArguments/virtualCallWithDefArg.kt");
|
||||
@@ -5318,6 +5336,12 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("js/js.translator/testData/box/multiModule"), Pattern.compile("^([^_](.+))\\.kt$"), TargetBackend.JS, true);
|
||||
}
|
||||
|
||||
@TestMetadata("interfaceMethodWithDefaultParameter.kt")
|
||||
public void testInterfaceMethodWithDefaultParameter() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/multiModule/interfaceMethodWithDefaultParameter.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("localClassMetadata.kt")
|
||||
public void testLocalClassMetadata() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/multiModule/localClassMetadata.kt");
|
||||
@@ -5681,6 +5705,12 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("js/js.translator/testData/box/native"), Pattern.compile("^([^_](.+))\\.kt$"), TargetBackend.JS, true);
|
||||
}
|
||||
|
||||
@TestMetadata("callbackOptionalParameter.kt")
|
||||
public void testCallbackOptionalParameter() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/native/callbackOptionalParameter.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("castToNativeClassChecked.kt")
|
||||
public void testCastToNativeClassChecked() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/native/castToNativeClassChecked.kt");
|
||||
|
||||
+24
-2
@@ -30,6 +30,7 @@ import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils
|
||||
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
|
||||
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils.pureFqn
|
||||
import org.jetbrains.kotlin.js.translate.utils.PsiUtils
|
||||
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.isDynamic
|
||||
@@ -241,8 +242,29 @@ object SuperCallCase : FunctionCallCase() {
|
||||
override fun FunctionCallInfo.dispatchReceiver(): JsExpression {
|
||||
// TODO: spread operator
|
||||
val prototypeClass = JsAstUtils.prototypeOf(calleeOwner)
|
||||
val functionRef = Namer.getFunctionCallRef(JsNameRef(functionName, prototypeClass))
|
||||
return JsInvocation(functionRef, argumentsInfo.argsWithReceiver(dispatchReceiver!!))
|
||||
val arguments = argumentsInfo.translateArguments.toMutableList()
|
||||
|
||||
val descriptor = callableDescriptor.original
|
||||
val shouldCallDefault = descriptor is FunctionDescriptor && TranslationUtils.isOverridableFunctionWithDefaultParameters(descriptor)
|
||||
|
||||
val functionRef = if (shouldCallDefault) {
|
||||
val defaultArgumentCount = descriptor.valueParameters.size - argumentsInfo.valueArguments.size
|
||||
repeat(defaultArgumentCount) {
|
||||
arguments += Namer.getUndefinedExpression()
|
||||
}
|
||||
val callbackName = context.getScopeForDescriptor(descriptor.containingDeclaration)
|
||||
.declareName(functionName.ident + Namer.DEFAULT_PARAMETER_IMPLEMENTOR_SUFFIX)
|
||||
val callbackRef = JsAstUtils.invokeBind(dispatchReceiver!!, JsNameRef(callbackName, prototypeClass))
|
||||
arguments += callbackRef
|
||||
|
||||
JsAstUtils.pureFqn(functionName, dispatchReceiver)
|
||||
}
|
||||
else {
|
||||
arguments.add(0, dispatchReceiver!!)
|
||||
Namer.getFunctionCallRef(JsNameRef(functionName, prototypeClass))
|
||||
}
|
||||
|
||||
return JsInvocation(functionRef, arguments)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -103,6 +103,7 @@ public final class Namer {
|
||||
|
||||
public static final JsNameRef IS_ARRAY_FUN_REF = new JsNameRef("isArray", "Array");
|
||||
public static final String DEFINE_INLINE_FUNCTION = "defineInlineFunction";
|
||||
public static final String DEFAULT_PARAMETER_IMPLEMENTOR_SUFFIX = "$default";
|
||||
|
||||
private static final JsNameRef JS_OBJECT = new JsNameRef("Object");
|
||||
private static final JsNameRef JS_OBJECT_CREATE_FUNCTION = new JsNameRef("create", JS_OBJECT);
|
||||
|
||||
+6
-2
@@ -143,8 +143,10 @@ public class TranslationContext {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public TranslationContext newFunctionBody(@NotNull JsFunction fun, @Nullable AliasingContext aliasingContext,
|
||||
DeclarationDescriptor descriptor) {
|
||||
private TranslationContext newFunctionBody(
|
||||
@NotNull JsFunction fun, @Nullable AliasingContext aliasingContext,
|
||||
DeclarationDescriptor descriptor
|
||||
) {
|
||||
DynamicContext dynamicContext = DynamicContext.newContext(fun.getScope(), fun.getBody());
|
||||
if (aliasingContext == null) {
|
||||
aliasingContext = this.aliasingContext.inner();
|
||||
@@ -204,11 +206,13 @@ public class TranslationContext {
|
||||
|
||||
@NotNull
|
||||
public TranslationContext innerContextWithAliasesForExpressions(@NotNull Map<KtExpression, JsExpression> aliases) {
|
||||
if (aliases.isEmpty()) return this;
|
||||
return this.innerWithAliasingContext(aliasingContext.withExpressionsAliased(aliases));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public TranslationContext innerContextWithDescriptorsAliased(@NotNull Map<DeclarationDescriptor, JsExpression> aliases) {
|
||||
if (aliases.isEmpty()) return this;
|
||||
return this.innerWithAliasingContext(aliasingContext.withDescriptorsAliased(aliases));
|
||||
}
|
||||
|
||||
|
||||
+16
-15
@@ -17,14 +17,14 @@
|
||||
package org.jetbrains.kotlin.js.translate.declaration
|
||||
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsExpression
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.js.translate.context.TranslationContext
|
||||
import org.jetbrains.kotlin.js.translate.general.Translation
|
||||
import org.jetbrains.kotlin.js.translate.expression.translateAndAliasParameters
|
||||
import org.jetbrains.kotlin.js.translate.expression.translateFunction
|
||||
import org.jetbrains.kotlin.js.translate.expression.wrapWithInlineMetadata
|
||||
import org.jetbrains.kotlin.js.translate.general.TranslatorVisitor
|
||||
import org.jetbrains.kotlin.js.translate.utils.BindingUtils
|
||||
import org.jetbrains.kotlin.js.translate.utils.FunctionBodyTranslator
|
||||
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.isExtensionProperty
|
||||
@@ -35,7 +35,7 @@ abstract class AbstractDeclarationVisitor : TranslatorVisitor<Unit>() {
|
||||
override fun visitClassOrObject(classOrObject: KtClassOrObject, context: TranslationContext) {
|
||||
ClassTranslator.translate(classOrObject, context)
|
||||
val descriptor = BindingUtils.getClassDescriptor(context.bindingContext(), classOrObject)
|
||||
addClass(descriptor)
|
||||
context.export(descriptor)
|
||||
}
|
||||
|
||||
override fun visitProperty(expression: KtProperty, context: TranslationContext) {
|
||||
@@ -81,9 +81,8 @@ abstract class AbstractDeclarationVisitor : TranslatorVisitor<Unit>() {
|
||||
|
||||
override fun visitNamedFunction(expression: KtNamedFunction, context: TranslationContext) {
|
||||
val descriptor = BindingUtils.getFunctionDescriptor(context.bindingContext(), expression)
|
||||
if (descriptor.modality === Modality.ABSTRACT) return
|
||||
|
||||
addFunction(descriptor, translateFunction(descriptor, expression, context))
|
||||
val jsFunction = if (descriptor.modality != Modality.ABSTRACT) translateFunction(descriptor, expression, context) else null
|
||||
addFunction(descriptor, jsFunction)
|
||||
}
|
||||
|
||||
override fun visitTypeAlias(typeAlias: KtTypeAlias, data: TranslationContext?) {}
|
||||
@@ -93,17 +92,19 @@ abstract class AbstractDeclarationVisitor : TranslatorVisitor<Unit>() {
|
||||
expression: KtDeclarationWithBody,
|
||||
context: TranslationContext
|
||||
): JsExpression {
|
||||
val innerContext = context.newDeclaration(descriptor)
|
||||
innerContext.getInnerNameForDescriptor(descriptor)
|
||||
val function = context.getFunctionObject(descriptor)
|
||||
return Translation.functionTranslator(expression, innerContext, function).translateAsMethod()
|
||||
val innerContext = context.newDeclaration(descriptor).translateAndAliasParameters(descriptor, function.parameters)
|
||||
innerContext.getInnerNameForDescriptor(descriptor)
|
||||
if (!descriptor.isOverridable) {
|
||||
function.body.statements += FunctionBodyTranslator.setDefaultValueForArguments(descriptor, innerContext)
|
||||
}
|
||||
innerContext.translateFunction(expression, function)
|
||||
return innerContext.wrapWithInlineMetadata(function, descriptor)
|
||||
}
|
||||
|
||||
protected abstract fun addClass(descriptor: ClassDescriptor)
|
||||
|
||||
protected abstract fun addFunction(
|
||||
descriptor: FunctionDescriptor,
|
||||
expression: JsExpression
|
||||
expression: JsExpression?
|
||||
)
|
||||
|
||||
protected abstract fun addProperty(
|
||||
|
||||
+4
-2
@@ -26,7 +26,8 @@ import org.jetbrains.kotlin.js.backend.ast.*
|
||||
import org.jetbrains.kotlin.js.descriptorUtils.hasPrimaryConstructor
|
||||
import org.jetbrains.kotlin.js.translate.callTranslator.CallTranslator
|
||||
import org.jetbrains.kotlin.js.translate.context.*
|
||||
import org.jetbrains.kotlin.js.translate.expression.FunctionTranslator
|
||||
import org.jetbrains.kotlin.js.translate.expression.translateAndAliasParameters
|
||||
import org.jetbrains.kotlin.js.translate.expression.translateFunction
|
||||
import org.jetbrains.kotlin.js.translate.general.AbstractTranslator
|
||||
import org.jetbrains.kotlin.js.translate.initializer.ClassInitializerTranslator
|
||||
import org.jetbrains.kotlin.js.translate.reference.ReferenceTranslator
|
||||
@@ -215,7 +216,8 @@ class ClassTranslator private constructor(
|
||||
val constructorInitializer = context.getFunctionObject(constructorDescriptor)
|
||||
constructorInitializer.name = context.getInnerNameForDescriptor(constructorDescriptor)
|
||||
context.addDeclarationStatement(constructorInitializer.makeStmt())
|
||||
FunctionTranslator.newInstance(constructor, context, constructorInitializer).translateAsMethodWithoutMetadata()
|
||||
context.translateAndAliasParameters(constructorDescriptor, constructorInitializer.parameters)
|
||||
.translateFunction(constructor, constructorInitializer)
|
||||
|
||||
// Translate super/this call
|
||||
val superCallGenerators = mutableListOf<(MutableList<JsStatement>) -> Unit>()
|
||||
|
||||
+45
-8
@@ -16,18 +16,20 @@
|
||||
|
||||
package org.jetbrains.kotlin.js.translate.declaration
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.js.backend.ast.*
|
||||
import org.jetbrains.kotlin.js.translate.context.Namer
|
||||
import org.jetbrains.kotlin.js.translate.context.TranslationContext
|
||||
import org.jetbrains.kotlin.js.translate.expression.translateAndAliasParameters
|
||||
import org.jetbrains.kotlin.js.translate.initializer.ClassInitializerTranslator
|
||||
import org.jetbrains.kotlin.js.translate.utils.*
|
||||
import org.jetbrains.kotlin.js.translate.utils.BindingUtils.getClassDescriptor
|
||||
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils.pureFqn
|
||||
import org.jetbrains.kotlin.js.translate.utils.JsDescriptorUtils.getSupertypesWithoutFakes
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.hasOwnParametersWithDefaultValue
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.hasOrInheritsParametersWithDefaultValue
|
||||
|
||||
class DeclarationBodyVisitor(
|
||||
private val containingClass: ClassDescriptor,
|
||||
@@ -92,12 +94,47 @@ class DeclarationBodyVisitor(
|
||||
initializerStatements.add(statement)
|
||||
}
|
||||
|
||||
override fun addClass(descriptor: ClassDescriptor) {
|
||||
context.export(descriptor)
|
||||
}
|
||||
override fun addFunction(descriptor: FunctionDescriptor, expression: JsExpression?) {
|
||||
if (!descriptor.hasOrInheritsParametersWithDefaultValue() || !descriptor.isOverridableOrOverrides) {
|
||||
if (expression != null) {
|
||||
context.addFunctionToPrototype(containingClass, descriptor, expression)
|
||||
}
|
||||
}
|
||||
else {
|
||||
val bodyName = context.scope().declareName(
|
||||
context.getNameForDescriptor(descriptor).ident + Namer.DEFAULT_PARAMETER_IMPLEMENTOR_SUFFIX)
|
||||
if (expression != null) {
|
||||
val prototypeRef = JsAstUtils.prototypeOf(context.getInnerReference(containingClass))
|
||||
val functionRef = JsNameRef(bodyName, prototypeRef)
|
||||
context.addDeclarationStatement(JsAstUtils.assignment(functionRef, expression).makeStmt())
|
||||
}
|
||||
|
||||
override fun addFunction(descriptor: FunctionDescriptor, expression: JsExpression) {
|
||||
context.addFunctionToPrototype(containingClass, descriptor, expression)
|
||||
if (descriptor.hasOwnParametersWithDefaultValue()) {
|
||||
val caller = JsFunction(context.getScopeForDescriptor(containingClass), JsBlock(), "")
|
||||
val callerContext = context
|
||||
.newDeclaration(descriptor)
|
||||
.translateAndAliasParameters(descriptor, caller.parameters)
|
||||
.innerBlock(caller.body)
|
||||
|
||||
val callbackName = caller.scope.declareTemporaryName("callback" + Namer.DEFAULT_PARAMETER_IMPLEMENTOR_SUFFIX)
|
||||
val callee = JsNameRef(bodyName, JsLiteral.THIS)
|
||||
|
||||
val defaultInvocation = JsInvocation(callee, java.util.ArrayList<JsExpression>())
|
||||
val callbackInvocation = JsInvocation(callbackName.makeRef())
|
||||
val chosenInvocation = JsConditional(callbackName.makeRef(), callbackInvocation, defaultInvocation)
|
||||
defaultInvocation.arguments += caller.parameters.map { it.name.makeRef() }
|
||||
callbackInvocation.arguments += defaultInvocation.arguments.map { it.deepCopy() }
|
||||
caller.parameters.add(JsParameter(callbackName))
|
||||
|
||||
caller.body.statements += FunctionBodyTranslator.setDefaultValueForArguments(descriptor, callerContext)
|
||||
|
||||
val returnType = descriptor.returnType!!
|
||||
val statement = if (KotlinBuiltIns.isUnit(returnType)) chosenInvocation.makeStmt() else JsReturn(chosenInvocation)
|
||||
caller.body.statements += statement
|
||||
|
||||
context.addFunctionToPrototype(containingClass, descriptor, caller)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun addProperty(descriptor: PropertyDescriptor, getter: JsExpression, setter: JsExpression?) {
|
||||
|
||||
+2
-6
@@ -18,7 +18,6 @@ package org.jetbrains.kotlin.js.translate.declaration
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsExpression
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsFunction
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsName
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.js.translate.context.TranslationContext
|
||||
@@ -45,11 +44,8 @@ class FileDeclarationVisitor(private val context: TranslationContext) : Abstract
|
||||
super.visitProperty(expression, context)
|
||||
}
|
||||
|
||||
override fun addClass(descriptor: ClassDescriptor) {
|
||||
context.export(descriptor)
|
||||
}
|
||||
|
||||
override fun addFunction(descriptor: FunctionDescriptor, expression: JsExpression) {
|
||||
override fun addFunction(descriptor: FunctionDescriptor, expression: JsExpression?) {
|
||||
if (expression == null) return
|
||||
addFunctionButNotExport(descriptor, expression)
|
||||
context.export(descriptor)
|
||||
}
|
||||
|
||||
+29
-3
@@ -21,12 +21,15 @@ import org.jetbrains.kotlin.js.backend.ast.JsName
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsNameRef
|
||||
import org.jetbrains.kotlin.backend.common.bridges.generateBridgesForFunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.js.translate.context.Namer
|
||||
import org.jetbrains.kotlin.js.translate.context.StaticContext
|
||||
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils.isNativeObject
|
||||
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
|
||||
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils.prototypeOf
|
||||
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils.pureFqn
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.hasOwnParametersWithDefaultValue
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.hasOrInheritsParametersWithDefaultValue
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
||||
import org.jetbrains.kotlin.utils.DFS
|
||||
@@ -54,15 +57,38 @@ class InterfaceFunctionCopier(val context: StaticContext) {
|
||||
.getContributedDescriptors(DescriptorKindFilter.FUNCTIONS)
|
||||
.mapNotNull { it as? CallableMemberDescriptor }
|
||||
|
||||
for (member in members.filter { it.modality != Modality.ABSTRACT && it.kind.isReal }) {
|
||||
for (member in members.filter { it.kind.isReal }) {
|
||||
val names = generateAllNames(member, context)
|
||||
val identifiers = names.map { it.ident }
|
||||
when (member) {
|
||||
is FunctionDescriptor -> classModel.copiedFunctions += identifiers
|
||||
is PropertyDescriptor -> classModel.copiedProperties += identifiers
|
||||
is FunctionDescriptor -> {
|
||||
if (member.hasOrInheritsParametersWithDefaultValue()) {
|
||||
if (member.hasOwnParametersWithDefaultValue()) {
|
||||
classModel.copiedFunctions += identifiers.map { it }
|
||||
}
|
||||
if (member.modality != Modality.ABSTRACT) {
|
||||
classModel.copiedFunctions += identifiers.map { it + Namer.DEFAULT_PARAMETER_IMPLEMENTOR_SUFFIX }
|
||||
}
|
||||
}
|
||||
else if (member.modality != Modality.ABSTRACT) {
|
||||
classModel.copiedFunctions += identifiers
|
||||
}
|
||||
}
|
||||
is PropertyDescriptor -> {
|
||||
if (member.modality != Modality.ABSTRACT) {
|
||||
classModel.copiedProperties += identifiers
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (member in members.filterIsInstance<FunctionDescriptor>()
|
||||
.filter { it.kind.isReal && it.hasOwnParametersWithDefaultValue() }) {
|
||||
val names = generateAllNames(member, context)
|
||||
val identifiers = names.map { it.ident }
|
||||
classModel.copiedFunctions += identifiers
|
||||
}
|
||||
|
||||
val superModels = DescriptorUtils.getSuperclassDescriptors(descriptor)
|
||||
.filter { it.kind == ClassKind.INTERFACE && !isNativeObject(it) }
|
||||
.map { classModels[it]!! }
|
||||
|
||||
+4
-1
@@ -24,6 +24,8 @@ import org.jetbrains.kotlin.js.translate.context.Namer
|
||||
import org.jetbrains.kotlin.js.translate.context.Namer.getDelegateNameRef
|
||||
import org.jetbrains.kotlin.js.translate.context.Namer.getReceiverParameterName
|
||||
import org.jetbrains.kotlin.js.translate.context.TranslationContext
|
||||
import org.jetbrains.kotlin.js.translate.expression.translateAndAliasParameters
|
||||
import org.jetbrains.kotlin.js.translate.expression.translateFunction
|
||||
import org.jetbrains.kotlin.js.translate.general.AbstractTranslator
|
||||
import org.jetbrains.kotlin.js.translate.general.Translation
|
||||
import org.jetbrains.kotlin.js.translate.utils.BindingUtils
|
||||
@@ -220,7 +222,8 @@ private class PropertyTranslator(
|
||||
private fun translateCustomAccessor(expression: KtPropertyAccessor): JsPropertyInitializer {
|
||||
val descriptor = BindingUtils.getFunctionDescriptor(bindingContext(), expression)
|
||||
val function = JsFunction(context().getScopeForDescriptor(descriptor), JsBlock(), descriptor.toString())
|
||||
return Translation.functionTranslator(expression, context(), function).translateAsEcma5PropertyDescriptor()
|
||||
context().translateAndAliasParameters(descriptor, function.parameters).translateFunction(expression, function)
|
||||
return translateFunctionAsEcma5PropertyDescriptor(function, descriptor, context())
|
||||
}
|
||||
|
||||
private fun createFunction(descriptor: VariableAccessorDescriptor) =
|
||||
|
||||
-195
@@ -1,195 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.js.translate.expression;
|
||||
|
||||
import com.intellij.util.SmartList;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
import org.jetbrains.kotlin.js.backend.ast.*;
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.MetadataProperties;
|
||||
import org.jetbrains.kotlin.js.translate.context.AliasingContext;
|
||||
import org.jetbrains.kotlin.js.translate.context.Namer;
|
||||
import org.jetbrains.kotlin.js.translate.context.TranslationContext;
|
||||
import org.jetbrains.kotlin.js.translate.general.AbstractTranslator;
|
||||
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils;
|
||||
import org.jetbrains.kotlin.psi.KtDeclarationWithBody;
|
||||
import org.jetbrains.kotlin.psi.KtLambdaExpression;
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils;
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.jetbrains.kotlin.js.translate.reference.CallExpressionTranslator.shouldBeInlined;
|
||||
import static org.jetbrains.kotlin.js.translate.utils.BindingUtils.getFunctionDescriptor;
|
||||
import static org.jetbrains.kotlin.js.translate.utils.ErrorReportingUtils.message;
|
||||
import static org.jetbrains.kotlin.js.translate.utils.FunctionBodyTranslator.translateFunctionBody;
|
||||
import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.setParameters;
|
||||
|
||||
public final class FunctionTranslator extends AbstractTranslator {
|
||||
@NotNull
|
||||
public static FunctionTranslator newInstance(
|
||||
@NotNull KtDeclarationWithBody declaration,
|
||||
@NotNull TranslationContext context,
|
||||
@NotNull JsFunction function
|
||||
) {
|
||||
return new FunctionTranslator(declaration, context, function);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private TranslationContext functionBodyContext;
|
||||
@NotNull
|
||||
private final KtDeclarationWithBody functionDeclaration;
|
||||
@Nullable
|
||||
private JsName extensionFunctionReceiverName;
|
||||
@NotNull
|
||||
private final JsFunction functionObject;
|
||||
@NotNull
|
||||
private final FunctionDescriptor descriptor;
|
||||
|
||||
private FunctionTranslator(@NotNull KtDeclarationWithBody functionDeclaration, @NotNull TranslationContext context,
|
||||
@NotNull JsFunction function) {
|
||||
super(context);
|
||||
this.descriptor = getFunctionDescriptor(context.bindingContext(), functionDeclaration);
|
||||
this.functionDeclaration = functionDeclaration;
|
||||
this.functionObject = function;
|
||||
if (!this.functionObject.getParameters().isEmpty()) {
|
||||
throw new AssertionError(message(descriptor, "Function " + functionDeclaration.getText() + " processed for the second time."));
|
||||
}
|
||||
//NOTE: it's important we compute the context before we start the computation
|
||||
this.functionBodyContext = getFunctionBodyContext();
|
||||
MetadataProperties.setFunctionDescriptor(functionObject, descriptor);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private TranslationContext getFunctionBodyContext() {
|
||||
Map<DeclarationDescriptor, JsExpression> aliases = new HashMap<DeclarationDescriptor, JsExpression>();
|
||||
if (isExtensionFunction()) {
|
||||
DeclarationDescriptor expectedReceiverDescriptor = descriptor.getExtensionReceiverParameter();
|
||||
assert expectedReceiverDescriptor != null;
|
||||
extensionFunctionReceiverName = functionObject.getScope().declareName(Namer.getReceiverParameterName());
|
||||
//noinspection ConstantConditions
|
||||
aliases.put(expectedReceiverDescriptor, extensionFunctionReceiverName.makeRef());
|
||||
}
|
||||
|
||||
AliasingContext aliasingContext = !aliases.isEmpty() ? context().aliasingContext().withDescriptorsAliased(aliases) : null;
|
||||
|
||||
return context().newFunctionBody(functionObject, aliasingContext, descriptor);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JsPropertyInitializer translateAsEcma5PropertyDescriptor() {
|
||||
generateFunctionObject();
|
||||
return TranslationUtils.translateFunctionAsEcma5PropertyDescriptor(functionObject, descriptor, context());
|
||||
}
|
||||
|
||||
public void translateAsMethodWithoutMetadata() {
|
||||
generateFunctionObject();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JsExpression translateAsMethod() {
|
||||
translateAsMethodWithoutMetadata();
|
||||
|
||||
if (shouldBeInlined(descriptor, context()) && DescriptorUtilsKt.isEffectivelyPublicApi(descriptor)) {
|
||||
InlineMetadata metadata = InlineMetadata.compose(functionObject, descriptor);
|
||||
return metadata.getFunctionWithMetadata();
|
||||
}
|
||||
else {
|
||||
return functionObject;
|
||||
}
|
||||
}
|
||||
|
||||
private void generateFunctionObject() {
|
||||
List<JsParameter> parameters = translateParameters();
|
||||
|
||||
VariableDescriptor continuationDescriptor = functionBodyContext.getContinuationParameterDescriptor();
|
||||
if (continuationDescriptor != null) {
|
||||
JsParameter jsParameter = new JsParameter(functionBodyContext.getNameForDescriptor(continuationDescriptor));
|
||||
parameters.add(jsParameter);
|
||||
}
|
||||
|
||||
setParameters(functionObject, parameters);
|
||||
translateBody();
|
||||
}
|
||||
|
||||
private void translateBody() {
|
||||
if (!functionDeclaration.hasBody()) {
|
||||
assert descriptor instanceof ConstructorDescriptor || descriptor.getModality().equals(Modality.ABSTRACT);
|
||||
return;
|
||||
}
|
||||
JsBlock body = translateFunctionBody(descriptor, functionDeclaration, functionBodyContext);
|
||||
functionObject.getBody().getStatements().addAll(body.getStatements());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private List<JsParameter> translateParameters() {
|
||||
List<JsParameter> jsParameters = new SmartList<JsParameter>();
|
||||
Map<DeclarationDescriptor, JsExpression> aliases = new HashMap<DeclarationDescriptor, JsExpression>();
|
||||
|
||||
for (TypeParameterDescriptor type : getTypeParameters(descriptor)) {
|
||||
if (type.isReified()) {
|
||||
JsName paramNameForType = context().getNameForDescriptor(type);
|
||||
jsParameters.add(new JsParameter(paramNameForType));
|
||||
|
||||
String suggestedName = Namer.isInstanceSuggestedName(type);
|
||||
JsName paramName = functionObject.getScope().declareTemporaryName(suggestedName);
|
||||
jsParameters.add(new JsParameter(paramName));
|
||||
aliases.put(type, paramName.makeRef());
|
||||
}
|
||||
}
|
||||
|
||||
functionBodyContext = functionBodyContext.innerContextWithDescriptorsAliased(aliases);
|
||||
|
||||
if (extensionFunctionReceiverName == null && descriptor.getValueParameters().isEmpty()) {
|
||||
return jsParameters;
|
||||
}
|
||||
|
||||
mayBeAddThisParameterForExtensionFunction(jsParameters);
|
||||
addParameters(jsParameters, descriptor, context());
|
||||
|
||||
return jsParameters;
|
||||
}
|
||||
|
||||
private static List<TypeParameterDescriptor> getTypeParameters(FunctionDescriptor functionDescriptor) {
|
||||
if (functionDescriptor instanceof PropertyAccessorDescriptor) {
|
||||
return ((PropertyAccessorDescriptor) functionDescriptor).getCorrespondingProperty().getTypeParameters();
|
||||
}
|
||||
return functionDescriptor.getTypeParameters();
|
||||
}
|
||||
|
||||
public static void addParameters(List<JsParameter> list, FunctionDescriptor descriptor, TranslationContext context) {
|
||||
for (ValueParameterDescriptor valueParameter : descriptor.getValueParameters()) {
|
||||
JsParameter jsParameter = new JsParameter(context.getNameForDescriptor(valueParameter));
|
||||
MetadataProperties.setHasDefaultValue(jsParameter, DescriptorUtilsKt.hasDefaultValue(valueParameter));
|
||||
list.add(jsParameter);
|
||||
}
|
||||
}
|
||||
|
||||
private void mayBeAddThisParameterForExtensionFunction(@NotNull List<JsParameter> jsParameters) {
|
||||
if (isExtensionFunction()) {
|
||||
assert extensionFunctionReceiverName != null;
|
||||
jsParameters.add(new JsParameter(extensionFunctionReceiverName));
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isExtensionFunction() {
|
||||
return DescriptorUtils.isExtension(descriptor) && !(functionDeclaration instanceof KtLambdaExpression);
|
||||
}
|
||||
}
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.js.translate.expression
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyAccessorDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsExpression
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsFunction
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsParameter
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.functionDescriptor
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.hasDefaultValue
|
||||
import org.jetbrains.kotlin.js.translate.context.Namer
|
||||
import org.jetbrains.kotlin.js.translate.context.TranslationContext
|
||||
import org.jetbrains.kotlin.js.translate.reference.CallExpressionTranslator.shouldBeInlined
|
||||
import org.jetbrains.kotlin.js.translate.utils.BindingUtils
|
||||
import org.jetbrains.kotlin.js.translate.utils.FunctionBodyTranslator.translateFunctionBody
|
||||
import org.jetbrains.kotlin.psi.KtDeclarationWithBody
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.hasDefaultValue
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.isEffectivelyPublicApi
|
||||
|
||||
fun TranslationContext.translateAndAliasParameters(
|
||||
descriptor: FunctionDescriptor,
|
||||
targetList: MutableList<JsParameter>
|
||||
): TranslationContext {
|
||||
val aliases = mutableMapOf<DeclarationDescriptor, JsExpression>()
|
||||
|
||||
for (type in descriptor.getCorrectTypeParameters()) {
|
||||
if (type.isReified) {
|
||||
val paramNameForType = getNameForDescriptor(type)
|
||||
targetList += JsParameter(paramNameForType)
|
||||
|
||||
val suggestedName = Namer.isInstanceSuggestedName(type)
|
||||
val paramName = scope().declareTemporaryName(suggestedName)
|
||||
targetList += JsParameter(paramName)
|
||||
aliases[type] = paramName.makeRef()
|
||||
}
|
||||
}
|
||||
|
||||
if (descriptor.requiresExtensionReceiverParameter) {
|
||||
val receiverParameterName = scope().declareTemporaryName(Namer.getReceiverParameterName())
|
||||
aliases[descriptor.extensionReceiverParameter!!] = receiverParameterName.makeRef()
|
||||
targetList += JsParameter(receiverParameterName)
|
||||
}
|
||||
|
||||
for (valueParameter in descriptor.valueParameters) {
|
||||
targetList += JsParameter(getNameForDescriptor(valueParameter)).apply { hasDefaultValue = valueParameter.hasDefaultValue() }
|
||||
}
|
||||
|
||||
val continuationDescriptor = continuationParameterDescriptor
|
||||
if (continuationDescriptor != null) {
|
||||
val jsParameter = JsParameter(getNameForDescriptor(continuationDescriptor))
|
||||
targetList += jsParameter
|
||||
}
|
||||
|
||||
return this.innerContextWithDescriptorsAliased(aliases)
|
||||
}
|
||||
|
||||
private fun FunctionDescriptor.getCorrectTypeParameters() =
|
||||
(this as? PropertyAccessorDescriptor)?.correspondingProperty?.typeParameters ?: typeParameters
|
||||
|
||||
|
||||
private val FunctionDescriptor.requiresExtensionReceiverParameter
|
||||
get() = DescriptorUtils.isExtension(this) && visibility != Visibilities.LOCAL
|
||||
|
||||
fun TranslationContext.translateFunction(declaration: KtDeclarationWithBody, function: JsFunction) {
|
||||
val descriptor = BindingUtils.getFunctionDescriptor(bindingContext(), declaration)
|
||||
if (declaration.hasBody()) {
|
||||
val body = translateFunctionBody(descriptor, declaration, this)
|
||||
function.body.statements += body.statements
|
||||
}
|
||||
function.functionDescriptor = descriptor
|
||||
}
|
||||
|
||||
fun TranslationContext.wrapWithInlineMetadata(function: JsFunction, descriptor: FunctionDescriptor): JsExpression {
|
||||
return if (shouldBeInlined(descriptor, this) && descriptor.isEffectivelyPublicApi) {
|
||||
val metadata = InlineMetadata.compose(function, descriptor)
|
||||
metadata.functionWithMetadata
|
||||
}
|
||||
else {
|
||||
function
|
||||
}
|
||||
}
|
||||
+4
-3
@@ -31,6 +31,7 @@ import org.jetbrains.kotlin.js.translate.context.isCaptured
|
||||
import org.jetbrains.kotlin.js.translate.general.AbstractTranslator
|
||||
import org.jetbrains.kotlin.js.translate.reference.ReferenceTranslator
|
||||
import org.jetbrains.kotlin.js.translate.utils.BindingUtils.getFunctionDescriptor
|
||||
import org.jetbrains.kotlin.js.translate.utils.FunctionBodyTranslator.setDefaultValueForArguments
|
||||
import org.jetbrains.kotlin.js.translate.utils.FunctionBodyTranslator.translateFunctionBody
|
||||
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
|
||||
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils
|
||||
@@ -66,7 +67,7 @@ class LiteralFunctionTranslator(context: TranslationContext) : AbstractTranslato
|
||||
val functionContext = invokingContext
|
||||
.newFunctionBodyWithUsageTracker(lambda, descriptor)
|
||||
.innerContextWithDescriptorsAliased(aliases)
|
||||
FunctionTranslator.addParameters(lambda.parameters, descriptor, functionContext)
|
||||
.translateAndAliasParameters(descriptor, lambda.parameters)
|
||||
|
||||
descriptor.valueParameters.forEach {
|
||||
if (it is ValueParameterDescriptorImpl.WithDestructuringDeclaration) {
|
||||
@@ -74,8 +75,8 @@ class LiteralFunctionTranslator(context: TranslationContext) : AbstractTranslato
|
||||
}
|
||||
}
|
||||
|
||||
val functionBody = translateFunctionBody(descriptor, declaration, functionContext)
|
||||
lambda.body.statements.addAll(functionBody.statements)
|
||||
lambda.body.statements += setDefaultValueForArguments(descriptor, functionContext)
|
||||
lambda.body.statements += translateFunctionBody(descriptor, declaration, functionContext)
|
||||
lambda.functionDescriptor = descriptor
|
||||
|
||||
val tracker = functionContext.usageTracker()!!
|
||||
|
||||
@@ -36,7 +36,6 @@ import org.jetbrains.kotlin.js.translate.context.TemporaryVariable;
|
||||
import org.jetbrains.kotlin.js.translate.context.TranslationContext;
|
||||
import org.jetbrains.kotlin.js.translate.declaration.PackageDeclarationTranslator;
|
||||
import org.jetbrains.kotlin.js.translate.expression.ExpressionVisitor;
|
||||
import org.jetbrains.kotlin.js.translate.expression.FunctionTranslator;
|
||||
import org.jetbrains.kotlin.js.translate.expression.PatternTranslator;
|
||||
import org.jetbrains.kotlin.js.translate.test.JSRhinoUnitTester;
|
||||
import org.jetbrains.kotlin.js.translate.test.JSTestGenerator;
|
||||
@@ -44,7 +43,10 @@ import org.jetbrains.kotlin.js.translate.test.JSTester;
|
||||
import org.jetbrains.kotlin.js.translate.test.QUnitTester;
|
||||
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils;
|
||||
import org.jetbrains.kotlin.js.translate.utils.mutator.AssignToExpressionMutator;
|
||||
import org.jetbrains.kotlin.psi.*;
|
||||
import org.jetbrains.kotlin.psi.KtExpression;
|
||||
import org.jetbrains.kotlin.psi.KtFile;
|
||||
import org.jetbrains.kotlin.psi.KtNamedFunction;
|
||||
import org.jetbrains.kotlin.psi.KtUnaryExpression;
|
||||
import org.jetbrains.kotlin.resolve.BindingTrace;
|
||||
import org.jetbrains.kotlin.resolve.bindingContextUtil.BindingContextUtilsKt;
|
||||
import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant;
|
||||
@@ -75,15 +77,6 @@ public final class Translation {
|
||||
private Translation() {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static FunctionTranslator functionTranslator(
|
||||
@NotNull KtDeclarationWithBody declaration,
|
||||
@NotNull TranslationContext context,
|
||||
@NotNull JsFunction function
|
||||
) {
|
||||
return FunctionTranslator.newInstance(declaration, context, function);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static PatternTranslator patternTranslator(@NotNull TranslationContext context) {
|
||||
return PatternTranslator.newInstance(context);
|
||||
|
||||
+1
-6
@@ -18,7 +18,6 @@ package org.jetbrains.kotlin.js.translate.utils;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
|
||||
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor;
|
||||
@@ -33,7 +32,6 @@ import org.jetbrains.kotlin.js.translate.general.Translation;
|
||||
import org.jetbrains.kotlin.js.translate.utils.mutator.Mutator;
|
||||
import org.jetbrains.kotlin.psi.KtDeclarationWithBody;
|
||||
import org.jetbrains.kotlin.psi.KtExpression;
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
|
||||
import org.jetbrains.kotlin.types.KotlinType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -78,7 +76,7 @@ public final class FunctionBodyTranslator extends AbstractTranslator {
|
||||
|
||||
List<JsStatement> result = new ArrayList<JsStatement>(valueParameters.size());
|
||||
for (ValueParameterDescriptor valueParameter : valueParameters) {
|
||||
if (!DescriptorUtilsKt.hasDefaultValue(valueParameter)) continue;
|
||||
if (!valueParameter.declaresDefaultValue()) continue;
|
||||
|
||||
JsNameRef jsNameRef = functionBodyContext.getNameForDescriptor(valueParameter).makeRef();
|
||||
KtExpression defaultArgument = getDefaultArgument(valueParameter);
|
||||
@@ -112,9 +110,6 @@ public final class FunctionBodyTranslator extends AbstractTranslator {
|
||||
KtExpression jetBodyExpression = declaration.getBodyExpression();
|
||||
assert jetBodyExpression != null : "Cannot translate a body of an abstract function.";
|
||||
JsBlock jsBlock = new JsBlock();
|
||||
if (!(descriptor instanceof ConstructorDescriptor) || ((ConstructorDescriptor) descriptor).isPrimary()) {
|
||||
jsBlock.getStatements().addAll(setDefaultValueForArguments(descriptor, context()));
|
||||
}
|
||||
|
||||
KotlinType returnType = descriptor.getReturnType();
|
||||
assert returnType != null;
|
||||
|
||||
@@ -37,6 +37,7 @@ import org.jetbrains.kotlin.psi.*;
|
||||
import org.jetbrains.kotlin.resolve.BindingContext;
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils;
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
|
||||
import org.jetbrains.kotlin.resolve.inline.InlineUtil;
|
||||
import org.jetbrains.kotlin.serialization.deserialization.FindClassInModuleKt;
|
||||
import org.jetbrains.kotlin.types.KotlinType;
|
||||
@@ -364,4 +365,12 @@ public final class TranslationUtils {
|
||||
.getContributedFunctions(Name.identifier("resume"), NoLookupLocation.FROM_DESERIALIZATION)
|
||||
.iterator().next();
|
||||
}
|
||||
|
||||
public static boolean isOverridableFunctionWithDefaultParameters(@NotNull FunctionDescriptor descriptor) {
|
||||
return DescriptorUtilsKt.hasOrInheritsParametersWithDefaultValue(descriptor) &&
|
||||
!(descriptor instanceof ConstructorDescriptor) &&
|
||||
descriptor.getContainingDeclaration() instanceof ClassDescriptor &&
|
||||
ModalityKt.isOverridable(descriptor);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Vendored
+25
@@ -0,0 +1,25 @@
|
||||
package foo
|
||||
|
||||
var global: String = ""
|
||||
|
||||
fun bar(): Int {
|
||||
global += ":bar:"
|
||||
return 100
|
||||
}
|
||||
|
||||
fun baz() = 1
|
||||
|
||||
class A(val x: Int = when (baz()) { 1 -> bar(); else -> 0 })
|
||||
|
||||
fun box(): String {
|
||||
global = ""
|
||||
val a1 = A(10)
|
||||
assertEquals(10, a1.x)
|
||||
assertEquals("", global)
|
||||
|
||||
val a2 = A()
|
||||
assertEquals(100, a2.x)
|
||||
assertEquals(":bar:", global)
|
||||
|
||||
return "OK"
|
||||
}
|
||||
+3
-1
@@ -10,7 +10,9 @@ fun bar(): Int {
|
||||
return 100
|
||||
}
|
||||
|
||||
fun foo(a: Int = when { else -> bar() }): Int = a + 1
|
||||
fun baz() = 1
|
||||
|
||||
fun foo(a: Int = when (baz()) { 1 -> bar(); else -> 0 }): Int = a + 1
|
||||
|
||||
fun bar0(x: String = try { global } finally {}): String {
|
||||
return "bar: ${x}"
|
||||
|
||||
Vendored
+42
@@ -0,0 +1,42 @@
|
||||
// http://youtrack.jetbrains.com/issue/KT-4879
|
||||
// JS: extra side effect when use when in default arguments
|
||||
|
||||
package foo
|
||||
|
||||
var global: String = ""
|
||||
|
||||
fun bar(): Int {
|
||||
global += ":bar:"
|
||||
return 100
|
||||
}
|
||||
|
||||
fun baz() = 1
|
||||
|
||||
open class A {
|
||||
open fun foo(a: Int = when (baz()) { 1 -> bar(); else -> 0 }): Int = a + 1
|
||||
|
||||
open fun bar0(x: String = try { global } finally {}): String {
|
||||
return "bar: ${x}"
|
||||
}
|
||||
}
|
||||
|
||||
class B : A() {
|
||||
override fun foo(a: Int) = a + 2
|
||||
|
||||
override fun bar0(x: String) = "B.bar: $x"
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
global = ""
|
||||
val b = B()
|
||||
assertEquals(102, b.foo(100))
|
||||
assertEquals("", global)
|
||||
|
||||
assertEquals(102, b.foo())
|
||||
assertEquals(":bar:", global)
|
||||
|
||||
assertEquals("B.bar: q", b.bar0("q"))
|
||||
assertEquals("B.bar: :bar:", b.bar0())
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package foo
|
||||
|
||||
open class A {
|
||||
open fun foo(x: Int = 20, y: Int = 3) = x + y
|
||||
}
|
||||
|
||||
open class B : A() {
|
||||
override fun foo(x: Int, y: Int) = 0
|
||||
|
||||
fun bar1() = super.foo()
|
||||
|
||||
fun bar2() = super.foo(30)
|
||||
|
||||
fun bar3() = super.foo(y = 4)
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val v1 = B().bar1()
|
||||
if (v1 != 23) return "fail1: $v1"
|
||||
|
||||
val v2 = B().bar2()
|
||||
if (v2 != 33) return "fail2: $v2"
|
||||
|
||||
val v3 = B().bar3()
|
||||
if (v3 != 24) return "fail3: $v3"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
// MODULE: lib
|
||||
// FILE: lib.kt
|
||||
public interface I {
|
||||
public fun f(p: String = "O"): String
|
||||
}
|
||||
|
||||
// MODULE: main(lib)
|
||||
// FILE: main.kt
|
||||
public class C : I {
|
||||
override fun f(p: String) = p + "K"
|
||||
}
|
||||
|
||||
fun box() = C().f()
|
||||
@@ -0,0 +1,4 @@
|
||||
function bar(a) {
|
||||
a.foo_za3lpa$();
|
||||
a.foo_za3lpa$(99);
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package foo
|
||||
|
||||
var global = ""
|
||||
|
||||
open class A {
|
||||
open fun foo(x: Int = 23) {
|
||||
global += "A.foo($x);"
|
||||
}
|
||||
}
|
||||
|
||||
class B : A() {
|
||||
override fun foo(x: Int) {
|
||||
global += "B.foo($x);"
|
||||
}
|
||||
}
|
||||
|
||||
@native fun bar(a: A)
|
||||
|
||||
fun box(): String {
|
||||
bar(A())
|
||||
bar(B())
|
||||
|
||||
if (global != "A.foo(23);A.foo(99);B.foo(23);B.foo(99);") return "fail: $global"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
Reference in New Issue
Block a user