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

org.jetbrains.kotlin.resolve.calls.model.ResolutionCandidate.kt Maven / Gradle / Ivy

There is a newer version: 2.0.0
Show newest version
/*
 * Copyright 2010-2017 JetBrains s.r.o.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.jetbrains.kotlin.resolve.calls.model

import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.renderer.DescriptorRenderer
import org.jetbrains.kotlin.resolve.calls.components.*
import org.jetbrains.kotlin.resolve.calls.inference.NewConstraintSystem
import org.jetbrains.kotlin.resolve.calls.inference.components.FreshVariableNewTypeSubstitutor
import org.jetbrains.kotlin.resolve.calls.inference.components.NewTypeSubstitutor
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintSystemError
import org.jetbrains.kotlin.resolve.calls.inference.model.LowerPriorityToPreserveCompatibility
import org.jetbrains.kotlin.resolve.calls.inference.model.NewConstraintSystemImpl
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
import org.jetbrains.kotlin.resolve.calls.tower.*
import org.jetbrains.kotlin.resolve.constants.IntegerValueTypeConstant
import org.jetbrains.kotlin.types.TypeSubstitutor
import org.jetbrains.kotlin.types.UnwrappedType
import org.jetbrains.kotlin.utils.SmartList


abstract class ResolutionPart {
    abstract fun KotlinResolutionCandidate.process(workIndex: Int)

    open fun KotlinResolutionCandidate.workCount(): Int = 1

    // helper functions
    protected inline val KotlinResolutionCandidate.candidateDescriptor get() = resolvedCall.candidateDescriptor
    protected inline val KotlinResolutionCandidate.kotlinCall get() = resolvedCall.atom
}

interface KotlinDiagnosticsHolder {
    fun addDiagnostic(diagnostic: KotlinCallDiagnostic)

    class SimpleHolder : KotlinDiagnosticsHolder {
        private val diagnostics = arrayListOf()

        override fun addDiagnostic(diagnostic: KotlinCallDiagnostic) {
            diagnostics.add(diagnostic)
        }

        fun getDiagnostics(): List = diagnostics
    }
}

fun KotlinDiagnosticsHolder.addDiagnosticIfNotNull(diagnostic: KotlinCallDiagnostic?) {
    diagnostic?.let { addDiagnostic(it) }
}

fun KotlinDiagnosticsHolder.addError(error: ConstraintSystemError) {
    addDiagnostic(error.asDiagnostic())
}

/**
 * baseSystem contains all information from arguments, i.e. it is union of all system of arguments
 * Also by convention we suppose that baseSystem has no contradiction
 */
class KotlinResolutionCandidate(
    val callComponents: KotlinCallComponents,
    val resolutionCallbacks: KotlinResolutionCallbacks,
    val callableReferenceResolver: CallableReferenceResolver,
    val scopeTower: ImplicitScopeTower,
    private val baseSystem: ConstraintStorage,
    val resolvedCall: MutableResolvedCallAtom,
    val knownTypeParametersResultingSubstitutor: TypeSubstitutor? = null,
    private val resolutionSequence: List = resolvedCall.atom.callKind.resolutionSequence
) : Candidate, KotlinDiagnosticsHolder {
    val diagnosticsFromResolutionParts = arrayListOf() // TODO: this is mutable list, take diagnostics only once!
    private var newSystem: NewConstraintSystemImpl? = null
    private var currentApplicability = CandidateApplicability.RESOLVED
    private var subResolvedAtoms: MutableList = arrayListOf()

    private val stepCount = resolutionSequence.sumBy { it.run { workCount() } }
    private var step = 0

    fun getSystem(): NewConstraintSystem {
        if (newSystem == null) {
            newSystem = NewConstraintSystemImpl(callComponents.constraintInjector, callComponents.builtIns)
            newSystem!!.addOtherSystem(baseSystem)
        }
        return newSystem!!
    }

    internal val csBuilder get() = getSystem().getBuilder()

    override fun addDiagnostic(diagnostic: KotlinCallDiagnostic) {
        diagnosticsFromResolutionParts.add(diagnostic)
        currentApplicability = minOf(diagnostic.candidateApplicability, currentApplicability)
    }

    fun getSubResolvedAtoms(): List = subResolvedAtoms

    fun addResolvedKtPrimitive(resolvedAtom: ResolvedAtom) {
        subResolvedAtoms.add(resolvedAtom)
    }

    private fun processParts(stopOnFirstError: Boolean) {
        if (stopOnFirstError && step > 0) return // error already happened
        if (step == stepCount) return

        var partIndex = 0
        var workStep = step
        while (workStep > 0) {
            val workCount = resolutionSequence[partIndex].run { workCount() }
            if (workStep >= workCount) {
                partIndex++
                workStep -= workCount
            } else {
                break
            }
        }
        if (partIndex < resolutionSequence.size) {
            if (processPart(resolutionSequence[partIndex], stopOnFirstError, workStep)) return
            partIndex++
        }

        while (partIndex < resolutionSequence.size) {
            if (processPart(resolutionSequence[partIndex], stopOnFirstError)) return
            partIndex++
        }
        if (step == stepCount) {
            resolvedCall.setAnalyzedResults(subResolvedAtoms)
        }
    }

    // true if part was interrupted
    private fun processPart(part: ResolutionPart, stopOnFirstError: Boolean, startWorkIndex: Int = 0): Boolean {
        for (workIndex in startWorkIndex until (part.run { workCount() })) {
            if (stopOnFirstError && !currentApplicability.isSuccess) return true

            part.run { process(workIndex) }
            step++
        }
        return false
    }

    val variableCandidateIfInvoke: KotlinResolutionCandidate?
        get() = callComponents.statelessCallbacks.getVariableCandidateIfInvoke(resolvedCall.atom)

    private val variableApplicability
        get() = variableCandidateIfInvoke?.resultingApplicability ?: CandidateApplicability.RESOLVED

    override val isSuccessful: Boolean
        get() {
            processParts(stopOnFirstError = true)
            return currentApplicability.isSuccess && variableApplicability.isSuccess && !getSystem().hasContradiction
        }

    override val resultingApplicability: CandidateApplicability
        get() {
            processParts(stopOnFirstError = false)

            val systemApplicability = getResultApplicability(getSystem().errors)
            return minOf(currentApplicability, systemApplicability, variableApplicability)
        }

    override fun addCompatibilityWarning(other: Candidate) {
        if (this !== other && other is KotlinResolutionCandidate) {
            addDiagnostic(CompatibilityWarning(other.resolvedCall.candidateDescriptor))
        }
    }

    override fun toString(): String {
        val descriptor = DescriptorRenderer.COMPACT.render(resolvedCall.candidateDescriptor)
        val okOrFail = if (currentApplicability.isSuccess) "OK" else "FAIL"
        val step = "$step/$stepCount"
        return "$okOrFail($step): $descriptor"
    }
}

