All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jetbrains.kotlin.backend.konan.ir.Ir.kt Maven / Gradle / Ivy

There is a newer version: 2.1.0-RC2
Show newest version
/*
 * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
 * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
 */

package org.jetbrains.kotlin.backend.konan.ir

import org.jetbrains.kotlin.backend.common.COROUTINE_SUSPENDED_NAME
import org.jetbrains.kotlin.backend.common.ir.Ir
import org.jetbrains.kotlin.backend.common.ir.Symbols
import org.jetbrains.kotlin.backend.konan.*
import org.jetbrains.kotlin.backend.konan.RuntimeNames
import org.jetbrains.kotlin.backend.konan.driver.PhaseContext
import org.jetbrains.kotlin.backend.konan.lower.TestProcessor
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.DescriptorVisibility
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.ir.IrBuiltIns
import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils
import kotlin.IllegalArgumentException
import kotlin.NoSuchElementException

object KonanNameConventions {
    val setWithoutBoundCheck = Name.special("")
    val getWithoutBoundCheck = Name.special("")
}

internal interface SymbolLookupUtils {
    fun findMemberFunction(clazz: IrClassSymbol, name: Name): IrSimpleFunctionSymbol?
    fun findMemberProperty(clazz: IrClassSymbol, name: Name): IrPropertySymbol?
    fun findMemberPropertyGetter(clazz: IrClassSymbol, name: Name): IrSimpleFunctionSymbol?
    fun findPrimaryConstructor(clazz: IrClassSymbol): IrConstructorSymbol?
    fun findNoParametersConstructor(clazz: IrClassSymbol): IrConstructorSymbol?
    fun findNestedClass(clazz: IrClassSymbol, name: Name): IrClassSymbol?
    fun findGetter(property: IrPropertySymbol): IrSimpleFunctionSymbol?

    fun getName(clazz: IrClassSymbol): Name
    fun isExtensionReceiverClass(property: IrPropertySymbol, expected: IrClassSymbol?): Boolean
    fun isExtensionReceiverClass(function: IrFunctionSymbol, expected: IrClassSymbol?): Boolean
    fun isExtensionReceiverNullable(function: IrFunctionSymbol): Boolean?
    fun getValueParametersCount(function: IrFunctionSymbol): Int
    fun getTypeParametersCount(function: IrFunctionSymbol): Int
    fun isTypeParameterUpperBoundClass(property: IrPropertySymbol, index: Int, expected: IrClassSymbol): Boolean
    fun isValueParameterClass(function: IrFunctionSymbol, index: Int, expected: IrClassSymbol?): Boolean
    fun isReturnClass(function: IrFunctionSymbol, expected: IrClassSymbol): Boolean
    fun isValueParameterTypeArgumentClass(function: IrFunctionSymbol, index: Int, argumentIndex: Int, expected: IrClassSymbol?): Boolean
    fun isValueParameterNullable(function: IrFunctionSymbol, index: Int): Boolean?
    fun isExpect(function: IrFunctionSymbol): Boolean
    fun isSuspend(functionSymbol: IrFunctionSymbol): Boolean
    fun getVisibility(function: IrFunctionSymbol): DescriptorVisibility
    fun getValueParameterPrimitiveBinaryType(function: IrFunctionSymbol, index: Int): PrimitiveBinaryType?
}

// This is what Context collects about IR.
internal class KonanIr(context: Context, override val symbols: KonanSymbols): Ir(context)

