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

org.jetbrains.kotlin.resolve.calls.tower.TowerResolver.kt Maven / Gradle / Ivy

There is a newer version: 2.1.0-Beta1
Show newest version
/*
 * Copyright 2010-2015 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.tower

import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
import org.jetbrains.kotlin.utils.addToStdlib.check

interface TowerContext {
    val name: Name
    val scopeTower: ScopeTower

    fun createCandidate(
            towerCandidate: CandidateWithBoundDispatchReceiver<*>,
            explicitReceiverKind: ExplicitReceiverKind,
            extensionReceiver: ReceiverValue?
    ): C

    fun getStatus(candidate: C): ResolutionCandidateStatus

    fun transformCandidate(variable: C, invoke: C): C

    fun contextForVariable(stripExplicitReceiver: Boolean): TowerContext

    // foo() -> ReceiverValue(foo), context for invoke
    fun contextForInvoke(variable: C, useExplicitReceiver: Boolean): Pair>
}

internal interface ScopeTowerProcessor {

    fun processTowerLevel(level: ScopeTowerLevel)
    fun processImplicitReceiver(implicitReceiver: ReceiverValue)

    // Candidates with matched receivers (dispatch receiver was already matched in ScopeTowerLevel)
    // Candidates in one groups have same priority, first group has highest priority.
    fun getCandidatesGroups(): List>
}

class TowerResolver {
    internal fun  runResolve(
            context: TowerContext,
            processor: ScopeTowerProcessor,
            useOrder: Boolean = true
    ): Collection {

        val resultCollector = ResultCollector { context.getStatus(it) }

        fun collectCandidates(action: ScopeTowerProcessor.() -> Unit): Collection? {
            processor.action()
            val candidatesGroups = if (useOrder) {
                    processor.getCandidatesGroups()
                }
                else {
                    listOf(processor.getCandidatesGroups().flatMap { it })
                }

            for (candidatesGroup in candidatesGroups) {
                resultCollector.pushCandidates(candidatesGroup)
                resultCollector.getResolved()?.let { return it }
            }
            return null
        }

        // possible there is explicit member
        collectCandidates { /* do nothing */ }?.let { return it }

        for (level in context.scopeTower.levels) {
            collectCandidates { processTowerLevel(level) }?.let { return it }

            for (implicitReceiver in context.scopeTower.implicitReceivers) {
                collectCandidates { processImplicitReceiver(implicitReceiver) }?.let { return it }
            }
        }

        return resultCollector.getFinalCandidates()
    }


    //todo collect all candidates
    internal class ResultCollector(private val getStatus: (C) -> ResolutionCandidateStatus) {
        private var currentCandidates: Collection = emptyList()
        private var currentLevel: ResolutionCandidateApplicability? = null

        fun getResolved() = currentCandidates.check { currentLevel == ResolutionCandidateApplicability.RESOLVED }

        fun getSyntheticResolved() = currentCandidates.check { currentLevel == ResolutionCandidateApplicability.RESOLVED_SYNTHESIZED }

        fun getErrors() = currentCandidates.check {
            currentLevel == null || currentLevel!! > ResolutionCandidateApplicability.RESOLVED_SYNTHESIZED
        }

        fun getFinalCandidates() = getResolved() ?: getSyntheticResolved() ?: getErrors() ?: emptyList()

        fun pushCandidates(candidates: Collection) {
            if (candidates.isEmpty()) return
            val minimalLevel = candidates.map { getStatus(it).resultingApplicability }.min()!!
            if (currentLevel == null || currentLevel!! > minimalLevel) {
                currentLevel = minimalLevel
                currentCandidates = candidates.filter { getStatus(it).resultingApplicability == minimalLevel }
            }
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy