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

org.jetbrains.kotlin.load.kotlin.UnsafeVarianceTypeSubstitution.kt Maven / Gradle / Ivy

There is a newer version: 2.0.0
Show newest version
/*
 * Copyright 2010-2016 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.load.kotlin

import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.descriptors.annotations.AnnotationsImpl
import org.jetbrains.kotlin.descriptors.annotations.composeAnnotations
import org.jetbrains.kotlin.descriptors.annotations.createUnsafeVarianceAnnotation
import org.jetbrains.kotlin.types.*

internal class UnsafeVarianceTypeSubstitution(kotlinBuiltIns: KotlinBuiltIns) : TypeSubstitution() {
    private val unsafeVarianceAnnotations = AnnotationsImpl(listOf(kotlinBuiltIns.createUnsafeVarianceAnnotation()))

    override fun get(key: KotlinType) = null

    override fun prepareTopLevelType(topLevelType: KotlinType, position: Variance): KotlinType {
        val unsafeVariancePaths = mutableListOf>()
        IndexedTypeHolder(topLevelType).checkTypePosition(
                position,
                { _, indexedTypeHolder, _ ->
                    unsafeVariancePaths.add(indexedTypeHolder.argumentIndices)
                },
                customVariance = { null })

        return topLevelType.unwrap().annotatePartsWithUnsafeVariance(unsafeVariancePaths)
    }
    private fun UnwrappedType.annotatePartsWithUnsafeVariance(unsafeVariancePaths: Collection>): UnwrappedType {
        if (unsafeVariancePaths.isEmpty()) return this
        return when (this) {
            is FlexibleType ->
                KotlinTypeFactory.flexibleType(
                        lowerBound.annotatePartsWithUnsafeVariance(subPathsWithIndex(unsafeVariancePaths, 0)),
                        upperBound.annotatePartsWithUnsafeVariance(subPathsWithIndex(unsafeVariancePaths, 1)))
            is SimpleType -> annotatePartsWithUnsafeVariance(unsafeVariancePaths)
        }
    }

    private fun SimpleType.annotatePartsWithUnsafeVariance(unsafeVariancePaths: Collection>): SimpleType {
        if (unsafeVariancePaths.isEmpty()) return this

        // if root is unsafe
        if (emptyList() in unsafeVariancePaths) {
            return replaceAnnotations(composeAnnotations(annotations, unsafeVarianceAnnotations))
        }

        return replace(newArguments = arguments.withIndex().map {
                    val (index, argument) = it
                    if (argument.isStarProjection) return@map argument
            TypeProjectionImpl(
                    argument.projectionKind,
                    argument.type.unwrap().annotatePartsWithUnsafeVariance(subPathsWithIndex(unsafeVariancePaths, index)))
                })
    }

    private fun subPathsWithIndex(paths: Collection>, index: Int) = paths.filter { it[0] == index }.map { it.subList(1, it.size) }

    private class IndexedTypeHolder(
            override val type: KotlinType,
            val argumentIndices: List = emptyList()
    ) : TypeHolder {
        override val flexibleBounds: Pair? get() =
            if (type.isFlexible())
                Pair(
                        IndexedTypeHolder(type.lowerIfFlexible(), argumentIndices + 0),
                        IndexedTypeHolder(type.upperIfFlexible(), argumentIndices + 1))
            else null

        override val arguments: List>
            get() = type.arguments.withIndex().map { projectionWithIndex ->

                val (index, projection) = projectionWithIndex
                object : TypeHolderArgument {
                    override val projection: TypeProjection
                        get() = projection
                    override val typeParameter: TypeParameterDescriptor?
                        get() = type.constructor.parameters[index]
                    override val holder: IndexedTypeHolder
                        get() = IndexedTypeHolder(projection.type, argumentIndices + index)

                }
            }

    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy