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) {
|
||||
var resolvedDependencies = [];
|
||||
var currentModule = {};
|
||||
modules[name] = currentModule;
|
||||
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 = {};
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@ package org.jetbrains.kotlin.js.naming
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor
|
||||
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.isNativeObject
|
||||
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
|
||||
is CallableDescriptor ->
|
||||
if (DescriptorUtils.isDescriptorWithLocalVisibility(descriptor)) {
|
||||
val name = getNameForAnnotatedObject(descriptor) ?: getSuggestedName(descriptor)
|
||||
return SuggestedName(listOf(name), false, descriptor, descriptor.containingDeclaration)
|
||||
val ownName = getNameForAnnotatedObject(descriptor) ?: getSuggestedName(descriptor)
|
||||
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
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.JsInvocation
|
||||
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.*
|
||||
import com.google.dart.compiler.backend.js.ast.metadata.staticRef
|
||||
import org.jetbrains.kotlin.js.translate.context.Namer
|
||||
|
||||
/**
|
||||
* Gets invocation qualifier name.
|
||||
@@ -62,19 +56,6 @@ fun getSimpleIdent(call: JsInvocation): String? {
|
||||
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
|
||||
*
|
||||
@@ -116,12 +97,6 @@ private fun getCallerQualifierImpl(invocation: JsInvocation): JsExpression? {
|
||||
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
|
||||
* 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
|
||||
get() {
|
||||
var qualifier = this
|
||||
while (qualifier is JsNameRef) {
|
||||
qualifier = qualifier.name?.staticRef as? JsExpression ?: break
|
||||
loop@while (true) {
|
||||
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
|
||||
}
|
||||
@@ -803,6 +803,12 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest {
|
||||
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")
|
||||
public void testObject() throws Exception {
|
||||
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)
|
||||
}
|
||||
else {
|
||||
context().getInnerNameForDescriptor(descriptor)
|
||||
invokingContext.getInnerNameForDescriptor(descriptor)
|
||||
}
|
||||
|
||||
if (tracker.hasCapturedExceptContaining()) {
|
||||
val lambdaCreator = simpleReturnFunction(invokingContext.scope(), lambda)
|
||||
lambdaCreator.name = context().getInnerNameForDescriptor(descriptor)
|
||||
lambdaCreator.name = invokingContext.getInnerNameForDescriptor(descriptor)
|
||||
lambdaCreator.isLocal = true
|
||||
if (!isRecursive) {
|
||||
lambda.name = null
|
||||
}
|
||||
lambdaCreator.name.staticRef = lambdaCreator
|
||||
return lambdaCreator.withCapturedParameters(functionContext, invokingContext)
|
||||
return lambdaCreator.withCapturedParameters(descriptor, functionContext, invokingContext)
|
||||
}
|
||||
|
||||
lambda.isLocal = true
|
||||
|
||||
context().addDeclarationStatement(lambda.makeStmt())
|
||||
invokingContext.addDeclarationStatement(lambda.makeStmt())
|
||||
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 {
|
||||
@@ -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())
|
||||
val ref = name.makeRef().apply { sideEffects = SideEffectKind.PURE }
|
||||
val ref = getReferenceToLambda(invokingContext, descriptor, name)
|
||||
val invocation = JsInvocation(ref).apply { sideEffects = SideEffectKind.PURE }
|
||||
|
||||
val invocationArguments = invocation.arguments
|
||||
@@ -128,6 +132,19 @@ fun JsFunction.withCapturedParameters(context: TranslationContext, invokingConte
|
||||
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())
|
||||
|
||||
/**
|
||||
|
||||
@@ -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