internal class KonanSymbols(
        context: PhaseContext,
        val lookup: SymbolLookupUtils,
        irBuiltIns: IrBuiltIns,
        symbolTable: ReferenceSymbolTable,
) : Symbols(irBuiltIns, symbolTable) {
    val entryPoint = run {
        val config = context.config.configuration
        if (config.get(KonanConfigKeys.PRODUCE) != CompilerOutputKind.PROGRAM) return@run null

        val entryPoint = FqName(config.get(KonanConfigKeys.ENTRY) ?: when (config.get(KonanConfigKeys.GENERATE_TEST_RUNNER)) {
            TestRunnerKind.MAIN_THREAD -> "kotlin.native.internal.test.main"
            TestRunnerKind.WORKER -> "kotlin.native.internal.test.worker"
            TestRunnerKind.MAIN_THREAD_NO_EXIT -> "kotlin.native.internal.test.mainNoExit"
            else -> "main"
        })

        val entryName = entryPoint.shortName()
        val packageName = entryPoint.parent()

        fun IrSimpleFunctionSymbol.isArrayStringMain() =
                lookup.getValueParametersCount(this) == 1 &&
                        lookup.isValueParameterClass(this, 0, array) &&
                        lookup.isValueParameterTypeArgumentClass(this, 0, 0, string)

        fun IrSimpleFunctionSymbol.isNoArgsMain() = lookup.getValueParametersCount(this) == 0

        val candidates = irBuiltIns.findFunctions(entryName, packageName)
                .filter {
                    lookup.isReturnClass(it, unit) &&
                            lookup.getTypeParametersCount(it) == 0 &&
                            lookup.getVisibility(it).isPublicAPI
                }

        val main = candidates.singleOrNull { it.isArrayStringMain() } ?: candidates.singleOrNull { it.isNoArgsMain() }
        if (main == null) context.reportCompilationError("Could not find '$entryName' in '$packageName' package.")
        if (lookup.isSuspend(main)) context.reportCompilationError("Entry point can not be a suspend function.")
        main
    }

    val nothing get() = irBuiltIns.nothingClass
    val throwable get() = irBuiltIns.throwableClass
    val enum get() = irBuiltIns.enumClass
    private val nativePtr = internalClass(NATIVE_PTR_NAME)
    val nativePointed = interopClass(InteropFqNames.nativePointedName)
    val nativePtrType = nativePtr.typeWith(arguments = emptyList())

    val immutableBlobOf = nativeFunction(IMMUTABLE_BLOB_OF)
    val immutableBlobOfImpl = internalFunction("immutableBlobOfImpl")

    val signedIntegerClasses = setOf(byte, short, int, long)
    val unsignedIntegerClasses = setOf(uByte!!, uShort!!, uInt!!, uLong!!)

    val allIntegerClasses = signedIntegerClasses + unsignedIntegerClasses

    val unsignedToSignedOfSameBitWidth = unsignedIntegerClasses.associateWith {
        when (it) {
            uByte -> byte
            uShort -> short
            uInt -> int
            uLong -> long
            else -> error(it.toString())
        }
    }

    val integerConversions = allIntegerClasses.flatMap { fromClass ->
        allIntegerClasses.map { toClass ->
            val name = Name.identifier("to${lookup.getName(toClass).asString().replaceFirstChar(Char::uppercaseChar)}")
            val symbol = if (fromClass in signedIntegerClasses && toClass in unsignedIntegerClasses) {
                irBuiltIns.getNonBuiltInFunctionsByExtensionReceiver(name, "kotlin")[fromClass]!!
            } else {
                lookup.findMemberFunction(fromClass, name)!!
            }

            (fromClass to toClass) to symbol
        }
    }.toMap()

    val symbolName = topLevelClass(RuntimeNames.symbolNameAnnotation)
    val filterExceptions = topLevelClass(RuntimeNames.filterExceptions)
    val exportForCppRuntime = topLevelClass(RuntimeNames.exportForCppRuntime)
    val typedIntrinsic = topLevelClass(RuntimeNames.typedIntrinsicAnnotation)

    val objCMethodImp = interopClass(InteropFqNames.objCMethodImpName)

    val processUnhandledException = nativeFunction("processUnhandledException")
    val terminateWithUnhandledException = nativeFunction("terminateWithUnhandledException")

    val interopNativePointedGetRawPointer = interopFunction(InteropFqNames.nativePointedGetRawPointerFunName) {
        lookup.isExtensionReceiverClass(it, nativePointed)
    }

    val interopCPointer = interopClass(InteropFqNames.cPointerName)
    val interopCPointed = interopClass(InteropFqNames.cPointedName)
    val interopCstr = findTopLevelPropertyGetter(InteropFqNames.packageName, InteropFqNames.cstrPropertyName, string)
    val interopWcstr = findTopLevelPropertyGetter(InteropFqNames.packageName, InteropFqNames.wcstrPropertyName, string)
    val interopMemScope = interopClass(InteropFqNames.memScopeName)
    val interopCValue = interopClass(InteropFqNames.cValueName)
    val interopCValuesRef = interopClass(InteropFqNames.cValuesRefName)
    val interopCValueWrite = interopFunction(InteropFqNames.cValueWriteFunName) {
        lookup.isExtensionReceiverClass(it, interopCValue)
    }
    val interopCValueRead = interopFunction(InteropFqNames.cValueReadFunName) {
        lookup.getValueParametersCount(it) == 1
    }
    val interopAllocType = interopFunction(InteropFqNames.allocTypeFunName) {
        lookup.getTypeParametersCount(it) == 0
    }

    val interopTypeOf = interopFunction(InteropFqNames.typeOfFunName)

    val interopCPointerGetRawValue = interopFunction(InteropFqNames.cPointerGetRawValueFunName) {
        lookup.isExtensionReceiverClass(it, interopCPointer)
    }

    val interopAllocObjCObject = interopFunction(InteropFqNames.allocObjCObjectFunName)

    val interopForeignObjCObject = interopClass(InteropFqNames.foreignObjCObjectName)

    // These are possible supertypes of forward declarations - we need to reference them explicitly to force their deserialization.
    // TODO: Do it lazily.
    val interopCOpaque = interopClass(InteropFqNames.cOpaqueName)
    val interopObjCObject = interopClass(InteropFqNames.objCObjectName)
    val interopObjCObjectBase = interopClass(InteropFqNames.objCObjectBaseName)
    val interopObjCObjectBaseMeta = interopClass(InteropFqNames.objCObjectBaseMetaName)
    val interopObjCClass = interopClass(InteropFqNames.objCClassName)
    val interopObjCClassOf = interopClass(InteropFqNames.objCClassOfName)
    val interopObjCProtocol = interopClass(InteropFqNames.objCProtocolName)

    val interopObjCRelease = interopFunction("objc_release")

    val interopObjCRetain = interopFunction("objc_retain")

    val interopObjcRetainAutoreleaseReturnValue = interopFunction("objc_retainAutoreleaseReturnValue")

    val interopCreateObjCObjectHolder = interopFunction("createObjCObjectHolder")

    val interopCreateKotlinObjectHolder = interopFunction("createKotlinObjectHolder")
    val interopUnwrapKotlinObjectHolderImpl = interopFunction("unwrapKotlinObjectHolderImpl")

    val interopCreateObjCSuperStruct = interopFunction("createObjCSuperStruct")

    val interopGetMessenger = interopFunction("getMessenger")
    val interopGetMessengerStret = interopFunction("getMessengerStret")

    val interopGetObjCClass = interopFunction(InteropFqNames.getObjCClassFunName)
    val interopObjCObjectSuperInitCheck = interopFunction(InteropFqNames.objCObjectSuperInitCheckFunName)
    val interopObjCObjectInitBy = interopFunction(InteropFqNames.objCObjectInitByFunName)
    val interopObjCObjectRawValueGetter = interopFunction(InteropFqNames.objCObjectRawPtrFunName)

    val interopNativePointedRawPtrGetter = lookup.findMemberPropertyGetter(interopClass(InteropFqNames.nativePointedName), Name.identifier(InteropFqNames.nativePointedRawPtrPropertyName))!!

    val interopCPointerRawValue: IrPropertySymbol = lookup.findMemberProperty(interopClass(InteropFqNames.cPointerName), Name.identifier(InteropFqNames.cPointerRawValuePropertyName))!!

    val interopInterpretObjCPointer = interopFunction(InteropFqNames.interpretObjCPointerFunName)
    val interopInterpretObjCPointerOrNull = interopFunction(InteropFqNames.interpretObjCPointerOrNullFunName)
    val interopInterpretNullablePointed = interopFunction(InteropFqNames.interpretNullablePointedFunName)
    val interopInterpretCPointer = interopFunction(InteropFqNames.interpretCPointerFunName)

    val createForeignException = interopFunction("CreateForeignException")

    val interopCEnumVar = interopClass("CEnumVar")

    val nativeMemUtils = interopClass(InteropFqNames.nativeMemUtilsName)
    val nativeHeap = interopClass(InteropFqNames.nativeHeapName)

    val cStuctVar = interopClass(InteropFqNames.cStructVarName)
    val cStructVarConstructorSymbol = lookup.findPrimaryConstructor(cStuctVar)!!
    val managedTypeConstructor = lookup.findPrimaryConstructor(interopClass(InteropFqNames.managedTypeName))!!
    val structVarPrimaryConstructor = lookup.findPrimaryConstructor(lookup.findNestedClass(cStuctVar, Name.identifier(InteropFqNames.TypeName))!!)!!

    val interopGetPtr = findTopLevelPropertyGetter(InteropFqNames.packageName, "ptr") {
        lookup.isTypeParameterUpperBoundClass(it, 0, interopCPointed)
    }

    val interopManagedType = interopClass(InteropFqNames.managedTypeName)

    val interopManagedGetPtr = findTopLevelPropertyGetter(InteropFqNames.packageName, "ptr") {
        lookup.isTypeParameterUpperBoundClass(it, 0, cStuctVar) && lookup.isExtensionReceiverClass(it, interopManagedType)
    }

    val interopCPlusPlusClass = interopClass(InteropFqNames.cPlusPlusClassName)
    val interopSkiaRefCnt = interopClass(InteropFqNames.skiaRefCntName)

    val readBits = interopFunction("readBits")
    val writeBits = interopFunction("writeBits")

    val objCExportTrapOnUndeclaredException = internalFunction("trapOnUndeclaredException")
    val objCExportResumeContinuation = internalFunction("resumeContinuation")
    val objCExportResumeContinuationWithException = internalFunction("resumeContinuationWithException")
    val objCExportGetCoroutineSuspended = internalFunction("getCoroutineSuspended")
    val objCExportInterceptedContinuation = internalFunction("interceptedContinuation")

    val getNativeNullPtr = internalFunction("getNativeNullPtr")

    val boxCachePredicates = BoxCache.entries.associateWith {
        internalFunction("in${it.name.lowercase().replaceFirstChar(Char::uppercaseChar)}BoxCache")
    }

    val boxCacheGetters = BoxCache.entries.associateWith {
        internalFunction("getCached${it.name.lowercase().replaceFirstChar(Char::uppercaseChar)}Box")
    }

    val immutableBlob = nativeClass("ImmutableBlob")

    val executeImpl = topLevelFunction(KonanFqNames.packageName.child(Name.identifier("concurrent")), "executeImpl")
    val createCleaner = topLevelFunction(KonanFqNames.packageName.child(Name.identifier("ref")), "createCleaner")

    // TODO: this is strange. It should be a map from IrClassSymbol
    val areEqualByValue = internalFunctions("areEqualByValue").associateBy {
        lookup.getValueParameterPrimitiveBinaryType(it, 0)!!
    }

    val reinterpret = internalFunction("reinterpret")

    val theUnitInstance = internalFunction("theUnitInstance")

    val ieee754Equals = internalFunctions("ieee754Equals").toList()

    val equals = lookup.findMemberFunction(any, Name.identifier("equals"))!!

    val throwArithmeticException = internalFunction("ThrowArithmeticException")

    val throwIndexOutOfBoundsException = internalFunction("ThrowIndexOutOfBoundsException")

    override val throwNullPointerException = internalFunction("ThrowNullPointerException")

    val throwNoWhenBranchMatchedException = internalFunction("ThrowNoWhenBranchMatchedException")
    val throwIrLinkageError = internalFunction("ThrowIrLinkageError")

    override val throwTypeCastException = internalFunction("ThrowTypeCastException")

    override val throwKotlinNothingValueException = internalFunction("ThrowKotlinNothingValueException")

    val throwClassCastException = internalFunction("ThrowClassCastException")

    val throwInvalidReceiverTypeException = internalFunction("ThrowInvalidReceiverTypeException")
    val throwIllegalStateException = internalFunction("ThrowIllegalStateException")
    val throwIllegalStateExceptionWithMessage = internalFunction("ThrowIllegalStateExceptionWithMessage")
    val throwIllegalArgumentException = internalFunction("ThrowIllegalArgumentException")
    val throwIllegalArgumentExceptionWithMessage = internalFunction("ThrowIllegalArgumentExceptionWithMessage")


    override val throwUninitializedPropertyAccessException = internalFunction("ThrowUninitializedPropertyAccessException")

    override val stringBuilder = topLevelClass(StandardNames.TEXT_PACKAGE_FQ_NAME, "StringBuilder")

    override val defaultConstructorMarker = internalClass("DefaultConstructorMarker")

    private fun arrayToExtensionSymbolMap(name: String, filter: (IrFunctionSymbol) -> Boolean = { true }) =
            arrays.associateWith { classSymbol ->
                topLevelFunction(StandardNames.COLLECTIONS_PACKAGE_FQ_NAME, name) { function ->
                    lookup.isExtensionReceiverClass(function, classSymbol) && !lookup.isExpect(function) && filter(function)
                }
            }

    val arrayContentToString = arrayToExtensionSymbolMap("contentToString") {
        lookup.isExtensionReceiverNullable(it) == true
    }
    val arrayContentHashCode = arrayToExtensionSymbolMap("contentHashCode") {
        lookup.isExtensionReceiverNullable(it) == true
    }
    val arrayContentEquals = arrayToExtensionSymbolMap("contentEquals") {
        lookup.isExtensionReceiverNullable(it) == true
    }

    override val arraysContentEquals by lazy { arrayContentEquals.mapKeys { it.key.defaultType } }

    val copyInto = arrayToExtensionSymbolMap("copyInto")
    val copyOf = arrayToExtensionSymbolMap("copyOf") { lookup.getValueParametersCount(it) == 0 }

    val arrayGet = arrays.associateWith { lookup.findMemberFunction(it, Name.identifier("get"))!! }

    val arraySet = arrays.associateWith { lookup.findMemberFunction(it, Name.identifier("set"))!! }

    val arraySize = arrays.associateWith { lookup.findMemberPropertyGetter(it, Name.identifier("size"))!! }

    val valuesForEnum = internalFunction("valuesForEnum")

    val valueOfForEnum = internalFunction("valueOfForEnum")

    val createEnumEntries = topLevelFunction(FqName("kotlin.enums"), "enumEntries") {
        lookup.getValueParametersCount(it) == 1 && lookup.isValueParameterClass(it, 0, array)
    }

    val enumEntriesInterface = topLevelClass(FqName("kotlin.enums"), "EnumEntries")

    val createUninitializedInstance = internalFunction("createUninitializedInstance")

    val createUninitializedArray = internalFunction("createUninitializedArray")

    val initInstance = internalFunction("initInstance")

    val isSubtype = internalFunction("isSubtype")

    val println = topLevelFunction(FqName("kotlin.io"), "println") {
        lookup.getValueParametersCount(it) == 1 && lookup.isValueParameterClass(it, 0, string)
    }

    override val getContinuation = internalFunction("getContinuation")

    override val continuationClass = topLevelClass(StandardNames.COROUTINES_PACKAGE_FQ_NAME, "Continuation")

    override val returnIfSuspended = internalFunction("returnIfSuspended")

    override val suspendCoroutineUninterceptedOrReturn = internalFunction("suspendCoroutineUninterceptedOrReturn")

    override val coroutineContextGetter =
            findTopLevelPropertyGetter(StandardNames.COROUTINES_PACKAGE_FQ_NAME, "coroutineContext", null)

    override val coroutineGetContext = internalFunction("getCoroutineContext")

    override val coroutineImpl get() = TODO()

    val baseContinuationImpl = internalCoroutinesClass("BaseContinuationImpl")

    val restrictedContinuationImpl = internalCoroutinesClass("RestrictedContinuationImpl")

    val continuationImpl = internalCoroutinesClass("ContinuationImpl")

    val invokeSuspendFunction = lookup.findMemberFunction(baseContinuationImpl, Name.identifier("invokeSuspend"))!!

    override val coroutineSuspendedGetter =
            findTopLevelPropertyGetter(StandardNames.COROUTINES_INTRINSICS_PACKAGE_FQ_NAME, COROUTINE_SUSPENDED_NAME.identifier, null)

    val saveCoroutineState = internalFunction("saveCoroutineState")
    val restoreCoroutineState = internalFunction("restoreCoroutineState")

    val cancellationException = topLevelClass(KonanFqNames.cancellationException)

    val kotlinResult = topLevelClass(StandardNames.BUILT_INS_PACKAGE_FQ_NAME, "Result")

    val kotlinResultGetOrThrow = topLevelFunction(StandardNames.BUILT_INS_PACKAGE_FQ_NAME, "getOrThrow") {
        lookup.isExtensionReceiverClass(it, kotlinResult)
    }

    override val functionAdapter = internalClass("FunctionAdapter")

    val refClass = internalClass("Ref")
    val kFunctionImpl = internalClass("KFunctionImpl")
    val kFunctionDescription = internalClass("KFunctionDescription")
    val kSuspendFunctionImpl = internalClass("KSuspendFunctionImpl")

    val kMutableProperty0 = reflectionClass("KMutableProperty0")
    val kMutableProperty1 = reflectionClass("KMutableProperty1")
    val kMutableProperty2 = reflectionClass("KMutableProperty2")

    val kProperty0Impl = internalClass("KProperty0Impl")
    val kProperty1Impl = internalClass("KProperty1Impl")
    val kProperty2Impl = internalClass("KProperty2Impl")
    val kMutableProperty0Impl = internalClass("KMutableProperty0Impl")
    val kMutableProperty1Impl = internalClass("KMutableProperty1Impl")
    val kMutableProperty2Impl = internalClass("KMutableProperty2Impl")

    val kLocalDelegatedPropertyImpl = internalClass("KLocalDelegatedPropertyImpl")
    val kLocalDelegatedMutablePropertyImpl = internalClass("KLocalDelegatedMutablePropertyImpl")

    val kType = reflectionClass("KType")
    val getObjectTypeInfo = internalFunction("getObjectTypeInfo")
    val kClassImpl = internalClass("KClassImpl")
    val kClassImplConstructor = lookup.findPrimaryConstructor(kClassImpl)!!
    val kClassImplIntrinsicConstructor = lookup.findNoParametersConstructor(kClassImpl)!!
    val kObjCClassImpl = topLevelClass(RuntimeNames.kotlinxCInteropInternalPackageName, "ObjectiveCKClassImpl")
    val kObjCClassImplConstructor = lookup.findPrimaryConstructor(kObjCClassImpl)!!
    val kObjCClassImplIntrinsicConstructor = lookup.findNoParametersConstructor(kObjCClassImpl)!!
    val kClassUnsupportedImpl = internalClass("KClassUnsupportedImpl")
    val kTypeParameterImpl = internalClass("KTypeParameterImpl")
    val kTypeImpl = internalClass("KTypeImpl")
    val kTypeImplForTypeParametersWithRecursiveBounds = internalClass("KTypeImplForTypeParametersWithRecursiveBounds")
    val kTypeProjectionList = internalClass("KTypeProjectionList")
    val typeOf = reflectionFunction("typeOf")

    val threadLocal = topLevelClass(KonanFqNames.threadLocal)

    val eagerInitialization = topLevelClass(KonanFqNames.eagerInitialization)

    val enumVarConstructorSymbol = lookup.findPrimaryConstructor(interopClass(InteropFqNames.cEnumVarName))!!
    val primitiveVarPrimaryConstructor = lookup.findPrimaryConstructor(lookup.findNestedClass(interopClass(InteropFqNames.cPrimitiveVarName), Name.identifier(InteropFqNames.TypeName))!!)!!

    val isAssertionThrowingErrorEnabled = topLevelFunction(StandardNames.BUILT_INS_PACKAGE_FQ_NAME, "isAssertionThrowingErrorEnabled")
    val isAssertionArgumentEvaluationEnabled = topLevelFunction(StandardNames.BUILT_INS_PACKAGE_FQ_NAME, "isAssertionArgumentEvaluationEnabled")

    private fun topLevelClass(fqName: FqName): IrClassSymbol = irBuiltIns.findClass(fqName.shortName(), fqName.parent()) ?: error("No class ${fqName} found")
    private fun topLevelClass(packageName: FqName, name: String): IrClassSymbol = irBuiltIns.findClass(Name.identifier(name), packageName) ?: error("No class ${packageName}.${name} found")

    private fun topLevelFunctions(packageName: FqName, name: String): Iterable = irBuiltIns.findFunctions(Name.identifier(name), packageName)
    private inline fun topLevelFunction(packageName: FqName, name: String, condition: (IrFunctionSymbol) -> Boolean = { true }): IrSimpleFunctionSymbol {
        val elements = topLevelFunctions(packageName, name).filter(condition)
        require(elements.isNotEmpty()) { "No function ${packageName}.$name found corresponding given condition"}
        require(elements.size == 1) { "Several functions ${packageName}.$name found corresponding given condition:\n${elements.joinToString("\n")}" }
        return elements.single()
    }

    private fun topLevelProperties(packageName: FqName, name: String): Iterable = irBuiltIns.findProperties(Name.identifier(name), packageName)
    private inline fun topLevelProperty(packageName: FqName, name: String, condition: (IrPropertySymbol) -> Boolean = { true }): IrPropertySymbol {
        val elements = topLevelProperties(packageName, name).filter(condition)
        require(elements.isNotEmpty()) { "No property ${packageName}.$name found corresponding given condition"}
        require(elements.size == 1) { "Several properties ${packageName}.$name found corresponding given condition:\n${elements.joinToString("\n")}" }
        return elements.single()
    }

    private fun findTopLevelPropertyGetter(packageName: FqName, name: String, extensionReceiverClass: IrClassSymbol?) =
            findTopLevelPropertyGetter(packageName, name) { lookup.isExtensionReceiverClass(it, extensionReceiverClass) }
    private fun findTopLevelPropertyGetter(packageName: FqName, name: String, predicate: (IrPropertySymbol) -> Boolean) =
            lookup.findGetter(topLevelProperty(packageName, name, predicate))!!

    private fun internalFunctions(name: String) = topLevelFunctions(RuntimeNames.kotlinNativeInternalPackageName, name)
    private inline fun nativeFunction(
            name: String,
            condition: (IrFunctionSymbol) -> Boolean = { true }
    ) = topLevelFunction(KonanFqNames.packageName, name, condition)

    private inline fun internalFunction(
            name: String,
            condition: (IrFunctionSymbol) -> Boolean = { true }
    ) = topLevelFunction(RuntimeNames.kotlinNativeInternalPackageName, name, condition)

    private inline fun interopFunction(
            name: String,
            condition: (IrFunctionSymbol) -> Boolean = { true }
    ) = topLevelFunction(InteropFqNames.packageName, name, condition)

    private inline fun reflectionFunction(
            name: String,
            condition: (IrFunctionSymbol) -> Boolean = { true }
    ) = topLevelFunction(StandardNames.KOTLIN_REFLECT_FQ_NAME, name, condition)


    private fun nativeClass(name: String) = topLevelClass(KonanFqNames.packageName, name)
    private fun internalClass(name: String) = topLevelClass(RuntimeNames.kotlinNativeInternalPackageName, name)
    private fun interopClass(name: String) = topLevelClass(InteropFqNames.packageName, name)
    private fun reflectionClass(name: String) = topLevelClass(StandardNames.KOTLIN_REFLECT_FQ_NAME, name)

    private fun internalCoroutinesClass(name: String) = topLevelClass(RuntimeNames.kotlinNativeCoroutinesInternalPackageName, name)
    private fun konanTestClass(name: String) = topLevelClass(RuntimeNames.kotlinNativeInternalTestPackageName, name)

    fun kFunctionN(n: Int) = irBuiltIns.kFunctionN(n).symbol

    fun kSuspendFunctionN(n: Int) = irBuiltIns.kSuspendFunctionN(n).symbol

    fun getKFunctionType(returnType: IrType, parameterTypes: List) =
            kFunctionN(parameterTypes.size).typeWith(parameterTypes + returnType)

    val baseClassSuite = konanTestClass("BaseClassSuite")
    val topLevelSuite = konanTestClass("TopLevelSuite")
    val testFunctionKind = konanTestClass("TestFunctionKind")

    override val getWithoutBoundCheckName: Name? = KonanNameConventions.getWithoutBoundCheck

    override val setWithoutBoundCheckName: Name? = KonanNameConventions.setWithoutBoundCheck

    private val testFunctionKindCache by lazy {
        TestProcessor.FunctionKind.entries.associateWith { kind ->
            if (kind.runtimeKindString.isEmpty())
                null
            else
                testFunctionKind.owner.declarations
                        .filterIsInstance()
                        .single { it.name == Name.identifier(kind.runtimeKindString) }
                        .symbol
        }
    }

    fun getTestFunctionKind(kind: TestProcessor.FunctionKind) = testFunctionKindCache[kind]!!
}