class MutableResolvedCallAtom(
    override val atom: KotlinCall,
    override val candidateDescriptor: CallableDescriptor, // original candidate descriptor
    override val explicitReceiverKind: ExplicitReceiverKind,
    override val dispatchReceiverArgument: SimpleKotlinCallArgument?,
    override val extensionReceiverArgument: SimpleKotlinCallArgument?
) : ResolvedCallAtom() {
    override lateinit var typeArgumentMappingByOriginal: TypeArgumentsToParametersMapper.TypeArgumentsMapping
    override lateinit var argumentMappingByOriginal: Map
    override lateinit var freshVariablesSubstitutor: FreshVariableNewTypeSubstitutor
    override lateinit var knownParametersSubstitutor: NewTypeSubstitutor
    lateinit var argumentToCandidateParameter: Map
    private var samAdapterMap: HashMap? = null
    private var suspendAdapterMap: HashMap? = null
    private var unitAdapterMap: HashMap? = null
    private var signedUnsignedConstantConversions: HashMap? = null

    val hasSamConversion: Boolean
        get() = samAdapterMap != null

    val hasSuspendConversion: Boolean
        get() = suspendAdapterMap != null

    override val argumentsWithConversion: Map
        get() = samAdapterMap ?: emptyMap()

    override val argumentsWithSuspendConversion: Map
        get() = suspendAdapterMap ?: emptyMap()

    override val argumentsWithUnitConversion: Map
        get() = unitAdapterMap ?: emptyMap()

    override val argumentsWithConstantConversion: Map
        get() = signedUnsignedConstantConversions ?: emptyMap()

    fun registerArgumentWithSamConversion(argument: KotlinCallArgument, samConversionDescription: SamConversionDescription) {
        if (samAdapterMap == null)
            samAdapterMap = hashMapOf()

        samAdapterMap!![argument] = samConversionDescription
    }

    fun registerArgumentWithSuspendConversion(argument: KotlinCallArgument, convertedType: UnwrappedType) {
        if (suspendAdapterMap == null)
            suspendAdapterMap = hashMapOf()

        suspendAdapterMap!![argument] = convertedType
    }

    fun registerArgumentWithUnitConversion(argument: KotlinCallArgument, convertedType: UnwrappedType) {
        if (unitAdapterMap == null)
            unitAdapterMap = hashMapOf()

        unitAdapterMap!![argument] = convertedType
    }

    fun registerArgumentWithConstantConversion(argument: KotlinCallArgument, convertedConstant: IntegerValueTypeConstant) {
        if (signedUnsignedConstantConversions == null)
            signedUnsignedConstantConversions = hashMapOf()

        signedUnsignedConstantConversions!![argument] = convertedConstant
    }


    override public fun setAnalyzedResults(subResolvedAtoms: List) {
        super.setAnalyzedResults(subResolvedAtoms)
    }

    override fun toString(): String = "$atom, candidate = $candidateDescriptor"
}

fun KotlinResolutionCandidate.markCandidateForCompatibilityResolve() {
    if (callComponents.languageVersionSettings.supportsFeature(LanguageFeature.DisableCompatibilityModeForNewInference)) return
    addDiagnostic(LowerPriorityToPreserveCompatibility.asDiagnostic())
}

fun CallableReferencesCandidateFactory.markCandidateForCompatibilityResolve(diagnostics: SmartList) {
    if (callComponents.languageVersionSettings.supportsFeature(LanguageFeature.DisableCompatibilityModeForNewInference)) return
    diagnostics.add(LowerPriorityToPreserveCompatibility.asDiagnostic())
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy