[JS IR BE] Support typeOf
This commit is contained in:
+2
-3
@@ -32,7 +32,7 @@ import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
|
||||
class FunctionInlining(val context: CommonBackendContext, val dontInlineTypeOf: Boolean = true) : IrElementTransformerVoidWithContext() {
|
||||
class FunctionInlining(val context: CommonBackendContext) : IrElementTransformerVoidWithContext() {
|
||||
|
||||
fun inline(irModule: IrModuleFragment) = irModule.accept(this, data = null)
|
||||
|
||||
@@ -47,8 +47,7 @@ class FunctionInlining(val context: CommonBackendContext, val dontInlineTypeOf:
|
||||
return expression
|
||||
if (Symbols.isLateinitIsInitializedPropertyGetter(callee.symbol))
|
||||
return expression
|
||||
// TODO: Temporary hack till typeOf is unimplemented in K/JS
|
||||
if (dontInlineTypeOf && Symbols.isTypeOfIntrinsic(callee.symbol))
|
||||
if (Symbols.isTypeOfIntrinsic(callee.symbol))
|
||||
return expression
|
||||
|
||||
val actualCallee = getFunctionDeclaration(callee.symbol)
|
||||
|
||||
@@ -15,17 +15,20 @@ import org.jetbrains.kotlin.ir.declarations.IrProperty
|
||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrExternalPackageFragmentImpl
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.IrExternalPackageFragmentSymbolImpl
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.defaultType
|
||||
import org.jetbrains.kotlin.ir.types.isLong
|
||||
import org.jetbrains.kotlin.ir.util.companionObject
|
||||
import org.jetbrains.kotlin.ir.util.constructors
|
||||
import org.jetbrains.kotlin.ir.util.findDeclaration
|
||||
import org.jetbrains.kotlin.ir.util.kotlinPackageFqn
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi2ir.findSingleFunction
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.util.capitalizeDecapitalize.toLowerCaseAsciiOnly
|
||||
import java.util.*
|
||||
|
||||
@@ -235,6 +238,14 @@ class JsIntrinsics(private val irBuiltIns: IrBuiltIns, val context: JsIrBackendC
|
||||
)
|
||||
)
|
||||
|
||||
val createKType = getInternalWithoutPackageOrNull("createKType")
|
||||
val createDynamicKType = getInternalWithoutPackageOrNull("createDynamicKType")
|
||||
val createKTypeParameter = getInternalWithoutPackageOrNull("createKTypeParameter")
|
||||
val getStarKTypeProjection = getInternalWithoutPackageOrNull("getStarKTypeProjection")
|
||||
val createCovariantKTypeProjection = getInternalWithoutPackageOrNull("createCovariantKTypeProjection")
|
||||
val createInvariantKTypeProjection = getInternalWithoutPackageOrNull("createInvariantKTypeProjection")
|
||||
val createContravariantKTypeProjection = getInternalWithoutPackageOrNull("createContravariantKTypeProjection")
|
||||
|
||||
val primitiveToSizeConstructor =
|
||||
PrimitiveType.values().associate { type ->
|
||||
type to (primitiveToTypedArrayMap[type]?.let {
|
||||
@@ -292,6 +303,11 @@ class JsIntrinsics(private val irBuiltIns: IrBuiltIns, val context: JsIrBackendC
|
||||
private fun getInternalWithoutPackage(name: String) =
|
||||
context.symbolTable.referenceSimpleFunction(context.getFunctions(FqName(name)).single())
|
||||
|
||||
private fun getInternalWithoutPackageOrNull(name: String): IrSimpleFunctionSymbol? {
|
||||
val descriptor = context.getFunctions(FqName(name)).singleOrNull() ?: return null
|
||||
return context.symbolTable.referenceSimpleFunction(descriptor)
|
||||
}
|
||||
|
||||
private fun getFunctionInKotlinPackage(name: String) =
|
||||
context.symbolTable.referenceSimpleFunction(context.getFunctions(kotlinPackageFqn.child(Name.identifier(name))).single())
|
||||
|
||||
|
||||
@@ -98,7 +98,7 @@ private val arrayConstructorPhase = makeJsModulePhase(
|
||||
|
||||
private val functionInliningPhase = makeCustomJsModulePhase(
|
||||
{ context, module ->
|
||||
FunctionInlining(context, false).inline(module)
|
||||
FunctionInlining(context).inline(module)
|
||||
module.patchDeclarationParents()
|
||||
},
|
||||
name = "FunctionInliningPhase",
|
||||
|
||||
+113
-6
@@ -6,20 +6,27 @@
|
||||
package org.jetbrains.kotlin.ir.backend.js.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
|
||||
import org.jetbrains.kotlin.backend.common.ir.Symbols
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.toJsArrayLiteral
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||
import org.jetbrains.kotlin.ir.declarations.IrTypeParameter
|
||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||
import org.jetbrains.kotlin.ir.expressions.IrClassReference
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrGetClass
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.util.isFunction
|
||||
import org.jetbrains.kotlin.ir.util.isThrowable
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.types.*
|
||||
|
||||
class ClassReferenceLowering(val context: JsIrBackendContext) : FileLoweringPass {
|
||||
private val intrinsics = context.intrinsics
|
||||
@@ -108,23 +115,116 @@ class ClassReferenceLowering(val context: JsIrBackendContext) : FileLoweringPass
|
||||
return null
|
||||
}
|
||||
|
||||
private fun callGetKClass(returnType: IrType, typeArgument: IrType): IrCall {
|
||||
private fun callGetKClass(
|
||||
returnType: IrType = intrinsics.jsGetKClass.owner.returnType,
|
||||
typeArgument: IrType
|
||||
): IrCall {
|
||||
val primitiveKClass =
|
||||
getFinalPrimitiveKClass(returnType, typeArgument) ?: getOpenPrimitiveKClass(returnType, typeArgument)
|
||||
|
||||
if (primitiveKClass != null)
|
||||
return primitiveKClass
|
||||
|
||||
return JsIrBuilder.buildCall(intrinsics.jsGetKClass, returnType, listOf(typeArgument)).apply {
|
||||
putValueArgument(0, callJsClass(typeArgument))
|
||||
}
|
||||
return JsIrBuilder.buildCall(intrinsics.jsGetKClass, returnType, listOf(typeArgument))
|
||||
.apply {
|
||||
putValueArgument(0, callJsClass(typeArgument))
|
||||
}
|
||||
}
|
||||
|
||||
private fun callJsClass(type: IrType) =
|
||||
JsIrBuilder.buildCall(intrinsics.jsClass, typeArguments = listOf(type))
|
||||
|
||||
private fun buildCall(name: IrSimpleFunctionSymbol, vararg args: IrExpression): IrExpression =
|
||||
JsIrBuilder.buildCall(name).apply {
|
||||
args.forEachIndexed { index, irExpression ->
|
||||
putValueArgument(index, irExpression)
|
||||
}
|
||||
}
|
||||
|
||||
fun createKType(type: IrType): IrExpression {
|
||||
if (type is IrSimpleType)
|
||||
return createSimpleKType(type)
|
||||
if (type is IrDynamicType)
|
||||
return createDynamicType()
|
||||
error("Unexpected type $type")
|
||||
}
|
||||
|
||||
private fun createDynamicType(): IrExpression {
|
||||
return buildCall(context.intrinsics.createDynamicKType!!)
|
||||
}
|
||||
|
||||
private fun createSimpleKType(type: IrSimpleType): IrExpression {
|
||||
val classifier: IrClassifierSymbol = type.classifier
|
||||
|
||||
if (classifier is IrTypeParameterSymbol && classifier.owner.isReified) {
|
||||
error("Fail")
|
||||
}
|
||||
|
||||
val kClassifier = createKClassifier(classifier)
|
||||
// TODO: Use static array types
|
||||
val arguments = type.arguments.map { createKTypeProjection(it) }.toJsArrayLiteral(
|
||||
context,
|
||||
context.dynamicType,
|
||||
context.dynamicType
|
||||
)
|
||||
val isMarkedNullable = JsIrBuilder.buildBoolean(context.irBuiltIns.booleanType, type.isMarkedNullable())
|
||||
return buildCall(
|
||||
context.intrinsics.createKType!!,
|
||||
kClassifier,
|
||||
arguments,
|
||||
isMarkedNullable
|
||||
)
|
||||
}
|
||||
|
||||
private fun createKTypeProjection(tp: IrTypeArgument): IrExpression {
|
||||
if (tp !is IrTypeProjection) {
|
||||
return buildCall(context.intrinsics.getStarKTypeProjection!!)
|
||||
}
|
||||
|
||||
val factoryName = when (tp.variance) {
|
||||
Variance.INVARIANT -> context.intrinsics.createInvariantKTypeProjection!!
|
||||
Variance.IN_VARIANCE -> context.intrinsics.createContravariantKTypeProjection!!
|
||||
Variance.OUT_VARIANCE -> context.intrinsics.createCovariantKTypeProjection!!
|
||||
}
|
||||
|
||||
val kType = createKType(tp.type)
|
||||
return buildCall(factoryName, kType)
|
||||
|
||||
}
|
||||
|
||||
private fun createKClassifier(classifier: IrClassifierSymbol): IrExpression =
|
||||
when (classifier) {
|
||||
is IrTypeParameterSymbol -> createKTypeParameter(classifier.owner)
|
||||
else -> callGetKClass(typeArgument = classifier.defaultType)
|
||||
}
|
||||
|
||||
private fun createKTypeParameter(typeParameter: IrTypeParameter): IrExpression {
|
||||
val name = JsIrBuilder.buildString(context.irBuiltIns.stringType, typeParameter.name.asString())
|
||||
val upperBounds = typeParameter.superTypes.map { createKType(it) }.toJsArrayLiteral(
|
||||
context,
|
||||
context.dynamicType,
|
||||
context.dynamicType
|
||||
)
|
||||
|
||||
val variance = when (typeParameter.variance) {
|
||||
Variance.INVARIANT -> JsIrBuilder.buildString(context.irBuiltIns.stringType, "invariant")
|
||||
Variance.IN_VARIANCE -> JsIrBuilder.buildString(context.irBuiltIns.stringType, "in")
|
||||
Variance.OUT_VARIANCE -> JsIrBuilder.buildString(context.irBuiltIns.stringType, "out")
|
||||
}
|
||||
if (typeParameter.isReified) {
|
||||
error("Reified parameter")
|
||||
}
|
||||
|
||||
return buildCall(
|
||||
context.intrinsics.createKTypeParameter!!,
|
||||
name,
|
||||
upperBounds,
|
||||
variance
|
||||
)
|
||||
}
|
||||
|
||||
override fun lower(irFile: IrFile) {
|
||||
irFile.transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||
irFile.transformChildrenVoid(object : IrElementTransformerVoidWithContext() {
|
||||
override fun visitGetClass(expression: IrGetClass) =
|
||||
callGetKClassFromExpression(
|
||||
returnType = expression.type,
|
||||
@@ -137,6 +237,13 @@ class ClassReferenceLowering(val context: JsIrBackendContext) : FileLoweringPass
|
||||
returnType = expression.type,
|
||||
typeArgument = expression.classType.makeNotNull()
|
||||
)
|
||||
|
||||
override fun visitCall(expression: IrCall): IrExpression =
|
||||
if (Symbols.isTypeOfIntrinsic(expression.symbol)) {
|
||||
createKType(expression.getTypeArgument(0)!!)
|
||||
} else {
|
||||
super.visitCall(expression)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
+3
-9
@@ -17,6 +17,7 @@ import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.toJsArrayLiteral
|
||||
import org.jetbrains.kotlin.ir.builders.*
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.buildField
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
@@ -382,23 +383,16 @@ class EnumClassTransformer(val context: JsIrBackendContext, private val irClass:
|
||||
}
|
||||
}
|
||||
|
||||
private fun List<IrExpression>.toArrayLiteral(arrayType: IrType, elementType: IrType): IrExpression {
|
||||
val irVararg = IrVarargImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, arrayType, elementType, this)
|
||||
|
||||
return IrCallImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, arrayType, context.intrinsics.arrayLiteral).apply {
|
||||
putValueArgument(0, irVararg)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createEnumValuesBody(): IrBody {
|
||||
val valuesFun = findFunctionDescriptorForMemberWithSyntheticBodyKind(IrSyntheticBodyKind.ENUM_VALUES)
|
||||
val entryInstanceToFunction = context.enumEntryToGetInstanceFunction
|
||||
|
||||
val backendContext = context
|
||||
return context.createIrBuilder(valuesFun.symbol).run {
|
||||
irBlockBody {
|
||||
+irReturn(
|
||||
enumEntries.map { irCall(entryInstanceToFunction[it.symbol]!!) }
|
||||
.toArrayLiteral(valuesFun.returnType, irClass.defaultType)
|
||||
.toJsArrayLiteral(backendContext, valuesFun.returnType, irClass.defaultType)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,13 @@
|
||||
package org.jetbrains.kotlin.ir.backend.js.utils
|
||||
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrVarargImpl
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.isNullableAny
|
||||
import org.jetbrains.kotlin.ir.util.isTopLevelDeclaration
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
@@ -24,4 +30,12 @@ fun IrDeclaration.hasStaticDispatch() = when (this) {
|
||||
is IrProperty -> isTopLevelDeclaration
|
||||
is IrField -> isStatic
|
||||
else -> true
|
||||
}
|
||||
|
||||
fun List<IrExpression>.toJsArrayLiteral(context: JsIrBackendContext, arrayType: IrType, elementType: IrType): IrExpression {
|
||||
val irVararg = IrVarargImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, arrayType, elementType, this)
|
||||
|
||||
return IrCallImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, arrayType, context.intrinsics.arrayLiteral).apply {
|
||||
putValueArgument(0, irVararg)
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
// !USE_EXPERIMENTAL: kotlin.ExperimentalStdlibApi
|
||||
// TARGET_BACKEND: JS
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// WITH_REFLECT
|
||||
// KJS_WITH_FULL_RUNTIME
|
||||
|
||||
package test
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// !USE_EXPERIMENTAL: kotlin.ExperimentalStdlibApi
|
||||
// TARGET_BACKEND: JS
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// WITH_REFLECT
|
||||
// KJS_WITH_FULL_RUNTIME
|
||||
|
||||
package test
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// !USE_EXPERIMENTAL: kotlin.ExperimentalStdlibApi
|
||||
// TARGET_BACKEND: JS
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// WITH_REFLECT
|
||||
// KJS_WITH_FULL_RUNTIME
|
||||
|
||||
import kotlin.test.*
|
||||
import kotlin.reflect.*
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// !USE_EXPERIMENTAL: kotlin.ExperimentalStdlibApi
|
||||
// TARGET_BACKEND: JS
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// WITH_REFLECT
|
||||
// KJS_WITH_FULL_RUNTIME
|
||||
|
||||
package test
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// !USE_EXPERIMENTAL: kotlin.ExperimentalStdlibApi
|
||||
// TARGET_BACKEND: JS
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// WITH_REFLECT
|
||||
// KJS_WITH_FULL_RUNTIME
|
||||
|
||||
package test
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// !USE_EXPERIMENTAL: kotlin.ExperimentalStdlibApi
|
||||
// TARGET_BACKEND: JS
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// WITH_REFLECT
|
||||
// KJS_WITH_FULL_RUNTIME
|
||||
|
||||
// MODULE: lib1
|
||||
// FILE: lib1.kt
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// !USE_EXPERIMENTAL: kotlin.ExperimentalStdlibApi
|
||||
// TARGET_BACKEND: JS
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// WITH_REFLECT
|
||||
// KJS_WITH_FULL_RUNTIME
|
||||
|
||||
import kotlin.reflect.typeOf
|
||||
|
||||
|
||||
Reference in New Issue
Block a user