@OptIn(ObsoleteDescriptorBasedAPI::class)
internal class SymbolOverDescriptorsLookupUtils(val symbolTable: SymbolTable) : SymbolLookupUtils {
    override fun findMemberFunction(clazz: IrClassSymbol, name: Name): IrSimpleFunctionSymbol? =
            // inspired by: irBuiltIns.findBuiltInClassMemberFunctions(this, name).singleOrNull()
            clazz.descriptor.unsubstitutedMemberScope.getContributedFunctions(name, NoLookupLocation.FROM_BACKEND)
                    .singleOrNull()
                    ?.let { symbolTable.descriptorExtension.referenceSimpleFunction(it) }

    override fun findMemberProperty(clazz: IrClassSymbol, name: Name): IrPropertySymbol? =
            clazz.descriptor.unsubstitutedMemberScope.getContributedVariables(name, NoLookupLocation.FROM_BACKEND)
                    .singleOrNull()
                    ?.let { symbolTable.descriptorExtension.referenceProperty(it) }

    override fun findMemberPropertyGetter(clazz: IrClassSymbol, name: Name): IrSimpleFunctionSymbol? =
            clazz.descriptor.unsubstitutedMemberScope.getContributedVariables(name, NoLookupLocation.FROM_BACKEND)
                    .singleOrNull()
                    ?.getter
                    ?.let { symbolTable.descriptorExtension.referenceSimpleFunction(it) }

