Fix translation of classes to work with new JS inliner

This commit is contained in:
Alexey Andreev
2017-07-14 12:45:40 +03:00
parent 8e6b1da592
commit eb6186b74d
7 changed files with 108 additions and 57 deletions
@@ -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
@@ -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) {
@@ -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)
}
@@ -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()