diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/inline/FunctionInlining.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/inline/FunctionInlining.kt index a154238b6aa..27965a00d44 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/inline/FunctionInlining.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/inline/FunctionInlining.kt @@ -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) diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIntrinsics.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIntrinsics.kt index 70f322bb0d2..fd10dba700a 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIntrinsics.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIntrinsics.kt @@ -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()) diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsLoweringPhases.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsLoweringPhases.kt index 648aa6f84a1..d7ac0c75ef1 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsLoweringPhases.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsLoweringPhases.kt @@ -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", diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/ClassReferenceLowering.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/ClassReferenceLowering.kt index 9f547ca5c50..869ad8eeb57 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/ClassReferenceLowering.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/ClassReferenceLowering.kt @@ -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) + } }) } } diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/EnumClassLowering.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/EnumClassLowering.kt index 645429f713f..adbe77d9e9d 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/EnumClassLowering.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/EnumClassLowering.kt @@ -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.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) ) } } diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/misc.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/misc.kt index ef7e639ac06..290e2148117 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/misc.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/misc.kt @@ -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.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) + } } \ No newline at end of file diff --git a/compiler/testData/codegen/box/reflection/typeOf/js/classes.kt b/compiler/testData/codegen/box/reflection/typeOf/js/classes.kt index 8b16dbf89f3..77f9b80a5de 100644 --- a/compiler/testData/codegen/box/reflection/typeOf/js/classes.kt +++ b/compiler/testData/codegen/box/reflection/typeOf/js/classes.kt @@ -1,7 +1,7 @@ // !USE_EXPERIMENTAL: kotlin.ExperimentalStdlibApi // TARGET_BACKEND: JS -// IGNORE_BACKEND: JS_IR // WITH_REFLECT +// KJS_WITH_FULL_RUNTIME package test diff --git a/compiler/testData/codegen/box/reflection/typeOf/js/inlineClasses.kt b/compiler/testData/codegen/box/reflection/typeOf/js/inlineClasses.kt index 77506627e2a..5a87c4fb36a 100644 --- a/compiler/testData/codegen/box/reflection/typeOf/js/inlineClasses.kt +++ b/compiler/testData/codegen/box/reflection/typeOf/js/inlineClasses.kt @@ -1,7 +1,7 @@ // !USE_EXPERIMENTAL: kotlin.ExperimentalStdlibApi // TARGET_BACKEND: JS -// IGNORE_BACKEND: JS_IR // WITH_REFLECT +// KJS_WITH_FULL_RUNTIME package test diff --git a/compiler/testData/codegen/box/reflection/typeOf/js/kType.kt b/compiler/testData/codegen/box/reflection/typeOf/js/kType.kt index e03a1f492da..1e27fa20e0f 100644 --- a/compiler/testData/codegen/box/reflection/typeOf/js/kType.kt +++ b/compiler/testData/codegen/box/reflection/typeOf/js/kType.kt @@ -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.* diff --git a/compiler/testData/codegen/box/reflection/typeOf/js/manyTypeArguments.kt b/compiler/testData/codegen/box/reflection/typeOf/js/manyTypeArguments.kt index a0990b30cab..58d59848d34 100644 --- a/compiler/testData/codegen/box/reflection/typeOf/js/manyTypeArguments.kt +++ b/compiler/testData/codegen/box/reflection/typeOf/js/manyTypeArguments.kt @@ -1,7 +1,7 @@ // !USE_EXPERIMENTAL: kotlin.ExperimentalStdlibApi // TARGET_BACKEND: JS -// IGNORE_BACKEND: JS_IR // WITH_REFLECT +// KJS_WITH_FULL_RUNTIME package test diff --git a/compiler/testData/codegen/box/reflection/typeOf/js/multipleLayers.kt b/compiler/testData/codegen/box/reflection/typeOf/js/multipleLayers.kt index c0d1fe42f15..9342b361809 100644 --- a/compiler/testData/codegen/box/reflection/typeOf/js/multipleLayers.kt +++ b/compiler/testData/codegen/box/reflection/typeOf/js/multipleLayers.kt @@ -1,7 +1,7 @@ // !USE_EXPERIMENTAL: kotlin.ExperimentalStdlibApi // TARGET_BACKEND: JS -// IGNORE_BACKEND: JS_IR // WITH_REFLECT +// KJS_WITH_FULL_RUNTIME package test diff --git a/compiler/testData/codegen/box/reflection/typeOf/js/multipleModules.kt b/compiler/testData/codegen/box/reflection/typeOf/js/multipleModules.kt index 08801847255..0a974e2cf56 100644 --- a/compiler/testData/codegen/box/reflection/typeOf/js/multipleModules.kt +++ b/compiler/testData/codegen/box/reflection/typeOf/js/multipleModules.kt @@ -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 diff --git a/compiler/testData/codegen/box/reflection/typeOf/js/typeOfReifiedUnit.kt b/compiler/testData/codegen/box/reflection/typeOf/js/typeOfReifiedUnit.kt index 65fc5d63129..2435abf2d23 100644 --- a/compiler/testData/codegen/box/reflection/typeOf/js/typeOfReifiedUnit.kt +++ b/compiler/testData/codegen/box/reflection/typeOf/js/typeOfReifiedUnit.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