    override fun getName(clazz: IrClassSymbol) = clazz.descriptor.name
    override fun isExtensionReceiverClass(property: IrPropertySymbol, expected: IrClassSymbol?): Boolean {
        return property.descriptor.extensionReceiverParameter?.type?.let { TypeUtils.getClassDescriptor(it) } == expected?.descriptor
    }

    override fun isExtensionReceiverClass(function: IrFunctionSymbol, expected: IrClassSymbol?): Boolean {
        return function.descriptor.extensionReceiverParameter?.type?.let { TypeUtils.getClassDescriptor(it) } == expected?.descriptor
    }

    override fun findGetter(property: IrPropertySymbol): IrSimpleFunctionSymbol = symbolTable.descriptorExtension.referenceSimpleFunction(property.descriptor.getter!!)

    override fun isExtensionReceiverNullable(function: IrFunctionSymbol): Boolean? {
        return function.descriptor.extensionReceiverParameter?.type?.isMarkedNullable
    }

    override fun getValueParametersCount(function: IrFunctionSymbol): Int = function.descriptor.valueParameters.size

    override fun getTypeParametersCount(function: IrFunctionSymbol): Int = function.descriptor.typeParameters.size

    private fun match(type: KotlinType?, symbol: IrClassSymbol?) =
            if (type == null)
                symbol == null
            else
                TypeUtils.getClassDescriptor(type) == symbol?.descriptor

