[JS IR BE] Make kotlinx.io compile

- Fix expect/actual default arguments
 - Fix dynamic type in inliner
 - Fix external varargs
This commit is contained in:
Roman Artemev
2019-05-27 14:06:33 +03:00
committed by romanart
parent 753a9a1c36
commit 5686de7e09
16 changed files with 111 additions and 21 deletions
@@ -0,0 +1,25 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.backend.common.lower
import org.jetbrains.kotlin.backend.common.BackendContext
import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.util.ExpectDeclarationRemover
import org.jetbrains.kotlin.ir.util.patchDeclarationParents
import org.jetbrains.kotlin.ir.visitors.acceptVoid
/**
* This pass removes all declarations with `isExpect == true`.
*/
class ExpectDeclarationsRemoveLowering(val context: BackendContext) : FileLoweringPass {
val visitor = ExpectDeclarationRemover(context.ir.symbols.externalSymbolTable, true)
override fun lower(irFile: IrFile) {
irFile.acceptVoid(visitor)
}
}
@@ -87,7 +87,7 @@ private val moveBodilessDeclarationsToSeparatePlacePhase = makeCustomJsModulePha
) )
private val expectDeclarationsRemovingPhase = makeJsModulePhase( private val expectDeclarationsRemovingPhase = makeJsModulePhase(
::ExpectDeclarationsRemoving, ::ExpectDeclarationsRemoveLowering,
name = "ExpectDeclarationsRemoving", name = "ExpectDeclarationsRemoving",
description = "Remove expect declaration from module fragment" description = "Remove expect declaration from module fragment"
) )
@@ -157,8 +157,10 @@ internal class DeepCopyIrTreeWithSymbolsForInliner(
if (type !is IrSimpleType) return type if (type !is IrSimpleType) return type
val substitutedType = typeArguments?.get(type.classifier) val substitutedType = typeArguments?.get(type.classifier)
if (substitutedType != null) {
substitutedType as IrSimpleType if (substitutedType is IrDynamicType) return substitutedType
if (substitutedType is IrSimpleType) {
return substitutedType.buildSimpleType { return substitutedType.buildSimpleType {
kotlinType = null kotlinType = null
hasQuestionMark = type.hasQuestionMark or substitutedType.isMarkedNullable() hasQuestionMark = type.hasQuestionMark or substitutedType.isMarkedNullable()
@@ -282,6 +282,8 @@ class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer<JsEx
JsInvocation( JsInvocation(
// Create scope for temporary variable holding dispatch receiver // Create scope for temporary variable holding dispatch receiver
// It is used both during method reference and passing `this` value to `apply` function. // It is used both during method reference and passing `this` value to `apply` function.
JsNameRef(
"call",
JsFunction( JsFunction(
context.currentScope, context.currentScope,
JsBlock( JsBlock(
@@ -297,7 +299,8 @@ class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer<JsEx
) )
), ),
"VarargIIFE" "VarargIIFE"
) )),
JsThisRef()
) )
} else { } else {
JsInvocation( JsInvocation(
@@ -78,7 +78,7 @@ fun translateCallArguments(expression: IrMemberAccessExpression, context: JsGene
val argument = expression.getValueArgument(index) val argument = expression.getValueArgument(index)
val result = argument?.accept(transformer, context) val result = argument?.accept(transformer, context)
if (result == null) { if (result == null) {
assert(expression is IrFunctionAccessExpression && expression.symbol.owner.isEffectivelyExternal()) require(expression is IrFunctionAccessExpression && expression.symbol.owner.isEffectivelyExternal())
JsPrefixOperation(JsUnaryOperator.VOID, JsIntLiteral(1)) JsPrefixOperation(JsUnaryOperator.VOID, JsIntLiteral(1))
} else } else
result result
@@ -48,7 +48,7 @@ private val arrayConstructorPhase = makeIrFilePhase(
) )
private val expectDeclarationsRemovingPhase = makeIrFilePhase( private val expectDeclarationsRemovingPhase = makeIrFilePhase(
::ExpectDeclarationsRemoving, ::ExpectDeclarationsRemoveLowering,
name = "ExpectDeclarationsRemoving", name = "ExpectDeclarationsRemoving",
description = "Remove expect declaration from module fragment" description = "Remove expect declaration from module fragment"
) )
@@ -1,12 +1,10 @@
/* /*
* Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors. * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
package org.jetbrains.kotlin.backend.common.lower package org.jetbrains.kotlin.ir.util
import org.jetbrains.kotlin.backend.common.BackendContext
import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.descriptors.MemberDescriptor import org.jetbrains.kotlin.descriptors.MemberDescriptor
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
@@ -15,8 +13,6 @@ import org.jetbrains.kotlin.ir.expressions.IrGetValue
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
import org.jetbrains.kotlin.ir.symbols.IrValueParameterSymbol import org.jetbrains.kotlin.ir.symbols.IrValueParameterSymbol
import org.jetbrains.kotlin.ir.symbols.IrValueSymbol import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
import org.jetbrains.kotlin.ir.util.patchDeclarationParents
import org.jetbrains.kotlin.ir.util.referenceFunction
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
@@ -25,18 +21,19 @@ import org.jetbrains.kotlin.resolve.checkers.ExpectedActualDeclarationChecker
import org.jetbrains.kotlin.resolve.descriptorUtil.module import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.resolve.multiplatform.ExpectedActualResolver import org.jetbrains.kotlin.resolve.multiplatform.ExpectedActualResolver
/** // `doRemove` means should expect-declaration be removed from IR
* This pass removes all declarations with `isExpect == true`. class ExpectDeclarationRemover(val symbolTable: ReferenceSymbolTable, private val doRemove: Boolean) : IrElementVisitorVoid {
*/ override fun visitElement(element: IrElement) {
class ExpectDeclarationsRemoving(val context: BackendContext) : FileLoweringPass { element.acceptChildrenVoid(this)
}
override fun lower(irFile: IrFile) { override fun visitFile(declaration: IrFile) {
// All declarations with `isExpect == true` are nested into a top-level declaration with `isExpect == true`. // All declarations with `isExpect == true` are nested into a top-level declaration with `isExpect == true`.
irFile.declarations.removeAll { declaration.declarations.removeAll {
val descriptor = it.descriptor val descriptor = it.descriptor
if (descriptor is MemberDescriptor && descriptor.isExpect) { if (descriptor is MemberDescriptor && descriptor.isExpect) {
copyDefaultArgumentsFromExpectToActual(it) copyDefaultArgumentsFromExpectToActual(it)
true doRemove
} else { } else {
false false
} }
@@ -83,10 +80,10 @@ class ExpectDeclarationsRemoving(val context: BackendContext) : FileLoweringPass
} }
private fun IrFunction.findActualForExpected(): IrFunction = private fun IrFunction.findActualForExpected(): IrFunction =
context.ir.symbols.externalSymbolTable.referenceFunction(descriptor.findActualForExpect()).owner symbolTable.referenceFunction(descriptor.findActualForExpect()).owner
private fun IrClass.findActualForExpected(): IrClass = private fun IrClass.findActualForExpected(): IrClass =
context.ir.symbols.externalSymbolTable.referenceClass(descriptor.findActualForExpect()).owner symbolTable.referenceClass(descriptor.findActualForExpect()).owner
private inline fun <reified T : MemberDescriptor> T.findActualForExpect() = with(ExpectedActualResolver) { private inline fun <reified T : MemberDescriptor> T.findActualForExpect() = with(ExpectedActualResolver) {
val descriptor = this@findActualForExpect val descriptor = this@findActualForExpect
@@ -29,7 +29,9 @@ import org.jetbrains.kotlin.ir.backend.js.lower.serialization.metadata.createJsK
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.metadata.* import org.jetbrains.kotlin.ir.backend.js.lower.serialization.metadata.*
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
import org.jetbrains.kotlin.ir.util.ExpectDeclarationRemover
import org.jetbrains.kotlin.ir.util.SymbolTable import org.jetbrains.kotlin.ir.util.SymbolTable
import org.jetbrains.kotlin.ir.visitors.acceptVoid
import org.jetbrains.kotlin.js.analyze.TopDownAnalyzerFacadeForJS import org.jetbrains.kotlin.js.analyze.TopDownAnalyzerFacadeForJS
import org.jetbrains.kotlin.js.analyzer.JsAnalysisResult import org.jetbrains.kotlin.js.analyzer.JsAnalysisResult
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
@@ -83,6 +85,9 @@ fun generateKLib(
val moduleFragment = psi2IrContext.generateModuleFragment(files) val moduleFragment = psi2IrContext.generateModuleFragment(files)
val moduleName = configuration[CommonConfigurationKeys.MODULE_NAME]!! val moduleName = configuration[CommonConfigurationKeys.MODULE_NAME]!!
moduleFragment.acceptVoid(ExpectDeclarationRemover(psi2IrContext.symbolTable, false))
serializeModuleIntoKlib( serializeModuleIntoKlib(
moduleName, moduleName,
configuration.metadataVersion, configuration.metadataVersion,
@@ -0,0 +1,17 @@
// !LANGUAGE: +MultiPlatformProjects
// WITH_RUNTIME
// MODULE: lib
// FILE: common.kt
expect fun foo(a: String, b: String = "O"): String
// FILE: platform.kt
actual fun foo(a: String, b: String) = a + b
// MODULE: main(lib)
// FILE: main.kt
fun box(): String {
return foo("") + foo("K", "")
}
@@ -16150,6 +16150,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/multiplatform/defaultArguments/inheritedFromExpectedClass.kt"); runTest("compiler/testData/codegen/box/multiplatform/defaultArguments/inheritedFromExpectedClass.kt");
} }
@TestMetadata("inheritedFromExpectedFunction.kt")
public void testInheritedFromExpectedFunction() throws Exception {
runTest("compiler/testData/codegen/box/multiplatform/defaultArguments/inheritedFromExpectedFunction.kt");
}
@TestMetadata("inheritedFromExpectedInterface.kt") @TestMetadata("inheritedFromExpectedInterface.kt")
public void testInheritedFromExpectedInterface() throws Exception { public void testInheritedFromExpectedInterface() throws Exception {
runTest("compiler/testData/codegen/box/multiplatform/defaultArguments/inheritedFromExpectedInterface.kt"); runTest("compiler/testData/codegen/box/multiplatform/defaultArguments/inheritedFromExpectedInterface.kt");
@@ -16155,6 +16155,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/multiplatform/defaultArguments/inheritedFromExpectedClass.kt"); runTest("compiler/testData/codegen/box/multiplatform/defaultArguments/inheritedFromExpectedClass.kt");
} }
@TestMetadata("inheritedFromExpectedFunction.kt")
public void testInheritedFromExpectedFunction() throws Exception {
runTest("compiler/testData/codegen/box/multiplatform/defaultArguments/inheritedFromExpectedFunction.kt");
}
@TestMetadata("inheritedFromExpectedInterface.kt") @TestMetadata("inheritedFromExpectedInterface.kt")
public void testInheritedFromExpectedInterface() throws Exception { public void testInheritedFromExpectedInterface() throws Exception {
runTest("compiler/testData/codegen/box/multiplatform/defaultArguments/inheritedFromExpectedInterface.kt"); runTest("compiler/testData/codegen/box/multiplatform/defaultArguments/inheritedFromExpectedInterface.kt");
@@ -16155,6 +16155,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/multiplatform/defaultArguments/inheritedFromExpectedClass.kt"); runTest("compiler/testData/codegen/box/multiplatform/defaultArguments/inheritedFromExpectedClass.kt");
} }
@TestMetadata("inheritedFromExpectedFunction.kt")
public void testInheritedFromExpectedFunction() throws Exception {
runTest("compiler/testData/codegen/box/multiplatform/defaultArguments/inheritedFromExpectedFunction.kt");
}
@TestMetadata("inheritedFromExpectedInterface.kt") @TestMetadata("inheritedFromExpectedInterface.kt")
public void testInheritedFromExpectedInterface() throws Exception { public void testInheritedFromExpectedInterface() throws Exception {
runTest("compiler/testData/codegen/box/multiplatform/defaultArguments/inheritedFromExpectedInterface.kt"); runTest("compiler/testData/codegen/box/multiplatform/defaultArguments/inheritedFromExpectedInterface.kt");
@@ -12365,6 +12365,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/multiplatform/defaultArguments/inheritedFromExpectedClass.kt"); runTest("compiler/testData/codegen/box/multiplatform/defaultArguments/inheritedFromExpectedClass.kt");
} }
@TestMetadata("inheritedFromExpectedFunction.kt")
public void testInheritedFromExpectedFunction() throws Exception {
runTest("compiler/testData/codegen/box/multiplatform/defaultArguments/inheritedFromExpectedFunction.kt");
}
@TestMetadata("inheritedFromExpectedInterface.kt") @TestMetadata("inheritedFromExpectedInterface.kt")
public void testInheritedFromExpectedInterface() throws Exception { public void testInheritedFromExpectedInterface() throws Exception {
runTest("compiler/testData/codegen/box/multiplatform/defaultArguments/inheritedFromExpectedInterface.kt"); runTest("compiler/testData/codegen/box/multiplatform/defaultArguments/inheritedFromExpectedInterface.kt");
@@ -13520,6 +13520,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/multiplatform/defaultArguments/inheritedFromExpectedClass.kt"); runTest("compiler/testData/codegen/box/multiplatform/defaultArguments/inheritedFromExpectedClass.kt");
} }
@TestMetadata("inheritedFromExpectedFunction.kt")
public void testInheritedFromExpectedFunction() throws Exception {
runTest("compiler/testData/codegen/box/multiplatform/defaultArguments/inheritedFromExpectedFunction.kt");
}
@TestMetadata("inheritedFromExpectedInterface.kt") @TestMetadata("inheritedFromExpectedInterface.kt")
public void testInheritedFromExpectedInterface() throws Exception { public void testInheritedFromExpectedInterface() throws Exception {
runTest("compiler/testData/codegen/box/multiplatform/defaultArguments/inheritedFromExpectedInterface.kt"); runTest("compiler/testData/codegen/box/multiplatform/defaultArguments/inheritedFromExpectedInterface.kt");
@@ -6,5 +6,9 @@ define("lib", [], function() {
return this.x + y; return this.x + y;
}; };
A.prototype.bar = function() {
return "(" + Array.prototype.join.call(arguments, "") + ")";
};
return A; return A;
}); });
+12
View File
@@ -7,12 +7,24 @@ external class A(x: Int = definedExternally) {
val x: Int val x: Int
fun foo(y: Int): Int = definedExternally fun foo(y: Int): Int = definedExternally
fun bar(vararg arg: String): String = definedExternally
} }
class C {
val e = arrayOf("e")
val f = arrayOf("f")
val a = A(1)
fun qux() = a.bar(*e, *f)
}
fun box(): String { fun box(): String {
val a = A(23) val a = A(23)
assertEquals(23, a.x) assertEquals(23, a.x)
assertEquals(65, a.foo(42)) assertEquals(65, a.foo(42))
assertEquals(C().qux(), "(ef)")
return "OK" return "OK"
} }