[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:
+25
@@ -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"
|
||||||
)
|
)
|
||||||
|
|||||||
+4
-2
@@ -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()
|
||||||
|
|||||||
+4
-1
@@ -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(
|
||||||
|
|||||||
+1
-1
@@ -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"
|
||||||
)
|
)
|
||||||
|
|||||||
+12
-15
@@ -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,
|
||||||
|
|||||||
Vendored
+17
@@ -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", "")
|
||||||
|
}
|
||||||
+5
@@ -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");
|
||||||
|
|||||||
+5
@@ -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");
|
||||||
|
|||||||
+5
@@ -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");
|
||||||
|
|||||||
Generated
+5
@@ -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");
|
||||||
|
|||||||
+5
@@ -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;
|
||||||
});
|
});
|
||||||
@@ -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"
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user