summaryrefslogtreecommitdiff
path: root/plugins/kotlin/fir-fe10-binding/src/org/jetbrains/kotlin/idea/fir/fe10/KtSymbolBasedKotlinTypes.kt
blob: 12a3d9f7662f5bcf7151b5eb07bb88f8c59afe8f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.

package org.jetbrains.kotlin.idea.fir.fe10

import org.jetbrains.kotlin.builtins.DefaultBuiltIns
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.analysis.api.KtStarProjectionTypeArgument
import org.jetbrains.kotlin.analysis.api.KtTypeArgument
import org.jetbrains.kotlin.analysis.api.KtTypeArgumentWithVariance
import org.jetbrains.kotlin.analysis.api.annotations.annotations
import org.jetbrains.kotlin.analysis.api.symbols.KtAnonymousObjectSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtNamedClassOrObjectSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtTypeAliasSymbol
import org.jetbrains.kotlin.analysis.api.types.*
import org.jetbrains.kotlin.incremental.components.LookupLocation
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.error.ErrorUtils
import org.jetbrains.kotlin.types.error.ErrorTypeKind
import org.jetbrains.kotlin.types.checker.KotlinTypeRefiner
import org.jetbrains.kotlin.utils.Printer
import org.jetbrains.kotlin.utils.addToStdlib.safeAs

abstract class KtSymbolBasedAbstractTypeConstructor<T> internal constructor(
    val ktSBDescriptor: T
) : ClassifierBasedTypeConstructor() where T : KtSymbolBasedDeclarationDescriptor, T : ClassifierDescriptor {
    override fun getDeclarationDescriptor(): ClassifierDescriptor = ktSBDescriptor

    // TODO: captured types
    override fun isDenotable(): Boolean = true

    // for Intention|inspection it shouldn't be important what to use.
    override fun getBuiltIns(): KotlinBuiltIns = DefaultBuiltIns.Instance

    // I don't think that we need to implement this method
    override fun isFinal(): Boolean = ktSBDescriptor.context.implementationPostponed("ktSBDescriptor = $ktSBDescriptor")

    @TypeRefinement
    override fun refine(kotlinTypeRefiner: KotlinTypeRefiner): TypeConstructor =
        ktSBDescriptor.context.noImplementation("ktSBDescriptor = $ktSBDescriptor")
}

class KtSymbolBasedClassTypeConstructor(ktSBDescriptor: KtSymbolBasedClassDescriptor) :
    KtSymbolBasedAbstractTypeConstructor<KtSymbolBasedClassDescriptor>(ktSBDescriptor) {
    override fun getParameters(): List<TypeParameterDescriptor> =
        ktSBDescriptor.ktSymbol.typeParameters.map { KtSymbolBasedTypeParameterDescriptor(it, ktSBDescriptor.context) }

    override fun getSupertypes(): Collection<KotlinType> =
        ktSBDescriptor.ktSymbol.superTypes.map { it.toKotlinType(ktSBDescriptor.context) }

    override fun isSameClassifier(classifier: ClassifierDescriptor): Boolean {
        return classifier is ClassDescriptor && areFqNamesEqual(declarationDescriptor, classifier)
    }

    override fun toString() = DescriptorUtils.getFqName(ktSBDescriptor).asString()
}

class KtSymbolBasedTypeParameterTypeConstructor(ktSBDescriptor: KtSymbolBasedTypeParameterDescriptor) :
    KtSymbolBasedAbstractTypeConstructor<KtSymbolBasedTypeParameterDescriptor>(ktSBDescriptor) {
    override fun getParameters(): List<TypeParameterDescriptor> = emptyList()

    override fun getSupertypes(): Collection<KotlinType> =
        ktSBDescriptor.ktSymbol.upperBounds.map { it.toKotlinType(ktSBDescriptor.context) }

    // TODO overrides: see AbstractTypeParameterDescriptor.TypeParameterTypeConstructor.isSameClassifier
    override fun isSameClassifier(classifier: ClassifierDescriptor): Boolean = ktSBDescriptor == classifier

    override fun toString(): String = ktSBDescriptor.name.asString()
}

