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

org.jetbrains.kotlin.ir.overrides.IrOverrideChecker.kt Maven / Gradle / Ivy

There is a newer version: 2.1.20-Beta1
Show newest version
/*
 * Copyright 2010-2023 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.overrides

import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.overrides.IrExternalOverridabilityCondition.Contract.CONFLICTS_ONLY
import org.jetbrains.kotlin.ir.overrides.IrExternalOverridabilityCondition.Contract.SUCCESS_ONLY
import org.jetbrains.kotlin.ir.overrides.IrExternalOverridabilityCondition.Result.*
import org.jetbrains.kotlin.ir.types.IrTypeSystemContext
import org.jetbrains.kotlin.ir.types.IrTypeSystemContextWithAdditionalAxioms
import org.jetbrains.kotlin.ir.types.createIrTypeCheckerState
import org.jetbrains.kotlin.resolve.OverridingUtil.OverrideCompatibilityInfo
import org.jetbrains.kotlin.resolve.OverridingUtil.OverrideCompatibilityInfo.*
import org.jetbrains.kotlin.types.AbstractTypeChecker
import org.jetbrains.kotlin.types.TypeCheckerState

class IrOverrideChecker(
    private val typeSystem: IrTypeSystemContext,
    private val externalOverridabilityConditions: List,
) {
    fun getBothWaysOverridability(
        overriderDescriptor: IrOverridableMember,
        candidateDescriptor: IrOverridableMember,
    ): Result {
        val result1 = isOverridableBy(
            candidateDescriptor,
            overriderDescriptor,
            checkIsInlineFlag = false,
        ).result

        val result2 = isOverridableBy(
            overriderDescriptor,
            candidateDescriptor,
            checkIsInlineFlag = false,
        ).result

        return if (result1 == result2) result1 else Result.INCOMPATIBLE
    }

    fun isOverridableBy(
        superMember: IrOverridableMember,
        subMember: IrOverridableMember,
        checkIsInlineFlag: Boolean,
    ): OverrideCompatibilityInfo {
        val basicResult = isOverridableByWithoutExternalConditions(superMember, subMember, checkIsInlineFlag)

        return runExternalOverridabilityConditions(superMember, subMember, basicResult)
    }

    private fun isOverridableByWithoutExternalConditions(
        superMember: IrOverridableMember,
        subMember: IrOverridableMember,
        checkIsInlineFlag: Boolean,
    ): OverrideCompatibilityInfo {
        val superTypeParameters: List
        val subTypeParameters: List

        val superValueParameters: List
        val subValueParameters: List

        when (superMember) {
            is IrSimpleFunction -> when {
                subMember !is IrSimpleFunction -> return incompatible("Member kind mismatch")
                superMember.hasExtensionReceiver != subMember.hasExtensionReceiver -> return incompatible("Receiver presence mismatch")
                superMember.isSuspend != subMember.isSuspend -> return incompatible("Incompatible suspendability")
                checkIsInlineFlag && superMember.isInline -> return incompatible("Inline function can't be overridden")

                else -> {
                    superTypeParameters = superMember.typeParameters
                    subTypeParameters = subMember.typeParameters
                    superValueParameters = superMember.compiledValueParameters
                    subValueParameters = subMember.compiledValueParameters
                }
            }
            is IrProperty -> when {
                subMember !is IrProperty -> return incompatible("Member kind mismatch")
                superMember.getter.hasExtensionReceiver != subMember.getter.hasExtensionReceiver -> return incompatible("Receiver presence mismatch")
                checkIsInlineFlag && superMember.isInline -> return incompatible("Inline property can't be overridden")

                else -> {
                    superTypeParameters = superMember.typeParameters
                    subTypeParameters = subMember.typeParameters
                    superValueParameters = superMember.compiledValueParameters
                    subValueParameters = subMember.compiledValueParameters
                }
            }
            else -> error("Unexpected type of declaration: ${superMember::class.java}, $superMember")
        }

        when {
            superMember.name != subMember.name -> {
                // Check name after member kind checks. This way FO builder will first check types of overridable members and crash
                // if member types are not supported (ex: IrConstructor).
                return incompatible("Name mismatch")
            }

            superTypeParameters.size != subTypeParameters.size -> return incompatible("Type parameter number mismatch")
            superValueParameters.size != subValueParameters.size -> return incompatible("Value parameter number mismatch")
        }

        val typeCheckerState = createIrTypeCheckerState(
            IrTypeSystemContextWithAdditionalAxioms(typeSystem, superTypeParameters, subTypeParameters)
        )

        for ((index, superTypeParameter) in superTypeParameters.withIndex()) {
            if (!areTypeParametersEquivalent(superTypeParameter, subTypeParameters[index], typeCheckerState)) {
                return incompatible("Type parameter bounds mismatch")
            }
        }

        for ((index, superValueParameter) in superValueParameters.withIndex()) {
            if (!AbstractTypeChecker.equalTypes(typeCheckerState, subValueParameters[index].type, superValueParameter.type)) {
                return incompatible("Value parameter type mismatch")
            }
        }

        return success()
    }

    private fun areTypeParametersEquivalent(
        superTypeParameter: IrTypeParameter,
        subTypeParameter: IrTypeParameter,
        typeCheckerState: TypeCheckerState,
    ): Boolean {
        val superBounds = superTypeParameter.superTypes
        val subBounds = subTypeParameter.superTypes.toMutableList()
        if (superBounds.size != subBounds.size) return false
        outer@ for (superBound in superBounds) {
            val it = subBounds.listIterator()
            while (it.hasNext()) {
                val subBound = it.next()
                if (AbstractTypeChecker.equalTypes(typeCheckerState, superBound, subBound)) {
                    it.remove()
                    continue@outer
                }
            }
            return false
        }
        return true
    }


    private fun runExternalOverridabilityConditions(
        superMember: IrOverridableMember,
        subMember: IrOverridableMember,
        basicResult: OverrideCompatibilityInfo,
    ): OverrideCompatibilityInfo {
        var wasSuccess = basicResult.result == OverrideCompatibilityInfo.Result.OVERRIDABLE

        for (externalCondition in externalOverridabilityConditions) {
            // Do not run CONFLICTS_ONLY while there was no success
            if (externalCondition.contract == CONFLICTS_ONLY) continue
            if (wasSuccess && externalCondition.contract == SUCCESS_ONLY) continue
            val result =
                externalCondition.isOverridable(superMember, subMember)
            when (result) {
                OVERRIDABLE -> wasSuccess = true
                INCOMPATIBLE -> return incompatible("External condition")
                UNKNOWN -> {}
            }
        }

        if (!wasSuccess) return basicResult

        // Search for conflicts from external conditions
        for (externalCondition in externalOverridabilityConditions) {
            // Run all conditions that was not run before (i.e. CONFLICTS_ONLY)
            if (externalCondition.contract != CONFLICTS_ONLY) continue
            val result =
                externalCondition.isOverridable(superMember, subMember)
            when (result) {
                INCOMPATIBLE -> return incompatible("External condition")
                OVERRIDABLE -> error(
                    "Contract violation in ${externalCondition.javaClass} condition. It's not supposed to end with success"
                )
                UNKNOWN -> {}
            }
        }

        return success()
    }
}

private val IrSimpleFunction?.hasExtensionReceiver: Boolean
    get() = this?.extensionReceiverParameter != null

internal val IrSimpleFunction?.hasDispatchReceiver: Boolean
    get() = this?.dispatchReceiverParameter != null

private val IrSimpleFunction.compiledValueParameters: List
    get() = ArrayList(valueParameters.size + 1).apply {
        extensionReceiverParameter?.let(::add)
        addAll(valueParameters)
    }

private val IrProperty.compiledValueParameters: List
    get() = getter?.extensionReceiverParameter?.let(::listOf).orEmpty()

private val IrProperty.typeParameters: List
    get() = getter?.typeParameters.orEmpty()

private val IrProperty.isInline: Boolean
    get() = getter?.isInline == true || setter?.isInline == true




© 2015 - 2025 Weber Informatics LLC | Privacy Policy