JS: make functions called call to inline properly. See KT-7004
This commit is contained in:
@@ -20,6 +20,7 @@ package org.jetbrains.kotlin.js.backend.ast.metadata
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.js.backend.ast.*
|
||||
import org.jetbrains.kotlin.resolve.inline.InlineStrategy
|
||||
@@ -27,6 +28,8 @@ import org.jetbrains.kotlin.types.KotlinType
|
||||
|
||||
var JsName.staticRef: JsNode? by MetadataProperty(default = null)
|
||||
|
||||
var JsName.descriptor: DeclarationDescriptor? by MetadataProperty(default = null)
|
||||
|
||||
// TODO: move this to module 'js.inliner' and change dependency on 'frontend' to dependency on 'descriptors'
|
||||
var JsInvocation.inlineStrategy: InlineStrategy? by MetadataProperty(default = null)
|
||||
|
||||
|
||||
@@ -17,8 +17,10 @@
|
||||
package org.jetbrains.kotlin.js.inline.util
|
||||
|
||||
import org.jetbrains.kotlin.js.backend.ast.*
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.descriptor
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.staticRef
|
||||
import org.jetbrains.kotlin.js.translate.context.Namer
|
||||
import org.jetbrains.kotlin.js.translate.utils.name
|
||||
|
||||
/**
|
||||
* Gets invocation qualifier name.
|
||||
@@ -66,6 +68,8 @@ fun isCallInvocation(invocation: JsInvocation): Boolean {
|
||||
val qualifier = invocation.qualifier as? JsNameRef
|
||||
val arguments = invocation.arguments
|
||||
|
||||
if (qualifier.name?.descriptor != null) return false
|
||||
|
||||
return qualifier?.ident == Namer.CALL_FUNCTION && arguments.isNotEmpty()
|
||||
}
|
||||
|
||||
|
||||
@@ -3656,6 +3656,12 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("callFunction.kt")
|
||||
public void testCallFunction() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/inline/callFunction.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("callInlineFunctionOnTopLevel.kt")
|
||||
public void testCallInlineFunctionOnTopLevel() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/inline/callInlineFunctionOnTopLevel.kt");
|
||||
@@ -4517,6 +4523,12 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("callFunction.kt")
|
||||
public void testCallFunction() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/inlineMultiModule/callFunction.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("callableReference.kt")
|
||||
public void testCallableReference() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/inlineMultiModule/callableReference.kt");
|
||||
|
||||
@@ -18,9 +18,6 @@ package org.jetbrains.kotlin.js.translate.context;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import org.jetbrains.kotlin.js.backend.ast.*;
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.MetadataProperties;
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.SideEffectKind;
|
||||
import com.intellij.openapi.util.Factory;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.hash.LinkedHashMap;
|
||||
@@ -29,6 +26,9 @@ import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor;
|
||||
import org.jetbrains.kotlin.js.backend.ast.*;
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.MetadataProperties;
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.SideEffectKind;
|
||||
import org.jetbrains.kotlin.js.config.JsConfig;
|
||||
import org.jetbrains.kotlin.js.naming.NameSuggestion;
|
||||
import org.jetbrains.kotlin.js.naming.SuggestedName;
|
||||
@@ -304,7 +304,9 @@ public final class StaticContext {
|
||||
@NotNull
|
||||
public JsName getNameForDescriptor(@NotNull DeclarationDescriptor descriptor) {
|
||||
if (descriptor instanceof ClassDescriptor && KotlinBuiltIns.isAny((ClassDescriptor) descriptor)) {
|
||||
return rootScope.declareName("Object");
|
||||
JsName result = rootScope.declareName("Object");
|
||||
MetadataProperties.setDescriptor(result, descriptor);
|
||||
return result;
|
||||
}
|
||||
SuggestedName suggested = nameSuggestion.suggest(descriptor);
|
||||
if (suggested == null) {
|
||||
@@ -360,7 +362,9 @@ public final class StaticContext {
|
||||
List<JsName> names = new ArrayList<JsName>();
|
||||
if (suggested.getStable()) {
|
||||
for (String namePart : suggested.getNames()) {
|
||||
names.add(scope.declareName(namePart));
|
||||
JsName name = scope.declareName(namePart);
|
||||
MetadataProperties.setDescriptor(name, suggested.getDescriptor());
|
||||
names.add(name);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -382,6 +386,7 @@ public final class StaticContext {
|
||||
}
|
||||
}
|
||||
nameCache.put(suggested.getDescriptor(), name);
|
||||
MetadataProperties.setDescriptor(name, suggested.getDescriptor());
|
||||
names.add(name);
|
||||
}
|
||||
|
||||
@@ -448,9 +453,11 @@ public final class StaticContext {
|
||||
@NotNull
|
||||
private JsName localOrImportedName(@NotNull DeclarationDescriptor descriptor, @NotNull String suggestedName) {
|
||||
ModuleDescriptor module = DescriptorUtilsKt.getModule(descriptor);
|
||||
return module != currentModule ?
|
||||
JsName name = module != currentModule ?
|
||||
importDeclaration(suggestedName, getQualifiedReference(descriptor)) :
|
||||
rootFunction.getScope().declareTemporaryName(suggestedName);
|
||||
MetadataProperties.setDescriptor(name, descriptor);
|
||||
return name;
|
||||
}
|
||||
|
||||
private final class InnerNameGenerator extends Generator<JsName> {
|
||||
|
||||
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.js.translate.context
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsName
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsScope
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.descriptor
|
||||
import org.jetbrains.kotlin.js.descriptorUtils.isCoroutineLambda
|
||||
import org.jetbrains.kotlin.js.naming.NameSuggestion
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
@@ -171,7 +172,7 @@ class UsageTracker(
|
||||
}
|
||||
}
|
||||
|
||||
return scope.declareTemporaryName(suggestedName)
|
||||
return scope.declareTemporaryName(suggestedName).apply { descriptor = this@getJsNameForCapturedDescriptor }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
@@ -58,6 +58,7 @@ public final class FunctionBodyTranslator extends AbstractTranslator {
|
||||
for (FunctionDescriptor localFunction : functionCollector.getFunctions()) {
|
||||
String localIdent = localFunction.getName().isSpecial() ? "lambda" : localFunction.getName().asString();
|
||||
JsName localName = functionBodyContext.scope().getParent().declareTemporaryName(NameSuggestion.sanitizeName(localIdent));
|
||||
MetadataProperties.setDescriptor(localName, localFunction);
|
||||
JsExpression alias = JsAstUtils.pureFqn(localName, null);
|
||||
aliases.put(localFunction, alias);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
// CHECK_CONTAINS_NO_CALLS: box except=equals;Baz_getInstance;callLocal;callLocalExtension
|
||||
// CHECK_CONTAINS_NO_CALLS: callLocal
|
||||
// CHECK_CONTAINS_NO_CALLS: callLocalExtension
|
||||
|
||||
object Foo {
|
||||
@JsName("call")
|
||||
inline fun call(a: Int) = "Foo.call($a)"
|
||||
}
|
||||
|
||||
class Bar {
|
||||
@JsName("call")
|
||||
inline fun call(a: Int) = "Bar.call($a)"
|
||||
}
|
||||
|
||||
|
||||
inline fun call(a: Int) = "call($a)"
|
||||
|
||||
fun callLocal(a: Int): String {
|
||||
inline fun call(a: Int) = "callLocal($a)"
|
||||
return call(a)
|
||||
}
|
||||
|
||||
object Baz
|
||||
|
||||
inline fun Baz.call(a: Int) = "Baz.call($a)"
|
||||
|
||||
class Boo
|
||||
|
||||
fun callLocalExtension(a: Int): String {
|
||||
inline fun Boo.call(a: Int) = "Boo.callLocal($a)"
|
||||
return Boo().call(a)
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
var result = call(1)
|
||||
if (result != "call(1)") return "fail1: $result"
|
||||
|
||||
result = Foo.call(2)
|
||||
if (result != "Foo.call(2)") return "fail2: $result"
|
||||
|
||||
result = Bar().call(3)
|
||||
if (result != "Bar.call(3)") return "fail3: $result"
|
||||
|
||||
result = Baz.call(4)
|
||||
if (result != "Baz.call(4)") return "fail4: $result"
|
||||
|
||||
result = callLocal(5)
|
||||
if (result != "callLocal(5)") return "fail5: $result"
|
||||
|
||||
result = callLocalExtension(6)
|
||||
if (result != "Boo.callLocal(6)") return "fail6: $result"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
// MODULE: lib
|
||||
// FILE: lib.kt
|
||||
|
||||
object Foo {
|
||||
@JsName("call")
|
||||
inline fun call(a: Int) = "Foo.call($a)"
|
||||
}
|
||||
|
||||
class Bar {
|
||||
@JsName("call")
|
||||
inline fun call(a: Int) = "Bar.call($a)"
|
||||
}
|
||||
|
||||
|
||||
inline fun call(a: Int) = "call($a)"
|
||||
|
||||
object Baz
|
||||
|
||||
inline fun Baz.call(a: Int) = "Baz.call($a)"
|
||||
|
||||
// MODULE: main(lib)
|
||||
// FILE: main.kt
|
||||
|
||||
// CHECK_CONTAINS_NO_CALLS: box except=equals
|
||||
|
||||
fun box(): String {
|
||||
var result = call(1)
|
||||
if (result != "call(1)") return "fail1: $result"
|
||||
|
||||
result = Foo.call(2)
|
||||
if (result != "Foo.call(2)") return "fail2: $result"
|
||||
|
||||
result = Bar().call(3)
|
||||
if (result != "Bar.call(3)") return "fail3: $result"
|
||||
|
||||
result = Baz.call(4)
|
||||
if (result != "Baz.call(4)") return "fail4: $result"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
Reference in New Issue
Block a user