// This class is not suppose to be used as "is instance of" because scopes could be wrapped into other scopes
// so generally it isn't a good idea
internal class MemberScopeForKtSymbolBasedDescriptors(lazyDebugInfo: () -> String) : MemberScope {
    private val additionalInfo by lazy(lazyDebugInfo)

    private fun noImplementation(): Nothing =
        error("Scope for descriptors based on KtSymbols should not be used, additional info: $additionalInfo")

    override fun getContributedVariables(name: Name, location: LookupLocation): Collection<PropertyDescriptor> = noImplementation()
    override fun getContributedFunctions(name: Name, location: LookupLocation): Collection<SimpleFunctionDescriptor> = noImplementation()
    override fun getFunctionNames(): Set<Name> = noImplementation()
    override fun getVariableNames(): Set<Name> = noImplementation()
    override fun getClassifierNames(): Set<Name> = noImplementation()
    override fun printScopeStructure(p: Printer): Unit = noImplementation()
    override fun getContributedClassifier(name: Name, location: LookupLocation): ClassifierDescriptor = noImplementation()

    override fun getContributedDescriptors(
        kindFilter: DescriptorKindFilter,
        nameFilter: (Name) -> Boolean
    ): Collection<DeclarationDescriptor> = noImplementation()
}

fun KtType.getDescriptorsAnnotations(context: FE10BindingContext): Annotations =
    Annotations.create(annotations.map { KtSymbolBasedAnnotationDescriptor(it, context) })

fun KtTypeArgument.toTypeProjection(context: FE10BindingContext): TypeProjection =
    when (this) {
        is KtStarProjectionTypeArgument -> StarProjectionForAbsentTypeParameter(context.builtIns)
        is KtTypeArgumentWithVariance -> TypeProjectionImpl(variance, type.toKotlinType(context))
    }

fun KtType.toKotlinType(context: FE10BindingContext, annotations: Annotations = getDescriptorsAnnotations(context)): UnwrappedType {
    val typeConstructor: TypeConstructor = when (this) {
        is KtTypeParameterType -> KtSymbolBasedTypeParameterDescriptor(this.symbol, context).typeConstructor
        is KtNonErrorClassType -> when (val classLikeSymbol = classSymbol) {
            is KtTypeAliasSymbol -> context.typeAliasImplementationPlanned()
            is KtNamedClassOrObjectSymbol -> KtSymbolBasedClassDescriptor(classLikeSymbol, context).typeConstructor
            is KtAnonymousObjectSymbol -> context.implementationPostponed()
        }
        is KtClassErrorType -> ErrorUtils.createErrorTypeConstructor(ErrorTypeKind.TYPE_FOR_ERROR_TYPE_CONSTRUCTOR, error)
        is KtFlexibleType -> {
            return KotlinTypeFactory.flexibleType(
                lowerBound.toKotlinType(context, annotations) as SimpleType,
                upperBound.toKotlinType(context, annotations) as SimpleType
            )
        }

        is KtIntersectionType -> {
            // most likely it isn't correct and intersectTypes(List<UnwrappedType>) should be used,
            // but I don't think that we will have the real problem with that implementation
            return IntersectionTypeConstructor(conjuncts.map { it.toKotlinType(context) }).createType()
        }
        else -> error("Unexpected subclass: ${this.javaClass}")
    }

    val ktTypeArguments = this.safeAs<KtNonErrorClassType>()?.typeArguments ?: emptyList()

    val markedAsNullable = this.nullability == KtTypeNullability.NULLABLE

    return KotlinTypeFactory.simpleTypeWithNonTrivialMemberScope(
        annotations.toDefaultAttributes(), typeConstructor, ktTypeArguments.map { it.toTypeProjection(context) }, markedAsNullable,
        MemberScopeForKtSymbolBasedDescriptors { this.asStringForDebugging() }
    )
}