    override fun isTypeParameterUpperBoundClass(property: IrPropertySymbol, index: Int, expected: IrClassSymbol): Boolean {
        return property.descriptor.typeParameters.getOrNull(index)?.upperBounds?.any { match(it, expected) } ?: false
    }

    override fun isValueParameterClass(function: IrFunctionSymbol, index: Int, expected: IrClassSymbol?): Boolean {
        return match(function.descriptor.valueParameters.getOrNull(index)?.type, expected)
    }

    override fun isReturnClass(function: IrFunctionSymbol, expected: IrClassSymbol): Boolean {
        return match(function.descriptor.returnType, expected)
    }

    override fun isValueParameterTypeArgumentClass(function: IrFunctionSymbol, index: Int, argumentIndex: Int, expected: IrClassSymbol?): Boolean {
        return match(function.descriptor.valueParameters.getOrNull(index)?.type?.arguments?.getOrNull(argumentIndex)?.type, expected)
    }

    override fun isValueParameterNullable(function: IrFunctionSymbol, index: Int): Boolean? {
        return function.descriptor.valueParameters.getOrNull(index)?.type?.isMarkedNullable
    }

    override fun isExpect(function: IrFunctionSymbol): Boolean = function.descriptor.isExpect

    override fun isSuspend(functionSymbol: IrFunctionSymbol): Boolean = functionSymbol.descriptor.isSuspend
    override fun getVisibility(function: IrFunctionSymbol): DescriptorVisibility = function.descriptor.visibility

