JS: fix translation of lambdas in public inline functions; fix AMD emulation for Ant test
This commit is contained in:
Vendored
+8
-2
@@ -4,10 +4,16 @@
|
|||||||
|
|
||||||
function define(name, dependencies, body) {
|
function define(name, dependencies, body) {
|
||||||
var resolvedDependencies = [];
|
var resolvedDependencies = [];
|
||||||
|
var currentModule = {};
|
||||||
|
modules[name] = currentModule;
|
||||||
for (var i = 0; i < dependencies.length; ++i) {
|
for (var i = 0; i < dependencies.length; ++i) {
|
||||||
resolvedDependencies[i] = modules[dependencies[i]];
|
var dependencyName = dependencies[i];
|
||||||
|
resolvedDependencies[i] = dependencyName === 'exports' ? currentModule : modules[dependencyName];
|
||||||
|
}
|
||||||
|
currentModule = body.apply(body, resolvedDependencies);
|
||||||
|
if (currentModule) {
|
||||||
|
modules[name] = currentModule;
|
||||||
}
|
}
|
||||||
modules[name] = body.apply(body, resolvedDependencies);
|
|
||||||
}
|
}
|
||||||
define.amd = {};
|
define.amd = {};
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ package org.jetbrains.kotlin.js.naming
|
|||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor
|
import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor
|
||||||
import org.jetbrains.kotlin.js.descriptorUtils.getJetTypeFqName
|
import org.jetbrains.kotlin.js.descriptorUtils.getJetTypeFqName
|
||||||
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils
|
|
||||||
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils.getNameForAnnotatedObject
|
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils.getNameForAnnotatedObject
|
||||||
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils.isNativeObject
|
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils.isNativeObject
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
@@ -105,8 +104,29 @@ class NameSuggestion {
|
|||||||
// Local functions and variables are always private with their own names as suggested names
|
// Local functions and variables are always private with their own names as suggested names
|
||||||
is CallableDescriptor ->
|
is CallableDescriptor ->
|
||||||
if (DescriptorUtils.isDescriptorWithLocalVisibility(descriptor)) {
|
if (DescriptorUtils.isDescriptorWithLocalVisibility(descriptor)) {
|
||||||
val name = getNameForAnnotatedObject(descriptor) ?: getSuggestedName(descriptor)
|
val ownName = getNameForAnnotatedObject(descriptor) ?: getSuggestedName(descriptor)
|
||||||
return SuggestedName(listOf(name), false, descriptor, descriptor.containingDeclaration)
|
var name = ownName
|
||||||
|
var scope = descriptor.containingDeclaration
|
||||||
|
|
||||||
|
// Local functions always lifted to the closest class or package when they are contained inside public inline function
|
||||||
|
if (descriptor is FunctionDescriptor) {
|
||||||
|
var container = descriptor.containingDeclaration
|
||||||
|
var liftedName = ownName
|
||||||
|
var hasInline = false
|
||||||
|
while (container is FunctionDescriptor) {
|
||||||
|
if (container.isInline && container.visibility.isPublicAPI) {
|
||||||
|
hasInline = true
|
||||||
|
}
|
||||||
|
liftedName = getSuggestedName(container) + "$" + liftedName
|
||||||
|
container = container.containingDeclaration
|
||||||
|
}
|
||||||
|
if (hasInline) {
|
||||||
|
scope = container
|
||||||
|
name = liftedName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return SuggestedName(listOf(name), false, descriptor, scope)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,15 +16,9 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.js.inline.util
|
package org.jetbrains.kotlin.js.inline.util
|
||||||
|
|
||||||
import com.google.dart.compiler.backend.js.ast.JsInvocation
|
import com.google.dart.compiler.backend.js.ast.*
|
||||||
import com.google.dart.compiler.backend.js.ast.JsName
|
|
||||||
import com.google.dart.compiler.backend.js.ast.JsExpression
|
|
||||||
import com.google.dart.compiler.backend.js.ast.JsNameRef
|
|
||||||
import com.google.dart.compiler.backend.js.ast.JsFunction
|
|
||||||
import org.jetbrains.kotlin.js.translate.context.Namer
|
|
||||||
import com.google.dart.compiler.backend.js.ast.HasName
|
|
||||||
import com.google.dart.compiler.backend.js.ast.JsNode
|
|
||||||
import com.google.dart.compiler.backend.js.ast.metadata.staticRef
|
import com.google.dart.compiler.backend.js.ast.metadata.staticRef
|
||||||
|
import org.jetbrains.kotlin.js.translate.context.Namer
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets invocation qualifier name.
|
* Gets invocation qualifier name.
|
||||||
@@ -62,19 +56,6 @@ fun getSimpleIdent(call: JsInvocation): String? {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if JsInvocation is function creator call.
|
|
||||||
*
|
|
||||||
* Function creator is a function, that creates closure.
|
|
||||||
*/
|
|
||||||
fun isFunctionCreatorInvocation(invocation: JsInvocation): Boolean {
|
|
||||||
val staticRef = getStaticRef(invocation)
|
|
||||||
return when (staticRef) {
|
|
||||||
is JsFunction -> isFunctionCreator(staticRef)
|
|
||||||
else -> false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests if invocation is JavaScript call function
|
* Tests if invocation is JavaScript call function
|
||||||
*
|
*
|
||||||
@@ -116,12 +97,6 @@ private fun getCallerQualifierImpl(invocation: JsInvocation): JsExpression? {
|
|||||||
return (invocation.qualifier as? JsNameRef)?.qualifier
|
return (invocation.qualifier as? JsNameRef)?.qualifier
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getStaticRef(invocation: JsInvocation): JsNode? {
|
|
||||||
val qualifier = invocation.qualifier
|
|
||||||
val qualifierName = (qualifier as? HasName)?.name
|
|
||||||
return qualifierName?.staticRef
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If an expression A references to another expression B, which in turn references to C, or a corresponding expression
|
* If an expression A references to another expression B, which in turn references to C, or a corresponding expression
|
||||||
* at the end of a chain of references. They are usually JsNameRef expressions with JsFunction at the very end.
|
* at the end of a chain of references. They are usually JsNameRef expressions with JsFunction at the very end.
|
||||||
@@ -131,8 +106,16 @@ private fun getStaticRef(invocation: JsInvocation): JsNode? {
|
|||||||
val JsExpression.transitiveStaticRef: JsExpression
|
val JsExpression.transitiveStaticRef: JsExpression
|
||||||
get() {
|
get() {
|
||||||
var qualifier = this
|
var qualifier = this
|
||||||
while (qualifier is JsNameRef) {
|
loop@while (true) {
|
||||||
qualifier = qualifier.name?.staticRef as? JsExpression ?: break
|
qualifier = when (qualifier) {
|
||||||
|
is JsNameRef -> {
|
||||||
|
qualifier.name?.staticRef as? JsExpression ?: break@loop
|
||||||
|
}
|
||||||
|
is JsInvocation -> {
|
||||||
|
getSimpleName(qualifier)?.staticRef as? JsExpression ?: break@loop
|
||||||
|
}
|
||||||
|
else -> break@loop
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return qualifier
|
return qualifier
|
||||||
}
|
}
|
||||||
@@ -803,6 +803,12 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("lambda.kt")
|
||||||
|
public void testLambda() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/crossModuleRef/lambda.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("object.kt")
|
@TestMetadata("object.kt")
|
||||||
public void testObject() throws Exception {
|
public void testObject() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/crossModuleRef/object.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/crossModuleRef/object.kt");
|
||||||
|
|||||||
+24
-7
@@ -62,25 +62,25 @@ class LiteralFunctionTranslator(context: TranslationContext) : AbstractTranslato
|
|||||||
tracker.getNameForCapturedDescriptor(descriptor)
|
tracker.getNameForCapturedDescriptor(descriptor)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
context().getInnerNameForDescriptor(descriptor)
|
invokingContext.getInnerNameForDescriptor(descriptor)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tracker.hasCapturedExceptContaining()) {
|
if (tracker.hasCapturedExceptContaining()) {
|
||||||
val lambdaCreator = simpleReturnFunction(invokingContext.scope(), lambda)
|
val lambdaCreator = simpleReturnFunction(invokingContext.scope(), lambda)
|
||||||
lambdaCreator.name = context().getInnerNameForDescriptor(descriptor)
|
lambdaCreator.name = invokingContext.getInnerNameForDescriptor(descriptor)
|
||||||
lambdaCreator.isLocal = true
|
lambdaCreator.isLocal = true
|
||||||
if (!isRecursive) {
|
if (!isRecursive) {
|
||||||
lambda.name = null
|
lambda.name = null
|
||||||
}
|
}
|
||||||
lambdaCreator.name.staticRef = lambdaCreator
|
lambdaCreator.name.staticRef = lambdaCreator
|
||||||
return lambdaCreator.withCapturedParameters(functionContext, invokingContext)
|
return lambdaCreator.withCapturedParameters(descriptor, functionContext, invokingContext)
|
||||||
}
|
}
|
||||||
|
|
||||||
lambda.isLocal = true
|
lambda.isLocal = true
|
||||||
|
|
||||||
context().addDeclarationStatement(lambda.makeStmt())
|
invokingContext.addDeclarationStatement(lambda.makeStmt())
|
||||||
lambda.name.staticRef = lambda
|
lambda.name.staticRef = lambda
|
||||||
return lambda.name.makeRef().apply { sideEffects = SideEffectKind.PURE }
|
return getReferenceToLambda(invokingContext, descriptor, lambda.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun ValueParameterDescriptorImpl.WithDestructuringDeclaration.translate(context: TranslationContext): JsVars {
|
fun ValueParameterDescriptorImpl.WithDestructuringDeclaration.translate(context: TranslationContext): JsVars {
|
||||||
@@ -93,9 +93,13 @@ class LiteralFunctionTranslator(context: TranslationContext) : AbstractTranslato
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun JsFunction.withCapturedParameters(context: TranslationContext, invokingContext: TranslationContext): JsExpression {
|
fun JsFunction.withCapturedParameters(
|
||||||
|
descriptor: CallableMemberDescriptor,
|
||||||
|
context: TranslationContext,
|
||||||
|
invokingContext: TranslationContext
|
||||||
|
): JsExpression {
|
||||||
context.addDeclarationStatement(makeStmt())
|
context.addDeclarationStatement(makeStmt())
|
||||||
val ref = name.makeRef().apply { sideEffects = SideEffectKind.PURE }
|
val ref = getReferenceToLambda(invokingContext, descriptor, name)
|
||||||
val invocation = JsInvocation(ref).apply { sideEffects = SideEffectKind.PURE }
|
val invocation = JsInvocation(ref).apply { sideEffects = SideEffectKind.PURE }
|
||||||
|
|
||||||
val invocationArguments = invocation.arguments
|
val invocationArguments = invocation.arguments
|
||||||
@@ -128,6 +132,19 @@ fun JsFunction.withCapturedParameters(context: TranslationContext, invokingConte
|
|||||||
return invocation
|
return invocation
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun getReferenceToLambda(context: TranslationContext, descriptor: CallableMemberDescriptor, name: JsName): JsExpression {
|
||||||
|
return if (context.isPublicInlineFunction) {
|
||||||
|
val fqn = context.getQualifiedReference(descriptor)
|
||||||
|
if (fqn is JsNameRef) {
|
||||||
|
fqn.name?.let { it.staticRef = name.staticRef }
|
||||||
|
}
|
||||||
|
fqn
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
JsAstUtils.pureFqn(name, null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private data class CapturedArgsParams(val arguments: List<JsExpression> = listOf(), val parameters: List<JsParameter> = listOf())
|
private data class CapturedArgsParams(val arguments: List<JsExpression> = listOf(), val parameters: List<JsParameter> = listOf())
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
// MODULE: lib
|
||||||
|
// FILE: lib.kt
|
||||||
|
package lib
|
||||||
|
|
||||||
|
fun bar(f: () -> String) = f()
|
||||||
|
|
||||||
|
inline fun foo(): String {
|
||||||
|
return bar { "OK" }
|
||||||
|
}
|
||||||
|
|
||||||
|
// MODULE: main(lib)
|
||||||
|
// FILE: main.kt
|
||||||
|
package main
|
||||||
|
|
||||||
|
import lib.*
|
||||||
|
|
||||||
|
fun box() = foo()
|
||||||
Reference in New Issue
Block a user