Fix translation of classes to work with new JS inliner
This commit is contained in:
@@ -4796,6 +4796,12 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("localObjectLiteralWithInheritance.kt")
|
||||
public void testLocalObjectLiteralWithInheritance() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/inlineMultiModule/localObjectLiteralWithInheritance.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("method.kt")
|
||||
public void testMethod() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/inlineMultiModule/method.kt");
|
||||
|
||||
@@ -161,7 +161,7 @@ public final class StaticContext {
|
||||
JsName kotlinName = rootScope.declareName(Namer.KOTLIN_NAME);
|
||||
createImportedModule(new JsImportedModuleKey(Namer.KOTLIN_LOWER_NAME, null), Namer.KOTLIN_LOWER_NAME, kotlinName, null);
|
||||
|
||||
classModelGenerator = new ClassModelGenerator(this);
|
||||
classModelGenerator = new ClassModelGenerator(TranslationContext.rootContext(this));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
+49
-31
@@ -28,12 +28,14 @@ import org.jetbrains.kotlin.js.backend.ast.*;
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.MetadataProperties;
|
||||
import org.jetbrains.kotlin.js.config.JsConfig;
|
||||
import org.jetbrains.kotlin.js.naming.SuggestedName;
|
||||
import org.jetbrains.kotlin.js.translate.declaration.ClassModelGenerator;
|
||||
import org.jetbrains.kotlin.js.translate.intrinsic.Intrinsics;
|
||||
import org.jetbrains.kotlin.js.translate.reference.CallExpressionTranslator;
|
||||
import org.jetbrains.kotlin.js.translate.reference.ReferenceTranslator;
|
||||
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils;
|
||||
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils;
|
||||
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils;
|
||||
import org.jetbrains.kotlin.js.translate.utils.UtilsKt;
|
||||
import org.jetbrains.kotlin.name.Name;
|
||||
import org.jetbrains.kotlin.psi.KtExpression;
|
||||
import org.jetbrains.kotlin.resolve.BindingContext;
|
||||
@@ -279,6 +281,40 @@ public class TranslationContext {
|
||||
return staticContext.getInnerNameForDescriptor(descriptor);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JsName getInlineableInnerNameForDescriptor(@NotNull DeclarationDescriptor descriptor) {
|
||||
JsName name;
|
||||
if (inlineFunctionContext == null || !isPublicInlineFunction() ||
|
||||
DescriptorUtils.isAncestor(inlineFunctionContext.getDescriptor(), descriptor, false)) {
|
||||
name = getInnerNameForDescriptor(descriptor);
|
||||
}
|
||||
else {
|
||||
String tag = staticContext.getTag(descriptor);
|
||||
name = inlineFunctionContext.getImports().computeIfAbsent(tag, t -> {
|
||||
JsExpression imported = createInlineLocalImportExpression(descriptor);
|
||||
if (imported instanceof JsNameRef) {
|
||||
JsNameRef importedNameRef = (JsNameRef) imported;
|
||||
if (importedNameRef.getQualifier() == null && importedNameRef.getIdent().equals(Namer.getRootPackageName()) &&
|
||||
(descriptor instanceof PackageFragmentDescriptor || descriptor instanceof ModuleDescriptor)) {
|
||||
return importedNameRef.getName();
|
||||
}
|
||||
}
|
||||
|
||||
JsName result = JsScope.declareTemporaryName(StaticContext.getSuggestedName(descriptor));
|
||||
if (isFromCurrentModule(descriptor) && !AnnotationsUtils.isNativeObject(descriptor)) {
|
||||
MetadataProperties.setLocalAlias(result, getInnerNameForDescriptor(descriptor));
|
||||
}
|
||||
MetadataProperties.setDescriptor(result, descriptor);
|
||||
MetadataProperties.setStaticRef(result, imported);
|
||||
MetadataProperties.setImported(result, true);
|
||||
inlineFunctionContext.getImportBlock().getStatements().add(JsAstUtils.newVar(result, imported));
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JsName getNameForObjectInstance(@NotNull ClassDescriptor descriptor) {
|
||||
return staticContext.getNameForObjectInstance(descriptor);
|
||||
@@ -340,36 +376,7 @@ public class TranslationContext {
|
||||
|
||||
@NotNull
|
||||
public JsExpression getInnerReference(@NotNull DeclarationDescriptor descriptor) {
|
||||
JsName name;
|
||||
if (inlineFunctionContext == null || !isPublicInlineFunction() ||
|
||||
DescriptorUtils.isAncestor(inlineFunctionContext.getDescriptor(), descriptor, false)) {
|
||||
name = getInnerNameForDescriptor(descriptor);
|
||||
}
|
||||
else {
|
||||
String tag = staticContext.getTag(descriptor);
|
||||
name = inlineFunctionContext.getImports().computeIfAbsent(tag, t -> {
|
||||
JsExpression imported = createInlineLocalImportExpression(descriptor);
|
||||
if (imported instanceof JsNameRef) {
|
||||
JsNameRef importedNameRef = (JsNameRef) imported;
|
||||
if (importedNameRef.getQualifier() == null && importedNameRef.getIdent().equals(Namer.getRootPackageName()) &&
|
||||
(descriptor instanceof PackageFragmentDescriptor || descriptor instanceof ModuleDescriptor)) {
|
||||
return importedNameRef.getName();
|
||||
}
|
||||
}
|
||||
|
||||
JsName result = JsScope.declareTemporaryName(StaticContext.getSuggestedName(descriptor));
|
||||
if (isFromCurrentModule(descriptor) && !AnnotationsUtils.isNativeObject(descriptor)) {
|
||||
MetadataProperties.setLocalAlias(result, getInnerNameForDescriptor(descriptor));
|
||||
}
|
||||
MetadataProperties.setDescriptor(result, descriptor);
|
||||
MetadataProperties.setStaticRef(result, imported);
|
||||
MetadataProperties.setImported(result, true);
|
||||
inlineFunctionContext.getImportBlock().getStatements().add(JsAstUtils.newVar(result, imported));
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
return pureFqn(name, null);
|
||||
return pureFqn(getInlineableInnerNameForDescriptor(descriptor), null);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -769,7 +776,18 @@ public class TranslationContext {
|
||||
}
|
||||
|
||||
public void addClass(@NotNull ClassDescriptor classDescriptor) {
|
||||
staticContext.addClass(classDescriptor);
|
||||
if (inlineFunctionContext != null) {
|
||||
JsClassModel classModel = new ClassModelGenerator(this).generateClassModel(classDescriptor);
|
||||
List<JsStatement> targetStatements = inlineFunctionContext.getPrototypeBlock().getStatements();
|
||||
JsName superName = classModel.getSuperName();
|
||||
if (superName != null) {
|
||||
targetStatements.addAll(UtilsKt.createPrototypeStatements(superName, classModel.getName()));
|
||||
}
|
||||
targetStatements.addAll(classModel.getPostDeclarationBlock().getStatements());
|
||||
}
|
||||
else {
|
||||
staticContext.addClass(classDescriptor);
|
||||
}
|
||||
}
|
||||
|
||||
public void export(@NotNull MemberDescriptor descriptor) {
|
||||
|
||||
+11
-15
@@ -22,7 +22,6 @@ import org.jetbrains.kotlin.backend.common.bridges.generateBridgesForFunctionDes
|
||||
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.StaticContext
|
||||
import org.jetbrains.kotlin.js.translate.context.TranslationContext
|
||||
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils
|
||||
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
|
||||
@@ -33,15 +32,14 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.hasOrInheritsParametersWithDefaultValue
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.hasOwnParametersWithDefaultValue
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
||||
import org.jetbrains.kotlin.resolve.source.getPsi
|
||||
import org.jetbrains.kotlin.utils.identity
|
||||
|
||||
class ClassModelGenerator(val context: StaticContext) {
|
||||
class ClassModelGenerator(val context: TranslationContext) {
|
||||
fun generateClassModel(descriptor: ClassDescriptor): JsClassModel {
|
||||
val superName = descriptor.getSuperClassNotAny()?.let { context.getInnerNameForDescriptor(it) }
|
||||
val model = JsClassModel(context.getInnerNameForDescriptor(descriptor), superName)
|
||||
val superName = descriptor.getSuperClassNotAny()?.let { context.getInlineableInnerNameForDescriptor(it) }
|
||||
val model = JsClassModel(context.getInlineableInnerNameForDescriptor(descriptor), superName)
|
||||
if (descriptor.kind != ClassKind.ANNOTATION_CLASS && !AnnotationsUtils.isNativeObject(descriptor)) {
|
||||
copyDefaultMembers(descriptor, model)
|
||||
generateBridgeMethods(descriptor, model)
|
||||
@@ -205,12 +203,11 @@ class ClassModelGenerator(val context: StaticContext) {
|
||||
}
|
||||
|
||||
private fun generateBridgesToTraitImpl(descriptor: ClassDescriptor, model: JsClassModel) {
|
||||
val translationContext = TranslationContext.rootContext(context)
|
||||
for ((key, value) in CodegenUtil.getNonPrivateTraitMethods(descriptor)) {
|
||||
val sourceName = context.getNameForDescriptor(key).ident
|
||||
val targetName = context.getNameForDescriptor(value).ident
|
||||
if (sourceName != targetName) {
|
||||
val statement = generateDelegateCall(descriptor, key, value, JsThisRef(), translationContext, false,
|
||||
val statement = generateDelegateCall(descriptor, key, value, JsThisRef(), context, false,
|
||||
descriptor.source.getPsi())
|
||||
model.postDeclarationBlock.statements += statement
|
||||
}
|
||||
@@ -246,9 +243,8 @@ class ClassModelGenerator(val context: StaticContext) {
|
||||
if (fromDescriptor.kind.isReal && fromDescriptor.modality != Modality.ABSTRACT && !toDescriptor.kind.isReal) return
|
||||
}
|
||||
|
||||
val translationContext = TranslationContext.rootContext(context)
|
||||
model.postDeclarationBlock.statements += generateDelegateCall(descriptor, fromDescriptor, toDescriptor, JsThisRef(),
|
||||
translationContext, false, descriptor.source.getPsi())
|
||||
context, false, descriptor.source.getPsi())
|
||||
}
|
||||
|
||||
private fun copyMethod(
|
||||
@@ -258,10 +254,10 @@ class ClassModelGenerator(val context: StaticContext) {
|
||||
targetDescriptor: ClassDescriptor,
|
||||
block: JsBlock
|
||||
) {
|
||||
if (targetDescriptor.module != context.currentModule) return
|
||||
if (!context.isFromCurrentModule(targetDescriptor)) return
|
||||
|
||||
val targetPrototype = prototypeOf(pureFqn(context.getInnerNameForDescriptor(targetDescriptor), null))
|
||||
val sourcePrototype = prototypeOf(pureFqn(context.getInnerNameForDescriptor(sourceDescriptor), null))
|
||||
val targetPrototype = prototypeOf(pureFqn(context.getInlineableInnerNameForDescriptor(targetDescriptor), null))
|
||||
val sourcePrototype = prototypeOf(pureFqn(context.getInlineableInnerNameForDescriptor(sourceDescriptor), null))
|
||||
val targetFunction = JsNameRef(targetName, targetPrototype)
|
||||
val sourceFunction = JsNameRef(sourceName, sourcePrototype)
|
||||
block.statements += JsAstUtils.assignment(targetFunction, sourceFunction).makeStmt()
|
||||
@@ -273,10 +269,10 @@ class ClassModelGenerator(val context: StaticContext) {
|
||||
targetDescriptor: ClassDescriptor,
|
||||
block: JsBlock
|
||||
) {
|
||||
if (targetDescriptor.module != context.currentModule) return
|
||||
if (!context.isFromCurrentModule(targetDescriptor)) return
|
||||
|
||||
val targetPrototype = prototypeOf(pureFqn(context.getInnerNameForDescriptor(targetDescriptor), null))
|
||||
val sourcePrototype = prototypeOf(pureFqn(context.getInnerNameForDescriptor(sourceDescriptor), null))
|
||||
val targetPrototype = prototypeOf(pureFqn(context.getInlineableInnerNameForDescriptor(targetDescriptor), null))
|
||||
val sourcePrototype = prototypeOf(pureFqn(context.getInlineableInnerNameForDescriptor(sourceDescriptor), null))
|
||||
val nameLiteral = JsStringLiteral(name)
|
||||
|
||||
val getPropertyDescriptor = JsInvocation(JsNameRef("getOwnPropertyDescriptor", "Object"), sourcePrototype, nameLiteral)
|
||||
|
||||
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.js.backend.ast.metadata.exportedPackage
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.exportedTag
|
||||
import org.jetbrains.kotlin.js.translate.context.Namer
|
||||
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
|
||||
import org.jetbrains.kotlin.js.translate.utils.createPrototypeStatements
|
||||
import org.jetbrains.kotlin.js.translate.utils.definePackageAlias
|
||||
|
||||
class Merger(private val rootFunction: JsFunction, val internalModuleName: JsName, val module: ModuleDescriptor) {
|
||||
@@ -193,16 +194,7 @@ class Merger(private val rootFunction: JsFunction, val internalModuleName: JsNam
|
||||
|
||||
addClassPrototypes(superName, visited, statements)
|
||||
|
||||
val superclassRef = superName.makeRef()
|
||||
val superPrototype = JsAstUtils.prototypeOf(superclassRef)
|
||||
val superPrototypeInstance = JsInvocation(JsNameRef("create", "Object"), superPrototype)
|
||||
|
||||
val classRef = name.makeRef()
|
||||
val prototype = JsAstUtils.prototypeOf(classRef)
|
||||
statements += JsAstUtils.assignment(prototype, superPrototypeInstance).makeStmt()
|
||||
|
||||
val constructorRef = JsNameRef("constructor", prototype.deepCopy())
|
||||
statements += JsAstUtils.assignment(constructorRef, classRef.deepCopy()).makeStmt()
|
||||
statements += createPrototypeStatements(superName, name)
|
||||
}
|
||||
|
||||
private fun addClassPostDeclarations(statements: MutableList<JsStatement>) {
|
||||
|
||||
@@ -228,3 +228,18 @@ fun TranslationContext.addFunctionButNotExport(name: JsName, expression: JsExpre
|
||||
}
|
||||
return name
|
||||
}
|
||||
|
||||
fun createPrototypeStatements(superName: JsName, name: JsName): List<JsStatement> {
|
||||
val superclassRef = superName.makeRef()
|
||||
val superPrototype = JsAstUtils.prototypeOf(superclassRef)
|
||||
val superPrototypeInstance = JsInvocation(JsNameRef("create", "Object"), superPrototype)
|
||||
|
||||
val classRef = name.makeRef()
|
||||
val prototype = JsAstUtils.prototypeOf(classRef)
|
||||
val prototypeStatement = JsAstUtils.assignment(prototype, superPrototypeInstance).makeStmt()
|
||||
|
||||
val constructorRef = JsNameRef("constructor", prototype.deepCopy())
|
||||
val constructorStatement = JsAstUtils.assignment(constructorRef, classRef.deepCopy()).makeStmt()
|
||||
|
||||
return listOf(prototypeStatement, constructorStatement)
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
// EXPECTED_REACHABLE_NODES: 509
|
||||
// MODULE: lib
|
||||
// FILE: lib.kt
|
||||
|
||||
abstract class A {
|
||||
fun f() = o() + k()
|
||||
|
||||
abstract fun o(): String
|
||||
|
||||
abstract fun k(): String
|
||||
}
|
||||
|
||||
inline fun foo(x: String): A {
|
||||
return object : A() {
|
||||
override fun o(): String = x
|
||||
|
||||
override fun k(): String = "K"
|
||||
}
|
||||
}
|
||||
|
||||
// MODULE: main(lib)
|
||||
// FILE: main.kt
|
||||
|
||||
fun box(): String = foo("O").f()
|
||||
Reference in New Issue
Block a user