    override fun findPrimaryConstructor(clazz: IrClassSymbol) = clazz.descriptor.unsubstitutedPrimaryConstructor?.let { symbolTable.descriptorExtension.referenceConstructor(it) }
    override fun findNoParametersConstructor(clazz: IrClassSymbol) = clazz.descriptor.constructors.singleOrNull { it.valueParameters.size == 0 }?.let { symbolTable.descriptorExtension.referenceConstructor(it) }

    override fun findNestedClass(clazz: IrClassSymbol, name: Name): IrClassSymbol? {
        val classDescriptor = clazz.descriptor.defaultType.memberScope.getContributedClassifier(name, NoLookupLocation.FROM_BUILTINS) as? ClassDescriptor
        return classDescriptor?.let {
            symbolTable.descriptorExtension.referenceClass(it)
        }
    }

    override fun getValueParameterPrimitiveBinaryType(function: IrFunctionSymbol, index: Int): PrimitiveBinaryType? {
        return function.descriptor.valueParameters[0].type.computePrimitiveBinaryTypeOrNull()
    }
}

internal class SymbolOverIrLookupUtils() : SymbolLookupUtils {
    override fun findMemberFunction(clazz: IrClassSymbol, name: Name): IrSimpleFunctionSymbol? =
            clazz.owner.findDeclaration { it.name == name }?.symbol

