From ee7f4c7278b7f0387f8709132115901edd844710 Mon Sep 17 00:00:00 2001 From: Igor Yakovlev Date: Fri, 29 Oct 2021 15:14:26 +0200 Subject: [PATCH] [WASM] Implementation typeOf support --- .../arguments/CommonCompilerArguments.kt | 1 + .../common/arguments/K2JSCompilerArguments.kt | 12 ++++ .../jetbrains/kotlin/config/AnalysisFlags.kt | 3 + .../checkers/JvmReflectionAPICallChecker.kt | 2 - .../AbstractReflectionApiCallChecker.kt | 18 +++-- .../org/jetbrains/kotlin/ir/backend/js/Dce.kt | 2 +- .../ir/backend/js/JsCommonBackendContext.kt | 6 +- .../kotlin/ir/backend/js/JsIntrinsics.kt | 49 ++++++-------- .../ir/backend/js/JsIrBackendContext.kt | 11 ++-- .../kotlin/ir/backend/js/ReflectionSymbols.kt | 25 +++++++ .../js/lower/ClassReferenceLowering.kt | 66 +++++++++++-------- .../irToJs/JsIntrinsicTransformers.kt | 3 - .../kotlin/ir/backend/js/utils/misc.kt | 13 ---- .../kotlin/backend/wasm/WasmBackendContext.kt | 34 +--------- .../kotlin/backend/wasm/WasmSymbols.kt | 29 +++++--- .../backend/wasm/ir2wasm/BodyGenerator.kt | 7 -- .../wasm/ir2wasm/DeclarationGenerator.kt | 6 +- .../backend/wasm/lower/BuiltInsLowering.kt | 19 ++++-- compiler/testData/cli/js/jsExtraHelp.out | 1 + .../reifiedIntersectionTypeArgument.kt | 2 - ...fiedIntersectionTypeArgumentCrossModule.kt | 2 - ...umentWithIntersectionTypeAsTypeArgument.kt | 2 - .../CommonEnvironmentConfigurator.kt | 13 ++++ .../JsEnvironmentConfigurator.kt | 13 ++++ .../diagnostics/JsReflectionAPICallChecker.kt | 8 ++- .../internal/kotlin/wasm/internal/TypeInfo.kt | 8 +-- .../wasm/src/kotlin/reflect/KClassImpl.kt | 17 ++--- .../wasm/src/kotlin/reflect/KTypeImpl.kt | 14 ++++ .../src/kotlin/reflect/KTypeParameterImpl.kt | 17 +++++ .../wasm/src/kotlin/reflect/primitives.kt | 1 + .../wasm/src/kotlin/reflect/reflection.kt | 52 ++++++++------- 31 files changed, 258 insertions(+), 198 deletions(-) create mode 100644 compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ReflectionSymbols.kt create mode 100644 libraries/stdlib/wasm/src/kotlin/reflect/KTypeImpl.kt create mode 100644 libraries/stdlib/wasm/src/kotlin/reflect/KTypeParameterImpl.kt diff --git a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/CommonCompilerArguments.kt b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/CommonCompilerArguments.kt index 9f26f8e7447..0235da97880 100644 --- a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/CommonCompilerArguments.kt +++ b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/CommonCompilerArguments.kt @@ -404,6 +404,7 @@ abstract class CommonCompilerArguments : CommonToolArguments() { put(AnalysisFlags.extendedCompilerChecks, extendedCompilerChecks) put(AnalysisFlags.allowKotlinPackage, allowKotlinPackage) put(AnalysisFlags.builtInsFromSources, builtInsFromSources) + put(AnalysisFlags.allowFullyQualifiedNameInKClass, true) } } diff --git a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JSCompilerArguments.kt b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JSCompilerArguments.kt index 7040c5e2947..3ab3df2ed30 100644 --- a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JSCompilerArguments.kt +++ b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JSCompilerArguments.kt @@ -7,7 +7,10 @@ package org.jetbrains.kotlin.cli.common.arguments import org.jetbrains.kotlin.cli.common.arguments.K2JsArgumentConstants.* import org.jetbrains.kotlin.cli.common.messages.MessageCollector +import org.jetbrains.kotlin.config.AnalysisFlag +import org.jetbrains.kotlin.config.AnalysisFlags.allowFullyQualifiedNameInKClass import org.jetbrains.kotlin.config.LanguageFeature +import org.jetbrains.kotlin.config.LanguageVersion class K2JSCompilerArguments : CommonCompilerArguments() { companion object { @@ -242,6 +245,15 @@ class K2JSCompilerArguments : CommonCompilerArguments() { ) var wasmLauncher: String? by NullableStringFreezableVar("esm") + @Argument(value = "-Xwasm-kclass-fqn", description = "Enable support for FQ names in KClass") + var wasmKClassFqn: Boolean by FreezableVar(false) + + override fun configureAnalysisFlags(collector: MessageCollector, languageVersion: LanguageVersion): MutableMap, Any> { + return super.configureAnalysisFlags(collector, languageVersion).also { + it[allowFullyQualifiedNameInKClass] = wasm && wasmKClassFqn //Only enabled WASM BE supports this flag + } + } + override fun configureLanguageFeatures(collector: MessageCollector): MutableMap { return super.configureLanguageFeatures(collector).apply { if (extensionFunctionsInExternals) { diff --git a/compiler/config/src/org/jetbrains/kotlin/config/AnalysisFlags.kt b/compiler/config/src/org/jetbrains/kotlin/config/AnalysisFlags.kt index a74997d241d..3197339f508 100644 --- a/compiler/config/src/org/jetbrains/kotlin/config/AnalysisFlags.kt +++ b/compiler/config/src/org/jetbrains/kotlin/config/AnalysisFlags.kt @@ -56,4 +56,7 @@ object AnalysisFlags { @JvmStatic val builtInsFromSources by AnalysisFlag.Delegates.Boolean + + @JvmStatic + val allowFullyQualifiedNameInKClass by AnalysisFlag.Delegates.Boolean } diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/JvmReflectionAPICallChecker.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/JvmReflectionAPICallChecker.kt index 0ed6ee7b2b4..feaa862e9fe 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/JvmReflectionAPICallChecker.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/JvmReflectionAPICallChecker.kt @@ -37,8 +37,6 @@ class JvmReflectionAPICallChecker( reflectionTypes: ReflectionTypes, storageManager: StorageManager ) : AbstractReflectionApiCallChecker(reflectionTypes, storageManager) { - override fun isAllowedKClassMember(name: Name): Boolean = - super.isAllowedKClassMember(name) || name.asString() == "qualifiedName" override val isWholeReflectionApiAvailable by storageManager.createLazyValue { module.findClassAcrossModuleDependencies(JvmAbi.REFLECTION_FACTORY_IMPL) != null diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/AbstractReflectionApiCallChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/AbstractReflectionApiCallChecker.kt index bf15bf9b0a7..9c8fb9010f3 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/AbstractReflectionApiCallChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/AbstractReflectionApiCallChecker.kt @@ -19,6 +19,7 @@ package org.jetbrains.kotlin.resolve.calls.checkers import com.intellij.psi.PsiElement import org.jetbrains.kotlin.builtins.StandardNames.KOTLIN_REFLECT_FQ_NAME import org.jetbrains.kotlin.builtins.ReflectionTypes +import org.jetbrains.kotlin.config.AnalysisFlags.allowFullyQualifiedNameInKClass import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.name.FqName @@ -58,8 +59,11 @@ abstract class AbstractReflectionApiCallChecker( private val kClass by storageManager.createLazyValue { reflectionTypes.kClass } - protected open fun isAllowedKClassMember(name: Name): Boolean = - name.asString() == "simpleName" || name.asString() == "isInstance" + protected open fun isAllowedKClassMember(name: Name, context: CallCheckerContext): Boolean = when (name.asString()) { + "simpleName", "isInstance" -> true + "qualifiedName" -> context.languageVersionSettings.getFlag(allowFullyQualifiedNameInKClass) + else -> false + } final override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) { if (isWholeReflectionApiAvailable) return @@ -71,15 +75,19 @@ abstract class AbstractReflectionApiCallChecker( val containingClass = descriptor.containingDeclaration as? ClassDescriptor ?: return if (!ReflectionTypes.isReflectionClass(containingClass)) return - if (!isAllowedReflectionApi(descriptor, containingClass)) { + if (!isAllowedReflectionApi(descriptor, containingClass, context)) { report(reportOn, context) } } - protected open fun isAllowedReflectionApi(descriptor: CallableDescriptor, containingClass: ClassDescriptor): Boolean { + protected open fun isAllowedReflectionApi( + descriptor: CallableDescriptor, + containingClass: ClassDescriptor, + context: CallCheckerContext + ): Boolean { val name = descriptor.name return name.asString() in ALLOWED_MEMBER_NAMES || - DescriptorUtils.isSubclass(containingClass, kClass) && isAllowedKClassMember(name) || + DescriptorUtils.isSubclass(containingClass, kClass) && isAllowedKClassMember(name, context) || (name.asString() == "get" || name.asString() == "set") && containingClass.isKPropertyClass() || containingClass.fqNameSafe in ALLOWED_CLASSES } diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/Dce.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/Dce.kt index a08fd46ac98..6b0f3e319ae 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/Dce.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/Dce.kt @@ -415,7 +415,7 @@ fun usefulDeclarations( } } } - context.intrinsics.jsGetKClassFromExpression -> { + context.reflectionSymbols.getKClassFromExpression -> { val ref = expression.getTypeArgument(0)?.classOrNull ?: context.irBuiltIns.anyClass referencedJsClassesFromExpressions += ref.owner } diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsCommonBackendContext.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsCommonBackendContext.kt index 45d30d6d39e..6e2c4c35014 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsCommonBackendContext.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsCommonBackendContext.kt @@ -30,16 +30,12 @@ import org.jetbrains.kotlin.resolve.scopes.MemberScope interface JsCommonBackendContext : CommonBackendContext { override val mapping: JsMapping - val intrinsics: Intrinsics - - val dynamicType: IrDynamicType + val reflectionSymbols: ReflectionSymbols val inlineClassesUtils: InlineClassesUtils val coroutineSymbols: JsCommonCoroutineSymbols - val primitiveClassesObject: IrClassSymbol - val catchAllThrowableType: IrType get() = irBuiltIns.throwableType 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 1a7c0766b4a..fd88caf3a18 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 @@ -10,6 +10,7 @@ import org.jetbrains.kotlin.ir.IrBuiltIns import org.jetbrains.kotlin.ir.declarations.IrFunction import org.jetbrains.kotlin.ir.declarations.IrProperty import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction +import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol import org.jetbrains.kotlin.ir.types.isLong import org.jetbrains.kotlin.ir.util.constructors @@ -21,21 +22,7 @@ import org.jetbrains.kotlin.psi2ir.findSingleFunction import org.jetbrains.kotlin.util.capitalizeDecapitalize.toLowerCaseAsciiOnly import java.util.* -interface Intrinsics { - val jsGetKClassFromExpression: IrSimpleFunctionSymbol - val jsGetKClass: IrSimpleFunctionSymbol - val jsClass: IrSimpleFunctionSymbol - val createKType: IrSimpleFunctionSymbol? - val createDynamicKType: IrSimpleFunctionSymbol? - val createKTypeParameter: IrSimpleFunctionSymbol? - val getStarKTypeProjection: IrSimpleFunctionSymbol? - val createCovariantKTypeProjection: IrSimpleFunctionSymbol? - val createInvariantKTypeProjection: IrSimpleFunctionSymbol? - val createContravariantKTypeProjection: IrSimpleFunctionSymbol? - val arrayLiteral: IrSimpleFunctionSymbol -} - -class JsIntrinsics(private val irBuiltIns: IrBuiltIns, val context: JsIrBackendContext) : Intrinsics { +class JsIntrinsics(private val irBuiltIns: IrBuiltIns, val context: JsIrBackendContext) { // TODO: Should we drop operator intrinsics in favor of IrDynamicOperatorExpression? @@ -184,10 +171,6 @@ class JsIntrinsics(private val irBuiltIns: IrBuiltIns, val context: JsIrBackendC val jsInvokeSuspendSuperTypeWithReceiverAndParam = getInternalWithoutPackage("kotlin.coroutines.intrinsics.invokeSuspendSuperTypeWithReceiverAndParam") - override val jsGetKClass = getInternalWithoutPackage("getKClass") - override val jsGetKClassFromExpression = getInternalWithoutPackage("getKClassFromExpression") - override val jsClass = getInternalFunction("jsClassIntrinsic") - val jsNumberRangeToNumber = getInternalFunction("numberRangeToNumber") val jsNumberRangeToLong = getInternalFunction("numberRangeToLong") @@ -249,7 +232,25 @@ class JsIntrinsics(private val irBuiltIns: IrBuiltIns, val context: JsIrBackendC val jsPrimitiveArrayIteratorFunctions = PrimitiveType.values().associate { it to getInternalFunction("${it.typeName.asString().toLowerCaseAsciiOnly()}ArrayIterator") } - override val arrayLiteral = getInternalFunction("arrayLiteral") + val jsClass = getInternalFunction("jsClassIntrinsic") + val arrayLiteral: IrSimpleFunctionSymbol = getInternalFunction("arrayLiteral") + + internal inner class JsReflectionSymbols : ReflectionSymbols { + override val createKType = getInternalWithoutPackageOrNull("createKType") + override val createDynamicKType = getInternalWithoutPackageOrNull("createDynamicKType") + override val createKTypeParameter = getInternalWithoutPackageOrNull("createKTypeParameter") + override val getStarKTypeProjection = getInternalWithoutPackageOrNull("getStarKTypeProjection") + override val createCovariantKTypeProjection = getInternalWithoutPackageOrNull("createCovariantKTypeProjection") + override val createInvariantKTypeProjection = getInternalWithoutPackageOrNull("createInvariantKTypeProjection") + override val createContravariantKTypeProjection = getInternalWithoutPackageOrNull("createContravariantKTypeProjection") + override val getKClass = getInternalWithoutPackage("getKClass") + override val getKClassFromExpression = getInternalWithoutPackage("getKClassFromExpression") + override val primitiveClassesObject = context.getIrClass(FqName("kotlin.reflect.js.internal.PrimitiveClasses")) + override val kTypeClass: IrClassSymbol = context.getIrClass(FqName("kotlin.reflect.KType")) + override val getClassData: IrSimpleFunctionSymbol get() = jsClass + } + + internal val reflectionSymbols: JsReflectionSymbols = JsReflectionSymbols() val primitiveToTypedArrayMap = EnumMap( mapOf( @@ -261,14 +262,6 @@ class JsIntrinsics(private val irBuiltIns: IrBuiltIns, val context: JsIrBackendC ) ) - override val createKType = getInternalWithoutPackageOrNull("createKType") - override val createDynamicKType = getInternalWithoutPackageOrNull("createDynamicKType") - override val createKTypeParameter = getInternalWithoutPackageOrNull("createKTypeParameter") - override val getStarKTypeProjection = getInternalWithoutPackageOrNull("getStarKTypeProjection") - override val createCovariantKTypeProjection = getInternalWithoutPackageOrNull("createCovariantKTypeProjection") - override val createInvariantKTypeProjection = getInternalWithoutPackageOrNull("createInvariantKTypeProjection") - override val createContravariantKTypeProjection = getInternalWithoutPackageOrNull("createContravariantKTypeProjection") - val primitiveToSizeConstructor = PrimitiveType.values().associate { type -> type to (primitiveToTypedArrayMap[type]?.let { diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIrBackendContext.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIrBackendContext.kt index 999ef102c82..ad897f5e9d9 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIrBackendContext.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIrBackendContext.kt @@ -157,8 +157,9 @@ class JsIrBackendContext( private val internalPackage = module.getPackage(JS_PACKAGE_FQNAME) - override val dynamicType: IrDynamicType = IrDynamicTypeImpl(null, emptyList(), Variance.INVARIANT) - override val intrinsics = JsIntrinsics(irBuiltIns, this) + val dynamicType: IrDynamicType = IrDynamicTypeImpl(null, emptyList(), Variance.INVARIANT) + val intrinsics: JsIntrinsics = JsIntrinsics(irBuiltIns, this) + override val reflectionSymbols: ReflectionSymbols get() = intrinsics.reflectionSymbols override val catchAllThrowableType: IrType get() = dynamicType @@ -284,16 +285,12 @@ class JsIrBackendContext( val errorCodeSymbol: IrSimpleFunctionSymbol? = if (errorPolicy.allowErrors) symbolTable.referenceSimpleFunction(getJsInternalFunction("errorCode")) else null - override val primitiveClassesObject = getIrClass(FqName("kotlin.reflect.js.internal.PrimitiveClasses")) - val throwableClass = getIrClass(JsIrBackendContext.KOTLIN_PACKAGE_FQN.child(Name.identifier("Throwable"))) val primitiveCompanionObjects = primitivesWithImplicitCompanionObject().associateWith { getIrClass(JS_INTERNAL_PACKAGE_FQNAME.child(Name.identifier("${it.identifier}CompanionObject"))) } - - // Top-level functions forced to be loaded @@ -355,7 +352,7 @@ class JsIrBackendContext( internal fun getProperty(fqName: FqName): PropertyDescriptor = findProperty(module.getPackage(fqName.parent()).memberScope, fqName.shortName()).single() - private fun getIrClass(fqName: FqName): IrClassSymbol = symbolTable.referenceClass(getClass(fqName)) + internal fun getIrClass(fqName: FqName): IrClassSymbol = symbolTable.referenceClass(getClass(fqName)) internal fun getJsInternalFunction(name: String): SimpleFunctionDescriptor = findFunctions(internalPackage.memberScope, Name.identifier(name)).singleOrNull() ?: error("Internal function '$name' not found") diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ReflectionSymbols.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ReflectionSymbols.kt new file mode 100644 index 00000000000..93ca7cfd442 --- /dev/null +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ReflectionSymbols.kt @@ -0,0 +1,25 @@ +/* + * Copyright 2010-2021 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.ir.backend.js + +import org.jetbrains.kotlin.ir.symbols.IrClassSymbol +import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol +import org.jetbrains.kotlin.ir.types.IrType + +interface ReflectionSymbols { + val getKClassFromExpression: IrSimpleFunctionSymbol + val getKClass: IrSimpleFunctionSymbol + val getClassData: IrSimpleFunctionSymbol + val createKType: IrSimpleFunctionSymbol? + val createDynamicKType: IrSimpleFunctionSymbol? + val createKTypeParameter: IrSimpleFunctionSymbol? + val getStarKTypeProjection: IrSimpleFunctionSymbol? + val createCovariantKTypeProjection: IrSimpleFunctionSymbol? + val createInvariantKTypeProjection: IrSimpleFunctionSymbol? + val createContravariantKTypeProjection: IrSimpleFunctionSymbol? + val primitiveClassesObject: IrClassSymbol + val kTypeClass: IrClassSymbol +} \ No newline at end of file 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 bdbae7cfa6e..309a07f37ef 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 @@ -8,9 +8,10 @@ package org.jetbrains.kotlin.ir.backend.js.lower import org.jetbrains.kotlin.backend.common.BodyLoweringPass import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext import org.jetbrains.kotlin.backend.common.ir.Symbols +import org.jetbrains.kotlin.backend.common.ir.createArrayOfExpression +import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.backend.js.* import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder -import org.jetbrains.kotlin.ir.backend.js.utils.toJsArrayLiteral import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol @@ -25,21 +26,22 @@ import org.jetbrains.kotlin.types.* class ClassReferenceLowering(val context: JsCommonBackendContext) : BodyLoweringPass { + private val reflectionSymbols get() = context.reflectionSymbols + private val primitiveClassProperties by lazy { - primitiveClassesObject.owner.declarations.filterIsInstance() + reflectionSymbols.primitiveClassesObject.owner.declarations.filterIsInstance() } private val primitiveClassFunctionClass by lazy { - primitiveClassesObject.owner.declarations + reflectionSymbols.primitiveClassesObject.owner.declarations .filterIsInstance() .find { it.name == Name.identifier("functionClass") }!! } - private val primitiveClassesObject = context.primitiveClassesObject - private fun primitiveClassProperty(name: String) = primitiveClassProperties.singleOrNull { it.name == Name.identifier(name) }?.getter - ?: primitiveClassesObject.owner.declarations.filterIsInstance().single { it.name == Name.special("") } + ?: reflectionSymbols.primitiveClassesObject.owner.declarations + .filterIsInstance().single { it.name == Name.special("") } private val finalPrimitiveClasses by lazy { mapOf( @@ -80,14 +82,17 @@ class ClassReferenceLowering(val context: JsCommonBackendContext) : BodyLowering if (primitiveKClass != null) return JsIrBuilder.buildBlock(returnType, listOf(argument, primitiveKClass)) - return JsIrBuilder.buildCall(context.intrinsics.jsGetKClassFromExpression, returnType, listOf(typeArgument)).apply { + return JsIrBuilder.buildCall(reflectionSymbols.getKClassFromExpression, returnType, listOf(typeArgument)).apply { putValueArgument(0, argument) } } private fun getPrimitiveClass(target: IrSimpleFunction, returnType: IrType) = JsIrBuilder.buildCall(target.symbol, returnType).apply { - dispatchReceiver = JsIrBuilder.buildGetObjectValue(primitiveClassesObject.defaultType, primitiveClassesObject) + dispatchReceiver = JsIrBuilder.buildGetObjectValue( + type = reflectionSymbols.primitiveClassesObject.defaultType, + classSymbol = reflectionSymbols.primitiveClassesObject + ) } private fun getFinalPrimitiveKClass(returnType: IrType, typeArgument: IrType): IrCall? { @@ -118,7 +123,7 @@ class ClassReferenceLowering(val context: JsCommonBackendContext) : BodyLowering } private fun callGetKClass( - returnType: IrType = context.intrinsics.jsGetKClass.owner.returnType, + returnType: IrType = reflectionSymbols.getKClass.owner.returnType, typeArgument: IrType ): IrCall { val primitiveKClass = @@ -127,15 +132,15 @@ class ClassReferenceLowering(val context: JsCommonBackendContext) : BodyLowering if (primitiveKClass != null) return primitiveKClass - return JsIrBuilder.buildCall(context.intrinsics.jsGetKClass, returnType, listOf(typeArgument)) + return JsIrBuilder.buildCall(reflectionSymbols.getKClass, returnType, listOf(typeArgument)) .apply { - putValueArgument(0, callJsClass(typeArgument)) + putValueArgument(0, callGetClassByType(typeArgument)) } } - private fun callJsClass(type: IrType) = + private fun callGetClassByType(type: IrType) = JsIrBuilder.buildCall( - context.intrinsics.jsClass, + reflectionSymbols.getClassData, typeArguments = listOf(type), origin = JsLoweredDeclarationOrigin.CLASS_REFERENCE ) @@ -157,7 +162,7 @@ class ClassReferenceLowering(val context: JsCommonBackendContext) : BodyLowering } private fun createDynamicType(): IrExpression { - return buildCall(context.intrinsics.createDynamicKType!!) + return buildCall(reflectionSymbols.createDynamicKType!!) } private fun createSimpleKType(type: IrSimpleType, visitedTypeParams: MutableSet): IrExpression { @@ -169,15 +174,16 @@ class ClassReferenceLowering(val context: JsCommonBackendContext) : BodyLowering // } val kClassifier = createKClassifier(classifier, visitedTypeParams) - // TODO: Use static array types - val arguments = type.arguments.map { createKTypeProjection(it, visitedTypeParams) }.toJsArrayLiteral( - context, - context.dynamicType, - context.dynamicType + val arguments = context.createArrayOfExpression( + startOffset = UNDEFINED_OFFSET, + endOffset = UNDEFINED_OFFSET, + arrayElementType = context.reflectionSymbols.kTypeClass.defaultType, + arrayElements = type.arguments.map { createKTypeProjection(it, visitedTypeParams) } ) + val isMarkedNullable = JsIrBuilder.buildBoolean(context.irBuiltIns.booleanType, type.isMarkedNullable()) return buildCall( - context.intrinsics.createKType!!, + reflectionSymbols.createKType!!, kClassifier, arguments, isMarkedNullable @@ -186,13 +192,13 @@ class ClassReferenceLowering(val context: JsCommonBackendContext) : BodyLowering private fun createKTypeProjection(tp: IrTypeArgument, visitedTypeParams: MutableSet): IrExpression { if (tp !is IrTypeProjection) { - return buildCall(context.intrinsics.getStarKTypeProjection!!) + return buildCall(reflectionSymbols.getStarKTypeProjection!!) } val factoryName = when (tp.variance) { - Variance.INVARIANT -> context.intrinsics.createInvariantKTypeProjection!! - Variance.IN_VARIANCE -> context.intrinsics.createContravariantKTypeProjection!! - Variance.OUT_VARIANCE -> context.intrinsics.createCovariantKTypeProjection!! + Variance.INVARIANT -> reflectionSymbols.createInvariantKTypeProjection!! + Variance.IN_VARIANCE -> reflectionSymbols.createContravariantKTypeProjection!! + Variance.OUT_VARIANCE -> reflectionSymbols.createCovariantKTypeProjection!! } val kType = createKType(tp.type, visitedTypeParams) @@ -213,10 +219,12 @@ class ClassReferenceLowering(val context: JsCommonBackendContext) : BodyLowering visitedTypeParams.add(typeParameter) val name = JsIrBuilder.buildString(context.irBuiltIns.stringType, typeParameter.name.asString()) - val upperBounds = typeParameter.superTypes.map { createKType(it, visitedTypeParams) }.toJsArrayLiteral( - context, - context.dynamicType, - context.dynamicType + + val upperBounds = context.createArrayOfExpression( + startOffset = UNDEFINED_OFFSET, + endOffset = UNDEFINED_OFFSET, + arrayElementType = context.reflectionSymbols.kTypeClass.defaultType, + arrayElements = typeParameter.superTypes.map { createKType(it, visitedTypeParams) } ) val variance = when (typeParameter.variance) { @@ -231,7 +239,7 @@ class ClassReferenceLowering(val context: JsCommonBackendContext) : BodyLowering // } return buildCall( - context.intrinsics.createKTypeParameter!!, + reflectionSymbols.createKTypeParameter!!, name, upperBounds, variance diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/JsIntrinsicTransformers.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/JsIntrinsicTransformers.kt index b77da023277..42167c4c6ed 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/JsIntrinsicTransformers.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/JsIntrinsicTransformers.kt @@ -7,7 +7,6 @@ package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext import org.jetbrains.kotlin.ir.backend.js.utils.* -import org.jetbrains.kotlin.ir.backend.js.utils.getClassRef import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrConstructor import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction @@ -15,11 +14,9 @@ import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol import org.jetbrains.kotlin.ir.symbols.IrSymbol import org.jetbrains.kotlin.ir.types.classifierOrFail -import org.jetbrains.kotlin.ir.types.getClass import org.jetbrains.kotlin.ir.util.getInlineClassBackingField import org.jetbrains.kotlin.ir.util.render import org.jetbrains.kotlin.js.backend.ast.* -import java.lang.IllegalArgumentException typealias IrCallTransformer = (IrCall, context: JsGenerationContext) -> JsExpression 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 799e06248d0..ef3c90d3f0a 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 @@ -71,19 +71,6 @@ fun IrDeclaration.hasStaticDispatch() = when (this) { else -> true } -fun List.toJsArrayLiteral(context: JsCommonBackendContext, 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, - valueArgumentsCount = 1, - typeArgumentsCount = 0 - ).apply { - putValueArgument(0, irVararg) - } -} - val IrValueDeclaration.isDispatchReceiver: Boolean get() { val parent = this.parent diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmBackendContext.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmBackendContext.kt index a8295b92458..390171c11e2 100644 --- a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmBackendContext.kt +++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmBackendContext.kt @@ -24,37 +24,12 @@ import org.jetbrains.kotlin.ir.declarations.impl.IrExternalPackageFragmentImpl import org.jetbrains.kotlin.ir.declarations.impl.IrFileImpl import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol import org.jetbrains.kotlin.ir.symbols.impl.DescriptorlessExternalPackageFragmentSymbol -import org.jetbrains.kotlin.ir.types.IrDynamicType import org.jetbrains.kotlin.ir.types.IrTypeSystemContext import org.jetbrains.kotlin.ir.types.IrTypeSystemContextImpl import org.jetbrains.kotlin.ir.util.SymbolTable import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name -class WasmIntrinsics(private val context: WasmBackendContext) : Intrinsics { - - override val jsGetKClass: IrSimpleFunctionSymbol get() = context.wasmSymbols.jsGetKClass - override val jsGetKClassFromExpression: IrSimpleFunctionSymbol get() = context.wasmSymbols.jsGetKClassFromExpression - override val jsClass: IrSimpleFunctionSymbol get() = context.wasmSymbols.jsClass - - override val createKType: IrSimpleFunctionSymbol? - get() = TODO("Not yet implemented") - override val createDynamicKType: IrSimpleFunctionSymbol? - get() = TODO("Not yet implemented") - override val createKTypeParameter: IrSimpleFunctionSymbol? - get() = TODO("Not yet implemented") - override val getStarKTypeProjection: IrSimpleFunctionSymbol? - get() = TODO("Not yet implemented") - override val createCovariantKTypeProjection: IrSimpleFunctionSymbol? - get() = TODO("Not yet implemented") - override val createInvariantKTypeProjection: IrSimpleFunctionSymbol? - get() = TODO("Not yet implemented") - override val createContravariantKTypeProjection: IrSimpleFunctionSymbol? - get() = TODO("Not yet implemented") - override val arrayLiteral: IrSimpleFunctionSymbol - get() = TODO("Not yet implemented") -} - class WasmBackendContext( val module: ModuleDescriptor, override val irBuiltIns: IrBuiltIns, @@ -68,11 +43,6 @@ class WasmBackendContext( override val scriptMode = false override val irFactory: IrFactory = symbolTable.irFactory - //TODO - override val dynamicType: IrDynamicType get() = TODO() - override val primitiveClassesObject get() = wasmSymbols.primitiveClassesObject - //TODO!!! - // Place to store declarations excluded from code generation private val excludedDeclarations = mutableMapOf() @@ -132,6 +102,8 @@ class WasmBackendContext( WasmSharedVariablesManager(this, irBuiltIns, internalPackageFragment) val wasmSymbols: WasmSymbols = WasmSymbols(this@WasmBackendContext, symbolTable) + override val reflectionSymbols: ReflectionSymbols get() = wasmSymbols.reflectionSymbols + override val ir = object : Ir(this, irModuleFragment) { override val symbols: Symbols = wasmSymbols override fun shouldGenerateHandlerParameterForDefaultBodyFun() = true @@ -199,6 +171,4 @@ class WasmBackendContext( } } } - - override val intrinsics: Intrinsics = WasmIntrinsics(this) } diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmSymbols.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmSymbols.kt index 6a453914dc5..986893063d4 100644 --- a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmSymbols.kt +++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmSymbols.kt @@ -12,8 +12,7 @@ import org.jetbrains.kotlin.descriptors.PackageViewDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor import org.jetbrains.kotlin.incremental.components.NoLookupLocation -import org.jetbrains.kotlin.ir.builders.declarations.addFunction -import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction +import org.jetbrains.kotlin.ir.backend.js.ReflectionSymbols import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol import org.jetbrains.kotlin.ir.symbols.IrPropertySymbol @@ -28,7 +27,6 @@ import org.jetbrains.kotlin.ir.util.render import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.scopes.MemberScope -import org.jetbrains.kotlin.util.OperatorNameConventions import java.lang.IllegalArgumentException class WasmSymbols( @@ -45,11 +43,25 @@ class WasmSymbols( private val kotlinTestPackage: PackageViewDescriptor = context.module.getPackage(FqName("kotlin.test")) - val jsGetKClass: IrSimpleFunctionSymbol = getInternalFunction("getKClass") - val jsGetKClassFromExpression: IrSimpleFunctionSymbol = getInternalFunction("getKClassFromExpression") - val jsClass: IrSimpleFunctionSymbol = getInternalFunction("wasmGetTypeInfoData") - val wasmTypeInfoData: IrClassSymbol = getInternalClass("TypeInfoData") - val primitiveClassesObject = getInternalClass("PrimitiveClasses") + internal inner class WasmReflectionSymbols : ReflectionSymbols { + override val createKType: IrSimpleFunctionSymbol = getInternalFunction("createKType") + override val getClassData: IrSimpleFunctionSymbol = getInternalFunction("wasmGetTypeInfoData") + override val getKClass: IrSimpleFunctionSymbol = getInternalFunction("getKClass") + override val getKClassFromExpression: IrSimpleFunctionSymbol = getInternalFunction("getKClassFromExpression") + override val createDynamicKType: IrSimpleFunctionSymbol get() = error("Dynamic type is not supported by WASM") + override val createKTypeParameter: IrSimpleFunctionSymbol = getInternalFunction("createKTypeParameter") + override val getStarKTypeProjection = getInternalFunction("getStarKTypeProjection") + override val createCovariantKTypeProjection = getInternalFunction("createCovariantKTypeProjection") + override val createInvariantKTypeProjection = getInternalFunction("createInvariantKTypeProjection") + override val createContravariantKTypeProjection = getInternalFunction("createContravariantKTypeProjection") + + override val primitiveClassesObject = getInternalClass("PrimitiveClasses") + override val kTypeClass: IrClassSymbol = getIrClass(FqName("kotlin.reflect.KClass")) + + val wasmTypeInfoData: IrClassSymbol = getInternalClass("TypeInfoData") + } + + internal val reflectionSymbols: WasmReflectionSymbols = WasmReflectionSymbols() override val throwNullPointerException = getInternalFunction("THROW_NPE") override val throwISE = getInternalFunction("THROW_ISE") @@ -151,7 +163,6 @@ class WasmSymbols( val wasmClassId = getInternalFunction("wasmClassId") val wasmInterfaceId = getInternalFunction("wasmInterfaceId") - val wasmTypeId = getInternalFunction("wasmTypeId") val getVirtualMethodId = getInternalFunction("getVirtualMethodId") val getInterfaceImplId = getInternalFunction("getInterfaceImplId") diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/BodyGenerator.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/BodyGenerator.kt index aa2f3d52aea..6cbef3c7236 100644 --- a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/BodyGenerator.kt +++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/BodyGenerator.kt @@ -348,13 +348,6 @@ class BodyGenerator(val context: WasmFunctionCodegenContext) : IrElementVisitorV body.buildConstI32Symbol(context.referenceInterfaceId(irInterface.symbol)) } - wasmSymbols.wasmTypeId -> { - val type = call.getTypeArgument(0)!!.getClass() - ?: error("No class given for wasmClassId intrinsic") - val id = if (type.isInterface) context.referenceInterfaceId(type.symbol) else context.referenceClassId(type.symbol) - body.buildConstI32Symbol(id) - } - wasmSymbols.wasmRefCast -> { val toType = call.getTypeArgument(0)!! generateTypeRTT(toType) diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/DeclarationGenerator.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/DeclarationGenerator.kt index d0a45858614..4ea2711189f 100644 --- a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/DeclarationGenerator.kt +++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/DeclarationGenerator.kt @@ -9,6 +9,8 @@ import org.jetbrains.kotlin.backend.common.ir.isOverridableOrOverrides import org.jetbrains.kotlin.backend.wasm.WasmBackendContext import org.jetbrains.kotlin.backend.wasm.lower.wasmSignature import org.jetbrains.kotlin.backend.wasm.utils.* +import org.jetbrains.kotlin.config.AnalysisFlags.allowFullyQualifiedNameInKClass +import org.jetbrains.kotlin.config.languageVersionSettings import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.ir.IrBuiltIns import org.jetbrains.kotlin.ir.IrElement @@ -276,7 +278,9 @@ class DeclarationGenerator(val context: WasmModuleCodegenContext) : IrElementVis private fun binaryDataStruct(classMetadata: ClassMetadata): ConstantDataStruct { val invalidIndex = -1 - val packageName = classMetadata.klass.kotlinFqName.parentOrNull()?.asString() ?: "" + val fqnShouldBeEmitted = context.backendContext.configuration.languageVersionSettings.getFlag(allowFullyQualifiedNameInKClass) + //TODO("FqName for inner classes could be invalid due to topping it out from outer class") + val packageName = if (fqnShouldBeEmitted) classMetadata.klass.kotlinFqName.parentOrNull()?.asString() ?: "" else "" val simpleName = classMetadata.klass.kotlinFqName.shortName().asString() val typeInfo = ConstantDataStruct( "TypeInfo", diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/BuiltInsLowering.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/BuiltInsLowering.kt index db59a614482..5f761f3669b 100644 --- a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/BuiltInsLowering.kt +++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/BuiltInsLowering.kt @@ -10,6 +10,8 @@ import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext import org.jetbrains.kotlin.backend.common.lower.DeclarationIrBuilder import org.jetbrains.kotlin.backend.common.lower.createIrBuilder import org.jetbrains.kotlin.backend.wasm.WasmBackendContext +import org.jetbrains.kotlin.config.AnalysisFlags +import org.jetbrains.kotlin.config.languageVersionSettings import org.jetbrains.kotlin.ir.backend.js.utils.isEqualsInheritedFromAny import org.jetbrains.kotlin.ir.builders.irCall import org.jetbrains.kotlin.ir.builders.irCallConstructor @@ -128,22 +130,27 @@ class BuiltInsLowering(val context: WasmBackendContext) : FileLoweringPass { val newSymbol = irBuiltins.suspendFunctionN(arity).getSimpleFunction("invoke")!! return irCall(call, newSymbol, argumentsAsReceivers = true) } - symbols.jsClass -> { - val infoDataCtor = symbols.wasmTypeInfoData.constructors.first() + symbols.reflectionSymbols.getClassData -> { + val infoDataCtor = symbols.reflectionSymbols.wasmTypeInfoData.constructors.first() val type = call.getTypeArgument(0)!! + val isInterface = type.isInterface() val fqName = type.classFqName!! - val packageName = fqName.parentOrNull()?.asString() ?: "" + val fqnShouldBeEmitted = + context.configuration.languageVersionSettings.getFlag(AnalysisFlags.allowFullyQualifiedNameInKClass) + val packageName = if (fqnShouldBeEmitted) fqName.parentOrNull()?.asString() ?: "" else "" val typeName = fqName.shortName().asString() return with(builder) { - val typeId = irCall(symbols.wasmTypeId).also { + val wasmIdGetter = if (type.isInterface()) symbols.wasmInterfaceId else symbols.wasmClassId + val typeId = irCall(wasmIdGetter).also { it.putTypeArgument(0, type) } irCallConstructor(infoDataCtor, emptyList()).also { it.putValueArgument(0, typeId) - it.putValueArgument(1, packageName.toIrConst(context.irBuiltIns.stringType)) - it.putValueArgument(2, typeName.toIrConst(context.irBuiltIns.stringType)) + it.putValueArgument(1, isInterface.toIrConst(context.irBuiltIns.booleanType)) + it.putValueArgument(2, packageName.toIrConst(context.irBuiltIns.stringType)) + it.putValueArgument(3, typeName.toIrConst(context.irBuiltIns.stringType)) } } } diff --git a/compiler/testData/cli/js/jsExtraHelp.out b/compiler/testData/cli/js/jsExtraHelp.out index 3a4af35e9d7..ec445738014 100644 --- a/compiler/testData/cli/js/jsExtraHelp.out +++ b/compiler/testData/cli/js/jsExtraHelp.out @@ -37,6 +37,7 @@ where advanced options include: -Xtyped-arrays Translate primitive arrays to JS typed arrays -Xwasm Use experimental WebAssembly compiler backend -Xwasm-debug-info Add debug info to WebAssembly compiled module + -Xwasm-kclass-fqn Enable support for FQ names in KClass -Xwasm-launcher=esm|nodejs Picks flavor for the wasm launcher. Default is ESM. -Xallow-kotlin-package Allow compiling code in package 'kotlin' and allow not requiring kotlin.stdlib in module-info -Xallow-result-return-type Allow compiling code when `kotlin.Result` is used as a return type diff --git a/compiler/testData/codegen/box/reified/reifiedIntersectionTypeArgument.kt b/compiler/testData/codegen/box/reified/reifiedIntersectionTypeArgument.kt index bfcdbdfa5cc..ecfcc5419e9 100644 --- a/compiler/testData/codegen/box/reified/reifiedIntersectionTypeArgument.kt +++ b/compiler/testData/codegen/box/reified/reifiedIntersectionTypeArgument.kt @@ -1,5 +1,3 @@ -// IGNORE_BACKEND: WASM -// WASM_MUTE_REASON: TYPEOF // WITH_RUNTIME // See KT-37163 diff --git a/compiler/testData/codegen/box/reified/reifiedIntersectionTypeArgumentCrossModule.kt b/compiler/testData/codegen/box/reified/reifiedIntersectionTypeArgumentCrossModule.kt index 18b2692268a..87e4d5e0543 100644 --- a/compiler/testData/codegen/box/reified/reifiedIntersectionTypeArgumentCrossModule.kt +++ b/compiler/testData/codegen/box/reified/reifiedIntersectionTypeArgumentCrossModule.kt @@ -1,5 +1,3 @@ -// IGNORE_BACKEND: WASM -// WASM_MUTE_REASON: TYPEOF // WITH_RUNTIME // See KT-37163 diff --git a/compiler/testData/codegen/box/reified/reifiedTypeArgumentWithIntersectionTypeAsTypeArgument.kt b/compiler/testData/codegen/box/reified/reifiedTypeArgumentWithIntersectionTypeAsTypeArgument.kt index 445047a035a..5a519753485 100644 --- a/compiler/testData/codegen/box/reified/reifiedTypeArgumentWithIntersectionTypeAsTypeArgument.kt +++ b/compiler/testData/codegen/box/reified/reifiedTypeArgumentWithIntersectionTypeAsTypeArgument.kt @@ -1,5 +1,3 @@ -// IGNORE_BACKEND: WASM -// WASM_MUTE_REASON: TYPEOF // WITH_RUNTIME // See KT-37163 diff --git a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/services/configuration/CommonEnvironmentConfigurator.kt b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/services/configuration/CommonEnvironmentConfigurator.kt index 6ea03c4075d..f11cfdc141e 100644 --- a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/services/configuration/CommonEnvironmentConfigurator.kt +++ b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/services/configuration/CommonEnvironmentConfigurator.kt @@ -5,10 +5,14 @@ package org.jetbrains.kotlin.test.services.configuration +import org.jetbrains.kotlin.config.AnalysisFlag +import org.jetbrains.kotlin.config.AnalysisFlags.allowFullyQualifiedNameInKClass import org.jetbrains.kotlin.config.CompilerConfiguration import org.jetbrains.kotlin.config.CompilerConfigurationKey +import org.jetbrains.kotlin.config.LanguageVersion import org.jetbrains.kotlin.test.directives.ConfigurationDirectives import org.jetbrains.kotlin.test.directives.model.DirectivesContainer +import org.jetbrains.kotlin.test.directives.model.RegisteredDirectives import org.jetbrains.kotlin.test.model.TestModule import org.jetbrains.kotlin.test.parseAnalysisFlags import org.jetbrains.kotlin.test.services.EnvironmentConfigurator @@ -18,6 +22,15 @@ class CommonEnvironmentConfigurator(testServices: TestServices) : EnvironmentCon override val directiveContainers: List get() = listOf(ConfigurationDirectives) + override fun provideAdditionalAnalysisFlags( + directives: RegisteredDirectives, + languageVersion: LanguageVersion + ): Map, Any?> { + return super.provideAdditionalAnalysisFlags(directives, languageVersion).toMutableMap().also { + it[allowFullyQualifiedNameInKClass] = true + } + } + override fun configureCompilerConfiguration(configuration: CompilerConfiguration, module: TestModule) { val rawFlags = module.directives[ConfigurationDirectives.KOTLIN_CONFIGURATION_FLAGS] parseAnalysisFlags(rawFlags).forEach { (key, value) -> diff --git a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/services/configuration/JsEnvironmentConfigurator.kt b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/services/configuration/JsEnvironmentConfigurator.kt index 320fa2338ac..bc17423529a 100644 --- a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/services/configuration/JsEnvironmentConfigurator.kt +++ b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/services/configuration/JsEnvironmentConfigurator.kt @@ -11,6 +11,9 @@ import org.jetbrains.kotlin.cli.common.messages.MessageCollector import org.jetbrains.kotlin.config.CommonConfigurationKeys import org.jetbrains.kotlin.config.CompilerConfiguration import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl +import org.jetbrains.kotlin.config.AnalysisFlag +import org.jetbrains.kotlin.config.AnalysisFlags.allowFullyQualifiedNameInKClass +import org.jetbrains.kotlin.config.LanguageVersion import org.jetbrains.kotlin.js.config.* import org.jetbrains.kotlin.js.facade.MainCallParameters import org.jetbrains.kotlin.library.KotlinLibrary @@ -30,6 +33,7 @@ import org.jetbrains.kotlin.test.directives.JsEnvironmentConfigurationDirectives import org.jetbrains.kotlin.test.directives.model.DirectivesContainer import org.jetbrains.kotlin.test.frontend.classic.moduleDescriptorProvider import org.jetbrains.kotlin.test.model.ArtifactKinds +import org.jetbrains.kotlin.test.directives.model.RegisteredDirectives import org.jetbrains.kotlin.test.model.DependencyDescription import org.jetbrains.kotlin.test.model.DependencyRelation import org.jetbrains.kotlin.test.model.TestModule @@ -203,6 +207,15 @@ class JsEnvironmentConfigurator(testServices: TestServices) : EnvironmentConfigu regularDependencies.flatMap { modules.single { module -> module.name == it.moduleName }.allTransitiveDependencies() } } + override fun provideAdditionalAnalysisFlags( + directives: RegisteredDirectives, + languageVersion: LanguageVersion + ): Map, Any?> { + return super.provideAdditionalAnalysisFlags(directives, languageVersion).toMutableMap().also { + it[allowFullyQualifiedNameInKClass] = false + } + } + override fun configureCompilerConfiguration(configuration: CompilerConfiguration, module: TestModule) { val registeredDirectives = module.directives val moduleKinds = registeredDirectives[MODULE_KIND] diff --git a/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsReflectionAPICallChecker.kt b/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsReflectionAPICallChecker.kt index 510365e1add..84a63bc9027 100644 --- a/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsReflectionAPICallChecker.kt +++ b/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsReflectionAPICallChecker.kt @@ -39,8 +39,12 @@ class JsReflectionAPICallChecker( override val isWholeReflectionApiAvailable: Boolean get() = false - override fun isAllowedReflectionApi(descriptor: CallableDescriptor, containingClass: ClassDescriptor): Boolean { - return super.isAllowedReflectionApi(descriptor, containingClass) || + override fun isAllowedReflectionApi( + descriptor: CallableDescriptor, + containingClass: ClassDescriptor, + context: CallCheckerContext + ): Boolean { + return super.isAllowedReflectionApi(descriptor, containingClass, context) || containingClass.fqNameSafe in ADDITIONAL_ALLOWED_CLASSES || descriptor.name.asString() == "findAssociatedObject" } diff --git a/libraries/stdlib/wasm/internal/kotlin/wasm/internal/TypeInfo.kt b/libraries/stdlib/wasm/internal/kotlin/wasm/internal/TypeInfo.kt index 124893bcd9b..4e4b3274ef2 100644 --- a/libraries/stdlib/wasm/internal/kotlin/wasm/internal/TypeInfo.kt +++ b/libraries/stdlib/wasm/internal/kotlin/wasm/internal/TypeInfo.kt @@ -18,7 +18,7 @@ internal const val TYPE_INFO_ITABLE_PTR_OFFSET = TYPE_INFO_SUPER_TYPE_OFFSET + T internal const val TYPE_INFO_VTABLE_LENGTH_OFFSET = TYPE_INFO_ITABLE_PTR_OFFSET + TYPE_INFO_ELEMENT_SIZE internal const val TYPE_INFO_VTABLE_OFFSET = TYPE_INFO_VTABLE_LENGTH_OFFSET + TYPE_INFO_ELEMENT_SIZE -internal class TypeInfoData(val typeId: Int, val packageName: String, val typeName: String) +internal class TypeInfoData(val typeId: Int, val isInterface: Boolean, val packageName: String, val typeName: String) internal fun getTypeInfoTypeDataByPtr(typeInfoPtr: Int): TypeInfoData { val fqNameLength = wasm_i32_load(typeInfoPtr + TYPE_INFO_TYPE_PACKAGE_NAME_LENGTH_OFFSET) @@ -27,7 +27,7 @@ internal fun getTypeInfoTypeDataByPtr(typeInfoPtr: Int): TypeInfoData { val simpleNamePtr = wasm_i32_load(typeInfoPtr + TYPE_INFO_TYPE_SIMPLE_NAME_PRT_OFFSET) val packageName = stringLiteral(fqNameLengthPtr, fqNameLength) val simpleName = stringLiteral(simpleNamePtr, simpleNameLength) - return TypeInfoData(typeInfoPtr, packageName, simpleName) + return TypeInfoData(typeInfoPtr, isInterface = false, packageName, simpleName) } internal fun getSuperTypeId(typeInfoPtr: Int): Int = @@ -83,8 +83,4 @@ internal fun wasmInterfaceId(): Int = @ExcludedFromCodegen internal fun wasmGetTypeInfoData(): TypeInfoData = - implementedAsIntrinsic - -@ExcludedFromCodegen -internal fun wasmTypeId(): Int = implementedAsIntrinsic \ No newline at end of file diff --git a/libraries/stdlib/wasm/src/kotlin/reflect/KClassImpl.kt b/libraries/stdlib/wasm/src/kotlin/reflect/KClassImpl.kt index 67dc1dc820a..d2257a5909c 100644 --- a/libraries/stdlib/wasm/src/kotlin/reflect/KClassImpl.kt +++ b/libraries/stdlib/wasm/src/kotlin/reflect/KClassImpl.kt @@ -6,18 +6,14 @@ package kotlin.reflect.wasm.internal import kotlin.reflect.* import kotlin.wasm.internal.TypeInfoData -import kotlin.wasm.internal.getInterfaceImplId import kotlin.wasm.internal.getSuperTypeId +import kotlin.wasm.internal.isInterface internal object NothingKClassImpl : KClass { override val simpleName: String = "Nothing" override val qualifiedName: String get() = "kotlin.Nothing" override fun isInstance(value: Any?): Boolean = false - - override fun equals(other: Any?): Boolean = other === this - - override fun hashCode(): Int = -1 } internal object ErrorKClass : KClass { @@ -25,10 +21,6 @@ internal object ErrorKClass : KClass { override val qualifiedName: String get() = error("Unknown qualifiedName for ErrorKClass") override fun isInstance(value: Any?): Boolean = error("Can's check isInstance on ErrorKClass") - - override fun equals(other: Any?): Boolean = other === this - - override fun hashCode(): Int = 0 } internal class KClassImpl(private val typeData: TypeInfoData) : KClass { @@ -45,11 +37,12 @@ internal class KClassImpl(private val typeData: TypeInfoData) : KClass< return false } - override fun isInstance(value: Any?): Boolean = - value != null && (checkSuperTypeInstance(value) || getInterfaceImplId(value, typeData.typeId) != -1) + override fun isInstance(value: Any?): Boolean = value?.let { + if (typeData.isInterface) isInterface(it, typeData.typeId) else checkSuperTypeInstance(it) + } ?: false override fun equals(other: Any?): Boolean = - (this === other) || (other is KClassImpl<*> && other.typeInfo == typeData.typeId) + (this === other) || (other is KClassImpl<*> && other.typeData.isInterface == typeData.isInterface && other.typeData.typeId == typeData.typeId) override fun hashCode(): Int = typeData.typeId } \ No newline at end of file diff --git a/libraries/stdlib/wasm/src/kotlin/reflect/KTypeImpl.kt b/libraries/stdlib/wasm/src/kotlin/reflect/KTypeImpl.kt new file mode 100644 index 00000000000..f2a87702e94 --- /dev/null +++ b/libraries/stdlib/wasm/src/kotlin/reflect/KTypeImpl.kt @@ -0,0 +1,14 @@ +/* + * Copyright 2010-2021 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 kotlin.wasm.internal + +import kotlin.reflect.* + +internal class KTypeImpl( + override val classifier: KClassifier?, + override val arguments: List, + override val isMarkedNullable: Boolean +) : KType diff --git a/libraries/stdlib/wasm/src/kotlin/reflect/KTypeParameterImpl.kt b/libraries/stdlib/wasm/src/kotlin/reflect/KTypeParameterImpl.kt new file mode 100644 index 00000000000..d8f4d4aa6db --- /dev/null +++ b/libraries/stdlib/wasm/src/kotlin/reflect/KTypeParameterImpl.kt @@ -0,0 +1,17 @@ +/* + * 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. + */ + +package kotlin.wasm.internal + +import kotlin.reflect.* + +internal data class KTypeParameterImpl( + override val name: String, + override val upperBounds: List, + override val variance: KVariance, + override val isReified: Boolean +) : KTypeParameter { + override fun toString(): String = name +} \ No newline at end of file diff --git a/libraries/stdlib/wasm/src/kotlin/reflect/primitives.kt b/libraries/stdlib/wasm/src/kotlin/reflect/primitives.kt index c4d76b13abf..4dd04aa31b2 100644 --- a/libraries/stdlib/wasm/src/kotlin/reflect/primitives.kt +++ b/libraries/stdlib/wasm/src/kotlin/reflect/primitives.kt @@ -14,6 +14,7 @@ internal object PrimitiveClasses { val anyClass = wasmGetKClass() val numberClass = wasmGetKClass() + val longClass = wasmGetKClass() val booleanClass = wasmGetKClass() val byteClass = wasmGetKClass() val shortClass = wasmGetKClass() diff --git a/libraries/stdlib/wasm/src/kotlin/reflect/reflection.kt b/libraries/stdlib/wasm/src/kotlin/reflect/reflection.kt index 144bc0d4aa7..b4ecd0ddb27 100644 --- a/libraries/stdlib/wasm/src/kotlin/reflect/reflection.kt +++ b/libraries/stdlib/wasm/src/kotlin/reflect/reflection.kt @@ -9,21 +9,8 @@ package kotlin.wasm.internal import kotlin.reflect.* import kotlin.reflect.wasm.internal.* -internal fun getKClass(typeInfoData: TypeInfoData): KClass { -// return if (js("Array").isArray(jClass)) { -// getKClassM(jClass.unsafeCast>>()) -// } else { -// getKClass1(jClass.unsafeCast>()) -// } - - return getKClass1(typeInfoData) -} - -internal fun getKClassM(jClasses: Array): KClass = when (jClasses.size) { - 1 -> getKClass1(jClasses[0]) - 0 -> NothingKClassImpl as KClass - else -> ErrorKClass as KClass -} +internal fun getKClass(typeInfoData: TypeInfoData): KClass = + KClassImpl(typeInfoData) internal fun getKClassFromExpression(e: T): KClass = when (e) { @@ -33,6 +20,7 @@ internal fun getKClassFromExpression(e: T): KClass = is Float -> PrimitiveClasses.floatClass is Boolean -> PrimitiveClasses.booleanClass is Double -> PrimitiveClasses.doubleClass + is Long -> PrimitiveClasses.longClass is Number -> PrimitiveClasses.numberClass is BooleanArray -> PrimitiveClasses.booleanArrayClass @@ -45,17 +33,33 @@ internal fun getKClassFromExpression(e: T): KClass = is DoubleArray -> PrimitiveClasses.doubleArrayClass is KClass<*> -> KClass::class is Array<*> -> PrimitiveClasses.arrayClass - - is Function<*> -> PrimitiveClasses.functionClass(0) //TODO - else -> { - getKClass1(getTypeInfoTypeDataByPtr(e.typeInfo)) - } + else -> getKClass(getTypeInfoTypeDataByPtr(e.typeInfo)) } as KClass -internal fun getKClass1(infoData: TypeInfoData): KClass { - return KClassImpl(infoData) -} - @Suppress("REIFIED_TYPE_PARAMETER_NO_INLINE") internal inline fun wasmGetKClass(): KClass = KClassImpl(wasmGetTypeInfoData()) + +internal fun createKType(classifier: KClassifier, arguments: Array, isMarkedNullable: Boolean): KType = + KTypeImpl(classifier, arguments.asList(), isMarkedNullable) + +internal fun createKTypeParameter(name: String, upperBounds: Array, variance: String): KTypeParameter { + val kVariance = when (variance) { + "in" -> KVariance.IN + "out" -> KVariance.OUT + else -> KVariance.INVARIANT + } + return KTypeParameterImpl(name, upperBounds.asList(), kVariance, false) +} + +internal fun getStarKTypeProjection(): KTypeProjection = + KTypeProjection.STAR + +internal fun createCovariantKTypeProjection(type: KType): KTypeProjection = + KTypeProjection.covariant(type) + +internal fun createInvariantKTypeProjection(type: KType): KTypeProjection = + KTypeProjection.invariant(type) + +internal fun createContravariantKTypeProjection(type: KType): KTypeProjection = + KTypeProjection.contravariant(type)