diff --git a/compiler/test/data/javascript/arguments/callResultModified.d.kt b/compiler/test/data/javascript/arguments/callResultModified.d.kt index 977e0cae1..5e98159cc 100644 --- a/compiler/test/data/javascript/arguments/callResultModified.d.kt +++ b/compiler/test/data/javascript/arguments/callResultModified.d.kt @@ -30,6 +30,6 @@ external interface `T$1` { set(value) = definedExternally } -external fun generateVector(vectorProvider: (`0`: Any? /* = null */, `1`: Any? /* = null */, `2`: Any? /* = null */) -> `T$0`): `T$1` +external fun generateVector(vectorProvider: (Any? /* = null */, Any? /* = null */, Any? /* = null */) -> `T$0`): `T$1` -external fun generateVector(vectorProvider: (`0`: Any? /* = null */, `1`: Any? /* = null */, `2`: Any? /* = null */) -> Any?): `T$1` \ No newline at end of file +external fun generateVector(vectorProvider: (Any? /* = null */, Any? /* = null */, Any? /* = null */) -> Any?): `T$1` \ No newline at end of file diff --git a/compiler/test/data/javascript/arguments/callable.d.kt b/compiler/test/data/javascript/arguments/callable.d.kt index 2f056ba82..70eb037ef 100644 --- a/compiler/test/data/javascript/arguments/callable.d.kt +++ b/compiler/test/data/javascript/arguments/callable.d.kt @@ -15,4 +15,4 @@ import org.w3c.performance.* import org.w3c.workers.* import org.w3c.xhr.* -external fun runOperation(numA: Number, numB: Number, operation: (`0`: Any? /* = null */, `1`: Any? /* = null */) -> Number): Number \ No newline at end of file +external fun runOperation(numA: Number, numB: Number, operation: (Any? /* = null */, Any? /* = null */) -> Number): Number \ No newline at end of file diff --git a/compiler/test/data/javascript/function/fromBranchingFunction.d.kt b/compiler/test/data/javascript/function/fromBranchingFunction.d.kt new file mode 100644 index 000000000..7e944a2c3 --- /dev/null +++ b/compiler/test/data/javascript/function/fromBranchingFunction.d.kt @@ -0,0 +1,20 @@ +@file:Suppress("INTERFACE_WITH_SUPERCLASS", "OVERRIDING_FINAL_MEMBER", "RETURN_TYPE_MISMATCH_ON_OVERRIDE", "CONFLICTING_OVERLOADS", "EXTERNAL_DELEGATION") + +import kotlin.js.* +import kotlin.js.Json +import org.khronos.webgl.* +import org.w3c.dom.* +import org.w3c.dom.events.* +import org.w3c.dom.parsing.* +import org.w3c.dom.svg.* +import org.w3c.dom.url.* +import org.w3c.fetch.* +import org.w3c.files.* +import org.w3c.notifications.* +import org.w3c.performance.* +import org.w3c.workers.* +import org.w3c.xhr.* + +external fun actuallyAFunction(): Any? + +external fun generateFun(message: Any?): () -> Any? \ No newline at end of file diff --git a/compiler/test/data/javascript/function/fromBranchingFunction.d.ts b/compiler/test/data/javascript/function/fromBranchingFunction.d.ts new file mode 100644 index 000000000..41f4308c6 --- /dev/null +++ b/compiler/test/data/javascript/function/fromBranchingFunction.d.ts @@ -0,0 +1,17 @@ + +function generateFun(message) { + if (typeof message === "function") { + function foo() { + return message() + } + } else { + function foo() { + return message + } + } + + return foo +} + +module.exports.actuallyAFunction = generateFun() +module.exports.generateFun = generateFun diff --git a/javascript/js-translator/src/org/jetbrains/dukat/js/translator/JavaScriptLowerer.kt b/javascript/js-translator/src/org/jetbrains/dukat/js/translator/JavaScriptLowerer.kt index 404d5ba92..7362252f0 100644 --- a/javascript/js-translator/src/org/jetbrains/dukat/js/translator/JavaScriptLowerer.kt +++ b/javascript/js-translator/src/org/jetbrains/dukat/js/translator/JavaScriptLowerer.kt @@ -6,6 +6,8 @@ import org.jetbrains.dukat.js.type.analysis.introduceTypes import org.jetbrains.dukat.moduleNameResolver.ModuleNameResolver import org.jetbrains.dukat.ts.translator.TypescriptLowerer import org.jetbrains.dukat.tsLowerings.mergeDuplicates.mergeDuplicates +import org.jetbrains.dukat.tsLowerings.nameUnnamedFunctionParameters +import org.jetbrains.dukat.tsLowerings.replaceFunctionTypeVariablesWithFunctions import org.jetbrains.dukat.tsmodel.SourceSetDeclaration import org.jetrbains.dukat.nodeLowering.lowerings.FqNode @@ -14,7 +16,9 @@ class JavaScriptLowerer(nameResolver: ModuleNameResolver) : TypescriptLowerer(na return super.lower( sourceSet .introduceTypes() - .mergeDuplicates(), + .mergeDuplicates() + .replaceFunctionTypeVariablesWithFunctions() + .nameUnnamedFunctionParameters(), stdLibSourceSet, renameMap, uidToFqNameMapper diff --git a/javascript/js-type-analysis/src/org/jetbrains/dukat/js/type/constraint/composite/CompositeConstraint.kt b/javascript/js-type-analysis/src/org/jetbrains/dukat/js/type/constraint/composite/CompositeConstraint.kt index 7ccbb92a6..0259171bf 100644 --- a/javascript/js-type-analysis/src/org/jetbrains/dukat/js/type/constraint/composite/CompositeConstraint.kt +++ b/javascript/js-type-analysis/src/org/jetbrains/dukat/js/type/constraint/composite/CompositeConstraint.kt @@ -81,7 +81,7 @@ class CompositeConstraint( overloads = callableConstraints.map { callable -> FunctionConstraint.Overload( callable.returnConstraints, - List(parameterCount) { i -> "`$i`" to NoTypeConstraint } + List(parameterCount) { "" to NoTypeConstraint } ) } ) diff --git a/typescript/ts-lowerings/src/org/jetbrains/dukat/tsLowerings/mergeDuplicates/mergeDuplicates.kt b/typescript/ts-lowerings/src/org/jetbrains/dukat/tsLowerings/mergeDuplicates/mergeDuplicates.kt index 8000fb3cf..0b8644f81 100644 --- a/typescript/ts-lowerings/src/org/jetbrains/dukat/tsLowerings/mergeDuplicates/mergeDuplicates.kt +++ b/typescript/ts-lowerings/src/org/jetbrains/dukat/tsLowerings/mergeDuplicates/mergeDuplicates.kt @@ -9,6 +9,7 @@ import org.jetbrains.dukat.tsmodel.FunctionLikeDeclaration import org.jetbrains.dukat.tsmodel.MemberDeclaration import org.jetbrains.dukat.tsmodel.ModuleDeclaration import org.jetbrains.dukat.tsmodel.ParameterDeclaration +import org.jetbrains.dukat.tsmodel.PropertyDeclaration import org.jetbrains.dukat.tsmodel.SourceFileDeclaration import org.jetbrains.dukat.tsmodel.SourceSetDeclaration import org.jetbrains.dukat.tsmodel.TopLevelDeclaration @@ -133,6 +134,7 @@ private fun List.mergeMembers() : List { is ConstructorDeclaration -> constructors += member.mergeDuplicates() is FunctionDeclaration -> methods += member.mergeDuplicates() is CallSignatureDeclaration -> callSignatures += member.mergeDuplicates() + is PropertyDeclaration -> otherMembers += member.mergeDuplicates() else -> otherMembers += member } } @@ -151,6 +153,10 @@ private fun ParameterDeclaration.mergeDuplicates() = copy( type = type.mergeDuplicates() ) +private fun PropertyDeclaration.mergeDuplicates() = copy( + type = type.mergeDuplicates() +) + private fun ConstructorDeclaration.mergeDuplicates() = copy( parameters = parameters.map { it.mergeDuplicates() } ) diff --git a/typescript/ts-lowerings/src/org/jetbrains/dukat/tsLowerings/mergeDuplicates/normalize.kt b/typescript/ts-lowerings/src/org/jetbrains/dukat/tsLowerings/mergeDuplicates/normalize.kt index cc8ad4794..9ed44b994 100644 --- a/typescript/ts-lowerings/src/org/jetbrains/dukat/tsLowerings/mergeDuplicates/normalize.kt +++ b/typescript/ts-lowerings/src/org/jetbrains/dukat/tsLowerings/mergeDuplicates/normalize.kt @@ -5,6 +5,7 @@ import org.jetbrains.dukat.tsmodel.ConstructorDeclaration import org.jetbrains.dukat.tsmodel.FunctionDeclaration import org.jetbrains.dukat.tsmodel.MemberDeclaration import org.jetbrains.dukat.tsmodel.ParameterDeclaration +import org.jetbrains.dukat.tsmodel.PropertyDeclaration import org.jetbrains.dukat.tsmodel.types.FunctionTypeDeclaration import org.jetbrains.dukat.tsmodel.types.ObjectLiteralDeclaration import org.jetbrains.dukat.tsmodel.types.ParameterValueDeclaration @@ -31,6 +32,7 @@ internal fun MemberDeclaration.normalize(): MemberDeclaration { is CallSignatureDeclaration -> this.normalize() is ConstructorDeclaration -> this.normalize() is FunctionDeclaration -> this.normalize() + is PropertyDeclaration -> this.normalize() else -> this } } @@ -47,6 +49,10 @@ internal fun FunctionDeclaration.normalize(substituteType: ParameterValueDeclara uid = IRRELEVANT_UID ) +internal fun PropertyDeclaration.normalize() = copy( + type = type.normalize() +) + internal fun UnionTypeDeclaration.normalize() = copy( params = params.map { it.normalize() } ) diff --git a/typescript/ts-lowerings/src/org/jetbrains/dukat/tsLowerings/nameUnnamedFunctionParameters.kt b/typescript/ts-lowerings/src/org/jetbrains/dukat/tsLowerings/nameUnnamedFunctionParameters.kt new file mode 100644 index 000000000..f37aeaea4 --- /dev/null +++ b/typescript/ts-lowerings/src/org/jetbrains/dukat/tsLowerings/nameUnnamedFunctionParameters.kt @@ -0,0 +1,66 @@ +package org.jetbrains.dukat.tsLowerings + +import org.jetbrains.dukat.ownerContext.NodeOwner +import org.jetbrains.dukat.tsmodel.CallSignatureDeclaration +import org.jetbrains.dukat.tsmodel.FunctionDeclaration +import org.jetbrains.dukat.tsmodel.FunctionOwnerDeclaration +import org.jetbrains.dukat.tsmodel.MemberDeclaration +import org.jetbrains.dukat.tsmodel.ModuleDeclaration +import org.jetbrains.dukat.tsmodel.ParameterDeclaration +import org.jetbrains.dukat.tsmodel.ParameterOwnerDeclaration +import org.jetbrains.dukat.tsmodel.SourceFileDeclaration +import org.jetbrains.dukat.tsmodel.SourceSetDeclaration + +private class NameUnnamedFunctionParameters : DeclarationTypeLowering { + + private fun Int.asLetter() = 'A' + (this % 26) + + private fun Int.toParameterName() : String { + var num = this + var name = num.asLetter().toString() + while (num >= 26) { + num = (num - 26) / 26 + name = num.asLetter() + name + } + + return "arg$name" + } + + private fun List.lowerParameters(parameterOwner: NodeOwner) : List { + var argumentId = 0 + + return this.map { parameter -> + if (parameter.name.isEmpty()) { + parameter.copy( + name = argumentId++.toParameterName(), + type = lowerParameterValue(parameter.type, parameterOwner) + ) + } else { + lowerParameterDeclaration(parameter, parameterOwner) + } + } + } + + override fun lowerFunctionDeclaration(declaration: FunctionDeclaration, owner: NodeOwner): FunctionDeclaration { + return declaration.copy( + parameters = declaration.parameters.lowerParameters(owner.wrap(declaration)), + type = lowerParameterValue(declaration.type, owner.wrap(declaration)) + ) + } + + override fun lowerCallSignatureDeclaration(declaration: CallSignatureDeclaration, owner: NodeOwner): CallSignatureDeclaration { + return declaration.copy( + parameters = declaration.parameters.lowerParameters(owner.wrap(declaration)), + type = lowerParameterValue(declaration.type, owner.wrap(declaration)) + ) + } + +} + +fun ModuleDeclaration.nameUnnamedFunctionParameters(): ModuleDeclaration { + return NameUnnamedFunctionParameters().lowerDocumentRoot(this) +} + +fun SourceFileDeclaration.nameUnnamedFunctionParameters() = copy(root = root.nameUnnamedFunctionParameters()) + +fun SourceSetDeclaration.nameUnnamedFunctionParameters() = copy(sources = sources.map(SourceFileDeclaration::nameUnnamedFunctionParameters)) \ No newline at end of file diff --git a/typescript/ts-lowerings/src/org/jetbrains/dukat/tsLowerings/replaceFunctionTypeVariablesWithFunctions.kt b/typescript/ts-lowerings/src/org/jetbrains/dukat/tsLowerings/replaceFunctionTypeVariablesWithFunctions.kt new file mode 100644 index 000000000..81b58b7e4 --- /dev/null +++ b/typescript/ts-lowerings/src/org/jetbrains/dukat/tsLowerings/replaceFunctionTypeVariablesWithFunctions.kt @@ -0,0 +1,89 @@ +package org.jetbrains.dukat.tsLowerings + +import org.jetbrains.dukat.ownerContext.NodeOwner +import org.jetbrains.dukat.tsmodel.BlockDeclaration +import org.jetbrains.dukat.tsmodel.CallSignatureDeclaration +import org.jetbrains.dukat.tsmodel.ClassDeclaration +import org.jetbrains.dukat.tsmodel.ClassLikeDeclaration +import org.jetbrains.dukat.tsmodel.ConstructorDeclaration +import org.jetbrains.dukat.tsmodel.FunctionDeclaration +import org.jetbrains.dukat.tsmodel.FunctionOwnerDeclaration +import org.jetbrains.dukat.tsmodel.GeneratedInterfaceDeclaration +import org.jetbrains.dukat.tsmodel.InterfaceDeclaration +import org.jetbrains.dukat.tsmodel.MemberDeclaration +import org.jetbrains.dukat.tsmodel.MemberOwnerDeclaration +import org.jetbrains.dukat.tsmodel.MethodSignatureDeclaration +import org.jetbrains.dukat.tsmodel.ModifierDeclaration +import org.jetbrains.dukat.tsmodel.ModuleDeclaration +import org.jetbrains.dukat.tsmodel.ParameterDeclaration +import org.jetbrains.dukat.tsmodel.ParameterOwnerDeclaration +import org.jetbrains.dukat.tsmodel.PropertyDeclaration +import org.jetbrains.dukat.tsmodel.SourceFileDeclaration +import org.jetbrains.dukat.tsmodel.SourceSetDeclaration +import org.jetbrains.dukat.tsmodel.TopLevelDeclaration +import org.jetbrains.dukat.tsmodel.TypeAliasDeclaration +import org.jetbrains.dukat.tsmodel.TypeParameterDeclaration +import org.jetbrains.dukat.tsmodel.VariableDeclaration +import org.jetbrains.dukat.tsmodel.types.FunctionTypeDeclaration +import org.jetbrains.dukat.tsmodel.types.IndexSignatureDeclaration +import org.jetbrains.dukat.tsmodel.types.ParameterValueDeclaration + +private class ReplaceFunctionTypeVariablesWithFunctions : DeclarationTypeLowering { + + fun PropertyDeclaration.replaceFunctionTypeVariablesWithFunctions(): MemberDeclaration { + return when (val type = type) { + is FunctionTypeDeclaration -> FunctionDeclaration( + name = name, + parameters = type.parameters, + type = type.type, + typeParameters = emptyList(), + modifiers = modifiers, + body = null, + uid = "" + ) + else -> this + } + } + + fun VariableDeclaration.replaceFunctionTypeVariablesWithFunctions(): TopLevelDeclaration { + return when (val type = type) { + is FunctionTypeDeclaration -> FunctionDeclaration( + name = name, + parameters = type.parameters, + type = type.type, + typeParameters = emptyList(), + modifiers = modifiers, + body = null, + uid = "" + ) + else -> this + } + } + + override fun lowerMemberDeclaration(declaration: MemberDeclaration, owner: NodeOwner): MemberDeclaration { + val convertedDeclaration = when (declaration) { + is PropertyDeclaration -> declaration.replaceFunctionTypeVariablesWithFunctions() + else -> declaration + } + + return super.lowerMemberDeclaration(convertedDeclaration, owner) + } + + @Suppress("UNCHECKED_CAST") + override fun lowerTopLevelDeclaration(declaration: TopLevelDeclaration, owner: NodeOwner): TopLevelDeclaration { + val convertedDeclaration = when (declaration) { + is VariableDeclaration -> declaration.replaceFunctionTypeVariablesWithFunctions() + else -> declaration + } + + return super.lowerTopLevelDeclaration(convertedDeclaration, owner) + } +} + +fun ModuleDeclaration.replaceFunctionTypeVariablesWithFunctions(): ModuleDeclaration { + return ReplaceFunctionTypeVariablesWithFunctions().lowerDocumentRoot(this) +} + +fun SourceFileDeclaration.replaceFunctionTypeVariablesWithFunctions() = copy(root = root.replaceFunctionTypeVariablesWithFunctions()) + +fun SourceSetDeclaration.replaceFunctionTypeVariablesWithFunctions() = copy(sources = sources.map(SourceFileDeclaration::replaceFunctionTypeVariablesWithFunctions)) \ No newline at end of file