    override fun findMemberProperty(clazz: IrClassSymbol, name: Name): IrPropertySymbol? =
            clazz.owner.findDeclaration { it.name == name }?.symbol

    override fun findMemberPropertyGetter(clazz: IrClassSymbol, name: Name): IrSimpleFunctionSymbol? =
            clazz.owner.findDeclaration { it.name == name }?.getter?.symbol

    override fun findPrimaryConstructor(clazz: IrClassSymbol): IrConstructorSymbol? = clazz.owner.primaryConstructor?.symbol
    override fun findNoParametersConstructor(clazz: IrClassSymbol): IrConstructorSymbol? = clazz.owner.constructors.singleOrNull { it.valueParameters.isEmpty() }?.symbol

    override fun findNestedClass(clazz: IrClassSymbol, name: Name): IrClassSymbol? {
        return clazz.owner.declarations.filterIsInstance().singleOrNull { it.name == name }?.symbol
    }

    override fun getName(clazz: IrClassSymbol): Name = clazz.owner.name

    override fun isExtensionReceiverClass(property: IrPropertySymbol, expected: IrClassSymbol?): Boolean {
        return property.owner.getter?.extensionReceiverParameter?.type?.classOrNull == expected
    }

    override fun isExtensionReceiverClass(function: IrFunctionSymbol, expected: IrClassSymbol?): Boolean {
        return function.owner.extensionReceiverParameter?.type?.classOrNull == expected
    }

    override fun findGetter(property: IrPropertySymbol): IrSimpleFunctionSymbol? = property.owner.getter?.symbol

    override fun isExtensionReceiverNullable(function: IrFunctionSymbol): Boolean? {
        return function.owner.extensionReceiverParameter?.type?.isMarkedNullable()
    }

    override fun getValueParametersCount(function: IrFunctionSymbol): Int = function.owner.valueParameters.size

    override fun getTypeParametersCount(function: IrFunctionSymbol): Int = function.owner.typeParameters.size

    override fun isTypeParameterUpperBoundClass(property: IrPropertySymbol, index: Int, expected: IrClassSymbol): Boolean {
        return property.owner.getter?.typeParameters?.getOrNull(index)?.superTypes?.any { it.classOrNull == expected } ?: false
    }

    override fun isValueParameterClass(function: IrFunctionSymbol, index: Int, expected: IrClassSymbol?): Boolean {
        return function.owner.valueParameters.getOrNull(index)?.type?.classOrNull == expected
    }

    override fun isReturnClass(function: IrFunctionSymbol, expected: IrClassSymbol): Boolean {
        return function.owner.returnType.classOrNull == expected
    }

    override fun isValueParameterTypeArgumentClass(function: IrFunctionSymbol, index: Int, argumentIndex: Int, expected: IrClassSymbol?): Boolean {
        val type = function.owner.valueParameters.getOrNull(index)?.type as? IrSimpleType ?: return false
        val argumentType = type.arguments.getOrNull(argumentIndex) as? IrSimpleType ?: return false
        return argumentType.classOrNull == expected
    }

    override fun isValueParameterNullable(function: IrFunctionSymbol, index: Int): Boolean? {
        return function.owner.valueParameters.getOrNull(index)?.type?.isMarkedNullable()
    }

    override fun isExpect(function: IrFunctionSymbol): Boolean = function.owner.isExpect

    override fun isSuspend(functionSymbol: IrFunctionSymbol): Boolean = functionSymbol.owner.isSuspend
    override fun getVisibility(function: IrFunctionSymbol): DescriptorVisibility = function.owner.visibility

    override fun getValueParameterPrimitiveBinaryType(function: IrFunctionSymbol, index: Int): PrimitiveBinaryType? {
        return function.owner.valueParameters[0].type.computePrimitiveBinaryTypeOrNull()
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy