[FIR] Split :compiler:fir:resolve module into three different modules
Those modules are:
- :compiler:fir:providers, which contains Fir and Symbol providers,
scopes, and different utilities used by them
- :compiler:fir:semantics, which contains different abstractions and
entities which are used in resolution and in checkers
- :compiler:fir:resolve, which contains all stuff related to resolution
and inference
There are two pros of this change:
1. It may increase gradle build, because it allows to compile :fir:resolve
and :fir:checkers modules in parallel
2. Logic of working FIR (scopes, providers, DFA logic system, etc) is
now separated from logic of resolution phases, so for example checkers,
which are depend on scopes physically will not be able to run resolve
in any way
This commit is contained in:
@@ -0,0 +1,20 @@
|
||||
plugins {
|
||||
kotlin("jvm")
|
||||
id("jps-compatible")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api(project(":core:compiler.common"))
|
||||
api(project(":compiler:resolution.common"))
|
||||
api(project(":compiler:fir:cones"))
|
||||
api(project(":compiler:fir:tree"))
|
||||
implementation(project(":core:util.runtime"))
|
||||
|
||||
compileOnly(project(":kotlin-reflect-api"))
|
||||
compileOnly(intellijCoreDep()) { includeJars("guava", rootProject = rootProject) }
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
"main" { projectDefault() }
|
||||
"test" { none() }
|
||||
}
|
||||
@@ -0,0 +1,217 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.fir
|
||||
|
||||
import org.jetbrains.kotlin.contracts.description.EventOccurrencesRange
|
||||
import org.jetbrains.kotlin.descriptors.EffectiveVisibility
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.descriptors.Visibility
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.declarations.builder.buildAnonymousFunction
|
||||
import org.jetbrains.kotlin.fir.declarations.builder.buildTypeParameter
|
||||
import org.jetbrains.kotlin.fir.declarations.impl.FirDeclarationStatusImpl
|
||||
import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic
|
||||
import org.jetbrains.kotlin.fir.expressions.*
|
||||
import org.jetbrains.kotlin.fir.expressions.builder.*
|
||||
import org.jetbrains.kotlin.fir.references.FirControlFlowGraphReference
|
||||
import org.jetbrains.kotlin.fir.references.FirNamedReference
|
||||
import org.jetbrains.kotlin.fir.references.FirReference
|
||||
import org.jetbrains.kotlin.fir.scopes.impl.FirIntegerOperatorCall
|
||||
import org.jetbrains.kotlin.fir.scopes.impl.FirIntegerOperatorCallBuilder
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.fir.types.builder.buildErrorTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
|
||||
|
||||
fun FirFunctionCall.copy(
|
||||
annotations: List<FirAnnotation> = this.annotations,
|
||||
argumentList: FirArgumentList = this.argumentList,
|
||||
calleeReference: FirNamedReference = this.calleeReference,
|
||||
explicitReceiver: FirExpression? = this.explicitReceiver,
|
||||
dispatchReceiver: FirExpression = this.dispatchReceiver,
|
||||
extensionReceiver: FirExpression = this.extensionReceiver,
|
||||
source: FirSourceElement? = this.source,
|
||||
typeArguments: List<FirTypeProjection> = this.typeArguments,
|
||||
resultType: FirTypeRef = this.typeRef
|
||||
): FirFunctionCall {
|
||||
val builder = if (this is FirIntegerOperatorCall) {
|
||||
FirIntegerOperatorCallBuilder().apply {
|
||||
this.calleeReference = calleeReference
|
||||
}
|
||||
} else {
|
||||
FirFunctionCallBuilder().apply {
|
||||
this.calleeReference = calleeReference
|
||||
}
|
||||
}
|
||||
builder.apply {
|
||||
this.source = source
|
||||
this.annotations.addAll(annotations)
|
||||
this.argumentList = argumentList
|
||||
this.explicitReceiver = explicitReceiver
|
||||
this.dispatchReceiver = dispatchReceiver
|
||||
this.extensionReceiver = extensionReceiver
|
||||
this.typeArguments.addAll(typeArguments)
|
||||
this.typeRef = resultType
|
||||
}
|
||||
return (builder as FirCallBuilder).build() as FirFunctionCall
|
||||
}
|
||||
|
||||
inline fun FirFunctionCall.copyAsImplicitInvokeCall(
|
||||
setupCopy: FirImplicitInvokeCallBuilder.() -> Unit
|
||||
): FirImplicitInvokeCall {
|
||||
val original = this
|
||||
|
||||
return buildImplicitInvokeCall {
|
||||
source = original.source
|
||||
annotations.addAll(original.annotations)
|
||||
typeArguments.addAll(original.typeArguments)
|
||||
explicitReceiver = original.explicitReceiver
|
||||
dispatchReceiver = original.dispatchReceiver
|
||||
extensionReceiver = original.extensionReceiver
|
||||
argumentList = original.argumentList
|
||||
calleeReference = original.calleeReference
|
||||
|
||||
setupCopy()
|
||||
}
|
||||
}
|
||||
|
||||
fun FirAnonymousFunction.copy(
|
||||
receiverTypeRef: FirTypeRef? = this.receiverTypeRef,
|
||||
source: FirSourceElement? = this.source,
|
||||
moduleData: FirModuleData = this.moduleData,
|
||||
origin: FirDeclarationOrigin = this.origin,
|
||||
returnTypeRef: FirTypeRef = this.returnTypeRef,
|
||||
valueParameters: List<FirValueParameter> = this.valueParameters,
|
||||
body: FirBlock? = this.body,
|
||||
annotations: List<FirAnnotation> = this.annotations,
|
||||
typeRef: FirTypeRef = this.typeRef,
|
||||
label: FirLabel? = this.label,
|
||||
controlFlowGraphReference: FirControlFlowGraphReference? = this.controlFlowGraphReference,
|
||||
invocationKind: EventOccurrencesRange? = this.invocationKind
|
||||
): FirAnonymousFunction {
|
||||
return buildAnonymousFunction {
|
||||
this.source = source
|
||||
this.moduleData = moduleData
|
||||
this.origin = origin
|
||||
this.returnTypeRef = returnTypeRef
|
||||
this.receiverTypeRef = receiverTypeRef
|
||||
symbol = this@copy.symbol
|
||||
isLambda = this@copy.isLambda
|
||||
this.valueParameters.addAll(valueParameters)
|
||||
this.body = body
|
||||
this.annotations.addAll(annotations)
|
||||
this.typeRef = typeRef
|
||||
this.label = label
|
||||
this.controlFlowGraphReference = controlFlowGraphReference
|
||||
this.invocationKind = invocationKind
|
||||
}
|
||||
}
|
||||
|
||||
fun FirTypeRef.resolvedTypeFromPrototype(
|
||||
type: ConeKotlinType
|
||||
): FirResolvedTypeRef {
|
||||
return if (type is ConeKotlinErrorType) {
|
||||
buildErrorTypeRef {
|
||||
source = this@resolvedTypeFromPrototype.source
|
||||
diagnostic = type.diagnostic
|
||||
}
|
||||
} else {
|
||||
buildResolvedTypeRef {
|
||||
source = this@resolvedTypeFromPrototype.source
|
||||
this.type = type
|
||||
annotations += this@resolvedTypeFromPrototype.annotations
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun FirTypeRef.errorTypeFromPrototype(
|
||||
diagnostic: ConeDiagnostic
|
||||
): FirErrorTypeRef {
|
||||
return buildErrorTypeRef {
|
||||
source = this@errorTypeFromPrototype.source
|
||||
this.diagnostic = diagnostic
|
||||
}
|
||||
}
|
||||
|
||||
fun FirTypeParameter.copy(
|
||||
bounds: List<FirTypeRef> = this.bounds,
|
||||
annotations: List<FirAnnotation> = this.annotations
|
||||
): FirTypeParameter {
|
||||
return buildTypeParameter {
|
||||
source = this@copy.source
|
||||
resolvePhase = this@copy.resolvePhase
|
||||
moduleData = this@copy.moduleData
|
||||
name = this@copy.name
|
||||
symbol = this@copy.symbol
|
||||
variance = this@copy.variance
|
||||
isReified = this@copy.isReified
|
||||
this.bounds += bounds
|
||||
this.annotations += annotations
|
||||
}
|
||||
}
|
||||
|
||||
fun FirWhenExpression.copy(
|
||||
resultType: FirTypeRef = this.typeRef,
|
||||
calleeReference: FirReference = this.calleeReference,
|
||||
annotations: List<FirAnnotation> = this.annotations
|
||||
): FirWhenExpression = buildWhenExpression {
|
||||
source = this@copy.source
|
||||
subject = this@copy.subject
|
||||
subjectVariable = this@copy.subjectVariable
|
||||
this.calleeReference = calleeReference
|
||||
branches += this@copy.branches
|
||||
typeRef = resultType
|
||||
this.annotations += annotations
|
||||
usedAsExpression = this@copy.usedAsExpression
|
||||
exhaustivenessStatus = this@copy.exhaustivenessStatus
|
||||
}
|
||||
|
||||
fun FirTryExpression.copy(
|
||||
resultType: FirTypeRef = this.typeRef,
|
||||
calleeReference: FirReference = this.calleeReference,
|
||||
annotations: List<FirAnnotation> = this.annotations
|
||||
): FirTryExpression = buildTryExpression {
|
||||
source = this@copy.source
|
||||
tryBlock = this@copy.tryBlock
|
||||
finallyBlock = this@copy.finallyBlock
|
||||
this.calleeReference = calleeReference
|
||||
catches += this@copy.catches
|
||||
typeRef = resultType
|
||||
this.annotations += annotations
|
||||
}
|
||||
|
||||
fun FirCheckNotNullCall.copy(
|
||||
resultType: FirTypeRef = this.typeRef,
|
||||
calleeReference: FirReference = this.calleeReference,
|
||||
annotations: List<FirAnnotation> = this.annotations
|
||||
): FirCheckNotNullCall = buildCheckNotNullCall {
|
||||
source = this@copy.source
|
||||
this.calleeReference = calleeReference
|
||||
argumentList = this@copy.argumentList
|
||||
this.typeRef = resultType
|
||||
this.annotations += annotations
|
||||
}
|
||||
|
||||
fun FirDeclarationStatus.copy(
|
||||
isExpect: Boolean = this.isExpect,
|
||||
newModality: Modality? = null,
|
||||
newVisibility: Visibility? = null,
|
||||
newEffectiveVisibility: EffectiveVisibility? = null,
|
||||
isOperator: Boolean = this.isOperator
|
||||
): FirDeclarationStatus {
|
||||
return if (this.isExpect == isExpect && newModality == null && newVisibility == null && this.isOperator == isOperator) {
|
||||
this
|
||||
} else {
|
||||
require(this is FirDeclarationStatusImpl) { "Unexpected class ${this::class}" }
|
||||
this.resolved(
|
||||
newVisibility ?: visibility,
|
||||
newModality ?: modality!!,
|
||||
newEffectiveVisibility ?: EffectiveVisibility.Public
|
||||
).apply {
|
||||
this.isExpect = isExpect
|
||||
this.isOperator = isOperator
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,319 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.fir
|
||||
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.descriptors.Visibility
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.declarations.synthetic.FirSyntheticPropertyAccessor
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.*
|
||||
import org.jetbrains.kotlin.fir.expressions.FirPropertyAccessExpression
|
||||
import org.jetbrains.kotlin.fir.references.FirSuperReference
|
||||
import org.jetbrains.kotlin.fir.resolve.calls.ExpressionReceiverValue
|
||||
import org.jetbrains.kotlin.fir.resolve.calls.FirSyntheticFunctionSymbol
|
||||
import org.jetbrains.kotlin.fir.resolve.calls.ReceiverValue
|
||||
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
||||
import org.jetbrains.kotlin.fir.resolve.lookupSuperTypes
|
||||
import org.jetbrains.kotlin.fir.resolve.providers.firProvider
|
||||
import org.jetbrains.kotlin.fir.resolve.toSymbol
|
||||
import org.jetbrains.kotlin.fir.resolve.typeWithStarProjections
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
|
||||
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
|
||||
import org.jetbrains.kotlin.fir.types.coneType
|
||||
import org.jetbrains.kotlin.fir.types.typeContext
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.types.AbstractTypeChecker
|
||||
|
||||
abstract class FirModuleVisibilityChecker : FirSessionComponent {
|
||||
abstract fun <T> isInFriendModule(declaration: T): Boolean where T : FirMemberDeclaration, T : FirDeclaration
|
||||
|
||||
class Standard(val session: FirSession) : FirModuleVisibilityChecker() {
|
||||
override fun <T> isInFriendModule(declaration: T): Boolean where T : FirMemberDeclaration, T : FirDeclaration {
|
||||
val useSiteModuleData = session.moduleData
|
||||
val declarationModuleData = declaration.moduleData
|
||||
return useSiteModuleData == declarationModuleData || declarationModuleData in useSiteModuleData.friendDependencies
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
abstract class FirVisibilityChecker : FirSessionComponent {
|
||||
@NoMutableState
|
||||
object Default : FirVisibilityChecker() {
|
||||
override fun platformVisibilityCheck(
|
||||
declarationVisibility: Visibility,
|
||||
symbol: FirBasedSymbol<*>,
|
||||
useSiteFile: FirFile,
|
||||
containingDeclarations: List<FirDeclaration>,
|
||||
dispatchReceiver: ReceiverValue?,
|
||||
session: FirSession,
|
||||
isCallToPropertySetter: Boolean,
|
||||
): Boolean {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
fun isVisible(
|
||||
declaration: FirMemberDeclaration,
|
||||
session: FirSession,
|
||||
useSiteFile: FirFile,
|
||||
containingDeclarations: List<FirDeclaration>,
|
||||
dispatchReceiver: ReceiverValue?,
|
||||
isCallToPropertySetter: Boolean = false,
|
||||
): Boolean {
|
||||
require(declaration is FirDeclaration)
|
||||
val provider = session.firProvider
|
||||
val symbol = declaration.symbol
|
||||
return when (declaration.visibility) {
|
||||
Visibilities.Internal -> {
|
||||
declaration.moduleData == session.moduleData || session.moduleVisibilityChecker?.isInFriendModule(declaration) == true
|
||||
}
|
||||
Visibilities.Private, Visibilities.PrivateToThis -> {
|
||||
val ownerLookupTag = symbol.getOwnerLookupTag()
|
||||
if (declaration.moduleData == session.moduleData) {
|
||||
when {
|
||||
ownerLookupTag == null -> {
|
||||
val candidateFile = when (symbol) {
|
||||
is FirSyntheticFunctionSymbol -> {
|
||||
// SAM case
|
||||
val classId = ClassId(symbol.callableId.packageName, symbol.callableId.callableName)
|
||||
provider.getFirClassifierContainerFile(classId)
|
||||
}
|
||||
is FirClassLikeSymbol<*> -> provider.getFirClassifierContainerFileIfAny(symbol)
|
||||
is FirCallableSymbol<*> -> provider.getFirCallableContainerFile(symbol)
|
||||
else -> null
|
||||
}
|
||||
// Top-level: visible in file
|
||||
candidateFile == useSiteFile
|
||||
}
|
||||
declaration is FirConstructor && declaration.isFromSealedClass -> {
|
||||
// Sealed class constructor: visible in same package
|
||||
declaration.symbol.callableId.packageName == useSiteFile.packageFqName
|
||||
}
|
||||
else -> {
|
||||
// Member: visible inside parent class, including all its member classes
|
||||
canSeePrivateMemberOf(containingDeclarations, ownerLookupTag, session)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
declaration is FirSimpleFunction && declaration.isAllowedToBeAccessedFromOutside()
|
||||
}
|
||||
}
|
||||
|
||||
Visibilities.Protected -> {
|
||||
val ownerId = symbol.getOwnerLookupTag()
|
||||
ownerId != null && canSeeProtectedMemberOf(
|
||||
containingDeclarations, dispatchReceiver, ownerId, session,
|
||||
isVariableOrNamedFunction = symbol is FirVariableSymbol || symbol is FirNamedFunctionSymbol || symbol is FirPropertyAccessorSymbol,
|
||||
symbol.fir is FirSyntheticPropertyAccessor
|
||||
)
|
||||
}
|
||||
|
||||
else -> platformVisibilityCheck(
|
||||
declaration.visibility,
|
||||
symbol,
|
||||
useSiteFile,
|
||||
containingDeclarations,
|
||||
dispatchReceiver,
|
||||
session,
|
||||
isCallToPropertySetter,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract fun platformVisibilityCheck(
|
||||
declarationVisibility: Visibility,
|
||||
symbol: FirBasedSymbol<*>,
|
||||
useSiteFile: FirFile,
|
||||
containingDeclarations: List<FirDeclaration>,
|
||||
dispatchReceiver: ReceiverValue?,
|
||||
session: FirSession,
|
||||
isCallToPropertySetter: Boolean,
|
||||
): Boolean
|
||||
|
||||
private fun canSeePrivateMemberOf(
|
||||
containingDeclarationOfUseSite: List<FirDeclaration>,
|
||||
ownerLookupTag: ConeClassLikeLookupTag,
|
||||
session: FirSession
|
||||
): Boolean {
|
||||
ownerLookupTag.ownerIfCompanion(session)?.let { companionOwnerLookupTag ->
|
||||
return canSeePrivateMemberOf(containingDeclarationOfUseSite, companionOwnerLookupTag, session)
|
||||
}
|
||||
|
||||
for (declaration in containingDeclarationOfUseSite) {
|
||||
if (declaration !is FirClass) continue
|
||||
val boundSymbol = declaration.symbol
|
||||
if (boundSymbol.classId.isSame(ownerLookupTag.classId)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// 'local' isn't taken into account here
|
||||
private fun ClassId.isSame(other: ClassId): Boolean =
|
||||
packageFqName == other.packageFqName && relativeClassName == other.relativeClassName
|
||||
|
||||
private fun ConeClassLikeLookupTag.ownerIfCompanion(session: FirSession): ConeClassLikeLookupTag? {
|
||||
if (classId.isLocal) return null
|
||||
val outerClassId = classId.outerClassId ?: return null
|
||||
val ownerSymbol = toSymbol(session) as? FirRegularClassSymbol
|
||||
|
||||
if (ownerSymbol?.fir?.isCompanion == true) {
|
||||
return ConeClassLikeLookupTagImpl(outerClassId)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private fun canSeeProtectedMemberOf(
|
||||
containingUseSiteClass: FirClass,
|
||||
dispatchReceiver: ReceiverValue?,
|
||||
ownerLookupTag: ConeClassLikeLookupTag,
|
||||
session: FirSession,
|
||||
isVariableOrNamedFunction: Boolean,
|
||||
isSyntheticProperty: Boolean
|
||||
): Boolean {
|
||||
dispatchReceiver?.ownerIfCompanion(session)?.let { companionOwnerLookupTag ->
|
||||
if (containingUseSiteClass.isSubClass(companionOwnerLookupTag, session)) return true
|
||||
}
|
||||
|
||||
return when {
|
||||
!containingUseSiteClass.isSubClass(ownerLookupTag, session) -> false
|
||||
isVariableOrNamedFunction -> doesReceiverFitForProtectedVisibility(
|
||||
dispatchReceiver,
|
||||
containingUseSiteClass,
|
||||
ownerLookupTag,
|
||||
isSyntheticProperty,
|
||||
session
|
||||
)
|
||||
else -> true
|
||||
}
|
||||
}
|
||||
|
||||
private fun doesReceiverFitForProtectedVisibility(
|
||||
dispatchReceiver: ReceiverValue?,
|
||||
containingUseSiteClass: FirClass,
|
||||
ownerLookupTag: ConeClassLikeLookupTag,
|
||||
isSyntheticProperty: Boolean,
|
||||
session: FirSession
|
||||
): Boolean {
|
||||
if (dispatchReceiver == null) return true
|
||||
var dispatchReceiverType = dispatchReceiver.type
|
||||
if (dispatchReceiver is ExpressionReceiverValue) {
|
||||
val explicitReceiver = dispatchReceiver.explicitReceiver
|
||||
if (explicitReceiver is FirPropertyAccessExpression && explicitReceiver.calleeReference is FirSuperReference) {
|
||||
// Special 'super' case: type of this, not of super, should be taken for the check below
|
||||
dispatchReceiverType = explicitReceiver.dispatchReceiver.typeRef.coneType
|
||||
}
|
||||
}
|
||||
val typeCheckerState = session.typeContext.newTypeCheckerState(
|
||||
errorTypesEqualToAnything = false,
|
||||
stubTypesEqualToAnything = false
|
||||
)
|
||||
if (AbstractTypeChecker.isSubtypeOf(
|
||||
typeCheckerState, dispatchReceiverType.fullyExpandedType(session), containingUseSiteClass.typeWithStarProjections()
|
||||
)
|
||||
) {
|
||||
return true
|
||||
}
|
||||
|
||||
if (isSyntheticProperty) {
|
||||
return if (session.languageVersionSettings.supportsFeature(LanguageFeature.ImproveReportingDiagnosticsOnProtectedMembersOfBaseClass))
|
||||
containingUseSiteClass.classId.packageFqName == ownerLookupTag.classId.packageFqName
|
||||
else
|
||||
true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
private fun FirClass.isSubClass(ownerLookupTag: ConeClassLikeLookupTag, session: FirSession): Boolean {
|
||||
if (classId.isSame(ownerLookupTag.classId)) return true
|
||||
|
||||
return lookupSuperTypes(this, lookupInterfaces = true, deep = true, session).any { superType ->
|
||||
(superType as? ConeClassLikeType)?.fullyExpandedType(session)?.lookupTag?.classId?.isSame(ownerLookupTag.classId) == true
|
||||
}
|
||||
}
|
||||
|
||||
private fun ReceiverValue?.ownerIfCompanion(session: FirSession): ConeClassLikeLookupTag? =
|
||||
(this?.type as? ConeClassLikeType)?.lookupTag?.ownerIfCompanion(session)
|
||||
|
||||
// monitorEnter/monitorExit are the only functions which are accessed "illegally" (see kotlin/util/Synchronized.kt).
|
||||
// Since they are intrinsified in the codegen, FIR should treat it as visible.
|
||||
private fun FirSimpleFunction.isAllowedToBeAccessedFromOutside(): Boolean {
|
||||
if (!isFromLibrary) return false
|
||||
val packageName = symbol.callableId.packageName.asString()
|
||||
val name = name.asString()
|
||||
return packageName == "kotlin.jvm.internal.unsafe" &&
|
||||
(name == "monitorEnter" || name == "monitorExit")
|
||||
}
|
||||
|
||||
protected fun canSeeProtectedMemberOf(
|
||||
containingDeclarationOfUseSite: List<FirDeclaration>,
|
||||
dispatchReceiver: ReceiverValue?,
|
||||
ownerLookupTag: ConeClassLikeLookupTag,
|
||||
session: FirSession,
|
||||
isVariableOrNamedFunction: Boolean,
|
||||
isSyntheticProperty: Boolean
|
||||
): Boolean {
|
||||
if (canSeePrivateMemberOf(containingDeclarationOfUseSite, ownerLookupTag, session)) return true
|
||||
|
||||
for (containingDeclaration in containingDeclarationOfUseSite) {
|
||||
if (containingDeclaration is FirClass) {
|
||||
val boundSymbol = containingDeclaration.symbol
|
||||
if (canSeeProtectedMemberOf(
|
||||
boundSymbol.fir,
|
||||
dispatchReceiver,
|
||||
ownerLookupTag,
|
||||
session,
|
||||
isVariableOrNamedFunction,
|
||||
isSyntheticProperty
|
||||
)
|
||||
) return true
|
||||
} else if (containingDeclaration is FirFile) {
|
||||
if (isSyntheticProperty &&
|
||||
session.languageVersionSettings.supportsFeature(LanguageFeature.ImproveReportingDiagnosticsOnProtectedMembersOfBaseClass) &&
|
||||
containingDeclaration.packageFqName == ownerLookupTag.classId.packageFqName
|
||||
) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
protected fun FirBasedSymbol<*>.packageFqName(): FqName {
|
||||
return when (this) {
|
||||
is FirClassLikeSymbol<*> -> classId.packageFqName
|
||||
is FirCallableSymbol<*> -> callableId.packageName
|
||||
else -> error("No package fq name for $this")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val FirSession.moduleVisibilityChecker: FirModuleVisibilityChecker? by FirSession.nullableSessionComponentAccessor()
|
||||
val FirSession.visibilityChecker: FirVisibilityChecker by FirSession.sessionComponentAccessor()
|
||||
|
||||
fun FirBasedSymbol<*>.getOwnerLookupTag(): ConeClassLikeLookupTag? {
|
||||
return when (this) {
|
||||
is FirBackingFieldSymbol -> fir.propertySymbol.getOwnerLookupTag()
|
||||
is FirClassLikeSymbol<*> -> {
|
||||
if (classId.isLocal) {
|
||||
(fir as? FirRegularClass)?.containingClassForLocal()
|
||||
} else {
|
||||
val ownerId = classId.outerClassId
|
||||
ownerId?.let { ConeClassLikeLookupTagImpl(it) }
|
||||
}
|
||||
}
|
||||
is FirCallableSymbol<*> -> containingClass()
|
||||
else -> error("Unsupported owner search for ${fir.javaClass}: ${fir.render()}")
|
||||
}
|
||||
}
|
||||
+163
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.fir.declarations
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
|
||||
import org.jetbrains.kotlin.fir.FirAnnotationContainer
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.expressions.*
|
||||
import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
|
||||
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
|
||||
import org.jetbrains.kotlin.fir.resolve.toSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
|
||||
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
|
||||
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
|
||||
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.coneType
|
||||
import org.jetbrains.kotlin.fir.types.coneTypeSafe
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.name.StandardClassIds
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
private fun FirAnnotation.toAnnotationLookupTag(): ConeClassLikeLookupTag? =
|
||||
// this cast fails when we have generic-typed annotations @T
|
||||
(annotationTypeRef.coneType as? ConeClassLikeType)?.lookupTag
|
||||
|
||||
fun FirAnnotation.toAnnotationClassId(): ClassId? =
|
||||
toAnnotationLookupTag()?.classId
|
||||
|
||||
private fun FirAnnotation.toAnnotationClass(session: FirSession): FirRegularClass? =
|
||||
toAnnotationLookupTag()?.toSymbol(session)?.fir as? FirRegularClass
|
||||
|
||||
// TODO: this is temporary solution, we need something better
|
||||
private val FirExpression.callableNameOfMetaAnnotationArgument: Name?
|
||||
get() =
|
||||
(this as? FirQualifiedAccessExpression)?.let {
|
||||
val callableSymbol = (it.calleeReference as? FirResolvedNamedReference)?.resolvedSymbol as? FirCallableSymbol<*>
|
||||
callableSymbol?.callableId?.callableName
|
||||
}
|
||||
|
||||
private val sourceName = Name.identifier("SOURCE")
|
||||
|
||||
fun FirAnnotationContainer.nonSourceAnnotations(session: FirSession): List<FirAnnotation> =
|
||||
annotations.filter { annotation ->
|
||||
val firAnnotationClass = annotation.toAnnotationClass(session)
|
||||
firAnnotationClass != null && firAnnotationClass.annotations.none { meta ->
|
||||
meta.toAnnotationClassId() == StandardClassIds.Annotations.Retention &&
|
||||
meta.findArgumentByName(StandardClassIds.Annotations.ParameterNames.retentionValue)
|
||||
?.callableNameOfMetaAnnotationArgument == sourceName
|
||||
}
|
||||
}
|
||||
|
||||
inline val FirProperty.hasJvmFieldAnnotation: Boolean
|
||||
get() = annotations.any { it.isJvmFieldAnnotation }
|
||||
|
||||
val FirAnnotation.isJvmFieldAnnotation: Boolean
|
||||
get() = toAnnotationClassId() == StandardClassIds.Annotations.JvmField
|
||||
|
||||
fun FirAnnotation.useSiteTargetsFromMetaAnnotation(session: FirSession): Set<AnnotationUseSiteTarget> {
|
||||
return toAnnotationClass(session)
|
||||
?.annotations
|
||||
?.find { it.toAnnotationClassId() == StandardClassIds.Annotations.Target }
|
||||
?.findArgumentByName(StandardClassIds.Annotations.ParameterNames.targetAllowedTargets)
|
||||
?.unwrapVarargValue()
|
||||
?.toAnnotationUseSiteTargets()
|
||||
?: DEFAULT_USE_SITE_TARGETS
|
||||
}
|
||||
|
||||
private fun List<FirExpression>.toAnnotationUseSiteTargets(): Set<AnnotationUseSiteTarget> =
|
||||
flatMapTo(mutableSetOf()) { arg ->
|
||||
when (val unwrappedArg = if (arg is FirNamedArgumentExpression) arg.expression else arg) {
|
||||
is FirArrayOfCall -> unwrappedArg.argumentList.arguments.toAnnotationUseSiteTargets()
|
||||
is FirVarargArgumentsExpression -> unwrappedArg.arguments.toAnnotationUseSiteTargets()
|
||||
else -> USE_SITE_TARGET_NAME_MAP[unwrappedArg.callableNameOfMetaAnnotationArgument?.identifier] ?: setOf()
|
||||
}
|
||||
}
|
||||
|
||||
// See [org.jetbrains.kotlin.descriptors.annotations.KotlinTarget.USE_SITE_MAPPING] (it's in reverse)
|
||||
private val USE_SITE_TARGET_NAME_MAP = mapOf(
|
||||
"FIELD" to setOf(AnnotationUseSiteTarget.FIELD, AnnotationUseSiteTarget.PROPERTY_DELEGATE_FIELD),
|
||||
"FILE" to setOf(AnnotationUseSiteTarget.FILE),
|
||||
"PROPERTY" to setOf(AnnotationUseSiteTarget.PROPERTY),
|
||||
"PROPERTY_GETTER" to setOf(AnnotationUseSiteTarget.PROPERTY_GETTER),
|
||||
"PROPERTY_SETTER" to setOf(AnnotationUseSiteTarget.PROPERTY_SETTER),
|
||||
"VALUE_PARAMETER" to setOf(
|
||||
AnnotationUseSiteTarget.CONSTRUCTOR_PARAMETER,
|
||||
AnnotationUseSiteTarget.RECEIVER,
|
||||
AnnotationUseSiteTarget.SETTER_PARAMETER,
|
||||
),
|
||||
)
|
||||
|
||||
// See [org.jetbrains.kotlin.descriptors.annotations.KotlinTarget] (the second argument of each entry)
|
||||
private val DEFAULT_USE_SITE_TARGETS: Set<AnnotationUseSiteTarget> =
|
||||
USE_SITE_TARGET_NAME_MAP.values.fold(setOf<AnnotationUseSiteTarget>()) { a, b -> a + b } - setOf(AnnotationUseSiteTarget.FILE)
|
||||
|
||||
fun FirAnnotatedDeclaration.hasAnnotation(classId: ClassId): Boolean {
|
||||
return annotations.any { it.toAnnotationClassId() == classId }
|
||||
}
|
||||
|
||||
fun <D> FirBasedSymbol<out D>.getAnnotationByClassId(classId: ClassId): FirAnnotation? where D : FirAnnotationContainer, D : FirDeclaration {
|
||||
return fir.getAnnotationByClassId(classId)
|
||||
}
|
||||
|
||||
fun FirAnnotationContainer.getAnnotationByClassId(classId: ClassId): FirAnnotation? {
|
||||
return annotations.find {
|
||||
it.annotationTypeRef.coneTypeSafe<ConeClassLikeType>()?.lookupTag?.classId == classId
|
||||
}
|
||||
}
|
||||
|
||||
fun FirAnnotationContainer.getAnnotationsByClassId(classId: ClassId): List<FirAnnotation> = annotations.getAnnotationsByClassId(classId)
|
||||
|
||||
fun List<FirAnnotation>.getAnnotationsByClassId(classId: ClassId): List<FirAnnotation> {
|
||||
return filter {
|
||||
it.annotationTypeRef.coneTypeSafe<ConeClassLikeType>()?.lookupTag?.classId == classId
|
||||
}
|
||||
}
|
||||
|
||||
fun FirExpression.unwrapVarargValue(): List<FirExpression> {
|
||||
return when (this) {
|
||||
is FirVarargArgumentsExpression -> arguments
|
||||
is FirArrayOfCall -> arguments
|
||||
else -> listOf(this)
|
||||
}
|
||||
}
|
||||
|
||||
fun FirAnnotation.findArgumentByName(name: Name): FirExpression? {
|
||||
argumentMapping.mapping[name]?.let { return it }
|
||||
if (this !is FirAnnotationCall) return null
|
||||
|
||||
// NB: we have to consider both cases, because deserializer does not create argument mapping
|
||||
for (argument in arguments) {
|
||||
if (argument is FirNamedArgumentExpression && argument.name == name) {
|
||||
return argument.expression
|
||||
}
|
||||
}
|
||||
// I'm lucky today!
|
||||
// TODO: this line is still needed. However it should be replaced with 'return null'
|
||||
return arguments.singleOrNull()
|
||||
}
|
||||
|
||||
fun FirAnnotation.getStringArgument(name: Name): String? =
|
||||
findArgumentByName(name)?.let { expression ->
|
||||
expression.safeAs<FirConstExpression<*>>()?.value as? String
|
||||
}
|
||||
|
||||
fun FirAnnotationContainer.getJvmNameFromAnnotation(target: AnnotationUseSiteTarget? = null): String? {
|
||||
val annotationCalls = getAnnotationsByClassId(StandardClassIds.Annotations.JvmName)
|
||||
return annotationCalls.firstNotNullOfOrNull { call ->
|
||||
call.getStringArgument(StandardClassIds.Annotations.ParameterNames.jvmNameName)
|
||||
?.takeIf { target == null || call.useSiteTarget == target }
|
||||
}
|
||||
}
|
||||
|
||||
val FirAnnotation.resolved: Boolean
|
||||
get() {
|
||||
if (annotationTypeRef !is FirResolvedTypeRef) return false
|
||||
if (this !is FirAnnotationCall) return true
|
||||
return calleeReference is FirResolvedNamedReference || calleeReference is FirErrorNamedReference
|
||||
}
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.fir.declarations
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirElement
|
||||
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
|
||||
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
|
||||
import org.jetbrains.kotlin.fir.expressions.FirArgumentList
|
||||
import org.jetbrains.kotlin.fir.expressions.impl.FirResolvedArgumentList
|
||||
import org.jetbrains.kotlin.fir.references.FirNamedReference
|
||||
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
|
||||
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
||||
import org.jetbrains.kotlin.fir.visitors.FirDefaultVisitor
|
||||
|
||||
fun FirElement.validate() {
|
||||
accept(FirGeneratedElementsValidator, null)
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO's:
|
||||
* - add proper error messages to all `require`
|
||||
* - add validation of declaration origin and resolve phase for all declarations
|
||||
*/
|
||||
object FirGeneratedElementsValidator : FirDefaultVisitor<Unit, Any?>() {
|
||||
override fun visitElement(element: FirElement, data: Any?) {
|
||||
element.acceptChildren(this, null)
|
||||
}
|
||||
|
||||
override fun visitAnnotation(annotation: FirAnnotation, data: Any?) {
|
||||
annotation.acceptChildren(this, null)
|
||||
}
|
||||
|
||||
override fun visitAnnotationCall(annotationCall: FirAnnotationCall, data: Any?) {
|
||||
annotationCall.acceptChildren(this, null)
|
||||
}
|
||||
|
||||
override fun visitRegularClass(regularClass: FirRegularClass, data: Any?) {
|
||||
regularClass.acceptChildren(this, null)
|
||||
}
|
||||
|
||||
override fun visitArgumentList(argumentList: FirArgumentList, data: Any?) {
|
||||
require(argumentList is FirResolvedArgumentList)
|
||||
argumentList.acceptChildren(this, null)
|
||||
}
|
||||
|
||||
override fun visitNamedReference(namedReference: FirNamedReference, data: Any?) {
|
||||
require(namedReference is FirResolvedNamedReference)
|
||||
namedReference.acceptChildren(this, null)
|
||||
}
|
||||
|
||||
override fun visitTypeRef(typeRef: FirTypeRef, data: Any?) {
|
||||
require(typeRef is FirResolvedTypeRef)
|
||||
typeRef.acceptChildren(this, null)
|
||||
}
|
||||
|
||||
override fun visitResolvedTypeRef(resolvedTypeRef: FirResolvedTypeRef, data: Any?) {
|
||||
resolvedTypeRef.annotations.forEach { it.accept(this, null) }
|
||||
}
|
||||
|
||||
override fun visitDeclarationStatus(declarationStatus: FirDeclarationStatus, data: Any?) {
|
||||
require(declarationStatus is FirResolvedDeclarationStatus)
|
||||
}
|
||||
|
||||
override fun visitTypeParameterRef(typeParameterRef: FirTypeParameterRef, data: Any?) {
|
||||
typeParameterRef.symbol.fir.accept(this, null)
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.fir.declarations
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isInline
|
||||
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.createTypeSubstitutorByTypeConstructor
|
||||
import org.jetbrains.kotlin.fir.resolve.toSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.ensureResolved
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
|
||||
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||
import org.jetbrains.kotlin.fir.types.ConeLookupTagBasedType
|
||||
import org.jetbrains.kotlin.fir.types.ConeTypeContext
|
||||
import org.jetbrains.kotlin.fir.types.coneType
|
||||
import org.jetbrains.kotlin.types.model.typeConstructor
|
||||
|
||||
internal fun ConeKotlinType.substitutedUnderlyingTypeForInlineClass(session: FirSession, context: ConeTypeContext): ConeKotlinType? {
|
||||
val unsubstitutedType = unsubstitutedUnderlyingTypeForInlineClass(session) ?: return null
|
||||
val substitutor = createTypeSubstitutorByTypeConstructor(mapOf(this.typeConstructor(context) to this), context)
|
||||
return substitutor.substituteOrNull(unsubstitutedType)
|
||||
}
|
||||
|
||||
internal fun ConeKotlinType.unsubstitutedUnderlyingTypeForInlineClass(session: FirSession): ConeKotlinType? {
|
||||
val symbol = (this.fullyExpandedType(session) as? ConeLookupTagBasedType)
|
||||
?.lookupTag
|
||||
?.toSymbol(session) as? FirRegularClassSymbol
|
||||
?: return null
|
||||
symbol.ensureResolved(FirResolvePhase.STATUS)
|
||||
return symbol.fir.getInlineClassUnderlyingParameter(session)?.returnTypeRef?.coneType
|
||||
}
|
||||
|
||||
// TODO: implement inlineClassRepresentation in FirRegularClass instead.
|
||||
fun FirRegularClass.getInlineClassUnderlyingParameter(session: FirSession): FirValueParameter? =
|
||||
if (isInline) primaryConstructorIfAny(session)?.fir?.valueParameters?.singleOrNull() else null
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.fir.declarations
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.scopes.impl.declaredMemberScope
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.runIf
|
||||
|
||||
fun FirClass.constructors(session: FirSession): List<FirConstructorSymbol> {
|
||||
val result = mutableListOf<FirConstructorSymbol>()
|
||||
session.declaredMemberScope(this).processDeclaredConstructors { result += it }
|
||||
return result
|
||||
}
|
||||
|
||||
fun FirClass.constructorsSortedByDelegation(session: FirSession): List<FirConstructorSymbol> {
|
||||
return constructors(session).sortedWith(ConstructorDelegationComparator)
|
||||
}
|
||||
|
||||
fun FirClass.primaryConstructorIfAny(session: FirSession): FirConstructorSymbol? {
|
||||
return constructors(session).find(FirConstructorSymbol::isPrimary)
|
||||
}
|
||||
|
||||
fun FirRegularClass.collectEnumEntries(): Collection<FirEnumEntry> {
|
||||
assert(classKind == ClassKind.ENUM_CLASS)
|
||||
return declarations.filterIsInstance<FirEnumEntry>()
|
||||
}
|
||||
|
||||
val FirConstructorSymbol.delegatedThisConstructor: FirConstructorSymbol?
|
||||
get() = runIf(delegatedConstructorCallIsThis) { this.resolvedDelegatedConstructor }
|
||||
|
||||
|
||||
private object ConstructorDelegationComparator : Comparator<FirConstructorSymbol> {
|
||||
override fun compare(p0: FirConstructorSymbol?, p1: FirConstructorSymbol?): Int {
|
||||
if (p0 == null && p1 == null) return 0
|
||||
if (p0 == null) return -1
|
||||
if (p1 == null) return 1
|
||||
if (p0.delegatedThisConstructor == p1) return 1
|
||||
if (p1.delegatedThisConstructor == p0) return -1
|
||||
// If neither is a delegation to each other, the order doesn't matter.
|
||||
// Here we return 0 to preserve the original order.
|
||||
return 0
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.fir.declarations
|
||||
|
||||
import org.jetbrains.kotlin.config.ApiVersion
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
|
||||
import org.jetbrains.kotlin.fir.FirAnnotationContainer
|
||||
import org.jetbrains.kotlin.fir.FirElement
|
||||
import org.jetbrains.kotlin.fir.expressions.*
|
||||
import org.jetbrains.kotlin.fir.references.FirNamedReference
|
||||
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.name.StandardClassIds
|
||||
import org.jetbrains.kotlin.name.StandardClassIds.Annotations.ParameterNames
|
||||
import org.jetbrains.kotlin.name.StandardClassIds.Annotations.ParameterNames.deprecatedSinceKotlinErrorSince
|
||||
import org.jetbrains.kotlin.name.StandardClassIds.Annotations.ParameterNames.deprecatedSinceKotlinHiddenSince
|
||||
import org.jetbrains.kotlin.name.StandardClassIds.Annotations.ParameterNames.deprecatedSinceKotlinWarningSince
|
||||
import org.jetbrains.kotlin.resolve.deprecation.DeprecationInfo
|
||||
import org.jetbrains.kotlin.resolve.deprecation.DeprecationLevelValue
|
||||
import org.jetbrains.kotlin.resolve.deprecation.SimpleDeprecationInfo
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
private val JAVA_ORIGINS = setOf(FirDeclarationOrigin.Java, FirDeclarationOrigin.Enhancement)
|
||||
|
||||
fun FirBasedSymbol<*>.getDeprecation(callSite: FirElement?): DeprecationInfo? {
|
||||
val deprecationInfos = mutableListOf<DeprecationInfo>()
|
||||
when (this) {
|
||||
is FirPropertySymbol ->
|
||||
when (callSite) {
|
||||
is FirVariableAssignment ->
|
||||
deprecationInfos.addIfNotNull(
|
||||
getDeprecationForCallSite(AnnotationUseSiteTarget.PROPERTY_SETTER, AnnotationUseSiteTarget.PROPERTY)
|
||||
)
|
||||
is FirPropertyAccessExpression ->
|
||||
deprecationInfos.addIfNotNull(
|
||||
getDeprecationForCallSite(AnnotationUseSiteTarget.PROPERTY_GETTER, AnnotationUseSiteTarget.PROPERTY)
|
||||
)
|
||||
else -> deprecationInfos.addIfNotNull(getDeprecationForCallSite(AnnotationUseSiteTarget.PROPERTY))
|
||||
}
|
||||
else -> deprecationInfos.addIfNotNull(getDeprecationForCallSite())
|
||||
}
|
||||
|
||||
return deprecationInfos.firstOrNull()
|
||||
}
|
||||
|
||||
fun FirAnnotationContainer.getDeprecationInfos(currentVersion: ApiVersion): DeprecationsPerUseSite {
|
||||
val deprecationByUseSite = mutableMapOf<AnnotationUseSiteTarget?, DeprecationInfo>()
|
||||
val fromJava = JAVA_ORIGINS.contains(this.safeAs<FirDeclaration>()?.origin)
|
||||
annotations.extractDeprecationInfoPerUseSite(currentVersion, fromJava).toMap(deprecationByUseSite)
|
||||
|
||||
if (this is FirProperty) {
|
||||
getDeprecationsFromAccessors(getter, setter, currentVersion).bySpecificSite?.forEach { (k, v) -> deprecationByUseSite[k] = v }
|
||||
}
|
||||
|
||||
return DeprecationsPerUseSite.fromMap(deprecationByUseSite)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalStdlibApi::class)
|
||||
fun getDeprecationsFromAccessors(
|
||||
getter: FirFunction?,
|
||||
setter: FirFunction?,
|
||||
currentVersion: ApiVersion
|
||||
): DeprecationsPerUseSite {
|
||||
val perUseSite = buildMap<AnnotationUseSiteTarget, DeprecationInfo> {
|
||||
val setterDeprecations = setter?.getDeprecationInfos(currentVersion)
|
||||
setterDeprecations?.all?.let { put(AnnotationUseSiteTarget.PROPERTY_SETTER, it) }
|
||||
setterDeprecations?.bySpecificSite?.let { putAll(it) }
|
||||
val getterDeprecations = getter?.getDeprecationInfos(currentVersion)
|
||||
getterDeprecations?.all?.let { put(AnnotationUseSiteTarget.PROPERTY_GETTER, it) }
|
||||
getterDeprecations?.bySpecificSite?.let { putAll(it) }
|
||||
}
|
||||
return if (perUseSite.isEmpty()) EmptyDeprecationsPerUseSite else DeprecationsPerUseSite(null, perUseSite)
|
||||
}
|
||||
|
||||
fun List<FirAnnotation>.getDeprecationInfosFromAnnotations(currentVersion: ApiVersion, fromJava: Boolean): DeprecationsPerUseSite {
|
||||
val deprecationByUseSite = extractDeprecationInfoPerUseSite(currentVersion, fromJava).toMap()
|
||||
return DeprecationsPerUseSite.fromMap(deprecationByUseSite)
|
||||
}
|
||||
|
||||
fun FirBasedSymbol<*>.getDeprecationForCallSite(
|
||||
vararg sites: AnnotationUseSiteTarget
|
||||
): DeprecationInfo? {
|
||||
val deprecations = when (this) {
|
||||
is FirCallableSymbol<*> -> deprecation
|
||||
is FirClassLikeSymbol<*> -> deprecation
|
||||
else -> null
|
||||
}
|
||||
return (deprecations ?: EmptyDeprecationsPerUseSite).forUseSite(*sites)
|
||||
}
|
||||
|
||||
private fun FirAnnotation.getVersionFromArgument(name: Name): ApiVersion? =
|
||||
getStringArgument(name)?.let { ApiVersion.parse(it) }
|
||||
|
||||
private fun FirAnnotation.getDeprecationLevel(): DeprecationLevelValue? {
|
||||
//take last because Annotation might be not resolved yet and arguments passed without explicit names
|
||||
val argument = if (resolved) {
|
||||
argumentMapping.mapping[ParameterNames.deprecatedLevel]
|
||||
} else {
|
||||
val call = this as? FirAnnotationCall ?: return null
|
||||
call.arguments
|
||||
.firstOrNull { it is FirNamedArgumentExpression && it.name == ParameterNames.deprecatedLevel }
|
||||
?.unwrapArgument()
|
||||
?: arguments.lastOrNull()
|
||||
} ?: return null
|
||||
val targetExpression = argument as? FirQualifiedAccessExpression ?: return null
|
||||
val targetName = (targetExpression.calleeReference as? FirNamedReference)?.name?.asString() ?: return null
|
||||
return DeprecationLevelValue.values().find { it.name == targetName }
|
||||
}
|
||||
|
||||
private fun List<FirAnnotation>.extractDeprecationInfoPerUseSite(
|
||||
currentVersion: ApiVersion,
|
||||
fromJava: Boolean
|
||||
): List<Pair<AnnotationUseSiteTarget?, DeprecationInfo>> {
|
||||
val annotations = getAnnotationsByClassId(StandardClassIds.Annotations.Deprecated).map { it to false } +
|
||||
getAnnotationsByClassId(StandardClassIds.Annotations.Java.Deprecated).map { it to true }
|
||||
return annotations.mapNotNull { (deprecated, fromJavaAnnotation) ->
|
||||
val deprecationLevel = deprecated.getDeprecationLevel() ?: DeprecationLevelValue.WARNING
|
||||
val deprecatedSinceKotlin = getAnnotationsByClassId(StandardClassIds.Annotations.DeprecatedSinceKotlin).firstOrNull()
|
||||
|
||||
fun levelApplied(name: Name, level: DeprecationLevelValue): DeprecationLevelValue? {
|
||||
deprecatedSinceKotlin?.getVersionFromArgument(name)?.takeIf { it <= currentVersion }?.let { return level }
|
||||
return level.takeIf { deprecatedSinceKotlin == null && level == deprecationLevel }
|
||||
}
|
||||
|
||||
val appliedLevel = (levelApplied(deprecatedSinceKotlinHiddenSince, DeprecationLevelValue.HIDDEN)
|
||||
?: levelApplied(deprecatedSinceKotlinErrorSince, DeprecationLevelValue.ERROR)
|
||||
?: levelApplied(deprecatedSinceKotlinWarningSince, DeprecationLevelValue.WARNING))
|
||||
|
||||
appliedLevel?.let {
|
||||
val inheritable = !fromJavaAnnotation && !fromJava
|
||||
deprecated.useSiteTarget to SimpleDeprecationInfo(
|
||||
it,
|
||||
inheritable,
|
||||
deprecated.getStringArgument(ParameterNames.deprecatedMessage)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.fir.extensions
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.FirClass
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||
import org.jetbrains.kotlin.name.CallableId
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
/*
|
||||
* TODO:
|
||||
* - check that annotations or meta-annotations is not empty
|
||||
*/
|
||||
abstract class FirDeclarationGenerationExtension(session: FirSession) : FirPredicateBasedExtension(session) {
|
||||
companion object {
|
||||
val NAME = FirExtensionPointName("ExistingClassModification")
|
||||
}
|
||||
|
||||
final override val name: FirExtensionPointName
|
||||
get() = NAME
|
||||
|
||||
final override val extensionType: KClass<out FirExtension> = FirDeclarationGenerationExtension::class
|
||||
|
||||
abstract fun needToGenerateAdditionalMembersInClass(klass: FirClass): Boolean
|
||||
abstract fun needToGenerateNestedClassifiersInClass(klass: FirClass): Boolean
|
||||
|
||||
// Can be called on SUPERTYPES stage
|
||||
open fun generateClassLikeDeclaration(classId: ClassId): FirClassLikeSymbol<*>? = null
|
||||
|
||||
// Can be called on STATUS stage
|
||||
open fun generateFunctions(callableId: CallableId, owner: FirClassSymbol<*>?): List<FirNamedFunctionSymbol> = emptyList()
|
||||
open fun generateProperties(callableId: CallableId, owner: FirClassSymbol<*>?): List<FirPropertySymbol> = emptyList()
|
||||
open fun generateConstructors(callableId: CallableId): List<FirConstructorSymbol> = emptyList()
|
||||
|
||||
// Can be called on IMPORTS stage
|
||||
open fun hasPackage(packageFqName: FqName): Boolean = false
|
||||
|
||||
// Can be called after BODY_RESOLVE stage (checkers and fir2ir)
|
||||
open fun getCallableNamesForClass(classSymbol: FirClassSymbol<*>): Set<Name> = emptySet()
|
||||
open fun getNestedClassifiersNames(classSymbol: FirClassSymbol<*>): Set<Name> = emptySet()
|
||||
open fun getTopLevelCallableIds(): Set<CallableId> = emptySet()
|
||||
open fun getTopLevelClassIds(): Set<ClassId> = emptySet()
|
||||
|
||||
fun interface Factory : FirExtension.Factory<FirDeclarationGenerationExtension>
|
||||
}
|
||||
|
||||
val FirExtensionService.declarationGenerators: List<FirDeclarationGenerationExtension> by FirExtensionService.registeredExtensions()
|
||||
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.fir.resolve
|
||||
|
||||
import org.jetbrains.kotlin.builtins.StandardNames
|
||||
import org.jetbrains.kotlin.fir.FirFakeSourceElementKind
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
|
||||
import org.jetbrains.kotlin.fir.declarations.FirValueParameter
|
||||
import org.jetbrains.kotlin.fir.declarations.getAnnotationsByClassId
|
||||
import org.jetbrains.kotlin.fir.expressions.builder.buildAnnotation
|
||||
import org.jetbrains.kotlin.fir.expressions.builder.buildAnnotationArgumentMapping
|
||||
import org.jetbrains.kotlin.fir.expressions.builder.buildConstExpression
|
||||
import org.jetbrains.kotlin.fir.fakeElement
|
||||
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider
|
||||
import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeClassifierLookupTag
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeClassifierLookupTagWithFixedSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
|
||||
import org.jetbrains.kotlin.fir.utils.WeakPair
|
||||
import org.jetbrains.kotlin.name.SpecialNames
|
||||
import org.jetbrains.kotlin.name.StandardClassIds
|
||||
import org.jetbrains.kotlin.types.ConstantValueKind
|
||||
|
||||
fun ConeClassifierLookupTag.toSymbol(useSiteSession: FirSession): FirClassifierSymbol<*>? =
|
||||
when (this) {
|
||||
is ConeClassLikeLookupTag -> toSymbol(useSiteSession)
|
||||
is ConeClassifierLookupTagWithFixedSymbol -> this.symbol
|
||||
else -> null
|
||||
}
|
||||
|
||||
@OptIn(LookupTagInternals::class)
|
||||
fun ConeClassLikeLookupTag.toSymbol(useSiteSession: FirSession): FirClassLikeSymbol<*>? {
|
||||
if (this is ConeClassLookupTagWithFixedSymbol) {
|
||||
return this.symbol
|
||||
}
|
||||
val firSymbolProvider = useSiteSession.symbolProvider
|
||||
(this as? ConeClassLikeLookupTagImpl)?.boundSymbol?.takeIf { it.first === useSiteSession }?.let { return it.second }
|
||||
|
||||
return firSymbolProvider.getClassLikeSymbolByClassId(classId).also {
|
||||
(this as? ConeClassLikeLookupTagImpl)?.bindSymbolToLookupTag(useSiteSession, it)
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(LookupTagInternals::class)
|
||||
fun ConeClassLikeLookupTag.toSymbolOrError(useSiteSession: FirSession): FirClassLikeSymbol<*> =
|
||||
toSymbol(useSiteSession)
|
||||
?: error("Class symbol with classId $classId was not found")
|
||||
|
||||
@OptIn(LookupTagInternals::class)
|
||||
fun ConeClassLikeLookupTag.toFirRegularClassSymbol(session: FirSession): FirRegularClassSymbol? =
|
||||
session.symbolProvider.getSymbolByLookupTag(this) as? FirRegularClassSymbol
|
||||
|
||||
@OptIn(LookupTagInternals::class)
|
||||
fun ConeClassLikeLookupTagImpl.bindSymbolToLookupTag(session: FirSession, symbol: FirClassLikeSymbol<*>?) {
|
||||
boundSymbol = WeakPair(session, symbol)
|
||||
}
|
||||
|
||||
@LookupTagInternals
|
||||
fun ConeClassLikeLookupTag.toFirRegularClass(session: FirSession): FirRegularClass? =
|
||||
session.symbolProvider.getSymbolByLookupTag(this)?.fir as? FirRegularClass
|
||||
|
||||
fun FirSymbolProvider.getSymbolByLookupTag(lookupTag: ConeClassifierLookupTag): FirClassifierSymbol<*>? {
|
||||
return lookupTag.toSymbol(session)
|
||||
}
|
||||
|
||||
fun FirSymbolProvider.getSymbolByLookupTag(lookupTag: ConeClassLikeLookupTag): FirClassLikeSymbol<*>? {
|
||||
return lookupTag.toSymbol(session)
|
||||
}
|
||||
|
||||
fun ConeKotlinType.withParameterNameAnnotation(valueParameter: FirValueParameter, context: ConeTypeContext): ConeKotlinType {
|
||||
if (valueParameter.name == SpecialNames.NO_NAME_PROVIDED || valueParameter.name == SpecialNames.UNDERSCORE_FOR_UNUSED_VAR) return this
|
||||
// Existing @ParameterName annotation takes precedence
|
||||
if (attributes.customAnnotations.getAnnotationsByClassId(StandardNames.FqNames.parameterNameClassId).isNotEmpty()) return this
|
||||
|
||||
val fakeSource = valueParameter.source?.fakeElement(FirFakeSourceElementKind.ParameterNameAnnotationCall)
|
||||
val parameterNameAnnotationCall = buildAnnotation {
|
||||
source = fakeSource
|
||||
annotationTypeRef =
|
||||
buildResolvedTypeRef {
|
||||
source = fakeSource
|
||||
type = ConeClassLikeTypeImpl(
|
||||
ConeClassLikeLookupTagImpl(StandardNames.FqNames.parameterNameClassId),
|
||||
emptyArray(),
|
||||
isNullable = false
|
||||
)
|
||||
}
|
||||
argumentMapping = buildAnnotationArgumentMapping {
|
||||
mapping[StandardClassIds.Annotations.ParameterNames.parameterNameName] =
|
||||
buildConstExpression(fakeSource, ConstantValueKind.String, valueParameter.name.asString(), setType = true)
|
||||
}
|
||||
}
|
||||
val attributesWithParameterNameAnnotation =
|
||||
ConeAttributes.create(listOf(CustomAnnotationTypeAttribute(listOf(parameterNameAnnotationCall))))
|
||||
return withCombinedCustomAttributesFrom(attributesWithParameterNameAnnotation, context)
|
||||
}
|
||||
|
||||
fun ConeKotlinType.withCombinedCustomAttributesFrom(other: ConeKotlinType, context: ConeTypeContext): ConeKotlinType =
|
||||
withCombinedCustomAttributesFrom(other.attributes, context)
|
||||
|
||||
private fun ConeKotlinType.withCombinedCustomAttributesFrom(other: ConeAttributes, context: ConeTypeContext): ConeKotlinType {
|
||||
val customAttributesFromOther = other.custom ?: return this
|
||||
val combinedConeAttributes = attributes.add(ConeAttributes.create(listOf(customAttributesFromOther)))
|
||||
return withAttributes(combinedConeAttributes, context)
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.fir.resolve
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.FirClass
|
||||
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
|
||||
import org.jetbrains.kotlin.fir.expressions.FirExpressionWithSmartcast
|
||||
import org.jetbrains.kotlin.fir.expressions.FirExpressionWithSmartcastToNull
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap
|
||||
import org.jetbrains.kotlin.fir.scopes.FakeOverrideTypeCalculator
|
||||
import org.jetbrains.kotlin.fir.scopes.FirTypeScope
|
||||
import org.jetbrains.kotlin.fir.scopes.FirUnstableSmartcastTypeScope
|
||||
import org.jetbrains.kotlin.fir.scopes.impl.FirScopeWithFakeOverrideTypeCalculator
|
||||
import org.jetbrains.kotlin.fir.scopes.impl.FirStandardOverrideChecker
|
||||
import org.jetbrains.kotlin.fir.scopes.impl.FirTypeIntersectionScope
|
||||
import org.jetbrains.kotlin.fir.scopes.scopeForClass
|
||||
import org.jetbrains.kotlin.fir.symbols.ensureResolved
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.ConeClassLikeLookupTagImpl
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
|
||||
import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
|
||||
fun FirExpressionWithSmartcast.smartcastScope(
|
||||
useSiteSession: FirSession,
|
||||
scopeSession: ScopeSession
|
||||
): FirTypeScope? {
|
||||
val smartcastType =
|
||||
if (this is FirExpressionWithSmartcastToNull) smartcastTypeWithoutNullableNothing.coneType else smartcastType.coneType
|
||||
val smartcastScope = smartcastType.scope(useSiteSession, scopeSession, FakeOverrideTypeCalculator.DoNothing)
|
||||
if (isStable) {
|
||||
return smartcastScope
|
||||
}
|
||||
val originalScope = originalType.coneType.scope(useSiteSession, scopeSession, FakeOverrideTypeCalculator.DoNothing)
|
||||
?: return smartcastScope
|
||||
|
||||
if (smartcastScope == null) {
|
||||
return originalScope
|
||||
}
|
||||
return FirUnstableSmartcastTypeScope(smartcastScope, originalScope)
|
||||
}
|
||||
|
||||
fun ConeKotlinType.scope(
|
||||
useSiteSession: FirSession,
|
||||
scopeSession: ScopeSession,
|
||||
fakeOverrideTypeCalculator: FakeOverrideTypeCalculator
|
||||
): FirTypeScope? {
|
||||
val scope = scope(useSiteSession, scopeSession, FirResolvePhase.DECLARATIONS) ?: return null
|
||||
if (fakeOverrideTypeCalculator == FakeOverrideTypeCalculator.DoNothing) return scope
|
||||
return FirScopeWithFakeOverrideTypeCalculator(scope, fakeOverrideTypeCalculator)
|
||||
}
|
||||
|
||||
private fun ConeKotlinType.scope(useSiteSession: FirSession, scopeSession: ScopeSession, requiredPhase: FirResolvePhase): FirTypeScope? {
|
||||
return when (this) {
|
||||
is ConeKotlinErrorType -> null
|
||||
is ConeClassLikeType -> {
|
||||
val fullyExpandedType = fullyExpandedType(useSiteSession)
|
||||
val fir = fullyExpandedType.lookupTag.toSymbol(useSiteSession)?.fir as? FirClass ?: return null
|
||||
|
||||
fir.symbol.ensureResolved(requiredPhase)
|
||||
|
||||
val substitution = createSubstitution(fir.typeParameters, fullyExpandedType, useSiteSession)
|
||||
|
||||
fir.scopeForClass(substitutorByMap(substitution, useSiteSession), useSiteSession, scopeSession)
|
||||
}
|
||||
is ConeTypeParameterType -> {
|
||||
val symbol = lookupTag.symbol
|
||||
scopeSession.getOrBuild(symbol, TYPE_PARAMETER_SCOPE_KEY) {
|
||||
val intersectionType = ConeTypeIntersector.intersectTypes(
|
||||
useSiteSession.typeContext,
|
||||
symbol.fir.bounds.map { it.coneType }
|
||||
)
|
||||
intersectionType.scope(useSiteSession, scopeSession, requiredPhase) ?: FirTypeScope.Empty
|
||||
}
|
||||
}
|
||||
is ConeRawType -> lowerBound.scope(useSiteSession, scopeSession, requiredPhase)
|
||||
is ConeFlexibleType -> lowerBound.scope(useSiteSession, scopeSession, requiredPhase)
|
||||
is ConeIntersectionType -> FirTypeIntersectionScope.prepareIntersectionScope(
|
||||
useSiteSession,
|
||||
FirStandardOverrideChecker(useSiteSession),
|
||||
intersectedTypes.mapNotNullTo(mutableListOf()) {
|
||||
it.scope(useSiteSession, scopeSession, requiredPhase)
|
||||
},
|
||||
type
|
||||
)
|
||||
is ConeDefinitelyNotNullType -> original.scope(useSiteSession, scopeSession, requiredPhase)
|
||||
is ConeIntegerLiteralType -> error("ILT should not be in receiver position")
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
fun FirClassSymbol<*>.defaultType(): ConeClassLikeType = fir.defaultType()
|
||||
|
||||
fun FirClass.defaultType(): ConeClassLikeType =
|
||||
ConeClassLikeTypeImpl(
|
||||
symbol.toLookupTag(),
|
||||
typeParameters.map {
|
||||
ConeTypeParameterTypeImpl(
|
||||
it.symbol.toLookupTag(),
|
||||
isNullable = false
|
||||
)
|
||||
}.toTypedArray(),
|
||||
isNullable = false
|
||||
)
|
||||
|
||||
fun ClassId.defaultType(parameters: List<FirTypeParameterSymbol>): ConeClassLikeType =
|
||||
ConeClassLikeTypeImpl(
|
||||
ConeClassLikeLookupTagImpl(this),
|
||||
parameters.map {
|
||||
ConeTypeParameterTypeImpl(
|
||||
it.toLookupTag(),
|
||||
isNullable = false
|
||||
)
|
||||
}.toTypedArray(),
|
||||
isNullable = false,
|
||||
)
|
||||
|
||||
fun FirClass.typeWithStarProjections(): ConeClassLikeType =
|
||||
ConeClassLikeTypeImpl(
|
||||
symbol.toLookupTag(),
|
||||
typeParameters.map { ConeStarProjection }.toTypedArray(),
|
||||
isNullable = false
|
||||
)
|
||||
|
||||
val TYPE_PARAMETER_SCOPE_KEY = scopeSessionKey<FirTypeParameterSymbol, FirTypeScope>()
|
||||
@@ -0,0 +1,219 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.fir.resolve
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.expandedConeType
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isLocal
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.superConeTypes
|
||||
import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic
|
||||
import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutorByMap
|
||||
import org.jetbrains.kotlin.fir.scopes.FirScope
|
||||
import org.jetbrains.kotlin.fir.scopes.FirTypeScope
|
||||
import org.jetbrains.kotlin.fir.symbols.ensureResolved
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.types.model.CaptureStatus
|
||||
import org.jetbrains.kotlin.utils.SmartList
|
||||
import org.jetbrains.kotlin.utils.SmartSet
|
||||
|
||||
abstract class SupertypeSupplier {
|
||||
abstract fun forClass(firClass: FirClass, useSiteSession: FirSession): List<ConeClassLikeType>
|
||||
abstract fun expansionForTypeAlias(typeAlias: FirTypeAlias, useSiteSession: FirSession): ConeClassLikeType?
|
||||
|
||||
object Default : SupertypeSupplier() {
|
||||
override fun forClass(firClass: FirClass, useSiteSession: FirSession): List<ConeClassLikeType> {
|
||||
if (!firClass.isLocal) {
|
||||
// for local classes the phase may not be updated till that moment
|
||||
firClass.ensureResolved(FirResolvePhase.SUPER_TYPES)
|
||||
}
|
||||
return firClass.superConeTypes
|
||||
}
|
||||
|
||||
override fun expansionForTypeAlias(typeAlias: FirTypeAlias, useSiteSession: FirSession): ConeClassLikeType? {
|
||||
typeAlias.ensureResolved(FirResolvePhase.SUPER_TYPES)
|
||||
return typeAlias.expandedConeType
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun lookupSuperTypes(
|
||||
klass: FirClass,
|
||||
lookupInterfaces: Boolean,
|
||||
deep: Boolean,
|
||||
useSiteSession: FirSession,
|
||||
supertypeSupplier: SupertypeSupplier = SupertypeSupplier.Default,
|
||||
substituteTypes: Boolean = false
|
||||
): List<ConeClassLikeType> {
|
||||
return SmartList<ConeClassLikeType>().also {
|
||||
klass.symbol.collectSuperTypes(it, SmartSet.create(), deep, lookupInterfaces, substituteTypes, useSiteSession, supertypeSupplier)
|
||||
}
|
||||
}
|
||||
|
||||
fun FirClass.isThereLoopInSupertypes(session: FirSession): Boolean {
|
||||
val visitedSymbols: MutableSet<FirClassifierSymbol<*>> = SmartSet.create()
|
||||
val inProcess: MutableSet<FirClassifierSymbol<*>> = mutableSetOf()
|
||||
|
||||
var isThereLoop = false
|
||||
|
||||
fun dfs(current: FirClassifierSymbol<*>) {
|
||||
if (current in visitedSymbols) return
|
||||
if (!inProcess.add(current)) {
|
||||
isThereLoop = true
|
||||
return
|
||||
}
|
||||
|
||||
when (val fir = current.fir) {
|
||||
is FirClass -> {
|
||||
fir.superConeTypes.forEach {
|
||||
it.lookupTag.toSymbol(session)?.let(::dfs)
|
||||
}
|
||||
}
|
||||
is FirTypeAlias -> {
|
||||
fir.expandedConeType?.lookupTag?.toSymbol(session)?.let(::dfs)
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
|
||||
visitedSymbols.add(current)
|
||||
inProcess.remove(current)
|
||||
}
|
||||
|
||||
dfs(symbol)
|
||||
|
||||
return isThereLoop
|
||||
}
|
||||
|
||||
fun lookupSuperTypes(
|
||||
symbol: FirClassifierSymbol<*>,
|
||||
lookupInterfaces: Boolean,
|
||||
deep: Boolean,
|
||||
useSiteSession: FirSession,
|
||||
supertypeSupplier: SupertypeSupplier = SupertypeSupplier.Default
|
||||
): List<ConeClassLikeType> {
|
||||
return SmartList<ConeClassLikeType>().also {
|
||||
symbol.collectSuperTypes(it, SmartSet.create(), deep, lookupInterfaces, false, useSiteSession, supertypeSupplier)
|
||||
}
|
||||
}
|
||||
|
||||
inline fun <reified ID : Any, reified FS : FirScope> scopeSessionKey(): ScopeSessionKey<ID, FS> {
|
||||
return object : ScopeSessionKey<ID, FS>() {}
|
||||
}
|
||||
|
||||
val USE_SITE = scopeSessionKey<FirClassSymbol<*>, FirTypeScope>()
|
||||
|
||||
/* TODO REMOVE */
|
||||
fun createSubstitution(
|
||||
typeParameters: List<FirTypeParameterRef>, // TODO: or really declared?
|
||||
type: ConeClassLikeType,
|
||||
session: FirSession
|
||||
): Map<FirTypeParameterSymbol, ConeKotlinType> {
|
||||
val capturedOrType = session.typeContext.captureFromArguments(type, CaptureStatus.FROM_EXPRESSION) ?: type
|
||||
val typeArguments = (capturedOrType as ConeClassLikeType).typeArguments
|
||||
return typeParameters.zip(typeArguments) { typeParameter, typeArgument ->
|
||||
val typeParameterSymbol = typeParameter.symbol
|
||||
typeParameterSymbol to when (typeArgument) {
|
||||
is ConeKotlinTypeProjection -> {
|
||||
typeArgument.type
|
||||
}
|
||||
else /* StarProjection */ -> {
|
||||
ConeTypeIntersector.intersectTypes(
|
||||
session.typeContext,
|
||||
typeParameterSymbol.fir.bounds.map { it.coneType }
|
||||
)
|
||||
}
|
||||
}
|
||||
}.toMap()
|
||||
}
|
||||
|
||||
private fun ConeClassLikeType.computePartialExpansion(
|
||||
useSiteSession: FirSession,
|
||||
supertypeSupplier: SupertypeSupplier
|
||||
): ConeClassLikeType = fullyExpandedType(useSiteSession) { supertypeSupplier.expansionForTypeAlias(it, useSiteSession) }
|
||||
|
||||
private fun FirClassifierSymbol<*>.collectSuperTypes(
|
||||
list: MutableList<ConeClassLikeType>,
|
||||
visitedSymbols: MutableSet<FirClassifierSymbol<*>>,
|
||||
deep: Boolean,
|
||||
lookupInterfaces: Boolean,
|
||||
substituteSuperTypes: Boolean,
|
||||
useSiteSession: FirSession,
|
||||
supertypeSupplier: SupertypeSupplier
|
||||
) {
|
||||
if (!visitedSymbols.add(this)) return
|
||||
when (this) {
|
||||
is FirClassSymbol<*> -> {
|
||||
val superClassTypes =
|
||||
supertypeSupplier.forClass(fir, useSiteSession).mapNotNull {
|
||||
it.computePartialExpansion(useSiteSession, supertypeSupplier)
|
||||
.takeIf { type -> lookupInterfaces || type.isClassBasedType(useSiteSession) }
|
||||
}
|
||||
list += superClassTypes
|
||||
if (deep)
|
||||
superClassTypes.forEach {
|
||||
if (it !is ConeClassErrorType) {
|
||||
if (substituteSuperTypes) {
|
||||
val substitutedTypes = SmartList<ConeClassLikeType>()
|
||||
it.lookupTag.toSymbol(useSiteSession)?.collectSuperTypes(
|
||||
substitutedTypes,
|
||||
visitedSymbols,
|
||||
deep,
|
||||
lookupInterfaces,
|
||||
substituteSuperTypes,
|
||||
useSiteSession,
|
||||
supertypeSupplier
|
||||
)
|
||||
val substitutor = createSubstitutionForSupertype(it, useSiteSession)
|
||||
substitutedTypes.mapTo(list) { superType -> substitutor.substituteOrSelf(superType) as ConeClassLikeType }
|
||||
} else {
|
||||
it.lookupTag.toSymbol(useSiteSession)?.collectSuperTypes(
|
||||
list,
|
||||
visitedSymbols,
|
||||
deep,
|
||||
lookupInterfaces,
|
||||
substituteSuperTypes,
|
||||
useSiteSession,
|
||||
supertypeSupplier
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
is FirTypeAliasSymbol -> {
|
||||
val expansion = supertypeSupplier
|
||||
.expansionForTypeAlias(fir, useSiteSession)
|
||||
?.computePartialExpansion(useSiteSession, supertypeSupplier)
|
||||
?: return
|
||||
expansion.lookupTag.toSymbol(useSiteSession)
|
||||
?.collectSuperTypes(list, visitedSymbols, deep, lookupInterfaces, substituteSuperTypes, useSiteSession, supertypeSupplier)
|
||||
}
|
||||
else -> error("?!id:1")
|
||||
}
|
||||
}
|
||||
|
||||
private fun ConeClassLikeType?.isClassBasedType(
|
||||
useSiteSession: FirSession
|
||||
): Boolean {
|
||||
if (this is ConeClassErrorType) return false
|
||||
val symbol = this?.lookupTag?.toSymbol(useSiteSession) as? FirClassSymbol ?: return false
|
||||
return when (symbol) {
|
||||
is FirAnonymousObjectSymbol -> true
|
||||
is FirRegularClassSymbol -> symbol.fir.classKind == ClassKind.CLASS
|
||||
}
|
||||
}
|
||||
|
||||
fun createSubstitutionForSupertype(superType: ConeLookupTagBasedType, session: FirSession): ConeSubstitutor {
|
||||
val klass = superType.lookupTag.toSymbol(session)?.fir as? FirRegularClass ?: return ConeSubstitutor.Empty
|
||||
val arguments = superType.typeArguments.map {
|
||||
it as? ConeKotlinType ?: ConeClassErrorType(ConeSimpleDiagnostic("illegal projection usage", DiagnosticKind.IllegalProjectionUsage))
|
||||
}
|
||||
val mapping = klass.typeParameters.map { it.symbol }.zip(arguments).toMap()
|
||||
return ConeSubstitutorByMap(mapping, session)
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.fir.resolve
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
|
||||
import org.jetbrains.kotlin.fir.declarations.FirTypeAlias
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.expandedConeType
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.AbstractConeSubstitutor
|
||||
import org.jetbrains.kotlin.fir.symbols.ensureResolved
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeAliasSymbol
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
|
||||
import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl
|
||||
import org.jetbrains.kotlin.fir.utils.WeakPair
|
||||
import org.jetbrains.kotlin.fir.utils.component1
|
||||
import org.jetbrains.kotlin.fir.utils.component2
|
||||
|
||||
fun ConeClassLikeType.fullyExpandedType(
|
||||
useSiteSession: FirSession,
|
||||
expandedConeType: (FirTypeAlias) -> ConeClassLikeType? = { alias ->
|
||||
alias.ensureResolved(FirResolvePhase.SUPER_TYPES)
|
||||
alias.expandedConeType
|
||||
},
|
||||
): ConeClassLikeType {
|
||||
if (this is ConeClassLikeTypeImpl) {
|
||||
val (cachedSession, cachedExpandedType) = cachedExpandedType
|
||||
if (cachedSession === useSiteSession && cachedExpandedType != null) {
|
||||
return cachedExpandedType
|
||||
}
|
||||
|
||||
val computedExpandedType = fullyExpandedTypeNoCache(useSiteSession, expandedConeType)
|
||||
this.cachedExpandedType = WeakPair(useSiteSession, computedExpandedType)
|
||||
return computedExpandedType
|
||||
}
|
||||
|
||||
return fullyExpandedTypeNoCache(useSiteSession, expandedConeType)
|
||||
}
|
||||
|
||||
fun ConeKotlinType.fullyExpandedType(
|
||||
useSiteSession: FirSession
|
||||
): ConeKotlinType = when (this) {
|
||||
is ConeFlexibleType ->
|
||||
ConeFlexibleType(lowerBound.fullyExpandedType(useSiteSession), upperBound.fullyExpandedType(useSiteSession))
|
||||
is ConeClassLikeType -> fullyExpandedType(useSiteSession)
|
||||
else -> this
|
||||
}
|
||||
|
||||
private fun ConeClassLikeType.fullyExpandedTypeNoCache(
|
||||
useSiteSession: FirSession,
|
||||
expandedConeType: (FirTypeAlias) -> ConeClassLikeType?,
|
||||
): ConeClassLikeType {
|
||||
val directExpansionType = directExpansionType(useSiteSession, expandedConeType) ?: return this
|
||||
return directExpansionType.fullyExpandedType(useSiteSession, expandedConeType)
|
||||
}
|
||||
|
||||
fun ConeClassLikeType.directExpansionType(
|
||||
useSiteSession: FirSession,
|
||||
expandedConeType: (FirTypeAlias) -> ConeClassLikeType? = { alias ->
|
||||
alias.ensureResolved(FirResolvePhase.SUPER_TYPES)
|
||||
alias.expandedConeType
|
||||
},
|
||||
): ConeClassLikeType? {
|
||||
val typeAliasSymbol = lookupTag.toSymbol(useSiteSession) as? FirTypeAliasSymbol ?: return null
|
||||
val typeAlias = typeAliasSymbol.fir
|
||||
|
||||
val resultType = expandedConeType(typeAlias)
|
||||
?.applyNullabilityFrom(useSiteSession, this)
|
||||
?.applyAttributesFrom(useSiteSession, this)
|
||||
?: return null
|
||||
|
||||
if (resultType.typeArguments.isEmpty()) return resultType
|
||||
return mapTypeAliasArguments(typeAlias, this, resultType, useSiteSession) as? ConeClassLikeType
|
||||
}
|
||||
|
||||
private fun ConeClassLikeType.applyNullabilityFrom(
|
||||
session: FirSession,
|
||||
abbreviation: ConeClassLikeType
|
||||
): ConeClassLikeType {
|
||||
if (abbreviation.isMarkedNullable) return withNullability(ConeNullability.NULLABLE, session.typeContext)
|
||||
return this
|
||||
}
|
||||
|
||||
private fun ConeClassLikeType.applyAttributesFrom(
|
||||
session: FirSession,
|
||||
abbreviation: ConeClassLikeType
|
||||
): ConeClassLikeType {
|
||||
val combinedAttributes = attributes.add(abbreviation.attributes)
|
||||
return withAttributes(combinedAttributes, session.typeContext)
|
||||
}
|
||||
|
||||
private fun mapTypeAliasArguments(
|
||||
typeAlias: FirTypeAlias,
|
||||
abbreviatedType: ConeClassLikeType,
|
||||
resultingType: ConeClassLikeType,
|
||||
useSiteSession: FirSession,
|
||||
): ConeKotlinType {
|
||||
if (typeAlias.typeParameters.isNotEmpty() && abbreviatedType.typeArguments.isEmpty()) {
|
||||
return resultingType.lookupTag.constructClassType(emptyArray(), resultingType.isNullable)
|
||||
}
|
||||
val typeAliasMap = typeAlias.typeParameters.map { it.symbol }.zip(abbreviatedType.typeArguments).toMap()
|
||||
|
||||
val substitutor = object : AbstractConeSubstitutor(useSiteSession.typeContext) {
|
||||
override fun substituteType(type: ConeKotlinType): ConeKotlinType? {
|
||||
return null
|
||||
}
|
||||
|
||||
override fun substituteArgument(projection: ConeTypeProjection): ConeTypeProjection? {
|
||||
val type = (projection as? ConeKotlinTypeProjection)?.type ?: return null
|
||||
val symbol = (type as? ConeTypeParameterType)?.lookupTag?.symbol ?: return super.substituteArgument(projection)
|
||||
val mappedProjection = typeAliasMap[symbol] ?: return super.substituteArgument(projection)
|
||||
var mappedType = (mappedProjection as? ConeKotlinTypeProjection)?.type.updateNullabilityIfNeeded(type)
|
||||
mappedType = when (mappedType) {
|
||||
is ConeClassErrorType,
|
||||
is ConeClassLikeTypeImpl,
|
||||
is ConeDefinitelyNotNullType,
|
||||
is ConeTypeParameterTypeImpl,
|
||||
is ConeFlexibleType -> {
|
||||
mappedType.withAttributes(type.attributes.add(mappedType.attributes), useSiteSession.typeContext)
|
||||
}
|
||||
null -> return mappedProjection
|
||||
else -> mappedType
|
||||
}
|
||||
|
||||
fun convertProjectionKindToConeTypeProjection(projectionKind: ProjectionKind): ConeTypeProjection {
|
||||
return when (projectionKind) {
|
||||
ProjectionKind.STAR -> ConeStarProjection
|
||||
ProjectionKind.IN -> ConeKotlinTypeProjectionIn(mappedType)
|
||||
ProjectionKind.OUT -> ConeKotlinTypeProjectionOut(mappedType)
|
||||
ProjectionKind.INVARIANT -> mappedType
|
||||
}
|
||||
}
|
||||
|
||||
if (mappedProjection.kind == projection.kind) {
|
||||
return convertProjectionKindToConeTypeProjection(mappedProjection.kind)
|
||||
}
|
||||
|
||||
if (mappedProjection.kind == ProjectionKind.STAR || projection.kind == ProjectionKind.STAR) {
|
||||
return ConeStarProjection
|
||||
}
|
||||
|
||||
if (mappedProjection.kind == ProjectionKind.INVARIANT) {
|
||||
return convertProjectionKindToConeTypeProjection(projection.kind)
|
||||
}
|
||||
|
||||
if (projection.kind == ProjectionKind.INVARIANT) {
|
||||
return convertProjectionKindToConeTypeProjection(mappedProjection.kind)
|
||||
}
|
||||
|
||||
return ConeKotlinTypeConflictingProjection(mappedType)
|
||||
}
|
||||
}
|
||||
|
||||
return substitutor.substituteOrSelf(resultingType)
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.fir.resolve.calls
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.diagnostics.ConeIntermediateDiagnostic
|
||||
import org.jetbrains.kotlin.fir.expressions.*
|
||||
import org.jetbrains.kotlin.fir.expressions.builder.buildExpressionWithSmartcast
|
||||
import org.jetbrains.kotlin.fir.expressions.builder.buildThisReceiverExpression
|
||||
import org.jetbrains.kotlin.fir.references.builder.buildImplicitThisReference
|
||||
import org.jetbrains.kotlin.fir.renderWithType
|
||||
import org.jetbrains.kotlin.fir.resolve.ScopeSession
|
||||
import org.jetbrains.kotlin.fir.resolve.constructType
|
||||
import org.jetbrains.kotlin.fir.resolve.scope
|
||||
import org.jetbrains.kotlin.fir.resolve.smartcastScope
|
||||
import org.jetbrains.kotlin.fir.resolvedTypeFromPrototype
|
||||
import org.jetbrains.kotlin.fir.scopes.FakeOverrideTypeCalculator
|
||||
import org.jetbrains.kotlin.fir.scopes.FirTypeScope
|
||||
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
|
||||
import org.jetbrains.kotlin.fir.types.ConeKotlinErrorType
|
||||
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.coneType
|
||||
import org.jetbrains.kotlin.fir.types.coneTypeSafe
|
||||
import org.jetbrains.kotlin.types.SmartcastStability
|
||||
|
||||
interface Receiver
|
||||
|
||||
interface ReceiverValue : Receiver {
|
||||
val type: ConeKotlinType
|
||||
|
||||
val receiverExpression: FirExpression
|
||||
|
||||
fun scope(useSiteSession: FirSession, scopeSession: ScopeSession): FirTypeScope? =
|
||||
type.scope(useSiteSession, scopeSession, FakeOverrideTypeCalculator.DoNothing)
|
||||
}
|
||||
|
||||
// TODO: should inherit just Receiver, not ReceiverValue
|
||||
abstract class AbstractExplicitReceiver<E : FirExpression> : Receiver {
|
||||
abstract val explicitReceiver: FirExpression
|
||||
}
|
||||
|
||||
abstract class AbstractExplicitReceiverValue<E : FirExpression> : AbstractExplicitReceiver<E>(), ReceiverValue {
|
||||
override val type: ConeKotlinType
|
||||
// NB: safe cast is necessary here
|
||||
get() = explicitReceiver.typeRef.coneTypeSafe()
|
||||
?: ConeKotlinErrorType(ConeIntermediateDiagnostic("No type calculated for: ${explicitReceiver.renderWithType()}")) // TODO: assert here
|
||||
|
||||
override val receiverExpression: FirExpression
|
||||
get() = explicitReceiver
|
||||
}
|
||||
|
||||
open class ExpressionReceiverValue(
|
||||
override val explicitReceiver: FirExpression
|
||||
) : AbstractExplicitReceiverValue<FirExpression>(), ReceiverValue {
|
||||
override fun scope(useSiteSession: FirSession, scopeSession: ScopeSession): FirTypeScope? {
|
||||
var receiverExpr: FirExpression? = receiverExpression
|
||||
// Unwrap `x!!` to `x` and use the resulted expression to derive receiver type. This is necessary so that smartcast types inside
|
||||
// `!!` is handled correctly.
|
||||
if (receiverExpr is FirCheckNotNullCall) {
|
||||
receiverExpr = receiverExpr.arguments.firstOrNull()
|
||||
}
|
||||
if (receiverExpr is FirExpressionWithSmartcast) {
|
||||
return receiverExpr.smartcastScope(useSiteSession, scopeSession)
|
||||
}
|
||||
return type.scope(useSiteSession, scopeSession, FakeOverrideTypeCalculator.DoNothing)
|
||||
}
|
||||
}
|
||||
|
||||
sealed class ImplicitReceiverValue<S : FirBasedSymbol<*>>(
|
||||
val boundSymbol: S,
|
||||
type: ConeKotlinType,
|
||||
protected val useSiteSession: FirSession,
|
||||
protected val scopeSession: ScopeSession,
|
||||
private val mutable: Boolean,
|
||||
) : ReceiverValue {
|
||||
final override var type: ConeKotlinType = type
|
||||
private set
|
||||
|
||||
val originalType: ConeKotlinType = type
|
||||
|
||||
var implicitScope: FirTypeScope? = type.scope(useSiteSession, scopeSession, FakeOverrideTypeCalculator.DoNothing)
|
||||
private set
|
||||
|
||||
override fun scope(useSiteSession: FirSession, scopeSession: ScopeSession): FirTypeScope? = implicitScope
|
||||
|
||||
private val originalReceiverExpression: FirThisReceiverExpression = receiverExpression(boundSymbol, type)
|
||||
final override var receiverExpression: FirExpression = originalReceiverExpression
|
||||
private set
|
||||
|
||||
/*
|
||||
* Should be called only in ImplicitReceiverStack
|
||||
*/
|
||||
fun replaceType(type: ConeKotlinType) {
|
||||
if (!mutable) throw IllegalStateException("Cannot mutate an immutable ImplicitReceiverValue")
|
||||
if (type == this.type) return
|
||||
this.type = type
|
||||
receiverExpression = if (type == originalReceiverExpression.typeRef.coneType) {
|
||||
originalReceiverExpression
|
||||
} else {
|
||||
buildExpressionWithSmartcast {
|
||||
originalExpression = originalReceiverExpression
|
||||
smartcastType = originalReceiverExpression.typeRef.resolvedTypeFromPrototype(type)
|
||||
typesFromSmartCast = listOf(type)
|
||||
smartcastStability = SmartcastStability.STABLE_VALUE
|
||||
}
|
||||
}
|
||||
implicitScope = type.scope(useSiteSession, scopeSession, FakeOverrideTypeCalculator.DoNothing)
|
||||
}
|
||||
|
||||
abstract fun createSnapshot(): ImplicitReceiverValue<S>
|
||||
}
|
||||
|
||||
private fun receiverExpression(symbol: FirBasedSymbol<*>, type: ConeKotlinType): FirThisReceiverExpression =
|
||||
buildThisReceiverExpression {
|
||||
// NB: we can't use `symbol.fir.source` as the source of `this` receiver. For instance, if this is an implicit receiver for a class,
|
||||
// the entire class itself will be set as a source. If combined with an implicit type operation, a certain assertion, like null
|
||||
// check assertion, will retrieve source as an assertion message, which is literally the entire class (!).
|
||||
calleeReference = buildImplicitThisReference {
|
||||
boundSymbol = symbol
|
||||
}
|
||||
typeRef = buildResolvedTypeRef {
|
||||
this.type = type
|
||||
}
|
||||
isImplicit = true
|
||||
}
|
||||
|
||||
class ImplicitDispatchReceiverValue(
|
||||
boundSymbol: FirClassSymbol<*>,
|
||||
type: ConeKotlinType,
|
||||
useSiteSession: FirSession,
|
||||
scopeSession: ScopeSession,
|
||||
mutable: Boolean = true,
|
||||
) : ImplicitReceiverValue<FirClassSymbol<*>>(boundSymbol, type, useSiteSession, scopeSession, mutable) {
|
||||
constructor(
|
||||
boundSymbol: FirClassSymbol<*>, useSiteSession: FirSession, scopeSession: ScopeSession
|
||||
) : this(
|
||||
boundSymbol, boundSymbol.constructType(typeArguments = emptyArray(), isNullable = false),
|
||||
useSiteSession, scopeSession
|
||||
)
|
||||
|
||||
override fun createSnapshot(): ImplicitReceiverValue<FirClassSymbol<*>> {
|
||||
return ImplicitDispatchReceiverValue(boundSymbol, type, useSiteSession, scopeSession, false)
|
||||
}
|
||||
}
|
||||
|
||||
class ImplicitExtensionReceiverValue(
|
||||
boundSymbol: FirCallableSymbol<*>,
|
||||
type: ConeKotlinType,
|
||||
useSiteSession: FirSession,
|
||||
scopeSession: ScopeSession,
|
||||
mutable: Boolean = true,
|
||||
) : ImplicitReceiverValue<FirCallableSymbol<*>>(boundSymbol, type, useSiteSession, scopeSession, mutable) {
|
||||
override fun createSnapshot(): ImplicitReceiverValue<FirCallableSymbol<*>> {
|
||||
return ImplicitExtensionReceiverValue(boundSymbol, type, useSiteSession, scopeSession, false)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class InaccessibleImplicitReceiverValue(
|
||||
boundSymbol: FirClassSymbol<*>,
|
||||
type: ConeKotlinType,
|
||||
useSiteSession: FirSession,
|
||||
scopeSession: ScopeSession,
|
||||
mutable: Boolean = true,
|
||||
) : ImplicitReceiverValue<FirClassSymbol<*>>(boundSymbol, type, useSiteSession, scopeSession, mutable) {
|
||||
override fun createSnapshot(): ImplicitReceiverValue<FirClassSymbol<*>> {
|
||||
return InaccessibleImplicitReceiverValue(boundSymbol, type, useSiteSession, scopeSession, false)
|
||||
}
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.fir.resolve.calls
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.FirSessionComponent
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
abstract class FirSyntheticNamesProvider : FirSessionComponent {
|
||||
abstract fun possibleGetterNamesByPropertyName(name: Name): List<Name>
|
||||
abstract fun setterNameByGetterName(name: Name): Name?
|
||||
abstract fun getterNameBySetterName(name: Name): Name?
|
||||
abstract fun possiblePropertyNamesByAccessorName(name: Name): List<Name>
|
||||
}
|
||||
|
||||
val FirSession.syntheticNamesProvider: FirSyntheticNamesProvider by FirSession.sessionComponentAccessor()
|
||||
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.fir.resolve.calls
|
||||
|
||||
import org.jetbrains.kotlin.fir.*
|
||||
import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
|
||||
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
|
||||
import org.jetbrains.kotlin.fir.declarations.getDeprecationsFromAccessors
|
||||
import org.jetbrains.kotlin.fir.declarations.synthetic.buildSyntheticProperty
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isStatic
|
||||
import org.jetbrains.kotlin.fir.scopes.*
|
||||
import org.jetbrains.kotlin.fir.symbols.SyntheticSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirAccessorSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol
|
||||
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
|
||||
import org.jetbrains.kotlin.fir.types.ConeNullability.NOT_NULL
|
||||
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.typeContext
|
||||
import org.jetbrains.kotlin.fir.types.withNullability
|
||||
import org.jetbrains.kotlin.name.CallableId
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.name.StandardClassIds
|
||||
import org.jetbrains.kotlin.types.AbstractTypeChecker
|
||||
|
||||
class FirSyntheticPropertySymbol(
|
||||
callableId: CallableId,
|
||||
override val accessorId: CallableId
|
||||
) : FirAccessorSymbol(callableId, accessorId), SyntheticSymbol
|
||||
|
||||
class FirSyntheticFunctionSymbol(
|
||||
callableId: CallableId
|
||||
) : FirNamedFunctionSymbol(callableId), SyntheticSymbol
|
||||
|
||||
class FirSyntheticPropertiesScope(
|
||||
val session: FirSession,
|
||||
private val baseScope: FirTypeScope
|
||||
) : FirContainingNamesAwareScope() {
|
||||
private val syntheticNamesProvider = session.syntheticNamesProvider
|
||||
|
||||
override fun processPropertiesByName(name: Name, processor: (FirVariableSymbol<*>) -> Unit) {
|
||||
val getterNames = syntheticNamesProvider.possibleGetterNamesByPropertyName(name)
|
||||
for (getterName in getterNames) {
|
||||
baseScope.processFunctionsByName(getterName) {
|
||||
checkGetAndCreateSynthetic(name, getterName, it, processor)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getCallableNames(): Set<Name> = baseScope.getCallableNames().flatMapTo(hashSetOf()) { propertyName ->
|
||||
syntheticNamesProvider.possiblePropertyNamesByAccessorName(propertyName)
|
||||
}
|
||||
|
||||
override fun getClassifierNames(): Set<Name> = emptySet()
|
||||
|
||||
private fun checkGetAndCreateSynthetic(
|
||||
propertyName: Name,
|
||||
getterName: Name,
|
||||
getterSymbol: FirFunctionSymbol<*>,
|
||||
processor: (FirVariableSymbol<*>) -> Unit
|
||||
) {
|
||||
if (getterSymbol !is FirNamedFunctionSymbol) return
|
||||
val getter = getterSymbol.fir
|
||||
|
||||
if (getter.typeParameters.isNotEmpty()) return
|
||||
if (getter.valueParameters.isNotEmpty()) return
|
||||
if (getter.isStatic) return
|
||||
val getterReturnType = (getter.returnTypeRef as? FirResolvedTypeRef)?.type
|
||||
if ((getterReturnType as? ConeClassLikeType)?.lookupTag?.classId == StandardClassIds.Unit) return
|
||||
|
||||
if (!getterSymbol.hasJavaOverridden()) return
|
||||
|
||||
var matchingSetter: FirSimpleFunction? = null
|
||||
if (getterReturnType != null) {
|
||||
val setterName = syntheticNamesProvider.setterNameByGetterName(getterName)
|
||||
if (setterName != null) {
|
||||
baseScope.processFunctionsByName(setterName, fun(setterSymbol: FirFunctionSymbol<*>) {
|
||||
if (matchingSetter != null) return
|
||||
val setter = setterSymbol.fir as? FirSimpleFunction ?: return
|
||||
val parameter = setter.valueParameters.singleOrNull() ?: return
|
||||
if (setter.typeParameters.isNotEmpty() || setter.isStatic) return
|
||||
val parameterType = (parameter.returnTypeRef as? FirResolvedTypeRef)?.type ?: return
|
||||
// TODO: at this moment it works for cases like
|
||||
// class Base {
|
||||
// void setSomething(Object value) {}
|
||||
// }
|
||||
// class Derived extends Base {
|
||||
// String getSomething() { return ""; }
|
||||
// }
|
||||
// In FE 1.0, we should have also Object getSomething() in class Base for this to work
|
||||
// I think details here are worth designing
|
||||
if (!AbstractTypeChecker.isSubtypeOf(
|
||||
session.typeContext,
|
||||
getterReturnType.withNullability(NOT_NULL, session.typeContext),
|
||||
parameterType.withNullability(NOT_NULL, session.typeContext)
|
||||
)
|
||||
) {
|
||||
return
|
||||
}
|
||||
matchingSetter = setter
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
val classLookupTag = getterSymbol.originalOrSelf().dispatchReceiverClassOrNull()
|
||||
val packageName = classLookupTag?.classId?.packageFqName ?: getterSymbol.callableId.packageName
|
||||
val className = classLookupTag?.classId?.relativeClassName
|
||||
|
||||
val property = buildSyntheticProperty {
|
||||
moduleData = session.moduleData
|
||||
name = propertyName
|
||||
symbol = FirSyntheticPropertySymbol(
|
||||
accessorId = getterSymbol.callableId,
|
||||
callableId = CallableId(packageName, className, propertyName)
|
||||
)
|
||||
delegateGetter = getter
|
||||
delegateSetter = matchingSetter
|
||||
deprecation = getDeprecationsFromAccessors(getter, matchingSetter, session.languageVersionSettings.apiVersion)
|
||||
}
|
||||
val syntheticSymbol = property.symbol
|
||||
(baseScope as? FirUnstableSmartcastTypeScope)?.apply {
|
||||
if (isSymbolFromUnstableSmartcast(getterSymbol)) {
|
||||
markSymbolFromUnstableSmartcast(syntheticSymbol)
|
||||
}
|
||||
}
|
||||
processor(syntheticSymbol)
|
||||
}
|
||||
|
||||
private fun FirNamedFunctionSymbol.hasJavaOverridden(): Boolean {
|
||||
var result = false
|
||||
baseScope.processOverriddenFunctionsAndSelf(this) {
|
||||
if (it.unwrapFakeOverrides().fir.origin == FirDeclarationOrigin.Enhancement) {
|
||||
result = true
|
||||
ProcessorAction.STOP
|
||||
} else {
|
||||
ProcessorAction.NEXT
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.fir.resolve.providers
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.FirSessionComponent
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
@RequiresOptIn
|
||||
annotation class FirProviderInternals
|
||||
|
||||
abstract class FirProvider : FirSessionComponent {
|
||||
/**
|
||||
* [symbolProvider] for [FirProvider] may provide only symbols from sources of current module
|
||||
*/
|
||||
abstract val symbolProvider: FirSymbolProvider
|
||||
|
||||
open val isPhasedFirAllowed: Boolean get() = false
|
||||
|
||||
abstract fun getFirClassifierByFqName(classId: ClassId): FirClassLikeDeclaration?
|
||||
|
||||
abstract fun getFirClassifierContainerFile(fqName: ClassId): FirFile
|
||||
|
||||
abstract fun getFirClassifierContainerFileIfAny(fqName: ClassId): FirFile?
|
||||
|
||||
open fun getFirClassifierContainerFile(symbol: FirClassLikeSymbol<*>): FirFile =
|
||||
getFirClassifierContainerFile(symbol.classId)
|
||||
|
||||
open fun getFirClassifierContainerFileIfAny(symbol: FirClassLikeSymbol<*>): FirFile? =
|
||||
getFirClassifierContainerFileIfAny(symbol.classId)
|
||||
|
||||
abstract fun getFirCallableContainerFile(symbol: FirCallableSymbol<*>): FirFile?
|
||||
|
||||
abstract fun getFirFilesByPackage(fqName: FqName): List<FirFile>
|
||||
|
||||
@FirProviderInternals
|
||||
abstract fun recordGeneratedClass(owner: FirAnnotatedDeclaration, klass: FirRegularClass)
|
||||
|
||||
@FirProviderInternals
|
||||
abstract fun recordGeneratedMember(owner: FirAnnotatedDeclaration, klass: FirDeclaration)
|
||||
|
||||
abstract fun getClassNamesInPackage(fqName: FqName): Set<Name>
|
||||
}
|
||||
|
||||
val FirSession.firProvider: FirProvider by FirSession.sessionComponentAccessor()
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.fir.resolve.providers
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.FirSessionComponent
|
||||
import org.jetbrains.kotlin.fir.resolve.getSymbolByLookupTag
|
||||
import org.jetbrains.kotlin.fir.scopes.FirScope
|
||||
import org.jetbrains.kotlin.fir.scopes.getDeclaredConstructors
|
||||
import org.jetbrains.kotlin.fir.scopes.getFunctions
|
||||
import org.jetbrains.kotlin.fir.scopes.getProperties
|
||||
import org.jetbrains.kotlin.fir.scopes.impl.declaredMemberScope
|
||||
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||
import org.jetbrains.kotlin.fir.types.ConeLookupTagBasedType
|
||||
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.coneTypeSafe
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
@RequiresOptIn
|
||||
annotation class FirSymbolProviderInternals
|
||||
|
||||
abstract class FirSymbolProvider(val session: FirSession) : FirSessionComponent {
|
||||
abstract fun getClassLikeSymbolByClassId(classId: ClassId): FirClassLikeSymbol<*>?
|
||||
|
||||
@OptIn(ExperimentalStdlibApi::class, FirSymbolProviderInternals::class)
|
||||
open fun getTopLevelCallableSymbols(packageFqName: FqName, name: Name): List<FirCallableSymbol<*>> {
|
||||
return buildList { getTopLevelCallableSymbolsTo(this, packageFqName, name) }
|
||||
}
|
||||
|
||||
@FirSymbolProviderInternals
|
||||
abstract fun getTopLevelCallableSymbolsTo(destination: MutableList<FirCallableSymbol<*>>, packageFqName: FqName, name: Name)
|
||||
|
||||
@OptIn(ExperimentalStdlibApi::class, FirSymbolProviderInternals::class)
|
||||
open fun getTopLevelFunctionSymbols(packageFqName: FqName, name: Name): List<FirNamedFunctionSymbol> {
|
||||
return buildList { getTopLevelFunctionSymbolsTo(this, packageFqName, name) }
|
||||
}
|
||||
|
||||
@FirSymbolProviderInternals
|
||||
abstract fun getTopLevelFunctionSymbolsTo(destination: MutableList<FirNamedFunctionSymbol>, packageFqName: FqName, name: Name)
|
||||
|
||||
@OptIn(ExperimentalStdlibApi::class, FirSymbolProviderInternals::class)
|
||||
open fun getTopLevelPropertySymbols(packageFqName: FqName, name: Name): List<FirPropertySymbol> {
|
||||
return buildList { getTopLevelPropertySymbolsTo(this, packageFqName, name) }
|
||||
}
|
||||
|
||||
@FirSymbolProviderInternals
|
||||
abstract fun getTopLevelPropertySymbolsTo(destination: MutableList<FirPropertySymbol>, packageFqName: FqName, name: Name)
|
||||
|
||||
abstract fun getPackage(fqName: FqName): FqName? // TODO: Replace to symbol sometime
|
||||
}
|
||||
|
||||
abstract class FirDependenciesSymbolProvider(session: FirSession) : FirSymbolProvider(session)
|
||||
|
||||
private fun FirSymbolProvider.getClassDeclaredMemberScope(classId: ClassId): FirScope? {
|
||||
val classSymbol = getClassLikeSymbolByClassId(classId) as? FirRegularClassSymbol ?: return null
|
||||
return session.declaredMemberScope(classSymbol.fir)
|
||||
}
|
||||
|
||||
fun FirSymbolProvider.getClassDeclaredConstructors(classId: ClassId): List<FirConstructorSymbol> {
|
||||
val classMemberScope = getClassDeclaredMemberScope(classId)
|
||||
return classMemberScope?.getDeclaredConstructors().orEmpty()
|
||||
}
|
||||
|
||||
fun FirSymbolProvider.getClassDeclaredFunctionSymbols(classId: ClassId, name: Name): List<FirNamedFunctionSymbol> {
|
||||
val classMemberScope = getClassDeclaredMemberScope(classId)
|
||||
return classMemberScope?.getFunctions(name).orEmpty()
|
||||
}
|
||||
|
||||
fun FirSymbolProvider.getClassDeclaredPropertySymbols(classId: ClassId, name: Name): List<FirVariableSymbol<*>> {
|
||||
val classMemberScope = getClassDeclaredMemberScope(classId)
|
||||
return classMemberScope?.getProperties(name).orEmpty()
|
||||
}
|
||||
|
||||
inline fun <reified T : FirBasedSymbol<*>> FirSymbolProvider.getSymbolByTypeRef(typeRef: FirTypeRef): T? {
|
||||
val lookupTag = typeRef.coneTypeSafe<ConeLookupTagBasedType>()?.lookupTag ?: return null
|
||||
return getSymbolByLookupTag(lookupTag) as? T
|
||||
}
|
||||
|
||||
val FirSession.symbolProvider: FirSymbolProvider by FirSession.sessionComponentAccessor()
|
||||
val FirSession.dependenciesSymbolProvider: FirSymbolProvider by FirSession.sessionComponentAccessor<FirDependenciesSymbolProvider>()
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2010-2018 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.fir.resolve.providers.impl
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.NoMutableState
|
||||
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider
|
||||
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProviderInternals
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
@NoMutableState
|
||||
class FirCompositeSymbolProvider(session: FirSession, val providers: List<FirSymbolProvider>) : FirSymbolProvider(session) {
|
||||
override fun getTopLevelCallableSymbols(packageFqName: FqName, name: Name): List<FirCallableSymbol<*>> {
|
||||
return providers.flatMap { it.getTopLevelCallableSymbols(packageFqName, name) }
|
||||
}
|
||||
|
||||
@FirSymbolProviderInternals
|
||||
override fun getTopLevelCallableSymbolsTo(destination: MutableList<FirCallableSymbol<*>>, packageFqName: FqName, name: Name) {
|
||||
destination += getTopLevelCallableSymbols(packageFqName, name)
|
||||
}
|
||||
|
||||
@FirSymbolProviderInternals
|
||||
override fun getTopLevelFunctionSymbolsTo(destination: MutableList<FirNamedFunctionSymbol>, packageFqName: FqName, name: Name) {
|
||||
providers.forEach {
|
||||
it.getTopLevelFunctionSymbolsTo(destination, packageFqName, name)
|
||||
}
|
||||
}
|
||||
|
||||
@FirSymbolProviderInternals
|
||||
override fun getTopLevelPropertySymbolsTo(destination: MutableList<FirPropertySymbol>, packageFqName: FqName, name: Name) {
|
||||
providers.forEach {
|
||||
it.getTopLevelPropertySymbolsTo(destination, packageFqName, name)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getPackage(fqName: FqName): FqName? {
|
||||
return providers.firstNotNullOfOrNull { it.getPackage(fqName) }
|
||||
}
|
||||
|
||||
override fun getClassLikeSymbolByClassId(classId: ClassId): FirClassLikeSymbol<*>? {
|
||||
return providers.firstNotNullOfOrNull { it.getClassLikeSymbolByClassId(classId) }
|
||||
}
|
||||
}
|
||||
+90
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.fir.resolve.providers.impl
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.ThreadSafeMutableState
|
||||
import org.jetbrains.kotlin.fir.caches.createCache
|
||||
import org.jetbrains.kotlin.fir.caches.firCachesFactory
|
||||
import org.jetbrains.kotlin.fir.caches.getValue
|
||||
import org.jetbrains.kotlin.fir.nullableModuleData
|
||||
import org.jetbrains.kotlin.fir.resolve.providers.FirDependenciesSymbolProvider
|
||||
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProviderInternals
|
||||
import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
|
||||
import org.jetbrains.kotlin.name.CallableId
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
@ThreadSafeMutableState
|
||||
open class FirDependenciesSymbolProviderImpl(session: FirSession) : FirDependenciesSymbolProvider(session) {
|
||||
private val classCache = session.firCachesFactory.createCache(::computeClass)
|
||||
private val topLevelCallableCache = session.firCachesFactory.createCache(::computeTopLevelCallables)
|
||||
private val topLevelFunctionCache = session.firCachesFactory.createCache(::computeTopLevelFunctions)
|
||||
private val topLevelPropertyCache = session.firCachesFactory.createCache(::computeTopLevelProperties)
|
||||
private val packageCache = session.firCachesFactory.createCache(::computePackage)
|
||||
|
||||
|
||||
protected open val dependencyProviders by lazy {
|
||||
val moduleData = session.nullableModuleData ?: return@lazy emptyList()
|
||||
(moduleData.dependencies + moduleData.friendDependencies + moduleData.dependsOnDependencies).mapNotNull {
|
||||
session.sessionProvider?.getSession(it)?.symbolProvider
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(FirSymbolProviderInternals::class, ExperimentalStdlibApi::class)
|
||||
private fun computeTopLevelCallables(callableId: CallableId): List<FirCallableSymbol<*>> = buildList {
|
||||
dependencyProviders.forEach { it.getTopLevelCallableSymbolsTo(this, callableId.packageName, callableId.callableName) }
|
||||
}
|
||||
|
||||
@OptIn(FirSymbolProviderInternals::class, ExperimentalStdlibApi::class)
|
||||
private fun computeTopLevelFunctions(callableId: CallableId): List<FirNamedFunctionSymbol> = buildList {
|
||||
dependencyProviders.forEach { it.getTopLevelFunctionSymbolsTo(this, callableId.packageName, callableId.callableName) }
|
||||
}
|
||||
|
||||
@OptIn(FirSymbolProviderInternals::class, ExperimentalStdlibApi::class)
|
||||
private fun computeTopLevelProperties(callableId: CallableId): List<FirPropertySymbol> = buildList {
|
||||
dependencyProviders.forEach { it.getTopLevelPropertySymbolsTo(this, callableId.packageName, callableId.callableName) }
|
||||
}
|
||||
|
||||
private fun computePackage(it: FqName): FqName? =
|
||||
dependencyProviders.firstNotNullOfOrNull { provider -> provider.getPackage(it) }
|
||||
|
||||
private fun computeClass(classId: ClassId): FirClassLikeSymbol<*>? =
|
||||
dependencyProviders.firstNotNullOfOrNull { provider -> provider.getClassLikeSymbolByClassId(classId) }
|
||||
|
||||
|
||||
@FirSymbolProviderInternals
|
||||
override fun getTopLevelFunctionSymbolsTo(destination: MutableList<FirNamedFunctionSymbol>, packageFqName: FqName, name: Name) {
|
||||
destination += topLevelFunctionCache.getValue(CallableId(packageFqName, name))
|
||||
}
|
||||
|
||||
@FirSymbolProviderInternals
|
||||
override fun getTopLevelPropertySymbolsTo(destination: MutableList<FirPropertySymbol>, packageFqName: FqName, name: Name) {
|
||||
destination += topLevelPropertyCache.getValue(CallableId(packageFqName, name))
|
||||
}
|
||||
|
||||
@FirSymbolProviderInternals
|
||||
override fun getTopLevelCallableSymbolsTo(destination: MutableList<FirCallableSymbol<*>>, packageFqName: FqName, name: Name) {
|
||||
destination += getTopLevelCallableSymbols(packageFqName, name)
|
||||
}
|
||||
|
||||
override fun getTopLevelCallableSymbols(packageFqName: FqName, name: Name): List<FirCallableSymbol<*>> {
|
||||
return topLevelCallableCache.getValue(CallableId(packageFqName, name))
|
||||
}
|
||||
|
||||
override fun getClassLikeSymbolByClassId(classId: ClassId): FirClassLikeSymbol<*>? {
|
||||
return classCache.getValue(classId)
|
||||
}
|
||||
|
||||
override fun getPackage(fqName: FqName): FqName? {
|
||||
return packageCache.getValue(fqName)
|
||||
}
|
||||
}
|
||||
+188
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.fir.resolve.substitution
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.resolve.withCombinedCustomAttributesFrom
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
|
||||
import org.jetbrains.kotlin.types.TypeApproximatorConfiguration
|
||||
import org.jetbrains.kotlin.types.model.TypeConstructorMarker
|
||||
import org.jetbrains.kotlin.types.model.TypeSubstitutorMarker
|
||||
import org.jetbrains.kotlin.types.model.typeConstructor
|
||||
|
||||
abstract class AbstractConeSubstitutor(private val typeContext: ConeTypeContext) : ConeSubstitutor() {
|
||||
private fun wrapProjection(old: ConeTypeProjection, newType: ConeKotlinType): ConeTypeProjection {
|
||||
return when (old) {
|
||||
is ConeStarProjection -> old
|
||||
is ConeKotlinTypeProjectionIn -> ConeKotlinTypeProjectionIn(newType)
|
||||
is ConeKotlinTypeProjectionOut -> ConeKotlinTypeProjectionOut(newType)
|
||||
is ConeKotlinTypeConflictingProjection -> ConeKotlinTypeConflictingProjection(newType)
|
||||
is ConeKotlinType -> newType
|
||||
else -> old
|
||||
}
|
||||
}
|
||||
|
||||
abstract fun substituteType(type: ConeKotlinType): ConeKotlinType?
|
||||
open fun substituteArgument(projection: ConeTypeProjection): ConeTypeProjection? {
|
||||
val type = (projection as? ConeKotlinTypeProjection)?.type ?: return null
|
||||
val newType = substituteOrNull(type) ?: return null
|
||||
return wrapProjection(projection, newType)
|
||||
}
|
||||
|
||||
fun ConeKotlinType?.updateNullabilityIfNeeded(originalType: ConeKotlinType): ConeKotlinType? {
|
||||
return when {
|
||||
originalType is ConeDefinitelyNotNullType -> this?.withNullability(ConeNullability.NOT_NULL, typeContext)
|
||||
originalType.isMarkedNullable -> this?.withNullability(ConeNullability.NULLABLE, typeContext)
|
||||
else -> this
|
||||
}
|
||||
}
|
||||
|
||||
override fun substituteOrNull(type: ConeKotlinType): ConeKotlinType? {
|
||||
val newType = substituteType(type)
|
||||
if (newType != null && type is ConeDefinitelyNotNullType) {
|
||||
return newType.makeConeTypeDefinitelyNotNullOrNotNull(typeContext)
|
||||
}
|
||||
return (newType ?: type.substituteRecursive())
|
||||
}
|
||||
|
||||
private fun ConeKotlinType.substituteRecursive(): ConeKotlinType? {
|
||||
return when (this) {
|
||||
is ConeClassErrorType -> return null
|
||||
is ConeClassLikeType -> this.substituteArguments()
|
||||
is ConeLookupTagBasedType -> return null
|
||||
is ConeFlexibleType -> this.substituteBounds()?.let {
|
||||
// TODO: may be (?) it's worth adding regular type comparison via AbstractTypeChecker
|
||||
// However, the simplified check here should be enough for typical flexible types
|
||||
if (it.lowerBound == it.upperBound) it.lowerBound
|
||||
else it
|
||||
}
|
||||
is ConeCapturedType -> return null
|
||||
is ConeDefinitelyNotNullType -> this.substituteOriginal()
|
||||
is ConeIntersectionType -> this.substituteIntersectedTypes()
|
||||
is ConeStubType -> return null
|
||||
is ConeIntegerLiteralType -> return null
|
||||
}
|
||||
}
|
||||
|
||||
private fun ConeIntersectionType.substituteIntersectedTypes(): ConeIntersectionType? {
|
||||
val substitutedTypes = ArrayList<ConeKotlinType>(intersectedTypes.size)
|
||||
var somethingIsSubstituted = false
|
||||
for (type in intersectedTypes) {
|
||||
val substitutedType = substituteOrNull(type)?.also {
|
||||
somethingIsSubstituted = true
|
||||
} ?: type
|
||||
substitutedTypes += substitutedType
|
||||
}
|
||||
if (!somethingIsSubstituted) return null
|
||||
return ConeIntersectionType(substitutedTypes)
|
||||
}
|
||||
|
||||
private fun ConeDefinitelyNotNullType.substituteOriginal(): ConeKotlinType? {
|
||||
val substituted = substituteOrNull(original)
|
||||
?.withNullability(ConeNullability.NOT_NULL, typeContext)
|
||||
?.withAttributes(original.attributes, typeContext)
|
||||
?: return null
|
||||
return ConeDefinitelyNotNullType.create(substituted, typeContext) ?: substituted
|
||||
}
|
||||
|
||||
private fun ConeFlexibleType.substituteBounds(): ConeFlexibleType? {
|
||||
val newLowerBound = substituteOrNull(lowerBound)
|
||||
val newUpperBound = substituteOrNull(upperBound)
|
||||
if (newLowerBound != null || newUpperBound != null) {
|
||||
return ConeFlexibleType(
|
||||
newLowerBound?.lowerBoundIfFlexible() ?: lowerBound,
|
||||
newUpperBound?.upperBoundIfFlexible() ?: upperBound
|
||||
)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private fun ConeKotlinType.substituteArguments(): ConeKotlinType? {
|
||||
val newArguments by lazy { arrayOfNulls<ConeTypeProjection>(typeArguments.size) }
|
||||
var initialized = false
|
||||
for ((index, typeArgument) in this.typeArguments.withIndex()) {
|
||||
newArguments[index] = substituteArgument(typeArgument)?.also {
|
||||
initialized = true
|
||||
}
|
||||
}
|
||||
|
||||
if (initialized) {
|
||||
for ((index, typeArgument) in this.typeArguments.withIndex()) {
|
||||
if (newArguments[index] == null) {
|
||||
newArguments[index] = typeArgument
|
||||
}
|
||||
}
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return when (this) {
|
||||
is ConeClassLikeTypeImpl -> ConeClassLikeTypeImpl(
|
||||
lookupTag,
|
||||
newArguments as Array<ConeTypeProjection>,
|
||||
nullability.isNullable,
|
||||
attributes
|
||||
)
|
||||
is ConeClassLikeType -> error("Unknown class-like type to substitute: $this, ${this::class}")
|
||||
else -> error("Unknown type to substitute: $this, ${this::class}")
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
fun substitutorByMap(substitution: Map<FirTypeParameterSymbol, ConeKotlinType>, useSiteSession: FirSession): ConeSubstitutor {
|
||||
// If all arguments match parameters, then substitutor isn't needed
|
||||
if (substitution.all { (parameterSymbol, argumentType) ->
|
||||
(argumentType as? ConeTypeParameterType)?.lookupTag?.typeParameterSymbol == parameterSymbol
|
||||
}
|
||||
) return ConeSubstitutor.Empty
|
||||
return ConeSubstitutorByMap(substitution, useSiteSession)
|
||||
}
|
||||
|
||||
data class ChainedSubstitutor(private val first: ConeSubstitutor, private val second: ConeSubstitutor) : ConeSubstitutor() {
|
||||
override fun substituteOrNull(type: ConeKotlinType): ConeKotlinType? {
|
||||
first.substituteOrNull(type)?.let { return second.substituteOrSelf(it) }
|
||||
return second.substituteOrNull(type)
|
||||
}
|
||||
}
|
||||
|
||||
fun ConeSubstitutor.chain(other: ConeSubstitutor): ConeSubstitutor {
|
||||
if (this == ConeSubstitutor.Empty) return other
|
||||
if (other == ConeSubstitutor.Empty) return this
|
||||
return ChainedSubstitutor(this, other)
|
||||
}
|
||||
|
||||
data class ConeSubstitutorByMap(
|
||||
val substitution: Map<FirTypeParameterSymbol, ConeKotlinType>,
|
||||
val useSiteSession: FirSession
|
||||
) : AbstractConeSubstitutor(useSiteSession.typeContext) {
|
||||
override fun substituteType(type: ConeKotlinType): ConeKotlinType? {
|
||||
if (type !is ConeTypeParameterType) return null
|
||||
val result =
|
||||
substitution[type.lookupTag.symbol].updateNullabilityIfNeeded(type)
|
||||
?.withCombinedCustomAttributesFrom(type, useSiteSession.typeContext)
|
||||
?: return null
|
||||
if (type.isUnsafeVarianceType(useSiteSession)) {
|
||||
return useSiteSession.typeApproximator.approximateToSuperType(
|
||||
result, TypeApproximatorConfiguration.FinalApproximationAfterResolutionAndInference
|
||||
) ?: result
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
fun createTypeSubstitutorByTypeConstructor(map: Map<TypeConstructorMarker, ConeKotlinType>, context: ConeTypeContext): ConeSubstitutor {
|
||||
if (map.isEmpty()) return ConeSubstitutor.Empty
|
||||
return object : AbstractConeSubstitutor(context), TypeSubstitutorMarker {
|
||||
override fun substituteType(type: ConeKotlinType): ConeKotlinType? {
|
||||
if (type !is ConeLookupTagBasedType && type !is ConeStubType) return null
|
||||
val new = map[type.typeConstructor(context)] ?: return null
|
||||
return new.approximateIntegerLiteralType().updateNullabilityIfNeeded(type)?.withCombinedCustomAttributesFrom(type, context)
|
||||
}
|
||||
}
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.fir.resolve.transformers
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
|
||||
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
||||
import org.jetbrains.kotlin.fir.resolve.toSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.ensureResolved
|
||||
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
|
||||
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.coneTypeSafe
|
||||
|
||||
fun FirBasedSymbol<*>.ensureResolvedForCalls() {
|
||||
if (fir.resolvePhase >= FirResolvePhase.DECLARATIONS) return
|
||||
|
||||
// val requiredPhase = when (fir) {
|
||||
// is FirFunction, is FirProperty -> FirResolvePhase.CONTRACTS
|
||||
// else -> FirResolvePhase.STATUS
|
||||
// }
|
||||
//
|
||||
// if (requiredPhase == FirResolvePhase.CONTRACTS) {
|
||||
// // Workaround for recursive contracts in CLI
|
||||
// // Otherwise the assertion about presence of fir.session.phaseManager would fail
|
||||
// // See org.jetbrains.kotlin.fir.FirOldFrontendDiagnosticsTestWithStdlibGenerated.Contracts.Dsl.Errors.testRecursiveContract
|
||||
// if (fir.session.phaseManager == null) return
|
||||
// }
|
||||
|
||||
val requiredPhase = FirResolvePhase.DECLARATIONS
|
||||
|
||||
ensureResolved(requiredPhase)
|
||||
}
|
||||
|
||||
fun ConeKotlinType.ensureResolvedTypeDeclaration(
|
||||
useSiteSession: FirSession,
|
||||
requiredPhase: FirResolvePhase = FirResolvePhase.DECLARATIONS,
|
||||
) {
|
||||
if (this !is ConeClassLikeType) return
|
||||
|
||||
lookupTag.toSymbol(useSiteSession)?.ensureResolved(requiredPhase)
|
||||
fullyExpandedType(useSiteSession).lookupTag.toSymbol(useSiteSession)?.ensureResolved(requiredPhase)
|
||||
}
|
||||
|
||||
fun FirTypeRef.ensureResolvedTypeDeclaration(
|
||||
useSiteSession: FirSession,
|
||||
requiredPhase: FirResolvePhase = FirResolvePhase.DECLARATIONS,
|
||||
) {
|
||||
coneTypeSafe<ConeKotlinType>()?.ensureResolvedTypeDeclaration(useSiteSession, requiredPhase)
|
||||
}
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.fir.scopes
|
||||
|
||||
import org.jetbrains.kotlin.fir.declarations.FirDeclarationAttributes
|
||||
import org.jetbrains.kotlin.fir.declarations.FirDeclarationDataKey
|
||||
import org.jetbrains.kotlin.fir.declarations.FirDeclarationDataRegistry
|
||||
import org.jetbrains.kotlin.fir.declarations.FirTypedDeclaration
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
||||
import org.jetbrains.kotlin.fir.resolvedTypeFromPrototype
|
||||
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
||||
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
||||
|
||||
abstract class FakeOverrideTypeCalculator {
|
||||
abstract fun computeReturnType(declaration: FirTypedDeclaration): FirTypeRef
|
||||
|
||||
object DoNothing : FakeOverrideTypeCalculator() {
|
||||
override fun computeReturnType(declaration: FirTypedDeclaration): FirTypeRef {
|
||||
return declaration.returnTypeRef
|
||||
}
|
||||
}
|
||||
|
||||
object Forced : FakeOverrideTypeCalculator() {
|
||||
override fun computeReturnType(declaration: FirTypedDeclaration): FirResolvedTypeRef {
|
||||
val fakeOverrideSubstitution = declaration.attributes.fakeOverrideSubstitution
|
||||
?: return declaration.returnTypeRef as FirResolvedTypeRef
|
||||
synchronized(fakeOverrideSubstitution) {
|
||||
if (declaration.attributes.fakeOverrideSubstitution == null) {
|
||||
return declaration.returnTypeRef as FirResolvedTypeRef
|
||||
}
|
||||
declaration.attributes.fakeOverrideSubstitution = null
|
||||
val (substitutor, baseSymbol) = fakeOverrideSubstitution
|
||||
val baseDeclaration = baseSymbol.fir as FirTypedDeclaration
|
||||
val baseReturnType = computeReturnType(baseDeclaration).type
|
||||
val coneType = substitutor.substituteOrSelf(baseReturnType)
|
||||
val returnType = declaration.returnTypeRef.resolvedTypeFromPrototype(coneType)
|
||||
declaration.replaceReturnTypeRef(returnType)
|
||||
return returnType
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
object FakeOverrideSubstitutionKey : FirDeclarationDataKey()
|
||||
|
||||
var FirDeclarationAttributes.fakeOverrideSubstitution: FakeOverrideSubstitution? by FirDeclarationDataRegistry.attributesAccessor(
|
||||
FakeOverrideSubstitutionKey
|
||||
)
|
||||
|
||||
data class FakeOverrideSubstitution(
|
||||
val substitutor: ConeSubstitutor,
|
||||
val baseSymbol: FirBasedSymbol<*>
|
||||
)
|
||||
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.fir.scopes
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.FirSessionComponent
|
||||
import org.jetbrains.kotlin.fir.declarations.FirClass
|
||||
import org.jetbrains.kotlin.fir.declarations.FirField
|
||||
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isExpect
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isSynthetic
|
||||
import org.jetbrains.kotlin.fir.resolve.*
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap
|
||||
import org.jetbrains.kotlin.fir.scopes.impl.*
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
|
||||
import org.jetbrains.kotlin.fir.types.ConeClassErrorType
|
||||
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
|
||||
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||
|
||||
class FirKotlinScopeProvider(
|
||||
val declaredMemberScopeDecorator: (
|
||||
klass: FirClass,
|
||||
declaredMemberScope: FirContainingNamesAwareScope,
|
||||
useSiteSession: FirSession,
|
||||
scopeSession: ScopeSession
|
||||
) -> FirContainingNamesAwareScope = { _, declaredMemberScope, _, _ -> declaredMemberScope }
|
||||
) : FirScopeProvider(), FirSessionComponent {
|
||||
override fun getUseSiteMemberScope(
|
||||
klass: FirClass,
|
||||
useSiteSession: FirSession,
|
||||
scopeSession: ScopeSession
|
||||
): FirTypeScope {
|
||||
return scopeSession.getOrBuild(klass.symbol, USE_SITE) {
|
||||
val declaredScope = useSiteSession.declaredMemberScope(klass)
|
||||
|
||||
val delegateFields = klass.declarations.filterIsInstance<FirField>().filter { it.isSynthetic }
|
||||
|
||||
val decoratedDeclaredMemberScope =
|
||||
declaredMemberScopeDecorator(klass, declaredScope, useSiteSession, scopeSession).let {
|
||||
if (delegateFields.isEmpty())
|
||||
it
|
||||
else
|
||||
FirDelegatedMemberScope(useSiteSession, scopeSession, klass, it, delegateFields)
|
||||
}
|
||||
|
||||
|
||||
val scopes = lookupSuperTypes(klass, lookupInterfaces = true, deep = false, useSiteSession = useSiteSession)
|
||||
.mapNotNull { useSiteSuperType ->
|
||||
useSiteSuperType.scopeForSupertype(useSiteSession, scopeSession, klass)
|
||||
}
|
||||
FirClassUseSiteMemberScope(
|
||||
useSiteSession,
|
||||
FirTypeIntersectionScope.prepareIntersectionScope(
|
||||
useSiteSession, FirStandardOverrideChecker(useSiteSession), scopes,
|
||||
klass.defaultType(),
|
||||
),
|
||||
decoratedDeclaredMemberScope,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getStaticMemberScopeForCallables(
|
||||
klass: FirClass,
|
||||
useSiteSession: FirSession,
|
||||
scopeSession: ScopeSession
|
||||
): FirContainingNamesAwareScope? {
|
||||
return when (klass.classKind) {
|
||||
ClassKind.ENUM_CLASS -> FirNameAwareOnlyCallablesScope(FirStaticScope(useSiteSession.declaredMemberScope(klass)))
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
override fun getNestedClassifierScope(
|
||||
klass: FirClass,
|
||||
useSiteSession: FirSession,
|
||||
scopeSession: ScopeSession
|
||||
): FirContainingNamesAwareScope? {
|
||||
return useSiteSession.nestedClassifierScope(klass)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
data class ConeSubstitutionScopeKey(
|
||||
val lookupTag: ConeClassLikeLookupTag, val isFromExpectClass: Boolean, val substitutor: ConeSubstitutor
|
||||
) : ScopeSessionKey<FirClass, FirClassSubstitutionScope>()
|
||||
|
||||
fun FirClass.unsubstitutedScope(
|
||||
useSiteSession: FirSession,
|
||||
scopeSession: ScopeSession,
|
||||
withForcedTypeCalculator: Boolean
|
||||
): FirTypeScope {
|
||||
val scope = scopeProvider.getUseSiteMemberScope(this, useSiteSession, scopeSession)
|
||||
if (withForcedTypeCalculator) return FirScopeWithFakeOverrideTypeCalculator(scope, FakeOverrideTypeCalculator.Forced)
|
||||
return scope
|
||||
}
|
||||
|
||||
fun FirClassSymbol<*>.unsubstitutedScope(
|
||||
useSiteSession: FirSession,
|
||||
scopeSession: ScopeSession,
|
||||
withForcedTypeCalculator: Boolean
|
||||
): FirTypeScope {
|
||||
return fir.unsubstitutedScope(useSiteSession, scopeSession, withForcedTypeCalculator)
|
||||
}
|
||||
|
||||
fun FirClass.scopeForClass(
|
||||
substitutor: ConeSubstitutor,
|
||||
useSiteSession: FirSession,
|
||||
scopeSession: ScopeSession
|
||||
): FirTypeScope = scopeForClassImpl(
|
||||
substitutor, useSiteSession, scopeSession,
|
||||
skipPrivateMembers = false,
|
||||
classFirDispatchReceiver = this,
|
||||
// TODO: why it's always false?
|
||||
isFromExpectClass = false
|
||||
)
|
||||
|
||||
fun ConeKotlinType.scopeForSupertype(
|
||||
useSiteSession: FirSession,
|
||||
scopeSession: ScopeSession,
|
||||
subClass: FirClass,
|
||||
): FirTypeScope? {
|
||||
if (this !is ConeClassLikeType) return null
|
||||
if (this is ConeClassErrorType) return null
|
||||
val symbol = lookupTag.toSymbol(useSiteSession)
|
||||
return if (symbol is FirRegularClassSymbol) {
|
||||
symbol.fir.scopeForClassImpl(
|
||||
substitutor(symbol, this, useSiteSession),
|
||||
useSiteSession,
|
||||
scopeSession,
|
||||
skipPrivateMembers = true,
|
||||
classFirDispatchReceiver = subClass,
|
||||
isFromExpectClass = (subClass as? FirRegularClass)?.isExpect == true
|
||||
)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
private fun substitutor(symbol: FirRegularClassSymbol, type: ConeClassLikeType, useSiteSession: FirSession): ConeSubstitutor {
|
||||
if (type.typeArguments.isEmpty()) return ConeSubstitutor.Empty
|
||||
val originalSubstitution = createSubstitution(symbol.fir.typeParameters, type, useSiteSession)
|
||||
return substitutorByMap(originalSubstitution, useSiteSession)
|
||||
}
|
||||
|
||||
private fun FirClass.scopeForClassImpl(
|
||||
substitutor: ConeSubstitutor,
|
||||
useSiteSession: FirSession,
|
||||
scopeSession: ScopeSession,
|
||||
skipPrivateMembers: Boolean,
|
||||
classFirDispatchReceiver: FirClass,
|
||||
isFromExpectClass: Boolean
|
||||
): FirTypeScope {
|
||||
val basicScope = unsubstitutedScope(useSiteSession, scopeSession, withForcedTypeCalculator = false)
|
||||
if (substitutor == ConeSubstitutor.Empty) return basicScope
|
||||
|
||||
val key = ConeSubstitutionScopeKey(classFirDispatchReceiver.symbol.toLookupTag(), isFromExpectClass, substitutor)
|
||||
return scopeSession.getOrBuild(
|
||||
this, key
|
||||
) {
|
||||
FirClassSubstitutionScope(
|
||||
useSiteSession, basicScope, key, substitutor, classFirDispatchReceiver.defaultType(),
|
||||
skipPrivateMembers, makeExpect = isFromExpectClass
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val FirSession.kotlinScopeProvider: FirKotlinScopeProvider by FirSession.sessionComponentAccessor()
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.fir.scopes
|
||||
|
||||
import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration
|
||||
import org.jetbrains.kotlin.fir.declarations.FirProperty
|
||||
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
|
||||
|
||||
interface FirOverrideChecker {
|
||||
fun isOverriddenFunction(
|
||||
overrideCandidate: FirSimpleFunction,
|
||||
baseDeclaration: FirSimpleFunction
|
||||
): Boolean
|
||||
|
||||
fun isOverriddenProperty(
|
||||
overrideCandidate: FirCallableDeclaration, // NB: in Java it can be a function which overrides accessor
|
||||
baseDeclaration: FirProperty
|
||||
): Boolean
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.fir.scopes
|
||||
|
||||
import org.jetbrains.kotlin.fir.declarations.FirTypeParameter
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassifierSymbol
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
abstract class FirTypeParameterScope : FirContainingNamesAwareScope() {
|
||||
abstract val typeParameters: Map<Name, List<FirTypeParameter>>
|
||||
|
||||
override fun processClassifiersByNameWithSubstitution(
|
||||
name: Name,
|
||||
processor: (FirClassifierSymbol<*>, ConeSubstitutor) -> Unit
|
||||
) {
|
||||
val matchedTypeParameters = typeParameters[name] ?: return
|
||||
|
||||
matchedTypeParameters.forEach { processor(it.symbol, ConeSubstitutor.Empty) }
|
||||
}
|
||||
|
||||
override fun getCallableNames(): Set<Name> = emptySet()
|
||||
|
||||
override fun getClassifierNames(): Set<Name> = typeParameters.keys
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.fir.scopes
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
|
||||
import org.jetbrains.kotlin.fir.resolve.ScopeSession
|
||||
import org.jetbrains.kotlin.fir.resolve.toSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
|
||||
|
||||
fun ConeClassLikeLookupTag.getNestedClassifierScope(session: FirSession, scopeSession: ScopeSession): FirContainingNamesAwareScope? {
|
||||
val klass = toSymbol(session)?.fir as? FirRegularClass ?: return null
|
||||
return klass.scopeProvider.getNestedClassifierScope(klass, session, scopeSession)
|
||||
}
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.fir.scopes.impl
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.modality
|
||||
import org.jetbrains.kotlin.fir.scopes.FirOverrideChecker
|
||||
import org.jetbrains.kotlin.fir.scopes.FirTypeScope
|
||||
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
|
||||
|
||||
abstract class AbstractFirOverrideScope(
|
||||
val session: FirSession,
|
||||
protected val overrideChecker: FirOverrideChecker
|
||||
) : FirTypeScope() {
|
||||
//base symbol as key, overridden as value
|
||||
val overrideByBase = mutableMapOf<FirCallableSymbol<*>, FirCallableSymbol<*>?>()
|
||||
|
||||
private fun isOverriddenFunction(overrideCandidate: FirSimpleFunction, baseDeclaration: FirSimpleFunction): Boolean {
|
||||
return overrideChecker.isOverriddenFunction(overrideCandidate, baseDeclaration)
|
||||
}
|
||||
|
||||
private fun isOverriddenProperty(overrideCandidate: FirCallableDeclaration, baseDeclaration: FirProperty): Boolean {
|
||||
return overrideChecker.isOverriddenProperty(overrideCandidate, baseDeclaration)
|
||||
}
|
||||
|
||||
protected fun similarFunctionsOrBothProperties(
|
||||
overrideCandidate: FirCallableDeclaration,
|
||||
baseDeclaration: FirCallableDeclaration
|
||||
): Boolean {
|
||||
return when (overrideCandidate) {
|
||||
is FirSimpleFunction -> when (baseDeclaration) {
|
||||
is FirSimpleFunction -> isOverriddenFunction(overrideCandidate, baseDeclaration)
|
||||
is FirProperty -> isOverriddenProperty(overrideCandidate, baseDeclaration)
|
||||
else -> false
|
||||
}
|
||||
is FirConstructor -> false
|
||||
is FirProperty -> baseDeclaration is FirProperty && isOverriddenProperty(overrideCandidate, baseDeclaration)
|
||||
is FirField -> baseDeclaration is FirField
|
||||
else -> error("Unknown fir callable type: $overrideCandidate, $baseDeclaration")
|
||||
}
|
||||
}
|
||||
|
||||
// Receiver is super-type function here
|
||||
protected open fun FirCallableSymbol<*>.getOverridden(overrideCandidates: Set<FirCallableSymbol<*>>): FirCallableSymbol<*>? {
|
||||
if (overrideByBase.containsKey(this)) return overrideByBase[this]
|
||||
|
||||
val baseDeclaration = (this as FirBasedSymbol<*>).fir as FirCallableDeclaration
|
||||
val override = overrideCandidates.firstOrNull {
|
||||
val overrideCandidate = (it as FirBasedSymbol<*>).fir as FirCallableDeclaration
|
||||
baseDeclaration.modality != Modality.FINAL && similarFunctionsOrBothProperties(overrideCandidate, baseDeclaration)
|
||||
} // TODO: two or more overrides for one fun?
|
||||
overrideByBase[this] = override
|
||||
return override
|
||||
}
|
||||
|
||||
}
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.fir.scopes.impl
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
||||
import org.jetbrains.kotlin.fir.scopes.FirContainingNamesAwareScope
|
||||
import org.jetbrains.kotlin.fir.scopes.FirOverrideChecker
|
||||
import org.jetbrains.kotlin.fir.scopes.FirTypeScope
|
||||
import org.jetbrains.kotlin.fir.scopes.ProcessorAction
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
abstract class AbstractFirUseSiteMemberScope(
|
||||
session: FirSession,
|
||||
overrideChecker: FirOverrideChecker,
|
||||
protected val superTypesScope: FirTypeScope,
|
||||
protected val declaredMemberScope: FirContainingNamesAwareScope
|
||||
) : AbstractFirOverrideScope(session, overrideChecker) {
|
||||
|
||||
private val functions = hashMapOf<Name, Collection<FirNamedFunctionSymbol>>()
|
||||
val directOverriddenFunctions = hashMapOf<FirNamedFunctionSymbol, Collection<FirNamedFunctionSymbol>>()
|
||||
protected val directOverriddenProperties = hashMapOf<FirPropertySymbol, MutableList<FirPropertySymbol>>()
|
||||
|
||||
private val callableNamesCached by lazy(LazyThreadSafetyMode.PUBLICATION) {
|
||||
declaredMemberScope.getCallableNames() + superTypesScope.getCallableNames()
|
||||
}
|
||||
|
||||
override fun processFunctionsByName(name: Name, processor: (FirNamedFunctionSymbol) -> Unit) {
|
||||
functions.getOrPut(name) {
|
||||
doProcessFunctions(name)
|
||||
}.forEach {
|
||||
processor(it)
|
||||
}
|
||||
}
|
||||
|
||||
private fun doProcessFunctions(
|
||||
name: Name
|
||||
): Collection<FirNamedFunctionSymbol> = mutableListOf<FirNamedFunctionSymbol>().apply {
|
||||
val overrideCandidates = mutableSetOf<FirFunctionSymbol<*>>()
|
||||
declaredMemberScope.processFunctionsByName(name) { symbol ->
|
||||
if (symbol.isStatic) return@processFunctionsByName
|
||||
val directOverridden = computeDirectOverridden(symbol)
|
||||
this@AbstractFirUseSiteMemberScope.directOverriddenFunctions[symbol] = directOverridden
|
||||
overrideCandidates += symbol
|
||||
add(symbol)
|
||||
}
|
||||
|
||||
superTypesScope.processFunctionsByName(name) {
|
||||
val overriddenBy = it.getOverridden(overrideCandidates)
|
||||
if (overriddenBy == null) {
|
||||
add(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun computeDirectOverridden(symbol: FirNamedFunctionSymbol): Collection<FirNamedFunctionSymbol> {
|
||||
val result = mutableListOf<FirNamedFunctionSymbol>()
|
||||
val firSimpleFunction = symbol.fir
|
||||
superTypesScope.processFunctionsByName(symbol.callableId.callableName) { superSymbol ->
|
||||
if (overrideChecker.isOverriddenFunction(firSimpleFunction, superSymbol.fir)) {
|
||||
result.add(superSymbol)
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
override fun processDirectOverriddenFunctionsWithBaseScope(
|
||||
functionSymbol: FirNamedFunctionSymbol,
|
||||
processor: (FirNamedFunctionSymbol, FirTypeScope) -> ProcessorAction
|
||||
): ProcessorAction =
|
||||
//directOverriddenFunctions might be not filled for functionSymbol if it is not from processFunctionsByName call
|
||||
doProcessDirectOverriddenCallables(
|
||||
functionSymbol, processor, directOverriddenFunctions, superTypesScope,
|
||||
FirTypeScope::processDirectOverriddenFunctionsWithBaseScope
|
||||
)
|
||||
|
||||
override fun processDirectOverriddenPropertiesWithBaseScope(
|
||||
propertySymbol: FirPropertySymbol,
|
||||
processor: (FirPropertySymbol, FirTypeScope) -> ProcessorAction
|
||||
): ProcessorAction =
|
||||
doProcessDirectOverriddenCallables(
|
||||
propertySymbol, processor, directOverriddenProperties, superTypesScope,
|
||||
FirTypeScope::processDirectOverriddenPropertiesWithBaseScope
|
||||
)
|
||||
|
||||
override fun processClassifiersByNameWithSubstitution(name: Name, processor: (FirClassifierSymbol<*>, ConeSubstitutor) -> Unit) {
|
||||
declaredMemberScope.processClassifiersByNameWithSubstitution(name, processor)
|
||||
superTypesScope.processClassifiersByNameWithSubstitution(name, processor)
|
||||
}
|
||||
|
||||
override fun processDeclaredConstructors(processor: (FirConstructorSymbol) -> Unit) {
|
||||
declaredMemberScope.processDeclaredConstructors(processor)
|
||||
}
|
||||
|
||||
override fun getCallableNames(): Set<Name> = callableNamesCached
|
||||
|
||||
override fun getClassifierNames(): Set<Name> {
|
||||
return declaredMemberScope.getClassifierNames() + superTypesScope.getClassifierNames()
|
||||
}
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.fir.scopes.impl
|
||||
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.resolve.ImportPath
|
||||
import org.jetbrains.kotlin.resolve.PlatformDependentAnalyzerServices
|
||||
|
||||
enum class DefaultImportPriority {
|
||||
HIGH {
|
||||
override fun getAllDefaultImports(
|
||||
platformDependentAnalyzerServices: PlatformDependentAnalyzerServices?,
|
||||
languageVersionSettings: LanguageVersionSettings
|
||||
): List<ImportPath>? =
|
||||
platformDependentAnalyzerServices?.getDefaultImports(languageVersionSettings, includeLowPriorityImports = false)
|
||||
},
|
||||
LOW {
|
||||
override fun getAllDefaultImports(
|
||||
platformDependentAnalyzerServices: PlatformDependentAnalyzerServices?,
|
||||
languageVersionSettings: LanguageVersionSettings
|
||||
): List<ImportPath>? =
|
||||
platformDependentAnalyzerServices?.defaultLowPriorityImports
|
||||
};
|
||||
|
||||
abstract fun getAllDefaultImports(
|
||||
platformDependentAnalyzerServices: PlatformDependentAnalyzerServices?,
|
||||
languageVersionSettings: LanguageVersionSettings
|
||||
): List<ImportPath>?
|
||||
}
|
||||
+137
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.fir.scopes.impl
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
|
||||
import org.jetbrains.kotlin.fir.declarations.FirResolvedImport
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.expandedConeType
|
||||
import org.jetbrains.kotlin.fir.moduleData
|
||||
import org.jetbrains.kotlin.fir.moduleVisibilityChecker
|
||||
import org.jetbrains.kotlin.fir.resolve.ScopeSession
|
||||
import org.jetbrains.kotlin.fir.resolve.toSymbol
|
||||
import org.jetbrains.kotlin.fir.resolve.transformers.ensureResolvedForCalls
|
||||
import org.jetbrains.kotlin.fir.scopes.FirContainingNamesAwareScope
|
||||
import org.jetbrains.kotlin.fir.scopes.unsubstitutedScope
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.annotations.JVM_THROWS_ANNOTATION_FQ_NAME
|
||||
import org.jetbrains.kotlin.resolve.annotations.KOTLIN_NATIVE_THROWS_ANNOTATION_FQ_NAME
|
||||
import org.jetbrains.kotlin.resolve.annotations.KOTLIN_THROWS_ANNOTATION_FQ_NAME
|
||||
|
||||
enum class FirImportingScopeFilter {
|
||||
ALL, INVISIBLE_CLASSES, MEMBERS_AND_VISIBLE_CLASSES;
|
||||
|
||||
fun check(symbol: FirClassLikeSymbol<*>, session: FirSession): Boolean {
|
||||
if (this == ALL) return true
|
||||
// TODO: also check DeprecationLevel.HIDDEN and required Kotlin version
|
||||
val fir = symbol.fir
|
||||
if (fir !is FirMemberDeclaration) return false
|
||||
val isVisible = when (fir.status.visibility) {
|
||||
// When importing from the same module, status may be unknown because the status resolver depends on super types
|
||||
// to determine visibility for functions, so it may not have finished yet. Since we only care about classes,
|
||||
// though, "unknown" will always become public anyway.
|
||||
Visibilities.Unknown -> true
|
||||
Visibilities.Internal ->
|
||||
symbol.fir.moduleData == session.moduleData || session.moduleVisibilityChecker?.isInFriendModule(fir) == true
|
||||
// All non-`internal` visibilities are either even more restrictive (e.g. `private`) or must not
|
||||
// be checked in imports (e.g. `protected` may be valid in some use sites).
|
||||
else -> !fir.status.visibility.mustCheckInImports()
|
||||
}
|
||||
return isVisible == (this == MEMBERS_AND_VISIBLE_CLASSES)
|
||||
}
|
||||
}
|
||||
|
||||
abstract class FirAbstractImportingScope(
|
||||
session: FirSession,
|
||||
protected val scopeSession: ScopeSession,
|
||||
protected val filter: FirImportingScopeFilter,
|
||||
lookupInFir: Boolean
|
||||
) : FirAbstractProviderBasedScope(session, lookupInFir) {
|
||||
private val FirClassLikeSymbol<*>.fullyExpandedSymbol: FirClassSymbol<*>?
|
||||
get() = when (this) {
|
||||
is FirTypeAliasSymbol -> fir.expandedConeType?.lookupTag?.toSymbol(session)?.fullyExpandedSymbol
|
||||
is FirClassSymbol<*> -> this
|
||||
}
|
||||
|
||||
private fun FirClassSymbol<*>.getStaticsScope(): FirContainingNamesAwareScope? =
|
||||
if (fir.classKind == ClassKind.OBJECT) {
|
||||
FirObjectImportedCallableScope(
|
||||
classId, fir.unsubstitutedScope(session, scopeSession, withForcedTypeCalculator = false)
|
||||
)
|
||||
} else {
|
||||
fir.scopeProvider.getStaticScope(fir, session, scopeSession)
|
||||
}
|
||||
|
||||
fun getStaticsScope(classId: ClassId): FirContainingNamesAwareScope? =
|
||||
provider.getClassLikeSymbolByClassId(classId)?.fullyExpandedSymbol?.getStaticsScope()
|
||||
|
||||
protected fun findSingleClassifierSymbolByName(name: Name?, imports: List<FirResolvedImport>): FirClassLikeSymbol<*>? {
|
||||
var result: FirClassLikeSymbol<*>? = null
|
||||
for (import in imports) {
|
||||
val importedName = name ?: import.importedName ?: continue
|
||||
val classId = import.resolvedParentClassId?.createNestedClassId(importedName)
|
||||
?: ClassId.topLevel(import.packageFqName.child(importedName))
|
||||
val symbol = provider.getClassLikeSymbolByClassId(classId) ?: continue
|
||||
if (!filter.check(symbol, session)) continue
|
||||
result = when {
|
||||
result == null || result == symbol -> symbol
|
||||
// Importing multiple versions of the same type is normally an ambiguity, but in the case of `kotlin.Throws`,
|
||||
// it should take precedence over platform-specific variants. This is lifted directly from `LazyImportScope`
|
||||
// from the old backend; most likely `Throws` predates expect-actual, and this is a backwards compatibility hack.
|
||||
// TODO: remove redundant versions of `Throws` from the standard library
|
||||
result.classId.isJvmOrNativeThrows && symbol.classId.isCommonThrows -> symbol
|
||||
result.classId.isCommonThrows && symbol.classId.isJvmOrNativeThrows -> result
|
||||
// TODO: if there is an ambiguity at this scope, further scopes should not be checked.
|
||||
// Doing otherwise causes KT-39073. Also, returning null here instead of an error symbol
|
||||
// or something produces poor quality diagnostics ("unresolved name" rather than "ambiguity").
|
||||
else -> return null
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
protected fun processFunctionsByName(name: Name?, imports: List<FirResolvedImport>, processor: (FirNamedFunctionSymbol) -> Unit) {
|
||||
if (filter == FirImportingScopeFilter.INVISIBLE_CLASSES) return
|
||||
for (import in imports) {
|
||||
val importedName = name ?: import.importedName ?: continue
|
||||
val staticsScope = import.resolvedParentClassId?.let(::getStaticsScope)
|
||||
if (staticsScope != null) {
|
||||
staticsScope.processFunctionsByName(importedName, processor)
|
||||
} else if (importedName.isSpecial || importedName.identifier.isNotEmpty()) {
|
||||
for (symbol in provider.getTopLevelFunctionSymbols(import.packageFqName, importedName)) {
|
||||
symbol.ensureResolvedForCalls()
|
||||
processor(symbol)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected fun processPropertiesByName(name: Name?, imports: List<FirResolvedImport>, processor: (FirVariableSymbol<*>) -> Unit) {
|
||||
if (filter == FirImportingScopeFilter.INVISIBLE_CLASSES) return
|
||||
for (import in imports) {
|
||||
val importedName = name ?: import.importedName ?: continue
|
||||
val staticsScope = import.resolvedParentClassId?.let(::getStaticsScope)
|
||||
if (staticsScope != null) {
|
||||
staticsScope.processPropertiesByName(importedName, processor)
|
||||
} else if (importedName.isSpecial || importedName.identifier.isNotEmpty()) {
|
||||
for (symbol in provider.getTopLevelPropertySymbols(import.packageFqName, importedName)) {
|
||||
symbol.ensureResolvedForCalls()
|
||||
processor(symbol)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val ClassId.isJvmOrNativeThrows: Boolean
|
||||
get() = asSingleFqName().let { it == JVM_THROWS_ANNOTATION_FQ_NAME || it == KOTLIN_NATIVE_THROWS_ANNOTATION_FQ_NAME }
|
||||
|
||||
private val ClassId.isCommonThrows: Boolean
|
||||
get() = asSingleFqName() == KOTLIN_THROWS_ANNOTATION_FQ_NAME
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.fir.scopes.impl
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap
|
||||
import org.jetbrains.kotlin.fir.scopes.FirOverrideChecker
|
||||
import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl
|
||||
|
||||
abstract class FirAbstractOverrideChecker : FirOverrideChecker {
|
||||
|
||||
protected abstract fun buildTypeParametersSubstitutorIfCompatible(
|
||||
overrideCandidate: FirCallableDeclaration,
|
||||
baseDeclaration: FirCallableDeclaration
|
||||
): ConeSubstitutor?
|
||||
}
|
||||
|
||||
fun buildSubstitutorForOverridesCheck(
|
||||
overrideCandidate: FirCallableDeclaration,
|
||||
baseDeclaration: FirCallableDeclaration,
|
||||
useSiteSession: FirSession
|
||||
): ConeSubstitutor? {
|
||||
if (overrideCandidate.typeParameters.size != baseDeclaration.typeParameters.size) return null
|
||||
|
||||
if (baseDeclaration.typeParameters.isEmpty()) return ConeSubstitutor.Empty
|
||||
val types = baseDeclaration.typeParameters.map {
|
||||
ConeTypeParameterTypeImpl(it.symbol.toLookupTag(), false)
|
||||
}
|
||||
return substitutorByMap(overrideCandidate.typeParameters.map { it.symbol }.zip(types).toMap(), useSiteSession)
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.fir.scopes.impl
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.resolve.providers.impl.FirCompositeSymbolProvider
|
||||
import org.jetbrains.kotlin.fir.resolve.providers.impl.FirDependenciesSymbolProviderImpl
|
||||
import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider
|
||||
import org.jetbrains.kotlin.fir.scopes.FirScope
|
||||
|
||||
abstract class FirAbstractProviderBasedScope(val session: FirSession, lookupInFir: Boolean = true) :
|
||||
FirScope() {
|
||||
val provider = when (val symbolProvider = session.symbolProvider) {
|
||||
is FirCompositeSymbolProvider -> symbolProvider.takeIf { !lookupInFir }?.providers?.find {
|
||||
it is FirDependenciesSymbolProviderImpl
|
||||
} ?: symbolProvider
|
||||
else -> symbolProvider
|
||||
}
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.fir.scopes.impl
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.FirResolvedImport
|
||||
import org.jetbrains.kotlin.fir.resolve.ScopeSession
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassifierSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
abstract class FirAbstractSimpleImportingScope(
|
||||
session: FirSession,
|
||||
scopeSession: ScopeSession
|
||||
) : FirAbstractImportingScope(session, scopeSession, FirImportingScopeFilter.ALL, lookupInFir = true) {
|
||||
|
||||
// TODO try to hide this
|
||||
abstract val simpleImports: Map<Name, List<FirResolvedImport>>
|
||||
|
||||
override fun processClassifiersByNameWithSubstitution(name: Name, processor: (FirClassifierSymbol<*>, ConeSubstitutor) -> Unit) {
|
||||
val imports = simpleImports[name] ?: return
|
||||
val symbol = findSingleClassifierSymbolByName(null, imports) ?: return
|
||||
processor(symbol, ConeSubstitutor.Empty)
|
||||
}
|
||||
|
||||
override fun processFunctionsByName(name: Name, processor: (FirNamedFunctionSymbol) -> Unit) {
|
||||
val imports = simpleImports[name] ?: return
|
||||
processFunctionsByName(null, imports, processor)
|
||||
}
|
||||
|
||||
override fun processPropertiesByName(name: Name, processor: (FirVariableSymbol<*>) -> Unit) {
|
||||
val imports = simpleImports[name] ?: return
|
||||
processPropertiesByName(null, imports, processor)
|
||||
}
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.fir.scopes.impl
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.FirResolvedImport
|
||||
import org.jetbrains.kotlin.fir.resolve.ScopeSession
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassifierSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
abstract class FirAbstractStarImportingScope(
|
||||
session: FirSession,
|
||||
scopeSession: ScopeSession,
|
||||
filter: FirImportingScopeFilter,
|
||||
lookupInFir: Boolean
|
||||
) : FirAbstractImportingScope(session, scopeSession, filter, lookupInFir) {
|
||||
|
||||
// TODO try to hide this
|
||||
abstract val starImports: List<FirResolvedImport>
|
||||
|
||||
private val absentClassifierNames = mutableSetOf<Name>()
|
||||
|
||||
override fun processClassifiersByNameWithSubstitution(name: Name, processor: (FirClassifierSymbol<*>, ConeSubstitutor) -> Unit) {
|
||||
if ((!name.isSpecial && name.identifier.isEmpty()) || starImports.isEmpty() || name in absentClassifierNames) {
|
||||
return
|
||||
}
|
||||
val symbol = findSingleClassifierSymbolByName(name, starImports)
|
||||
if (symbol != null) {
|
||||
processor(symbol, ConeSubstitutor.Empty)
|
||||
} else {
|
||||
absentClassifierNames += name
|
||||
}
|
||||
}
|
||||
|
||||
override fun processFunctionsByName(name: Name, processor: (FirNamedFunctionSymbol) -> Unit) =
|
||||
processFunctionsByName(name, starImports, processor)
|
||||
|
||||
override fun processPropertiesByName(name: Name, processor: (FirVariableSymbol<*>) -> Unit) =
|
||||
processPropertiesByName(name, starImports, processor)
|
||||
}
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.fir.scopes.impl
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isSynthetic
|
||||
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
||||
import org.jetbrains.kotlin.fir.scopes.FirContainingNamesAwareScope
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.name.SpecialNames
|
||||
|
||||
abstract class FirClassDeclaredMemberScope : FirContainingNamesAwareScope()
|
||||
|
||||
class FirClassDeclaredMemberScopeImpl(
|
||||
val useSiteSession: FirSession,
|
||||
klass: FirClass,
|
||||
useLazyNestedClassifierScope: Boolean = false,
|
||||
existingNames: List<Name>? = null,
|
||||
symbolProvider: FirSymbolProvider? = null
|
||||
) : FirClassDeclaredMemberScope() {
|
||||
private val nestedClassifierScope: FirContainingNamesAwareScope? = if (useLazyNestedClassifierScope) {
|
||||
lazyNestedClassifierScope(klass.symbol.classId, existingNames!!, symbolProvider!!)
|
||||
} else {
|
||||
useSiteSession.nestedClassifierScope(klass)
|
||||
}
|
||||
|
||||
private val callablesIndex: Map<Name, List<FirCallableSymbol<*>>> = run {
|
||||
val result = mutableMapOf<Name, MutableList<FirCallableSymbol<*>>>()
|
||||
loop@ for (declaration in klass.declarations) {
|
||||
if (declaration is FirCallableDeclaration) {
|
||||
val name = when (declaration) {
|
||||
is FirConstructor -> SpecialNames.INIT
|
||||
is FirVariable -> if (declaration.isSynthetic) continue@loop else declaration.name
|
||||
is FirSimpleFunction -> declaration.name
|
||||
else -> continue@loop
|
||||
}
|
||||
result.getOrPut(name) { mutableListOf() } += declaration.symbol
|
||||
}
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
override fun processFunctionsByName(name: Name, processor: (FirNamedFunctionSymbol) -> Unit) {
|
||||
if (name == SpecialNames.INIT) return
|
||||
processCallables(name, processor)
|
||||
}
|
||||
|
||||
override fun processDeclaredConstructors(processor: (FirConstructorSymbol) -> Unit) {
|
||||
processCallables(SpecialNames.INIT, processor)
|
||||
}
|
||||
|
||||
override fun processPropertiesByName(name: Name, processor: (FirVariableSymbol<*>) -> Unit) {
|
||||
processCallables(name, processor)
|
||||
}
|
||||
|
||||
private inline fun <reified D : FirCallableSymbol<*>> processCallables(
|
||||
name: Name,
|
||||
processor: (D) -> Unit
|
||||
) {
|
||||
val symbols = callablesIndex[name] ?: emptyList()
|
||||
for (symbol in symbols) {
|
||||
if (symbol is D) {
|
||||
processor(symbol)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun processClassifiersByNameWithSubstitution(
|
||||
name: Name,
|
||||
processor: (FirClassifierSymbol<*>, ConeSubstitutor) -> Unit
|
||||
) {
|
||||
nestedClassifierScope?.processClassifiersByNameWithSubstitution(name, processor)
|
||||
}
|
||||
|
||||
override fun getCallableNames(): Set<Name> {
|
||||
return callablesIndex.keys
|
||||
}
|
||||
|
||||
override fun getClassifierNames(): Set<Name> {
|
||||
return nestedClassifierScope?.getClassifierNames().orEmpty()
|
||||
}
|
||||
}
|
||||
+372
@@ -0,0 +1,372 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.fir.scopes.impl
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.FirSessionComponent
|
||||
import org.jetbrains.kotlin.fir.caches.*
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.declarations.synthetic.FirSyntheticProperty
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.visibility
|
||||
import org.jetbrains.kotlin.fir.dispatchReceiverClassOrNull
|
||||
import org.jetbrains.kotlin.fir.originalForSubstitutionOverride
|
||||
import org.jetbrains.kotlin.fir.resolve.ScopeSessionKey
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.chain
|
||||
import org.jetbrains.kotlin.fir.scopes.FakeOverrideSubstitution
|
||||
import org.jetbrains.kotlin.fir.scopes.FirTypeScope
|
||||
import org.jetbrains.kotlin.fir.scopes.ProcessorAction
|
||||
import org.jetbrains.kotlin.fir.symbols.ensureResolved
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
|
||||
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||
import org.jetbrains.kotlin.fir.types.coneType
|
||||
import org.jetbrains.kotlin.fir.types.coneTypeSafe
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.runIf
|
||||
|
||||
class FirClassSubstitutionScope(
|
||||
private val session: FirSession,
|
||||
private val useSiteMemberScope: FirTypeScope,
|
||||
key: ScopeSessionKey<*, *>,
|
||||
private val substitutor: ConeSubstitutor,
|
||||
private val dispatchReceiverTypeForSubstitutedMembers: ConeClassLikeType,
|
||||
private val skipPrivateMembers: Boolean,
|
||||
private val makeExpect: Boolean = false
|
||||
) : FirTypeScope() {
|
||||
companion object {
|
||||
private val FirVariableSymbol<*>.isOverridable: Boolean
|
||||
get() = when (this) {
|
||||
is FirPropertySymbol,
|
||||
is FirFieldSymbol,
|
||||
is FirAccessorSymbol -> true
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
private val substitutionOverrideCache = session.substitutionOverrideStorage.substitutionOverrideCacheByScope.getValue(key, null)
|
||||
private val newOwnerClassId = dispatchReceiverTypeForSubstitutedMembers.lookupTag.classId
|
||||
|
||||
override fun processFunctionsByName(name: Name, processor: (FirNamedFunctionSymbol) -> Unit) {
|
||||
useSiteMemberScope.processFunctionsByName(name) process@{ original ->
|
||||
val function = substitutionOverrideCache.overridesForFunctions.getValue(original, this)
|
||||
processor(function)
|
||||
}
|
||||
|
||||
return super.processFunctionsByName(name, processor)
|
||||
}
|
||||
|
||||
override fun processDirectOverriddenFunctionsWithBaseScope(
|
||||
functionSymbol: FirNamedFunctionSymbol,
|
||||
processor: (FirNamedFunctionSymbol, FirTypeScope) -> ProcessorAction
|
||||
): ProcessorAction =
|
||||
processDirectOverriddenWithBaseScope(
|
||||
functionSymbol,
|
||||
processor,
|
||||
FirTypeScope::processDirectOverriddenFunctionsWithBaseScope,
|
||||
) { it in substitutionOverrideCache.overridesForFunctions }
|
||||
|
||||
private inline fun <reified D : FirCallableSymbol<*>> processDirectOverriddenWithBaseScope(
|
||||
callableSymbol: D,
|
||||
noinline processor: (D, FirTypeScope) -> ProcessorAction,
|
||||
processDirectOverriddenCallablesWithBaseScope: FirTypeScope.(D, ((D, FirTypeScope) -> ProcessorAction)) -> ProcessorAction,
|
||||
originalInCache: (D) -> Boolean
|
||||
): ProcessorAction {
|
||||
val original = callableSymbol.originalForSubstitutionOverride?.takeIf { originalInCache(it) }
|
||||
?: return useSiteMemberScope.processDirectOverriddenCallablesWithBaseScope(callableSymbol, processor)
|
||||
|
||||
if (original != callableSymbol) {
|
||||
if (!processor(original, useSiteMemberScope)) return ProcessorAction.STOP
|
||||
}
|
||||
|
||||
return useSiteMemberScope.processDirectOverriddenCallablesWithBaseScope(original, processor)
|
||||
}
|
||||
|
||||
override fun processPropertiesByName(name: Name, processor: (FirVariableSymbol<*>) -> Unit) {
|
||||
return useSiteMemberScope.processPropertiesByName(name) process@{ original ->
|
||||
val symbol = if (original.isOverridable) {
|
||||
substitutionOverrideCache.overridesForVariables.getValue(original, this)
|
||||
} else {
|
||||
original
|
||||
}
|
||||
processor(symbol)
|
||||
}
|
||||
}
|
||||
|
||||
override fun processDirectOverriddenPropertiesWithBaseScope(
|
||||
propertySymbol: FirPropertySymbol,
|
||||
processor: (FirPropertySymbol, FirTypeScope) -> ProcessorAction
|
||||
): ProcessorAction =
|
||||
processDirectOverriddenWithBaseScope(
|
||||
propertySymbol, processor, FirTypeScope::processDirectOverriddenPropertiesWithBaseScope,
|
||||
) { it in substitutionOverrideCache.overridesForVariables }
|
||||
|
||||
override fun processClassifiersByNameWithSubstitution(name: Name, processor: (FirClassifierSymbol<*>, ConeSubstitutor) -> Unit) {
|
||||
useSiteMemberScope.processClassifiersByNameWithSubstitution(name) { symbol, substitutor ->
|
||||
processor(symbol, substitutor.chain(this.substitutor))
|
||||
}
|
||||
}
|
||||
|
||||
private fun ConeKotlinType.substitute(): ConeKotlinType? {
|
||||
return substitutor.substituteOrNull(this)
|
||||
}
|
||||
|
||||
private fun ConeKotlinType.substitute(substitutor: ConeSubstitutor): ConeKotlinType? {
|
||||
return substitutor.substituteOrNull(this)
|
||||
}
|
||||
|
||||
fun createSubstitutionOverrideFunction(original: FirNamedFunctionSymbol): FirNamedFunctionSymbol {
|
||||
if (substitutor == ConeSubstitutor.Empty) return original
|
||||
val member = original.fir
|
||||
if (skipPrivateMembers && member.visibility == Visibilities.Private) return original
|
||||
|
||||
val (newTypeParameters, newDispatchReceiverType, newReceiverType, newReturnType, newSubstitutor, fakeOverrideSubstitution) = createSubstitutedData(
|
||||
member
|
||||
)
|
||||
val newParameterTypes = member.valueParameters.map {
|
||||
it.returnTypeRef.coneType.substitute(newSubstitutor)
|
||||
}
|
||||
|
||||
if (newReceiverType == null &&
|
||||
newReturnType == null &&
|
||||
newParameterTypes.all { it == null } &&
|
||||
newTypeParameters === member.typeParameters &&
|
||||
fakeOverrideSubstitution == null
|
||||
) {
|
||||
if (original.dispatchReceiverType?.substitute(substitutor) != null) {
|
||||
return FirFakeOverrideGenerator.createSubstitutionOverrideFunction(
|
||||
session,
|
||||
member,
|
||||
original,
|
||||
newDispatchReceiverType ?: dispatchReceiverTypeForSubstitutedMembers,
|
||||
derivedClassId = newOwnerClassId,
|
||||
isExpect = makeExpect,
|
||||
)
|
||||
}
|
||||
return original
|
||||
}
|
||||
|
||||
/*
|
||||
* Member functions can't capture type parameters, so
|
||||
* it's safe to cast newTypeParameters to List<FirTypeParameter>
|
||||
*/
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return FirFakeOverrideGenerator.createSubstitutionOverrideFunction(
|
||||
session,
|
||||
member,
|
||||
original,
|
||||
newDispatchReceiverType ?: dispatchReceiverTypeForSubstitutedMembers,
|
||||
newReceiverType,
|
||||
newReturnType,
|
||||
newParameterTypes,
|
||||
newTypeParameters as List<FirTypeParameter>,
|
||||
newOwnerClassId,
|
||||
makeExpect,
|
||||
fakeOverrideSubstitution
|
||||
)
|
||||
}
|
||||
|
||||
fun createSubstitutionOverrideConstructor(original: FirConstructorSymbol): FirConstructorSymbol {
|
||||
if (substitutor == ConeSubstitutor.Empty) return original
|
||||
val constructor = original.fir
|
||||
|
||||
val (newTypeParameters, _, _, newReturnType, newSubstitutor, fakeOverrideSubstitution) = createSubstitutedData(constructor)
|
||||
|
||||
// If constructor has a dispatch receiver, it should be an inner class' constructor.
|
||||
// It means that we need to substitute its dispatcher as every other type,
|
||||
// instead of using dispatchReceiverTypeForSubstitutedMembers
|
||||
val newDispatchReceiverType = original.dispatchReceiverType?.substitute(substitutor)
|
||||
|
||||
val newParameterTypes = constructor.valueParameters.map {
|
||||
it.returnTypeRef.coneType.substitute(newSubstitutor)
|
||||
}
|
||||
|
||||
if (newReturnType == null && newParameterTypes.all { it == null } && newTypeParameters === constructor.typeParameters) {
|
||||
return original
|
||||
}
|
||||
|
||||
return FirFakeOverrideGenerator.createSubstitutionOverrideConstructor(
|
||||
FirConstructorSymbol(original.callableId),
|
||||
session,
|
||||
constructor,
|
||||
newDispatchReceiverType,
|
||||
newReturnType,
|
||||
newParameterTypes,
|
||||
newTypeParameters,
|
||||
makeExpect,
|
||||
fakeOverrideSubstitution
|
||||
).symbol
|
||||
}
|
||||
|
||||
fun createSubstitutionOverrideProperty(original: FirPropertySymbol): FirPropertySymbol {
|
||||
if (substitutor == ConeSubstitutor.Empty) return original
|
||||
val member = original.fir
|
||||
if (skipPrivateMembers && member.visibility == Visibilities.Private) return original
|
||||
|
||||
val (newTypeParameters, newDispatchReceiverType, newReceiverType, newReturnType, _, fakeOverrideSubstitution) = createSubstitutedData(
|
||||
member
|
||||
)
|
||||
|
||||
if (newReceiverType == null &&
|
||||
newReturnType == null &&
|
||||
newTypeParameters === member.typeParameters &&
|
||||
fakeOverrideSubstitution == null
|
||||
) {
|
||||
if (original.dispatchReceiverType?.substitute(substitutor) != null) {
|
||||
return FirFakeOverrideGenerator.createSubstitutionOverrideProperty(
|
||||
session,
|
||||
member,
|
||||
original,
|
||||
newDispatchReceiverType ?: dispatchReceiverTypeForSubstitutedMembers,
|
||||
derivedClassId = newOwnerClassId,
|
||||
isExpect = makeExpect,
|
||||
)
|
||||
}
|
||||
return original
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return FirFakeOverrideGenerator.createSubstitutionOverrideProperty(
|
||||
session,
|
||||
member,
|
||||
original,
|
||||
newDispatchReceiverType ?: dispatchReceiverTypeForSubstitutedMembers,
|
||||
newReceiverType,
|
||||
newReturnType,
|
||||
newTypeParameters as List<FirTypeParameter>,
|
||||
newOwnerClassId,
|
||||
makeExpect,
|
||||
fakeOverrideSubstitution
|
||||
)
|
||||
}
|
||||
|
||||
private data class SubstitutedData(
|
||||
val typeParameters: List<FirTypeParameterRef>,
|
||||
val dispatchReceiverType: ConeKotlinType?,
|
||||
val receiverType: ConeKotlinType?,
|
||||
val returnType: ConeKotlinType?,
|
||||
val substitutor: ConeSubstitutor,
|
||||
val fakeOverrideSubstitution: FakeOverrideSubstitution?
|
||||
)
|
||||
|
||||
private fun createSubstitutedData(member: FirCallableDeclaration): SubstitutedData {
|
||||
val (newTypeParameters, substitutor) = FirFakeOverrideGenerator.createNewTypeParametersAndSubstitutor(
|
||||
session,
|
||||
member as FirTypeParameterRefsOwner,
|
||||
substitutor,
|
||||
forceTypeParametersRecreation = dispatchReceiverTypeForSubstitutedMembers.lookupTag != member.dispatchReceiverClassOrNull()
|
||||
)
|
||||
|
||||
val receiverType = member.receiverTypeRef?.coneType
|
||||
val newReceiverType = receiverType?.substitute(substitutor)
|
||||
|
||||
val newDispatchReceiverType = dispatchReceiverTypeForSubstitutedMembers.substitute(substitutor)
|
||||
|
||||
member.symbol.ensureResolved(FirResolvePhase.STATUS)
|
||||
val returnType = member.returnTypeRef.coneTypeSafe<ConeKotlinType>()
|
||||
val fakeOverrideSubstitution = runIf(returnType == null) { FakeOverrideSubstitution(substitutor, member.symbol) }
|
||||
val newReturnType = returnType?.substitute(substitutor)
|
||||
return SubstitutedData(
|
||||
newTypeParameters,
|
||||
newDispatchReceiverType,
|
||||
newReceiverType,
|
||||
newReturnType,
|
||||
substitutor,
|
||||
fakeOverrideSubstitution
|
||||
)
|
||||
}
|
||||
|
||||
fun createSubstitutionOverrideField(original: FirFieldSymbol): FirFieldSymbol {
|
||||
if (substitutor == ConeSubstitutor.Empty) return original
|
||||
val member = original.fir
|
||||
if (skipPrivateMembers && member.visibility == Visibilities.Private) return original
|
||||
|
||||
member.symbol.ensureResolved(FirResolvePhase.STATUS)
|
||||
val returnType = member.returnTypeRef.coneTypeSafe<ConeKotlinType>()
|
||||
// TODO: do we have fields with implicit type?
|
||||
val newReturnType = returnType?.substitute() ?: return original
|
||||
|
||||
return FirFakeOverrideGenerator.createSubstitutionOverrideField(session, member, original, newReturnType, newOwnerClassId)
|
||||
}
|
||||
|
||||
fun createSubstitutionOverrideAccessor(original: FirAccessorSymbol): FirAccessorSymbol {
|
||||
if (substitutor == ConeSubstitutor.Empty) return original
|
||||
val member = original.fir as FirSyntheticProperty
|
||||
if (skipPrivateMembers && member.visibility == Visibilities.Private) return original
|
||||
|
||||
member.symbol.ensureResolved(FirResolvePhase.STATUS)
|
||||
val returnType = member.returnTypeRef.coneTypeSafe<ConeKotlinType>()
|
||||
val fakeOverrideSubstitution = runIf(returnType == null) { FakeOverrideSubstitution(substitutor, original) }
|
||||
val newReturnType = returnType?.substitute()
|
||||
|
||||
val newGetterParameterTypes = member.getter.valueParameters.map {
|
||||
it.returnTypeRef.coneType.substitute()
|
||||
}
|
||||
val newSetterParameterTypes = member.setter?.valueParameters?.map {
|
||||
it.returnTypeRef.coneType.substitute()
|
||||
}.orEmpty()
|
||||
|
||||
if (original.dispatchReceiverType?.substitute(substitutor) == null &&
|
||||
newReturnType == null &&
|
||||
newGetterParameterTypes.all { it == null } &&
|
||||
newSetterParameterTypes.all { it == null }
|
||||
) {
|
||||
return original
|
||||
}
|
||||
|
||||
return FirFakeOverrideGenerator.createSubstitutionOverrideAccessor(
|
||||
session,
|
||||
member,
|
||||
original,
|
||||
substitutor.substituteOrSelf(dispatchReceiverTypeForSubstitutedMembers),
|
||||
newReturnType,
|
||||
newGetterParameterTypes,
|
||||
newSetterParameterTypes,
|
||||
fakeOverrideSubstitution
|
||||
)
|
||||
}
|
||||
|
||||
override fun processDeclaredConstructors(processor: (FirConstructorSymbol) -> Unit) {
|
||||
useSiteMemberScope.processDeclaredConstructors process@{ original ->
|
||||
val constructor = substitutionOverrideCache.overridesForConstructors.getValue(original, this)
|
||||
processor(constructor)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getCallableNames(): Set<Name> {
|
||||
return useSiteMemberScope.getCallableNames()
|
||||
}
|
||||
|
||||
override fun getClassifierNames(): Set<Name> {
|
||||
return useSiteMemberScope.getClassifierNames()
|
||||
}
|
||||
}
|
||||
|
||||
class FirSubstitutionOverrideStorage(val session: FirSession) : FirSessionComponent {
|
||||
private val cachesFactory = session.firCachesFactory
|
||||
|
||||
val substitutionOverrideCacheByScope: FirCache<ScopeSessionKey<*, *>, SubstitutionOverrideCache, Nothing?> =
|
||||
cachesFactory.createCache { _ -> SubstitutionOverrideCache(session.firCachesFactory) }
|
||||
|
||||
class SubstitutionOverrideCache(cachesFactory: FirCachesFactory) {
|
||||
val overridesForFunctions: FirCache<FirNamedFunctionSymbol, FirNamedFunctionSymbol, FirClassSubstitutionScope> =
|
||||
cachesFactory.createCache { original, scope -> scope.createSubstitutionOverrideFunction(original) }
|
||||
val overridesForConstructors: FirCache<FirConstructorSymbol, FirConstructorSymbol, FirClassSubstitutionScope> =
|
||||
cachesFactory.createCache { original, scope -> scope.createSubstitutionOverrideConstructor(original) }
|
||||
val overridesForVariables: FirCache<FirVariableSymbol<*>, FirVariableSymbol<*>, FirClassSubstitutionScope> =
|
||||
cachesFactory.createCache { original, scope ->
|
||||
when (original) {
|
||||
is FirPropertySymbol -> scope.createSubstitutionOverrideProperty(original)
|
||||
is FirFieldSymbol -> scope.createSubstitutionOverrideField(original)
|
||||
is FirAccessorSymbol -> scope.createSubstitutionOverrideAccessor(original)
|
||||
else -> error("symbol $original is not overridable")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val FirSession.substitutionOverrideStorage: FirSubstitutionOverrideStorage by FirSession.sessionComponentAccessor()
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.fir.scopes.impl
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.FirProperty
|
||||
import org.jetbrains.kotlin.fir.scopes.FirContainingNamesAwareScope
|
||||
import org.jetbrains.kotlin.fir.scopes.FirTypeScope
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.isStatic
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
class FirClassUseSiteMemberScope(
|
||||
session: FirSession,
|
||||
superTypesScope: FirTypeScope,
|
||||
declaredMemberScope: FirContainingNamesAwareScope
|
||||
) : AbstractFirUseSiteMemberScope(session, FirStandardOverrideChecker(session), superTypesScope, declaredMemberScope) {
|
||||
|
||||
override fun processPropertiesByName(name: Name, processor: (FirVariableSymbol<*>) -> Unit) {
|
||||
val seen = mutableSetOf<FirVariableSymbol<*>>()
|
||||
declaredMemberScope.processPropertiesByName(name) l@{
|
||||
if (it.isStatic) return@l
|
||||
if (it is FirPropertySymbol) {
|
||||
val directOverridden = computeDirectOverridden(it.fir)
|
||||
this@FirClassUseSiteMemberScope.directOverriddenProperties[it] = directOverridden
|
||||
}
|
||||
seen += it
|
||||
processor(it)
|
||||
}
|
||||
|
||||
superTypesScope.processPropertiesByName(name) {
|
||||
val overriddenBy = it.getOverridden(seen)
|
||||
if (overriddenBy == null) {
|
||||
processor(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun computeDirectOverridden(property: FirProperty): MutableList<FirPropertySymbol> {
|
||||
val result = mutableListOf<FirPropertySymbol>()
|
||||
superTypesScope.processPropertiesByName(property.name) l@{ superSymbol ->
|
||||
if (superSymbol !is FirPropertySymbol) return@l
|
||||
if (overrideChecker.isOverriddenProperty(property, superSymbol.fir)) {
|
||||
result.add(superSymbol)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
+134
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.fir.scopes.impl
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.FirSessionComponent
|
||||
import org.jetbrains.kotlin.fir.ThreadSafeMutableState
|
||||
import org.jetbrains.kotlin.fir.caches.FirCache
|
||||
import org.jetbrains.kotlin.fir.caches.firCachesFactory
|
||||
import org.jetbrains.kotlin.fir.caches.getValue
|
||||
import org.jetbrains.kotlin.fir.declarations.FirClass
|
||||
import org.jetbrains.kotlin.fir.extensions.declarationGenerators
|
||||
import org.jetbrains.kotlin.fir.extensions.extensionService
|
||||
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider
|
||||
import org.jetbrains.kotlin.fir.scopes.FirContainingNamesAwareScope
|
||||
import org.jetbrains.kotlin.fir.scopes.FirNameAwareCompositeScope
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
@ThreadSafeMutableState
|
||||
class FirDeclaredMemberScopeProvider(val useSiteSession: FirSession) : FirSessionComponent {
|
||||
private val declaredMemberCache: FirCache<FirClass, FirContainingNamesAwareScope, DeclaredMemberScopeContext> =
|
||||
useSiteSession.firCachesFactory.createCache { klass, context ->
|
||||
createDeclaredMemberScope(klass, context.useLazyNestedClassifierScope, context.existingNames, context.symbolProvider)
|
||||
}
|
||||
|
||||
private val nestedClassifierCache: FirCache<FirClass, FirNestedClassifierScope?, Nothing?> =
|
||||
useSiteSession.firCachesFactory.createCache { klass, _ -> createNestedClassifierScope(klass) }
|
||||
|
||||
private val extensions by lazy(LazyThreadSafetyMode.PUBLICATION) { useSiteSession.extensionService.declarationGenerators }
|
||||
|
||||
fun declaredMemberScope(
|
||||
klass: FirClass,
|
||||
useLazyNestedClassifierScope: Boolean,
|
||||
existingNames: List<Name>?,
|
||||
symbolProvider: FirSymbolProvider?
|
||||
): FirContainingNamesAwareScope {
|
||||
return declaredMemberCache.getValue(klass, DeclaredMemberScopeContext(useLazyNestedClassifierScope, existingNames, symbolProvider))
|
||||
}
|
||||
|
||||
private data class DeclaredMemberScopeContext(
|
||||
val useLazyNestedClassifierScope: Boolean,
|
||||
val existingNames: List<Name>?,
|
||||
val symbolProvider: FirSymbolProvider?
|
||||
)
|
||||
|
||||
private fun createDeclaredMemberScope(
|
||||
klass: FirClass,
|
||||
useLazyNestedClassifierScope: Boolean,
|
||||
existingNames: List<Name>?,
|
||||
symbolProvider: FirSymbolProvider?
|
||||
): FirContainingNamesAwareScope {
|
||||
return when {
|
||||
klass.origin.generated -> {
|
||||
FirGeneratedClassDeclaredMemberScope(useSiteSession, klass, needNestedClassifierScope = true)
|
||||
}
|
||||
else -> {
|
||||
val baseScope = FirClassDeclaredMemberScopeImpl(
|
||||
useSiteSession,
|
||||
klass,
|
||||
useLazyNestedClassifierScope,
|
||||
existingNames,
|
||||
symbolProvider
|
||||
)
|
||||
if (extensions.any { it.needToGenerateAdditionalMembersInClass(klass) }) {
|
||||
FirNameAwareCompositeScope(
|
||||
listOf(baseScope, FirGeneratedClassDeclaredMemberScope(useSiteSession, klass, needNestedClassifierScope = false))
|
||||
)
|
||||
} else {
|
||||
baseScope
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun nestedClassifierScope(klass: FirClass): FirNestedClassifierScope? {
|
||||
return nestedClassifierCache.getValue(klass)
|
||||
}
|
||||
|
||||
private fun createNestedClassifierScope(klass: FirClass): FirNestedClassifierScope? {
|
||||
return if (klass.origin.generated) {
|
||||
FirGeneratedClassNestedClassifierScope(klass, useSiteSession)
|
||||
} else {
|
||||
val baseScope = FirNestedClassifierScopeImpl(klass, useSiteSession)
|
||||
if (extensions.any { it.needToGenerateNestedClassifiersInClass(klass) }) {
|
||||
FirCompositeNestedClassifierScope(
|
||||
listOf(baseScope, FirGeneratedClassNestedClassifierScope(klass, useSiteSession)),
|
||||
klass,
|
||||
useSiteSession
|
||||
)
|
||||
} else {
|
||||
baseScope
|
||||
}
|
||||
}.takeUnless { it.isEmpty() }
|
||||
}
|
||||
}
|
||||
|
||||
fun FirSession.declaredMemberScope(klass: FirClass): FirContainingNamesAwareScope {
|
||||
return declaredMemberScopeProvider
|
||||
.declaredMemberScope(klass, useLazyNestedClassifierScope = false, existingNames = null, symbolProvider = null)
|
||||
}
|
||||
|
||||
fun FirSession.declaredMemberScope(klass: FirClassSymbol<*>): FirContainingNamesAwareScope {
|
||||
return declaredMemberScope(klass.fir)
|
||||
}
|
||||
|
||||
fun FirSession.declaredMemberScopeWithLazyNestedScope(
|
||||
klass: FirClass,
|
||||
existingNames: List<Name>,
|
||||
symbolProvider: FirSymbolProvider
|
||||
): FirContainingNamesAwareScope {
|
||||
return declaredMemberScopeProvider
|
||||
.declaredMemberScope(klass, useLazyNestedClassifierScope = true, existingNames = existingNames, symbolProvider = symbolProvider)
|
||||
}
|
||||
|
||||
fun FirSession.nestedClassifierScope(klass: FirClass): FirNestedClassifierScope? {
|
||||
return declaredMemberScopeProvider
|
||||
.nestedClassifierScope(klass)
|
||||
}
|
||||
|
||||
fun lazyNestedClassifierScope(
|
||||
classId: ClassId,
|
||||
existingNames: List<Name>,
|
||||
symbolProvider: FirSymbolProvider
|
||||
): FirLazyNestedClassifierScope? {
|
||||
if (existingNames.isEmpty()) return null
|
||||
return FirLazyNestedClassifierScope(classId, existingNames, symbolProvider)
|
||||
}
|
||||
|
||||
val FirSession.declaredMemberScopeProvider: FirDeclaredMemberScopeProvider by FirSession.sessionComponentAccessor()
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.fir.scopes.impl
|
||||
|
||||
import org.jetbrains.kotlin.config.AnalysisFlags
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.builder.buildImport
|
||||
import org.jetbrains.kotlin.fir.declarations.builder.buildResolvedImport
|
||||
import org.jetbrains.kotlin.fir.languageVersionSettings
|
||||
import org.jetbrains.kotlin.fir.moduleData
|
||||
import org.jetbrains.kotlin.fir.resolve.ScopeSession
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
class FirDefaultStarImportingScope(
|
||||
session: FirSession,
|
||||
scopeSession: ScopeSession,
|
||||
filter: FirImportingScopeFilter,
|
||||
priority: DefaultImportPriority
|
||||
) : FirAbstractStarImportingScope(
|
||||
session, scopeSession, filter,
|
||||
lookupInFir = session.languageVersionSettings.getFlag(AnalysisFlags.allowKotlinPackage)
|
||||
) {
|
||||
// TODO: put languageVersionSettings into FirSession?
|
||||
override val starImports = run {
|
||||
val analyzerServices = session.moduleData.analyzerServices
|
||||
val allDefaultImports = priority.getAllDefaultImports(analyzerServices, LanguageVersionSettingsImpl.DEFAULT)
|
||||
allDefaultImports
|
||||
?.filter { it.isAllUnder }
|
||||
?.map {
|
||||
buildResolvedImport {
|
||||
delegate = buildImport {
|
||||
importedFqName = it.fqName
|
||||
isAllUnder = true
|
||||
}
|
||||
packageFqName = it.fqName
|
||||
}
|
||||
} ?: emptyList()
|
||||
}
|
||||
|
||||
override fun processFunctionsByName(name: Name, processor: (FirNamedFunctionSymbol) -> Unit) {
|
||||
if (filter == FirImportingScopeFilter.INVISIBLE_CLASSES) return
|
||||
if (name.isSpecial || name.identifier.isNotEmpty()) {
|
||||
for (import in starImports) {
|
||||
for (symbol in provider.getTopLevelFunctionSymbols(import.packageFqName, name)) {
|
||||
processor(symbol)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun processPropertiesByName(name: Name, processor: (FirVariableSymbol<*>) -> Unit) {
|
||||
if (filter == FirImportingScopeFilter.INVISIBLE_CLASSES) return
|
||||
if (name.isSpecial || name.identifier.isNotEmpty()) {
|
||||
for (import in starImports) {
|
||||
for (symbol in provider.getTopLevelPropertySymbols(import.packageFqName, name)) {
|
||||
processor(symbol)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+248
@@ -0,0 +1,248 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.fir.scopes.impl
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.modality
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.visibility
|
||||
import org.jetbrains.kotlin.fir.resolve.ScopeSession
|
||||
import org.jetbrains.kotlin.fir.resolve.defaultType
|
||||
import org.jetbrains.kotlin.fir.resolve.scope
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
||||
import org.jetbrains.kotlin.fir.scopes.*
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
|
||||
import org.jetbrains.kotlin.fir.symbols.ensureResolved
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
|
||||
import org.jetbrains.kotlin.fir.types.ConeFlexibleType
|
||||
import org.jetbrains.kotlin.fir.types.coneType
|
||||
import org.jetbrains.kotlin.fir.types.isMarkedNullable
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.name.StandardClassIds
|
||||
|
||||
class FirDelegatedMemberScope(
|
||||
private val session: FirSession,
|
||||
private val scopeSession: ScopeSession,
|
||||
private val containingClass: FirClass,
|
||||
private val declaredMemberScope: FirContainingNamesAwareScope,
|
||||
private val delegateFields: List<FirField>,
|
||||
) : FirContainingNamesAwareScope() {
|
||||
private val dispatchReceiverType = containingClass.defaultType()
|
||||
private val overrideChecker = FirStandardOverrideChecker(session)
|
||||
|
||||
override fun processFunctionsByName(name: Name, processor: (FirNamedFunctionSymbol) -> Unit) {
|
||||
declaredMemberScope.processFunctionsByName(name, processor)
|
||||
val result = mutableListOf<FirNamedFunctionSymbol>()
|
||||
|
||||
for (delegateField in delegateFields) {
|
||||
collectFunctionsFromSpecificField(delegateField, name, result)
|
||||
}
|
||||
|
||||
result.forEach(processor)
|
||||
}
|
||||
|
||||
private fun buildScope(delegateField: FirField): FirTypeScope? {
|
||||
delegateField.ensureResolved(FirResolvePhase.TYPES)
|
||||
return delegateField.returnTypeRef.coneType.scope(session, scopeSession, FakeOverrideTypeCalculator.DoNothing)
|
||||
}
|
||||
|
||||
private fun collectFunctionsFromSpecificField(
|
||||
delegateField: FirField,
|
||||
name: Name,
|
||||
result: MutableList<FirNamedFunctionSymbol>
|
||||
) {
|
||||
val scope = buildScope(delegateField) ?: return
|
||||
|
||||
scope.processFunctionsByName(name) processor@{ functionSymbol ->
|
||||
val original = functionSymbol.fir
|
||||
// KT-6014: If the original is abstract, we still need a delegation
|
||||
// For example,
|
||||
// interface IBase { override fun toString(): String }
|
||||
// object BaseImpl : IBase { override fun toString(): String = ... }
|
||||
// class Test : IBase by BaseImpl
|
||||
if (original.isPublicInAny() && original.modality != Modality.ABSTRACT) {
|
||||
return@processor
|
||||
}
|
||||
|
||||
if (original.modality == Modality.FINAL || original.visibility == Visibilities.Private) {
|
||||
return@processor
|
||||
}
|
||||
|
||||
if (declaredMemberScope.getFunctions(name).any { overrideChecker.isOverriddenFunction(it.fir, original) }) {
|
||||
return@processor
|
||||
}
|
||||
|
||||
result.firstOrNull {
|
||||
overrideChecker.isOverriddenFunction(it.fir, original)
|
||||
}?.let {
|
||||
it.fir.multipleDelegatesWithTheSameSignature = true
|
||||
return@processor
|
||||
}
|
||||
|
||||
val delegatedSymbol =
|
||||
FirFakeOverrideGenerator.createCopyForFirFunction(
|
||||
FirNamedFunctionSymbol(
|
||||
functionSymbol.callableId,
|
||||
),
|
||||
original,
|
||||
session,
|
||||
FirDeclarationOrigin.Delegated,
|
||||
newDispatchReceiverType = dispatchReceiverType,
|
||||
newModality = Modality.OPEN,
|
||||
).apply {
|
||||
delegatedWrapperData = DelegatedWrapperData(functionSymbol.fir, containingClass.symbol.toLookupTag(), delegateField)
|
||||
}.symbol
|
||||
|
||||
result += delegatedSymbol
|
||||
}
|
||||
}
|
||||
|
||||
override fun processPropertiesByName(name: Name, processor: (FirVariableSymbol<*>) -> Unit) {
|
||||
declaredMemberScope.processPropertiesByName(name, processor)
|
||||
|
||||
val result = mutableListOf<FirPropertySymbol>()
|
||||
for (delegateField in delegateFields) {
|
||||
collectPropertiesFromSpecificField(delegateField, name, result)
|
||||
}
|
||||
|
||||
result.forEach(processor)
|
||||
}
|
||||
|
||||
override fun processClassifiersByNameWithSubstitution(name: Name, processor: (FirClassifierSymbol<*>, ConeSubstitutor) -> Unit) {
|
||||
declaredMemberScope.processClassifiersByNameWithSubstitution(name, processor)
|
||||
}
|
||||
|
||||
override fun processDeclaredConstructors(processor: (FirConstructorSymbol) -> Unit) {
|
||||
declaredMemberScope.processDeclaredConstructors(processor)
|
||||
}
|
||||
|
||||
private fun collectPropertiesFromSpecificField(
|
||||
delegateField: FirField,
|
||||
name: Name,
|
||||
result: MutableList<FirPropertySymbol>
|
||||
) {
|
||||
val scope = buildScope(delegateField) ?: return
|
||||
|
||||
scope.processPropertiesByName(name) processor@{ propertySymbol ->
|
||||
if (propertySymbol !is FirPropertySymbol) {
|
||||
return@processor
|
||||
}
|
||||
|
||||
val original = propertySymbol.fir
|
||||
|
||||
if (original.modality == Modality.FINAL || original.visibility == Visibilities.Private) {
|
||||
return@processor
|
||||
}
|
||||
|
||||
if (declaredMemberScope.getProperties(name)
|
||||
.any { it is FirPropertySymbol && overrideChecker.isOverriddenProperty(it.fir, original) }
|
||||
) {
|
||||
return@processor
|
||||
}
|
||||
|
||||
|
||||
result.firstOrNull {
|
||||
overrideChecker.isOverriddenProperty(it.fir, original)
|
||||
}?.let {
|
||||
it.fir.multipleDelegatesWithTheSameSignature = true
|
||||
return@processor
|
||||
}
|
||||
|
||||
val delegatedSymbol =
|
||||
FirFakeOverrideGenerator.createCopyForFirProperty(
|
||||
FirPropertySymbol(
|
||||
propertySymbol.callableId
|
||||
),
|
||||
original,
|
||||
session,
|
||||
FirDeclarationOrigin.Delegated,
|
||||
newModality = Modality.OPEN,
|
||||
newDispatchReceiverType = dispatchReceiverType,
|
||||
).apply {
|
||||
delegatedWrapperData = DelegatedWrapperData(propertySymbol.fir, containingClass.symbol.toLookupTag(), delegateField)
|
||||
}.symbol
|
||||
result += delegatedSymbol
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalStdlibApi::class)
|
||||
private val callableNamesLazy: Set<Name> by lazy(LazyThreadSafetyMode.PUBLICATION) {
|
||||
buildSet {
|
||||
addAll(declaredMemberScope.getCallableNames())
|
||||
|
||||
delegateFields.flatMapTo(this) {
|
||||
buildScope(it)?.getCallableNames() ?: emptySet()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalStdlibApi::class)
|
||||
private val classifierNamesLazy: Set<Name> by lazy(LazyThreadSafetyMode.PUBLICATION) {
|
||||
buildSet {
|
||||
addAll(declaredMemberScope.getClassifierNames())
|
||||
|
||||
delegateFields.flatMapTo(this) {
|
||||
buildScope(it)?.getClassifierNames() ?: emptySet()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getCallableNames(): Set<Name> = callableNamesLazy
|
||||
override fun getClassifierNames(): Set<Name> = classifierNamesLazy
|
||||
}
|
||||
|
||||
private object MultipleDelegatesWithTheSameSignatureKey : FirDeclarationDataKey()
|
||||
|
||||
var FirCallableDeclaration.multipleDelegatesWithTheSameSignature: Boolean? by FirDeclarationDataRegistry.data(
|
||||
MultipleDelegatesWithTheSameSignatureKey
|
||||
)
|
||||
|
||||
val FirCallableSymbol<*>.multipleDelegatesWithTheSameSignature: Boolean?
|
||||
get() = fir.multipleDelegatesWithTheSameSignature
|
||||
|
||||
private object DelegatedWrapperDataKey : FirDeclarationDataKey()
|
||||
class DelegatedWrapperData<D : FirCallableDeclaration>(
|
||||
val wrapped: D,
|
||||
val containingClass: ConeClassLikeLookupTag,
|
||||
val delegateField: FirField,
|
||||
)
|
||||
var <D : FirCallableDeclaration>
|
||||
D.delegatedWrapperData: DelegatedWrapperData<D>? by FirDeclarationDataRegistry.data(DelegatedWrapperDataKey)
|
||||
|
||||
val <D : FirCallableDeclaration> FirCallableSymbol<out D>.delegatedWrapperData: DelegatedWrapperData<D>?
|
||||
get() = fir.delegatedWrapperData
|
||||
|
||||
|
||||
// From the definition of function interfaces in the Java specification (pt. 9.8):
|
||||
// "methods that are members of I that do not have the same signature as any public instance method of the class Object"
|
||||
// It means that if an interface declares `int hashCode()` then the method won't be taken into account when
|
||||
// checking if the interface is SAM.
|
||||
fun FirSimpleFunction.isPublicInAny(): Boolean {
|
||||
if (name.asString() !in PUBLIC_METHOD_NAMES_IN_ANY) return false
|
||||
|
||||
return when (name.asString()) {
|
||||
"hashCode", "toString" -> valueParameters.isEmpty()
|
||||
"equals" -> valueParameters.singleOrNull()?.hasTypeOf(StandardClassIds.Any, allowNullable = true) == true
|
||||
else -> error("Unexpected method name: $name")
|
||||
}
|
||||
}
|
||||
|
||||
fun FirValueParameter.hasTypeOf(classId: ClassId, allowNullable: Boolean): Boolean {
|
||||
val classLike = when (val type = returnTypeRef.coneType) {
|
||||
is ConeClassLikeType -> type
|
||||
is ConeFlexibleType -> type.upperBound as? ConeClassLikeType ?: return false
|
||||
else -> return false
|
||||
}
|
||||
|
||||
if (classLike.isMarkedNullable && !allowNullable) return false
|
||||
return classLike.lookupTag.classId == classId
|
||||
}
|
||||
|
||||
private val PUBLIC_METHOD_NAMES_IN_ANY = setOf("equals", "hashCode", "toString")
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.fir.scopes.impl
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.FirImport
|
||||
import org.jetbrains.kotlin.fir.declarations.FirResolvedImport
|
||||
import org.jetbrains.kotlin.fir.resolve.ScopeSession
|
||||
|
||||
class FirExplicitSimpleImportingScope(
|
||||
imports: List<FirImport>,
|
||||
session: FirSession,
|
||||
scopeSession: ScopeSession
|
||||
) : FirAbstractSimpleImportingScope(session, scopeSession) {
|
||||
override val simpleImports =
|
||||
imports.filterIsInstance<FirResolvedImport>()
|
||||
.filter { !it.isAllUnder && it.importedName != null }
|
||||
.groupBy { it.aliasName ?: it.importedName!! }
|
||||
|
||||
override val scopeOwnerLookupNames: List<String> by lazy(LazyThreadSafetyMode.PUBLICATION) {
|
||||
simpleImports.values.flatMapTo(LinkedHashSet()) { it.map { it.packageFqName.asString() } }.toList()
|
||||
}
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.fir.scopes.impl
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.FirImport
|
||||
import org.jetbrains.kotlin.fir.declarations.FirResolvedImport
|
||||
import org.jetbrains.kotlin.fir.resolve.ScopeSession
|
||||
|
||||
class FirExplicitStarImportingScope(
|
||||
imports: List<FirImport>,
|
||||
session: FirSession,
|
||||
scopeSession: ScopeSession,
|
||||
filter: FirImportingScopeFilter
|
||||
) : FirAbstractStarImportingScope(session, scopeSession, filter, lookupInFir = true) {
|
||||
override val starImports = imports.filterIsInstance<FirResolvedImport>().filter { it.isAllUnder }
|
||||
|
||||
override val scopeOwnerLookupNames: List<String> by lazy(LazyThreadSafetyMode.PUBLICATION) {
|
||||
starImports.mapTo(LinkedHashSet()) { it.packageFqName.asString() }.toList()
|
||||
}
|
||||
}
|
||||
+530
@@ -0,0 +1,530 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.fir.scopes.impl
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.descriptors.Visibility
|
||||
import org.jetbrains.kotlin.fir.*
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.declarations.builder.*
|
||||
import org.jetbrains.kotlin.fir.declarations.synthetic.FirSyntheticProperty
|
||||
import org.jetbrains.kotlin.fir.declarations.synthetic.buildSyntheticProperty
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isExpect
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.ChainedSubstitutor
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap
|
||||
import org.jetbrains.kotlin.fir.scopes.FakeOverrideSubstitution
|
||||
import org.jetbrains.kotlin.fir.scopes.fakeOverrideSubstitution
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.fir.types.builder.buildImplicitTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl
|
||||
import org.jetbrains.kotlin.name.CallableId
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.StandardClassIds
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.runIf
|
||||
|
||||
object FirFakeOverrideGenerator {
|
||||
fun createSubstitutionOverrideFunction(
|
||||
session: FirSession,
|
||||
baseFunction: FirSimpleFunction,
|
||||
baseSymbol: FirNamedFunctionSymbol,
|
||||
newDispatchReceiverType: ConeKotlinType?,
|
||||
newReceiverType: ConeKotlinType? = null,
|
||||
newReturnType: ConeKotlinType? = null,
|
||||
newParameterTypes: List<ConeKotlinType?>? = null,
|
||||
newTypeParameters: List<FirTypeParameter>? = null,
|
||||
derivedClassId: ClassId? = null,
|
||||
isExpect: Boolean = baseFunction.isExpect,
|
||||
fakeOverrideSubstitution: FakeOverrideSubstitution? = null
|
||||
): FirNamedFunctionSymbol {
|
||||
val symbol = if (derivedClassId == null) {
|
||||
FirNamedFunctionSymbol(baseSymbol.callableId)
|
||||
} else {
|
||||
FirNamedFunctionSymbol(CallableId(derivedClassId, baseFunction.name))
|
||||
}
|
||||
createSubstitutionOverrideFunction(
|
||||
symbol, session, baseFunction, newDispatchReceiverType, newReceiverType, newReturnType,
|
||||
newParameterTypes, newTypeParameters, isExpect, fakeOverrideSubstitution
|
||||
)
|
||||
return symbol
|
||||
}
|
||||
|
||||
private fun createSubstitutionOverrideFunction(
|
||||
fakeOverrideSymbol: FirNamedFunctionSymbol,
|
||||
session: FirSession,
|
||||
baseFunction: FirSimpleFunction,
|
||||
newDispatchReceiverType: ConeKotlinType?,
|
||||
newReceiverType: ConeKotlinType?,
|
||||
newReturnType: ConeKotlinType?,
|
||||
newParameterTypes: List<ConeKotlinType?>?,
|
||||
newTypeParameters: List<FirTypeParameter>?,
|
||||
isExpect: Boolean = baseFunction.isExpect,
|
||||
fakeOverrideSubstitution: FakeOverrideSubstitution?,
|
||||
): FirSimpleFunction {
|
||||
// TODO: consider using here some light-weight functions instead of pseudo-real FirMemberFunctionImpl
|
||||
// As second alternative, we can invent some light-weight kind of FirRegularClass
|
||||
return createCopyForFirFunction(
|
||||
fakeOverrideSymbol,
|
||||
baseFunction,
|
||||
session,
|
||||
FirDeclarationOrigin.SubstitutionOverride,
|
||||
isExpect,
|
||||
newDispatchReceiverType,
|
||||
newParameterTypes,
|
||||
newTypeParameters,
|
||||
newReceiverType,
|
||||
newReturnType,
|
||||
fakeOverrideSubstitution = fakeOverrideSubstitution
|
||||
).apply {
|
||||
originalForSubstitutionOverrideAttr = baseFunction
|
||||
}
|
||||
}
|
||||
|
||||
fun createCopyForFirFunction(
|
||||
newSymbol: FirNamedFunctionSymbol,
|
||||
baseFunction: FirSimpleFunction,
|
||||
session: FirSession,
|
||||
origin: FirDeclarationOrigin,
|
||||
isExpect: Boolean = baseFunction.isExpect,
|
||||
newDispatchReceiverType: ConeKotlinType?,
|
||||
newParameterTypes: List<ConeKotlinType?>? = null,
|
||||
newTypeParameters: List<FirTypeParameter>? = null,
|
||||
newReceiverType: ConeKotlinType? = null,
|
||||
newReturnType: ConeKotlinType? = null,
|
||||
newModality: Modality? = null,
|
||||
newVisibility: Visibility? = null,
|
||||
fakeOverrideSubstitution: FakeOverrideSubstitution? = null
|
||||
): FirSimpleFunction {
|
||||
return buildSimpleFunction {
|
||||
source = baseFunction.source
|
||||
moduleData = session.nullableModuleData ?: baseFunction.moduleData
|
||||
this.origin = origin
|
||||
name = baseFunction.name
|
||||
status = baseFunction.status.copy(isExpect, newModality, newVisibility)
|
||||
symbol = newSymbol
|
||||
resolvePhase = baseFunction.resolvePhase
|
||||
|
||||
dispatchReceiverType = newDispatchReceiverType
|
||||
attributes = baseFunction.attributes.copy()
|
||||
typeParameters += configureAnnotationsTypeParametersAndSignature(
|
||||
session, baseFunction, newParameterTypes, newTypeParameters, newReceiverType, newReturnType, fakeOverrideSubstitution
|
||||
).filterIsInstance<FirTypeParameter>()
|
||||
deprecation = baseFunction.deprecation
|
||||
}
|
||||
}
|
||||
|
||||
fun createSubstitutionOverrideConstructor(
|
||||
fakeOverrideSymbol: FirConstructorSymbol,
|
||||
session: FirSession,
|
||||
baseConstructor: FirConstructor,
|
||||
newDispatchReceiverType: ConeKotlinType?,
|
||||
newReturnType: ConeKotlinType?,
|
||||
newParameterTypes: List<ConeKotlinType?>?,
|
||||
newTypeParameters: List<FirTypeParameterRef>?,
|
||||
isExpect: Boolean,
|
||||
fakeOverrideSubstitution: FakeOverrideSubstitution?
|
||||
): FirConstructor {
|
||||
// TODO: consider using here some light-weight functions instead of pseudo-real FirMemberFunctionImpl
|
||||
// As second alternative, we can invent some light-weight kind of FirRegularClass
|
||||
return buildConstructor {
|
||||
moduleData = session.moduleData
|
||||
origin = FirDeclarationOrigin.SubstitutionOverride
|
||||
receiverTypeRef = baseConstructor.receiverTypeRef?.withReplacedConeType(null)
|
||||
status = baseConstructor.status.copy(isExpect)
|
||||
symbol = fakeOverrideSymbol
|
||||
|
||||
typeParameters += configureAnnotationsTypeParametersAndSignature(
|
||||
session,
|
||||
baseConstructor,
|
||||
newParameterTypes,
|
||||
newTypeParameters,
|
||||
newReceiverType = null,
|
||||
newReturnType,
|
||||
fakeOverrideSubstitution
|
||||
)
|
||||
|
||||
dispatchReceiverType = newDispatchReceiverType
|
||||
|
||||
resolvePhase = baseConstructor.resolvePhase
|
||||
source = baseConstructor.source
|
||||
attributes = baseConstructor.attributes.copy()
|
||||
deprecation = baseConstructor.deprecation
|
||||
}.apply {
|
||||
originalForSubstitutionOverrideAttr = baseConstructor
|
||||
}
|
||||
}
|
||||
|
||||
private fun FirFunctionBuilder.configureAnnotationsTypeParametersAndSignature(
|
||||
useSiteSession: FirSession,
|
||||
baseFunction: FirFunction,
|
||||
newParameterTypes: List<ConeKotlinType?>?,
|
||||
newTypeParameters: List<FirTypeParameterRef>?,
|
||||
newReceiverType: ConeKotlinType?,
|
||||
newReturnType: ConeKotlinType?,
|
||||
fakeOverrideSubstitution: FakeOverrideSubstitution?
|
||||
): List<FirTypeParameterRef> {
|
||||
return when {
|
||||
baseFunction.typeParameters.isEmpty() -> {
|
||||
configureAnnotationsAndSignature(
|
||||
baseFunction,
|
||||
newParameterTypes,
|
||||
newReceiverType,
|
||||
newReturnType,
|
||||
fakeOverrideSubstitution
|
||||
)
|
||||
emptyList()
|
||||
}
|
||||
newTypeParameters == null -> {
|
||||
val (copiedTypeParameters, substitutor) = createNewTypeParametersAndSubstitutor(
|
||||
useSiteSession, baseFunction, ConeSubstitutor.Empty
|
||||
)
|
||||
val copiedParameterTypes = baseFunction.valueParameters.map {
|
||||
substitutor.substituteOrNull(it.returnTypeRef.coneType)
|
||||
}
|
||||
val symbol = baseFunction.symbol
|
||||
val (copiedReceiverType, possibleReturnType) = substituteReceiverAndReturnType(
|
||||
baseFunction as FirCallableDeclaration, newReceiverType, newReturnType, substitutor
|
||||
)
|
||||
val (copiedReturnType, newFakeOverrideSubstitution) = when (possibleReturnType) {
|
||||
is Maybe.Value -> possibleReturnType.value to null
|
||||
else -> null to FakeOverrideSubstitution(substitutor, symbol)
|
||||
}
|
||||
configureAnnotationsAndSignature(
|
||||
baseFunction,
|
||||
copiedParameterTypes,
|
||||
copiedReceiverType,
|
||||
copiedReturnType,
|
||||
newFakeOverrideSubstitution
|
||||
)
|
||||
copiedTypeParameters
|
||||
}
|
||||
else -> {
|
||||
configureAnnotationsAndSignature(
|
||||
baseFunction,
|
||||
newParameterTypes,
|
||||
newReceiverType,
|
||||
newReturnType,
|
||||
fakeOverrideSubstitution
|
||||
)
|
||||
newTypeParameters
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun FirFunctionBuilder.configureAnnotationsAndSignature(
|
||||
baseFunction: FirFunction,
|
||||
newParameterTypes: List<ConeKotlinType?>?,
|
||||
newReceiverType: ConeKotlinType?,
|
||||
newReturnType: ConeKotlinType?,
|
||||
fakeOverrideSubstitution: FakeOverrideSubstitution?
|
||||
) {
|
||||
annotations += baseFunction.annotations
|
||||
|
||||
@Suppress("NAME_SHADOWING")
|
||||
val fakeOverrideSubstitution = fakeOverrideSubstitution ?: runIf(baseFunction.returnTypeRef is FirImplicitTypeRef) {
|
||||
FakeOverrideSubstitution(ConeSubstitutor.Empty, baseFunction.symbol)
|
||||
}
|
||||
|
||||
if (fakeOverrideSubstitution != null) {
|
||||
returnTypeRef = buildImplicitTypeRef()
|
||||
attributes.fakeOverrideSubstitution = fakeOverrideSubstitution
|
||||
} else {
|
||||
returnTypeRef = baseFunction.returnTypeRef.withReplacedReturnType(newReturnType)
|
||||
}
|
||||
|
||||
if (this is FirSimpleFunctionBuilder) {
|
||||
receiverTypeRef = baseFunction.receiverTypeRef?.withReplacedConeType(newReceiverType)
|
||||
}
|
||||
valueParameters += baseFunction.valueParameters.zip(
|
||||
newParameterTypes ?: List(baseFunction.valueParameters.size) { null }
|
||||
) { valueParameter, newType ->
|
||||
buildValueParameterCopy(valueParameter) {
|
||||
origin = FirDeclarationOrigin.SubstitutionOverride
|
||||
returnTypeRef = valueParameter.returnTypeRef.withReplacedConeType(newType)
|
||||
symbol = FirValueParameterSymbol(valueParameter.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun createSubstitutionOverrideProperty(
|
||||
session: FirSession,
|
||||
baseProperty: FirProperty,
|
||||
baseSymbol: FirPropertySymbol,
|
||||
newDispatchReceiverType: ConeKotlinType?,
|
||||
newReceiverType: ConeKotlinType? = null,
|
||||
newReturnType: ConeKotlinType? = null,
|
||||
newTypeParameters: List<FirTypeParameter>? = null,
|
||||
derivedClassId: ClassId? = null,
|
||||
isExpect: Boolean = baseProperty.isExpect,
|
||||
fakeOverrideSubstitution: FakeOverrideSubstitution? = null
|
||||
): FirPropertySymbol {
|
||||
val symbol = if (derivedClassId == null) {
|
||||
FirPropertySymbol(baseSymbol.callableId)
|
||||
} else {
|
||||
FirPropertySymbol(CallableId(derivedClassId, baseProperty.name))
|
||||
}
|
||||
createCopyForFirProperty(
|
||||
symbol, baseProperty, session, FirDeclarationOrigin.SubstitutionOverride, isExpect,
|
||||
newDispatchReceiverType, newTypeParameters, newReceiverType, newReturnType,
|
||||
fakeOverrideSubstitution = fakeOverrideSubstitution
|
||||
).apply {
|
||||
originalForSubstitutionOverrideAttr = baseProperty
|
||||
}
|
||||
return symbol
|
||||
}
|
||||
|
||||
fun createCopyForFirProperty(
|
||||
newSymbol: FirPropertySymbol,
|
||||
baseProperty: FirProperty,
|
||||
session: FirSession,
|
||||
origin: FirDeclarationOrigin,
|
||||
isExpect: Boolean = baseProperty.isExpect,
|
||||
newDispatchReceiverType: ConeKotlinType?,
|
||||
newTypeParameters: List<FirTypeParameter>? = null,
|
||||
newReceiverType: ConeKotlinType? = null,
|
||||
newReturnType: ConeKotlinType? = null,
|
||||
newModality: Modality? = null,
|
||||
newVisibility: Visibility? = null,
|
||||
fakeOverrideSubstitution: FakeOverrideSubstitution? = null
|
||||
): FirProperty {
|
||||
return buildProperty {
|
||||
source = baseProperty.source
|
||||
moduleData = session.moduleData
|
||||
this.origin = origin
|
||||
name = baseProperty.name
|
||||
isVar = baseProperty.isVar
|
||||
this.symbol = newSymbol
|
||||
isLocal = false
|
||||
status = baseProperty.status.copy(isExpect, newModality, newVisibility)
|
||||
|
||||
resolvePhase = baseProperty.resolvePhase
|
||||
dispatchReceiverType = newDispatchReceiverType
|
||||
attributes = baseProperty.attributes.copy()
|
||||
typeParameters += configureAnnotationsTypeParametersAndSignature(
|
||||
session,
|
||||
baseProperty,
|
||||
newTypeParameters,
|
||||
newReceiverType,
|
||||
newReturnType,
|
||||
fakeOverrideSubstitution
|
||||
)
|
||||
deprecation = baseProperty.deprecation
|
||||
}
|
||||
}
|
||||
|
||||
private fun FirPropertyBuilder.configureAnnotationsTypeParametersAndSignature(
|
||||
useSiteSession: FirSession,
|
||||
baseProperty: FirProperty,
|
||||
newTypeParameters: List<FirTypeParameter>?,
|
||||
newReceiverType: ConeKotlinType?,
|
||||
newReturnType: ConeKotlinType?,
|
||||
fakeOverrideSubstitution: FakeOverrideSubstitution?
|
||||
): List<FirTypeParameter> {
|
||||
return when {
|
||||
baseProperty.typeParameters.isEmpty() -> {
|
||||
configureAnnotationsAndSignature(baseProperty, newReceiverType, newReturnType, fakeOverrideSubstitution)
|
||||
emptyList()
|
||||
}
|
||||
newTypeParameters == null -> {
|
||||
val (copiedTypeParameters, substitutor) = createNewTypeParametersAndSubstitutor(
|
||||
useSiteSession, baseProperty, ConeSubstitutor.Empty
|
||||
)
|
||||
val (copiedReceiverType, possibleReturnType) = substituteReceiverAndReturnType(
|
||||
baseProperty, newReceiverType, newReturnType, substitutor
|
||||
)
|
||||
val (copiedReturnType, newFakeOverrideSubstitution) = when (possibleReturnType) {
|
||||
is Maybe.Value -> possibleReturnType.value to null
|
||||
else -> null to FakeOverrideSubstitution(substitutor, baseProperty.symbol)
|
||||
}
|
||||
configureAnnotationsAndSignature(baseProperty, copiedReceiverType, copiedReturnType, newFakeOverrideSubstitution)
|
||||
copiedTypeParameters.filterIsInstance<FirTypeParameter>()
|
||||
}
|
||||
else -> {
|
||||
configureAnnotationsAndSignature(baseProperty, newReceiverType, newReturnType, fakeOverrideSubstitution)
|
||||
newTypeParameters
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun substituteReceiverAndReturnType(
|
||||
baseCallable: FirCallableDeclaration,
|
||||
newReceiverType: ConeKotlinType?,
|
||||
newReturnType: ConeKotlinType?,
|
||||
substitutor: ConeSubstitutor
|
||||
): Pair<ConeKotlinType?, Maybe<ConeKotlinType?>> {
|
||||
val copiedReceiverType = newReceiverType?.let {
|
||||
substitutor.substituteOrNull(it)
|
||||
} ?: baseCallable.receiverTypeRef?.let {
|
||||
substitutor.substituteOrNull(it.coneType)
|
||||
}
|
||||
|
||||
val copiedReturnType = newReturnType?.let {
|
||||
substitutor.substituteOrNull(it)
|
||||
} ?: baseCallable.returnTypeRef.let {
|
||||
val coneType = baseCallable.returnTypeRef.coneTypeSafe<ConeKotlinType>() ?: return copiedReceiverType to Maybe.Nothing
|
||||
substitutor.substituteOrNull(coneType)
|
||||
}
|
||||
return copiedReceiverType to Maybe.Value(copiedReturnType)
|
||||
}
|
||||
|
||||
private fun FirPropertyBuilder.configureAnnotationsAndSignature(
|
||||
baseProperty: FirProperty,
|
||||
newReceiverType: ConeKotlinType?,
|
||||
newReturnType: ConeKotlinType?,
|
||||
fakeOverrideSubstitution: FakeOverrideSubstitution?
|
||||
) {
|
||||
annotations += baseProperty.annotations
|
||||
|
||||
@Suppress("NAME_SHADOWING")
|
||||
val fakeOverrideSubstitution = fakeOverrideSubstitution ?: runIf(baseProperty.returnTypeRef is FirImplicitTypeRef) {
|
||||
FakeOverrideSubstitution(ConeSubstitutor.Empty, baseProperty.symbol)
|
||||
}
|
||||
if (fakeOverrideSubstitution != null) {
|
||||
returnTypeRef = buildImplicitTypeRef()
|
||||
attributes.fakeOverrideSubstitution = fakeOverrideSubstitution
|
||||
} else {
|
||||
returnTypeRef = baseProperty.returnTypeRef.withReplacedReturnType(newReturnType)
|
||||
}
|
||||
receiverTypeRef = baseProperty.receiverTypeRef?.withReplacedConeType(newReceiverType)
|
||||
}
|
||||
|
||||
fun createSubstitutionOverrideField(
|
||||
session: FirSession,
|
||||
baseField: FirField,
|
||||
baseSymbol: FirFieldSymbol,
|
||||
newReturnType: ConeKotlinType?,
|
||||
derivedClassId: ClassId?
|
||||
): FirFieldSymbol {
|
||||
val symbol = FirFieldSymbol(
|
||||
CallableId(derivedClassId ?: baseSymbol.callableId.classId!!, baseField.name)
|
||||
)
|
||||
buildField {
|
||||
moduleData = session.moduleData
|
||||
this.symbol = symbol
|
||||
origin = FirDeclarationOrigin.SubstitutionOverride
|
||||
returnTypeRef = baseField.returnTypeRef.withReplacedConeType(newReturnType)
|
||||
|
||||
source = baseField.source
|
||||
resolvePhase = baseField.resolvePhase
|
||||
name = baseField.name
|
||||
isVar = baseField.isVar
|
||||
status = baseField.status
|
||||
resolvePhase = baseField.resolvePhase
|
||||
annotations += baseField.annotations
|
||||
attributes = baseField.attributes.copy()
|
||||
dispatchReceiverType = baseField.dispatchReceiverType
|
||||
}.apply {
|
||||
originalForSubstitutionOverrideAttr = baseField
|
||||
}
|
||||
return symbol
|
||||
}
|
||||
|
||||
fun createSubstitutionOverrideAccessor(
|
||||
session: FirSession,
|
||||
baseProperty: FirSyntheticProperty,
|
||||
baseSymbol: FirAccessorSymbol,
|
||||
newDispatchReceiverType: ConeKotlinType?,
|
||||
newReturnType: ConeKotlinType?,
|
||||
newGetterParameterTypes: List<ConeKotlinType?>?,
|
||||
newSetterParameterTypes: List<ConeKotlinType?>?,
|
||||
fakeOverrideSubstitution: FakeOverrideSubstitution?
|
||||
): FirAccessorSymbol {
|
||||
val getterSymbol = FirNamedFunctionSymbol(baseSymbol.accessorId)
|
||||
val getter = createSubstitutionOverrideFunction(
|
||||
getterSymbol,
|
||||
session,
|
||||
baseProperty.getter.delegate,
|
||||
newDispatchReceiverType,
|
||||
newReceiverType = null,
|
||||
newReturnType,
|
||||
newGetterParameterTypes,
|
||||
newTypeParameters = null,
|
||||
fakeOverrideSubstitution = fakeOverrideSubstitution
|
||||
)
|
||||
val setterSymbol = FirNamedFunctionSymbol(baseSymbol.accessorId)
|
||||
val baseSetter = baseProperty.setter
|
||||
val setter = if (baseSetter == null) null else createSubstitutionOverrideFunction(
|
||||
setterSymbol,
|
||||
session,
|
||||
baseSetter.delegate,
|
||||
newDispatchReceiverType,
|
||||
newReceiverType = null,
|
||||
StandardClassIds.Unit.constructClassLikeType(emptyArray(), isNullable = false),
|
||||
newSetterParameterTypes,
|
||||
newTypeParameters = null,
|
||||
fakeOverrideSubstitution = fakeOverrideSubstitution
|
||||
)
|
||||
return buildSyntheticProperty {
|
||||
moduleData = session.moduleData
|
||||
name = baseProperty.name
|
||||
symbol = FirAccessorSymbol(baseSymbol.callableId, baseSymbol.accessorId)
|
||||
delegateGetter = getter
|
||||
delegateSetter = setter
|
||||
status = baseProperty.status
|
||||
deprecation = getDeprecationsFromAccessors(getter, setter, session.languageVersionSettings.apiVersion)
|
||||
}.symbol
|
||||
}
|
||||
|
||||
// Returns a list of type parameters, and a substitutor that should be used for all other types
|
||||
fun createNewTypeParametersAndSubstitutor(
|
||||
useSiteSession: FirSession,
|
||||
member: FirTypeParameterRefsOwner,
|
||||
substitutor: ConeSubstitutor,
|
||||
forceTypeParametersRecreation: Boolean = true
|
||||
): Pair<List<FirTypeParameterRef>, ConeSubstitutor> {
|
||||
if (member.typeParameters.isEmpty()) return Pair(member.typeParameters, substitutor)
|
||||
val newTypeParameters = member.typeParameters.map { typeParameterRef ->
|
||||
val typeParameter = typeParameterRef.symbol.fir
|
||||
FirTypeParameterBuilder().apply {
|
||||
source = typeParameter.source
|
||||
moduleData = typeParameter.moduleData
|
||||
origin = FirDeclarationOrigin.SubstitutionOverride
|
||||
resolvePhase = FirResolvePhase.DECLARATIONS
|
||||
name = typeParameter.name
|
||||
symbol = FirTypeParameterSymbol()
|
||||
variance = typeParameter.variance
|
||||
isReified = typeParameter.isReified
|
||||
annotations += typeParameter.annotations
|
||||
}
|
||||
}
|
||||
|
||||
val substitutionMapForNewParameters = member.typeParameters.zip(newTypeParameters).associate { (original, new) ->
|
||||
Pair(original.symbol, ConeTypeParameterTypeImpl(new.symbol.toLookupTag(), isNullable = false))
|
||||
}
|
||||
|
||||
val additionalSubstitutor = substitutorByMap(substitutionMapForNewParameters, useSiteSession)
|
||||
|
||||
var wereChangesInTypeParameters = forceTypeParametersRecreation
|
||||
for ((newTypeParameter, oldTypeParameter) in newTypeParameters.zip(member.typeParameters)) {
|
||||
val original = oldTypeParameter.symbol.fir
|
||||
for (boundTypeRef in original.bounds) {
|
||||
val typeForBound = boundTypeRef.coneType
|
||||
val substitutedBound = substitutor.substituteOrNull(typeForBound)
|
||||
if (substitutedBound != null) {
|
||||
wereChangesInTypeParameters = true
|
||||
}
|
||||
newTypeParameter.bounds +=
|
||||
buildResolvedTypeRef {
|
||||
source = boundTypeRef.source
|
||||
type = additionalSubstitutor.substituteOrSelf(substitutedBound ?: typeForBound)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!wereChangesInTypeParameters) return Pair(member.typeParameters, substitutor)
|
||||
return Pair(
|
||||
newTypeParameters.map(FirTypeParameterBuilder::build),
|
||||
ChainedSubstitutor(substitutor, additionalSubstitutor)
|
||||
)
|
||||
}
|
||||
|
||||
private sealed class Maybe<out A> {
|
||||
class Value<out A>(val value: A) : Maybe<A>()
|
||||
object Nothing : Maybe<kotlin.Nothing>()
|
||||
}
|
||||
}
|
||||
+169
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.fir.scopes.impl
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.caches.FirCache
|
||||
import org.jetbrains.kotlin.fir.caches.FirLazyValue
|
||||
import org.jetbrains.kotlin.fir.caches.firCachesFactory
|
||||
import org.jetbrains.kotlin.fir.caches.getValue
|
||||
import org.jetbrains.kotlin.fir.declarations.FirClass
|
||||
import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.classId
|
||||
import org.jetbrains.kotlin.fir.declarations.validate
|
||||
import org.jetbrains.kotlin.fir.extensions.FirDeclarationGenerationExtension
|
||||
import org.jetbrains.kotlin.fir.extensions.declarationGenerators
|
||||
import org.jetbrains.kotlin.fir.extensions.extensionService
|
||||
import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||
import org.jetbrains.kotlin.name.CallableId
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.runIf
|
||||
|
||||
class FirGeneratedClassDeclaredMemberScope(
|
||||
val useSiteSession: FirSession,
|
||||
val firClass: FirClass,
|
||||
needNestedClassifierScope: Boolean
|
||||
) : FirClassDeclaredMemberScope() {
|
||||
private val extensions: List<FirDeclarationGenerationExtension> = firClass.findGeneratedExtensions(useSiteSession) {
|
||||
needToGenerateAdditionalMembersInClass(it)
|
||||
}
|
||||
|
||||
private val nestedClassifierScope: FirNestedClassifierScope? = runIf(needNestedClassifierScope) {
|
||||
useSiteSession.nestedClassifierScope(firClass)
|
||||
}
|
||||
|
||||
private val firCachesFactory = useSiteSession.firCachesFactory
|
||||
|
||||
// ------------------------------------------ caches ------------------------------------------
|
||||
|
||||
private val functionCache: FirCache<Name, List<FirNamedFunctionSymbol>, Nothing?> = firCachesFactory.createCache { callableId, _ ->
|
||||
generateMemberFunctions(callableId)
|
||||
}
|
||||
|
||||
private val propertyCache: FirCache<Name, List<FirPropertySymbol>, Nothing?> = firCachesFactory.createCache { callableId, _ ->
|
||||
generateMemberProperties(callableId)
|
||||
}
|
||||
|
||||
private val constructorCache: FirLazyValue<List<FirConstructorSymbol>, Nothing?> = firCachesFactory.createLazyValue {
|
||||
generateConstructors()
|
||||
}
|
||||
|
||||
private val callableNamesCache: FirLazyValue<Set<Name>, Nothing?> = firCachesFactory.createLazyValue {
|
||||
extensions.flatMapTo(mutableSetOf()) { it.getCallableNamesForClass(firClass.symbol) }
|
||||
}
|
||||
|
||||
// ------------------------------------------ generators ------------------------------------------
|
||||
|
||||
private fun generateMemberFunctions(name: Name): List<FirNamedFunctionSymbol> {
|
||||
return extensions
|
||||
.flatMap { it.generateFunctions(CallableId(firClass.classId, name), firClass.symbol) }
|
||||
.onEach { it.fir.validate() }
|
||||
}
|
||||
|
||||
private fun generateMemberProperties(name: Name): List<FirPropertySymbol> {
|
||||
return extensions
|
||||
.flatMap { it.generateProperties(CallableId(firClass.classId, name), firClass.symbol) }
|
||||
.onEach { it.fir.validate() }
|
||||
}
|
||||
|
||||
private fun generateConstructors(): List<FirConstructorSymbol> {
|
||||
val classId = firClass.symbol.classId
|
||||
val callableId = if (classId.isNestedClass) {
|
||||
CallableId(classId.parentClassId!!, classId.shortClassName)
|
||||
} else {
|
||||
CallableId(classId.asSingleFqName().parent(), classId.shortClassName)
|
||||
}
|
||||
return extensions.flatMap { it.generateConstructors(callableId) }.onEach { it.fir.validate() }
|
||||
}
|
||||
|
||||
// ------------------------------------------ scope methods ------------------------------------------
|
||||
|
||||
override fun getCallableNames(): Set<Name> {
|
||||
return callableNamesCache.getValue()
|
||||
}
|
||||
|
||||
override fun getClassifierNames(): Set<Name> {
|
||||
return nestedClassifierScope?.getClassifierNames() ?: emptySet()
|
||||
}
|
||||
|
||||
override fun processClassifiersByNameWithSubstitution(name: Name, processor: (FirClassifierSymbol<*>, ConeSubstitutor) -> Unit) {
|
||||
nestedClassifierScope?.processClassifiersByNameWithSubstitution(name, processor)
|
||||
}
|
||||
|
||||
override fun processFunctionsByName(name: Name, processor: (FirNamedFunctionSymbol) -> Unit) {
|
||||
if (name !in getCallableNames()) return
|
||||
for (functionSymbol in functionCache.getValue(name)) {
|
||||
processor(functionSymbol)
|
||||
}
|
||||
}
|
||||
|
||||
override fun processPropertiesByName(name: Name, processor: (FirVariableSymbol<*>) -> Unit) {
|
||||
if (name !in getCallableNames()) return
|
||||
for (propertySymbol in propertyCache.getValue(name)) {
|
||||
processor(propertySymbol)
|
||||
}
|
||||
}
|
||||
|
||||
override fun processDeclaredConstructors(processor: (FirConstructorSymbol) -> Unit) {
|
||||
for (constructorSymbol in constructorCache.getValue()) {
|
||||
processor(constructorSymbol)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class FirGeneratedClassNestedClassifierScope(
|
||||
klass: FirClass,
|
||||
useSiteSession: FirSession
|
||||
) : FirNestedClassifierScope(klass, useSiteSession) {
|
||||
private val extensions = klass.findGeneratedExtensions(useSiteSession) { needToGenerateNestedClassifiersInClass(it) }
|
||||
|
||||
private val nestedClassifierCache: FirCache<Name, FirRegularClassSymbol?, Nothing?> =
|
||||
useSiteSession.firCachesFactory.createCache { name, _ ->
|
||||
generateNestedClassifier(name)
|
||||
}
|
||||
|
||||
private val nestedClassifiersNames: FirLazyValue<Set<Name>, Nothing?> =
|
||||
useSiteSession.firCachesFactory.createLazyValue {
|
||||
extensions.flatMapTo(mutableSetOf()) { it.getNestedClassifiersNames(klass.symbol) }
|
||||
}
|
||||
|
||||
private fun generateNestedClassifier(name: Name): FirRegularClassSymbol? {
|
||||
if (name !in getClassifierNames()) return null
|
||||
val generatedClass = useSiteSession.symbolProvider.getClassLikeSymbolByClassId(klass.classId.createNestedClassId(name))
|
||||
require(generatedClass is FirRegularClassSymbol?) { "Only regular class are allowed as nested classes" }
|
||||
return generatedClass
|
||||
}
|
||||
|
||||
override fun getNestedClassSymbol(name: Name): FirRegularClassSymbol? {
|
||||
return nestedClassifierCache.getValue(name)
|
||||
}
|
||||
|
||||
override fun isEmpty(): Boolean {
|
||||
return getClassifierNames().isEmpty()
|
||||
}
|
||||
|
||||
override fun getClassifierNames(): Set<Name> {
|
||||
return nestedClassifiersNames.getValue()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private inline fun FirClass.findGeneratedExtensions(
|
||||
useSiteSession: FirSession,
|
||||
predicate: FirDeclarationGenerationExtension.(FirClass) -> Boolean
|
||||
): List<FirDeclarationGenerationExtension> {
|
||||
val origin = origin
|
||||
val declarationGenerators = useSiteSession.extensionService.declarationGenerators
|
||||
return if (origin is FirDeclarationOrigin.Plugin) {
|
||||
declarationGenerators.filter { it.key == origin.key }.also {
|
||||
require(it.isNotEmpty()) { "Extension for ${origin.key} not found" }
|
||||
}
|
||||
} else {
|
||||
declarationGenerators.filter { it.predicate(this) }
|
||||
}
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.fir.scopes.impl
|
||||
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.fir.scopes.impl
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirImplementationDetail
|
||||
import org.jetbrains.kotlin.fir.FirSourceElement
|
||||
import org.jetbrains.kotlin.fir.builder.FirAnnotationContainerBuilder
|
||||
import org.jetbrains.kotlin.fir.builder.FirBuilderDsl
|
||||
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
|
||||
import org.jetbrains.kotlin.fir.expressions.FirArgumentList
|
||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.FirFunctionCallOrigin
|
||||
import org.jetbrains.kotlin.fir.expressions.builder.FirCallBuilder
|
||||
import org.jetbrains.kotlin.fir.expressions.builder.FirExpressionBuilder
|
||||
import org.jetbrains.kotlin.fir.expressions.builder.FirQualifiedAccessBuilder
|
||||
import org.jetbrains.kotlin.fir.expressions.impl.FirFunctionCallImpl
|
||||
import org.jetbrains.kotlin.fir.expressions.impl.FirNoReceiverExpression
|
||||
import org.jetbrains.kotlin.fir.references.FirNamedReference
|
||||
import org.jetbrains.kotlin.fir.types.FirTypeProjection
|
||||
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.builder.buildImplicitTypeRef
|
||||
|
||||
@OptIn(FirImplementationDetail::class)
|
||||
class FirIntegerOperatorCall @FirImplementationDetail constructor(
|
||||
source: FirSourceElement?,
|
||||
typeRef: FirTypeRef,
|
||||
annotations: MutableList<FirAnnotation>,
|
||||
typeArguments: MutableList<FirTypeProjection>,
|
||||
explicitReceiver: FirExpression?,
|
||||
dispatchReceiver: FirExpression,
|
||||
extensionReceiver: FirExpression,
|
||||
argumentList: FirArgumentList,
|
||||
calleeReference: FirNamedReference,
|
||||
) : FirFunctionCallImpl(
|
||||
source,
|
||||
typeRef,
|
||||
annotations,
|
||||
typeArguments,
|
||||
explicitReceiver,
|
||||
dispatchReceiver,
|
||||
extensionReceiver,
|
||||
argumentList,
|
||||
calleeReference,
|
||||
FirFunctionCallOrigin.Operator
|
||||
)
|
||||
|
||||
@FirBuilderDsl
|
||||
class FirIntegerOperatorCallBuilder : FirQualifiedAccessBuilder, FirCallBuilder, FirAnnotationContainerBuilder, FirExpressionBuilder {
|
||||
override var source: FirSourceElement? = null
|
||||
override var typeRef: FirTypeRef = buildImplicitTypeRef()
|
||||
override val annotations: MutableList<FirAnnotation> = mutableListOf()
|
||||
override val typeArguments: MutableList<FirTypeProjection> = mutableListOf()
|
||||
override var explicitReceiver: FirExpression? = null
|
||||
override var dispatchReceiver: FirExpression = FirNoReceiverExpression
|
||||
override var extensionReceiver: FirExpression = FirNoReceiverExpression
|
||||
lateinit var calleeReference: FirNamedReference
|
||||
override lateinit var argumentList: FirArgumentList
|
||||
|
||||
@OptIn(FirImplementationDetail::class)
|
||||
override fun build(): FirIntegerOperatorCall {
|
||||
return FirIntegerOperatorCall(
|
||||
source,
|
||||
typeRef,
|
||||
annotations,
|
||||
typeArguments,
|
||||
explicitReceiver,
|
||||
dispatchReceiver,
|
||||
extensionReceiver,
|
||||
argumentList,
|
||||
calleeReference,
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
inline fun buildIntegerOperatorFunctionCall(init: FirIntegerOperatorCallBuilder.() -> Unit): FirIntegerOperatorCall {
|
||||
return FirIntegerOperatorCallBuilder().apply(init).build()
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.fir.scopes.impl
|
||||
|
||||
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
||||
import org.jetbrains.kotlin.fir.scopes.FirContainingNamesAwareScope
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassifierSymbol
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
// TODO: we could get rid of this scope and use FirNestedClassifierScope instead,
|
||||
// but in this case we should make JavaSymbolProvider greedy related to nested classifiers
|
||||
// (or make possible to calculate nested classifiers on-the-fly)
|
||||
class FirLazyNestedClassifierScope(
|
||||
val classId: ClassId,
|
||||
private val existingNames: List<Name>,
|
||||
private val symbolProvider: FirSymbolProvider
|
||||
) : FirContainingNamesAwareScope() {
|
||||
override fun processClassifiersByNameWithSubstitution(
|
||||
name: Name,
|
||||
processor: (FirClassifierSymbol<*>, ConeSubstitutor) -> Unit
|
||||
) {
|
||||
if (name !in existingNames) {
|
||||
return
|
||||
}
|
||||
val child = classId.createNestedClassId(name)
|
||||
val symbol = symbolProvider.getClassLikeSymbolByClassId(child) ?: return
|
||||
|
||||
processor(symbol, ConeSubstitutor.Empty)
|
||||
}
|
||||
|
||||
override fun getClassifierNames(): Set<Name> = existingNames.toSet()
|
||||
|
||||
override fun getCallableNames(): Set<Name> = emptySet()
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.fir.scopes.impl
|
||||
|
||||
import kotlinx.collections.immutable.PersistentMap
|
||||
import kotlinx.collections.immutable.persistentMapOf
|
||||
import org.jetbrains.kotlin.builtins.StandardNames.BACKING_FIELD
|
||||
import org.jetbrains.kotlin.fir.declarations.FirProperty
|
||||
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
|
||||
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
|
||||
import org.jetbrains.kotlin.fir.declarations.FirVariable
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
||||
import org.jetbrains.kotlin.fir.scopes.FirContainingNamesAwareScope
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassifierSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol
|
||||
import org.jetbrains.kotlin.fir.util.PersistentMultimap
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
class FirLocalScope private constructor(
|
||||
val properties: PersistentMap<Name, FirVariableSymbol<*>>,
|
||||
val functions: PersistentMultimap<Name, FirNamedFunctionSymbol>,
|
||||
val classes: PersistentMap<Name, FirRegularClassSymbol>
|
||||
) : FirContainingNamesAwareScope() {
|
||||
constructor() : this(persistentMapOf(), PersistentMultimap(), persistentMapOf())
|
||||
|
||||
fun storeClass(klass: FirRegularClass): FirLocalScope {
|
||||
return FirLocalScope(
|
||||
properties, functions, classes.put(klass.name, klass.symbol)
|
||||
)
|
||||
}
|
||||
|
||||
fun storeFunction(function: FirSimpleFunction): FirLocalScope {
|
||||
return FirLocalScope(
|
||||
properties, functions.put(function.name, function.symbol), classes
|
||||
)
|
||||
}
|
||||
|
||||
fun storeVariable(variable: FirVariable): FirLocalScope {
|
||||
return FirLocalScope(
|
||||
properties.put(variable.name, variable.symbol), functions, classes
|
||||
)
|
||||
}
|
||||
|
||||
fun storeBackingField(property: FirProperty): FirLocalScope {
|
||||
val enhancedProperties = property.backingField?.symbol?.let {
|
||||
properties.put(BACKING_FIELD, it)
|
||||
}
|
||||
|
||||
return FirLocalScope(
|
||||
enhancedProperties ?: properties,
|
||||
functions,
|
||||
classes
|
||||
)
|
||||
}
|
||||
|
||||
override fun processFunctionsByName(name: Name, processor: (FirNamedFunctionSymbol) -> Unit) {
|
||||
for (function in functions[name]) {
|
||||
processor(function)
|
||||
}
|
||||
}
|
||||
|
||||
override fun processPropertiesByName(name: Name, processor: (FirVariableSymbol<*>) -> Unit) {
|
||||
val property = properties[name]
|
||||
if (property != null) {
|
||||
processor(property)
|
||||
}
|
||||
}
|
||||
|
||||
override fun processClassifiersByNameWithSubstitution(name: Name, processor: (FirClassifierSymbol<*>, ConeSubstitutor) -> Unit) {
|
||||
val klass = classes[name]
|
||||
if (klass != null) {
|
||||
processor(klass, ConeSubstitutor.Empty)
|
||||
}
|
||||
}
|
||||
|
||||
override fun mayContainName(name: Name) = properties.containsKey(name) || functions[name].isNotEmpty() || classes.containsKey(name)
|
||||
|
||||
override fun getCallableNames(): Set<Name> = properties.keys + functions.keys
|
||||
override fun getClassifierNames(): Set<Name> = classes.keys
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.fir.scopes.impl
|
||||
|
||||
import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
|
||||
import org.jetbrains.kotlin.fir.declarations.FirTypeParameter
|
||||
import org.jetbrains.kotlin.fir.scopes.FirTypeParameterScope
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
class FirMemberTypeParameterScope(callableMember: FirMemberDeclaration) : FirTypeParameterScope() {
|
||||
override val typeParameters: Map<Name, List<FirTypeParameter>> =
|
||||
callableMember.typeParameters.filterIsInstance<FirTypeParameter>().groupBy { it.name }
|
||||
}
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.fir.scopes.impl
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.FirClass
|
||||
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
|
||||
import org.jetbrains.kotlin.fir.declarations.FirTypeParameterRef
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutorByMap
|
||||
import org.jetbrains.kotlin.fir.scopes.FirContainingNamesAwareScope
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterLookupTag
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassifierSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
|
||||
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||
import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
abstract class FirNestedClassifierScope(val klass: FirClass, val useSiteSession: FirSession) : FirContainingNamesAwareScope() {
|
||||
protected abstract fun getNestedClassSymbol(name: Name): FirRegularClassSymbol?
|
||||
|
||||
override fun processClassifiersByNameWithSubstitution(
|
||||
name: Name,
|
||||
processor: (FirClassifierSymbol<*>, ConeSubstitutor) -> Unit
|
||||
) {
|
||||
val matchedClass = getNestedClassSymbol(name) ?: return
|
||||
val substitution = klass.typeParameters.associate {
|
||||
it.symbol to it.toConeType()
|
||||
}
|
||||
processor(matchedClass, ConeSubstitutorByMap(substitution, useSiteSession))
|
||||
}
|
||||
|
||||
abstract fun isEmpty(): Boolean
|
||||
|
||||
override fun getCallableNames(): Set<Name> = emptySet()
|
||||
}
|
||||
|
||||
class FirNestedClassifierScopeImpl(klass: FirClass, useSiteSession: FirSession) : FirNestedClassifierScope(klass, useSiteSession) {
|
||||
private val classIndex: Map<Name, FirRegularClassSymbol> = run {
|
||||
val result = mutableMapOf<Name, FirRegularClassSymbol>()
|
||||
for (declaration in klass.declarations) {
|
||||
if (declaration is FirRegularClass) {
|
||||
result[declaration.name] = declaration.symbol
|
||||
}
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
override fun getNestedClassSymbol(name: Name): FirRegularClassSymbol? {
|
||||
return classIndex[name]
|
||||
}
|
||||
|
||||
override fun isEmpty(): Boolean = classIndex.isEmpty()
|
||||
|
||||
override fun getClassifierNames(): Set<Name> = classIndex.keys
|
||||
}
|
||||
|
||||
class FirCompositeNestedClassifierScope(
|
||||
val scopes: List<FirNestedClassifierScope>,
|
||||
klass: FirClass,
|
||||
useSiteSession: FirSession
|
||||
) : FirNestedClassifierScope(klass, useSiteSession) {
|
||||
override fun getNestedClassSymbol(name: Name): FirRegularClassSymbol? {
|
||||
error("Should not be called")
|
||||
}
|
||||
|
||||
override fun processClassifiersByNameWithSubstitution(name: Name, processor: (FirClassifierSymbol<*>, ConeSubstitutor) -> Unit) {
|
||||
scopes.forEach { it.processClassifiersByNameWithSubstitution(name, processor) }
|
||||
}
|
||||
|
||||
override fun isEmpty(): Boolean {
|
||||
return scopes.all { it.isEmpty() }
|
||||
}
|
||||
|
||||
override fun getClassifierNames(): Set<Name> {
|
||||
return scopes.flatMapTo(mutableSetOf()) { it.getClassifierNames() }
|
||||
}
|
||||
}
|
||||
|
||||
fun FirTypeParameterRef.toConeType(): ConeKotlinType = symbol.toConeType()
|
||||
|
||||
fun FirTypeParameterSymbol.toConeType(): ConeKotlinType = ConeTypeParameterTypeImpl(ConeTypeParameterLookupTag(this), isNullable = false)
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.fir.scopes.impl
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isInner
|
||||
import org.jetbrains.kotlin.fir.resolve.createSubstitutionForSupertype
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
||||
import org.jetbrains.kotlin.fir.scopes.FirContainingNamesAwareScope
|
||||
import org.jetbrains.kotlin.fir.scopes.getSingleClassifier
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
private class FirNestedClassifierScopeWithSubstitution(
|
||||
private val scope: FirContainingNamesAwareScope,
|
||||
private val substitutor: ConeSubstitutor
|
||||
) : FirContainingNamesAwareScope() {
|
||||
|
||||
override fun processFunctionsByName(name: Name, processor: (FirNamedFunctionSymbol) -> Unit) {
|
||||
scope.processFunctionsByName(name, processor)
|
||||
}
|
||||
|
||||
override fun processPropertiesByName(name: Name, processor: (FirVariableSymbol<*>) -> Unit) {
|
||||
scope.processPropertiesByName(name, processor)
|
||||
}
|
||||
|
||||
override fun processDeclaredConstructors(processor: (FirConstructorSymbol) -> Unit) {
|
||||
scope.processDeclaredConstructors(processor)
|
||||
}
|
||||
|
||||
override fun mayContainName(name: Name): Boolean {
|
||||
return scope.mayContainName(name)
|
||||
}
|
||||
|
||||
override fun processClassifiersByNameWithSubstitution(name: Name, processor: (FirClassifierSymbol<*>, ConeSubstitutor) -> Unit) {
|
||||
val matchedClass = scope.getSingleClassifier(name) as? FirRegularClassSymbol ?: return
|
||||
val substitutor = substitutor.takeIf { matchedClass.fir.isInner } ?: ConeSubstitutor.Empty
|
||||
processor(matchedClass, substitutor)
|
||||
}
|
||||
|
||||
override fun getCallableNames(): Set<Name> = scope.getCallableNames()
|
||||
override fun getClassifierNames(): Set<Name> = scope.getClassifierNames()
|
||||
|
||||
override val scopeOwnerLookupNames: List<String>
|
||||
get() = scope.scopeOwnerLookupNames
|
||||
}
|
||||
|
||||
fun FirContainingNamesAwareScope.wrapNestedClassifierScopeWithSubstitutionForSuperType(
|
||||
superType: ConeClassLikeType,
|
||||
session: FirSession
|
||||
): FirContainingNamesAwareScope {
|
||||
val substitutor = createSubstitutionForSupertype(superType, session)
|
||||
return FirNestedClassifierScopeWithSubstitution(this, substitutor)
|
||||
}
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.fir.scopes.impl
|
||||
|
||||
import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration
|
||||
import org.jetbrains.kotlin.fir.declarations.FirDeclarationDataKey
|
||||
import org.jetbrains.kotlin.fir.declarations.FirDeclarationDataRegistry
|
||||
import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
|
||||
import org.jetbrains.kotlin.fir.declarations.builder.buildPropertyCopy
|
||||
import org.jetbrains.kotlin.fir.declarations.builder.buildSimpleFunctionCopy
|
||||
import org.jetbrains.kotlin.fir.scopes.FirContainingNamesAwareScope
|
||||
import org.jetbrains.kotlin.fir.scopes.FirTypeScope
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol
|
||||
import org.jetbrains.kotlin.name.CallableId
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
class FirObjectImportedCallableScope(
|
||||
private val importedClassId: ClassId,
|
||||
private val objectUseSiteScope: FirTypeScope
|
||||
) : FirContainingNamesAwareScope() {
|
||||
override fun processFunctionsByName(name: Name, processor: (FirNamedFunctionSymbol) -> Unit) {
|
||||
objectUseSiteScope.processFunctionsByName(name) wrapper@{ symbol ->
|
||||
val function = symbol.fir
|
||||
val syntheticFunction = buildSimpleFunctionCopy(function) {
|
||||
origin = FirDeclarationOrigin.ImportedFromObject
|
||||
this.symbol = FirNamedFunctionSymbol(CallableId(importedClassId, name))
|
||||
}.apply {
|
||||
importedFromObjectData = ImportedFromObjectData(importedClassId, function)
|
||||
}
|
||||
processor(syntheticFunction.symbol)
|
||||
}
|
||||
}
|
||||
|
||||
override fun processPropertiesByName(name: Name, processor: (FirVariableSymbol<*>) -> Unit) {
|
||||
objectUseSiteScope.processPropertiesByName(name) wrapper@{ symbol ->
|
||||
if (symbol !is FirPropertySymbol) {
|
||||
processor(symbol)
|
||||
return@wrapper
|
||||
}
|
||||
val property = symbol.fir
|
||||
val syntheticFunction = buildPropertyCopy(property) {
|
||||
origin = FirDeclarationOrigin.ImportedFromObject
|
||||
this.symbol = FirPropertySymbol(CallableId(importedClassId, name))
|
||||
this.delegateFieldSymbol = null
|
||||
}.apply {
|
||||
importedFromObjectData = ImportedFromObjectData(importedClassId, property)
|
||||
}
|
||||
processor(syntheticFunction.symbol)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getCallableNames(): Set<Name> = objectUseSiteScope.getCallableNames()
|
||||
|
||||
override fun getClassifierNames(): Set<Name> = emptySet()
|
||||
}
|
||||
|
||||
private object ImportedFromObjectClassIdKey : FirDeclarationDataKey()
|
||||
|
||||
class ImportedFromObjectData<D : FirCallableDeclaration>(
|
||||
val objectClassId: ClassId,
|
||||
val original: D,
|
||||
)
|
||||
|
||||
var <D : FirCallableDeclaration>
|
||||
D.importedFromObjectData: ImportedFromObjectData<D>? by FirDeclarationDataRegistry.data(ImportedFromObjectClassIdKey)
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.fir.scopes.impl
|
||||
|
||||
import org.jetbrains.kotlin.fir.scopes.FirContainingNamesAwareScope
|
||||
import org.jetbrains.kotlin.fir.scopes.FirScope
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
class FirOnlyCallablesScope(val delegate: FirScope) : FirScope() {
|
||||
override fun processFunctionsByName(name: Name, processor: (FirNamedFunctionSymbol) -> Unit) {
|
||||
return delegate.processFunctionsByName(name, processor)
|
||||
}
|
||||
|
||||
override fun processPropertiesByName(name: Name, processor: (FirVariableSymbol<*>) -> Unit) {
|
||||
return delegate.processPropertiesByName(name, processor)
|
||||
}
|
||||
|
||||
override val scopeOwnerLookupNames: List<String>
|
||||
get() = delegate.scopeOwnerLookupNames
|
||||
}
|
||||
|
||||
class FirNameAwareOnlyCallablesScope(val delegate: FirContainingNamesAwareScope) : FirContainingNamesAwareScope() {
|
||||
override fun processFunctionsByName(name: Name, processor: (FirNamedFunctionSymbol) -> Unit) {
|
||||
return delegate.processFunctionsByName(name, processor)
|
||||
}
|
||||
|
||||
override fun processPropertiesByName(name: Name, processor: (FirVariableSymbol<*>) -> Unit) {
|
||||
return delegate.processPropertiesByName(name, processor)
|
||||
}
|
||||
|
||||
override val scopeOwnerLookupNames: List<String>
|
||||
get() = delegate.scopeOwnerLookupNames
|
||||
|
||||
override fun getCallableNames(): Set<Name> = delegate.getCallableNames()
|
||||
|
||||
override fun getClassifierNames(): Set<Name> = emptySet()
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.fir.scopes.impl
|
||||
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
||||
import org.jetbrains.kotlin.fir.scopes.FirContainingNamesAwareScope
|
||||
import org.jetbrains.kotlin.fir.scopes.FirScope
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassifierSymbol
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
class FirOnlyClassifiersScope(val delegate: FirScope) : FirScope() {
|
||||
override fun processClassifiersByNameWithSubstitution(name: Name, processor: (FirClassifierSymbol<*>, ConeSubstitutor) -> Unit) {
|
||||
return delegate.processClassifiersByNameWithSubstitution(name, processor)
|
||||
}
|
||||
}
|
||||
|
||||
class FirNameAwareOnlyClassifiersScope(val delegate: FirContainingNamesAwareScope) : FirContainingNamesAwareScope() {
|
||||
override fun processClassifiersByNameWithSubstitution(name: Name, processor: (FirClassifierSymbol<*>, ConeSubstitutor) -> Unit) {
|
||||
return delegate.processClassifiersByNameWithSubstitution(name, processor)
|
||||
}
|
||||
|
||||
override fun getCallableNames(): Set<Name> = emptySet()
|
||||
|
||||
override fun getClassifierNames(): Set<Name> = delegate.getClassifierNames()
|
||||
}
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.fir.scopes.impl
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider
|
||||
import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider
|
||||
import org.jetbrains.kotlin.fir.resolve.scopeSessionKey
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
||||
import org.jetbrains.kotlin.fir.scopes.FirScope
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassifierSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.utils.SmartList
|
||||
|
||||
class FirPackageMemberScope(
|
||||
val fqName: FqName,
|
||||
val session: FirSession,
|
||||
private val symbolProvider: FirSymbolProvider = session.symbolProvider
|
||||
) : FirScope() {
|
||||
private val classifierCache: MutableMap<Name, FirClassifierSymbol<*>?> = mutableMapOf()
|
||||
private val functionCache: MutableMap<Name, List<FirNamedFunctionSymbol>> = mutableMapOf()
|
||||
private val propertyCache: MutableMap<Name, List<FirPropertySymbol>> = mutableMapOf()
|
||||
|
||||
override fun processClassifiersByNameWithSubstitution(
|
||||
name: Name,
|
||||
processor: (FirClassifierSymbol<*>, ConeSubstitutor) -> Unit
|
||||
) {
|
||||
if (name.asString().isEmpty()) return
|
||||
|
||||
val symbol = classifierCache.getOrPut(name) {
|
||||
val unambiguousFqName = ClassId(fqName, name)
|
||||
symbolProvider.getClassLikeSymbolByClassId(unambiguousFqName)
|
||||
}
|
||||
|
||||
if (symbol != null) {
|
||||
processor(symbol, ConeSubstitutor.Empty)
|
||||
}
|
||||
}
|
||||
|
||||
override fun processFunctionsByName(name: Name, processor: (FirNamedFunctionSymbol) -> Unit) {
|
||||
val symbols = functionCache.getOrPut(name) {
|
||||
symbolProvider.getTopLevelFunctionSymbols(fqName, name)
|
||||
}
|
||||
for (symbol in symbols) {
|
||||
processor(symbol)
|
||||
}
|
||||
}
|
||||
|
||||
override fun processPropertiesByName(name: Name, processor: (FirVariableSymbol<*>) -> Unit) {
|
||||
val symbols = propertyCache.getOrPut(name) {
|
||||
symbolProvider.getTopLevelPropertySymbols(fqName, name)
|
||||
}
|
||||
for (symbol in symbols) {
|
||||
processor(symbol)
|
||||
}
|
||||
}
|
||||
|
||||
override val scopeOwnerLookupNames: List<String> = SmartList(fqName.asString())
|
||||
}
|
||||
|
||||
val PACKAGE_MEMBER = scopeSessionKey<FqName, FirPackageMemberScope>()
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.fir.scopes.impl
|
||||
|
||||
import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration
|
||||
import org.jetbrains.kotlin.fir.declarations.FirTypedDeclaration
|
||||
import org.jetbrains.kotlin.fir.isIntersectionOverride
|
||||
import org.jetbrains.kotlin.fir.isSubstitutionOverride
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
||||
import org.jetbrains.kotlin.fir.scopes.FakeOverrideTypeCalculator
|
||||
import org.jetbrains.kotlin.fir.scopes.FirTypeScope
|
||||
import org.jetbrains.kotlin.fir.scopes.ProcessorAction
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
class FirScopeWithFakeOverrideTypeCalculator(
|
||||
private val delegate: FirTypeScope,
|
||||
private val fakeOverrideTypeCalculator: FakeOverrideTypeCalculator
|
||||
) : FirTypeScope() {
|
||||
override fun processClassifiersByNameWithSubstitution(name: Name, processor: (FirClassifierSymbol<*>, ConeSubstitutor) -> Unit) {
|
||||
delegate.processClassifiersByNameWithSubstitution(name, processor)
|
||||
}
|
||||
|
||||
override fun processFunctionsByName(name: Name, processor: (FirNamedFunctionSymbol) -> Unit) {
|
||||
delegate.processFunctionsByName(name) {
|
||||
updateReturnType(it.fir)
|
||||
processor(it)
|
||||
}
|
||||
}
|
||||
|
||||
override fun processPropertiesByName(name: Name, processor: (FirVariableSymbol<*>) -> Unit) {
|
||||
delegate.processPropertiesByName(name) {
|
||||
updateReturnType(it.fir)
|
||||
processor(it)
|
||||
}
|
||||
}
|
||||
|
||||
override fun processDeclaredConstructors(processor: (FirConstructorSymbol) -> Unit) {
|
||||
delegate.processDeclaredConstructors(processor)
|
||||
}
|
||||
|
||||
override fun mayContainName(name: Name): Boolean {
|
||||
return delegate.mayContainName(name)
|
||||
}
|
||||
|
||||
override fun processDirectOverriddenFunctionsWithBaseScope(
|
||||
functionSymbol: FirNamedFunctionSymbol,
|
||||
processor: (FirNamedFunctionSymbol, FirTypeScope) -> ProcessorAction
|
||||
): ProcessorAction {
|
||||
return delegate.processDirectOverriddenFunctionsWithBaseScope(functionSymbol) { symbol, scope ->
|
||||
updateReturnType(symbol.fir)
|
||||
processor(symbol, scope)
|
||||
}
|
||||
}
|
||||
|
||||
override fun processDirectOverriddenPropertiesWithBaseScope(
|
||||
propertySymbol: FirPropertySymbol,
|
||||
processor: (FirPropertySymbol, FirTypeScope) -> ProcessorAction
|
||||
): ProcessorAction {
|
||||
return delegate.processDirectOverriddenPropertiesWithBaseScope(propertySymbol) { symbol, scope ->
|
||||
updateReturnType(symbol.fir)
|
||||
processor(symbol, scope)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getCallableNames(): Set<Name> {
|
||||
return delegate.getCallableNames()
|
||||
}
|
||||
|
||||
override fun getClassifierNames(): Set<Name> {
|
||||
return delegate.getClassifierNames()
|
||||
}
|
||||
|
||||
private fun updateReturnType(declaration: FirTypedDeclaration) {
|
||||
if (declaration !is FirCallableDeclaration) return
|
||||
if (declaration.isSubstitutionOverride || declaration.isIntersectionOverride) {
|
||||
fakeOverrideTypeCalculator.computeReturnType(declaration)
|
||||
}
|
||||
}
|
||||
|
||||
override val scopeOwnerLookupNames: List<String>
|
||||
get() = delegate.scopeOwnerLookupNames
|
||||
}
|
||||
+152
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.fir.scopes.impl
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.visibility
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
||||
import org.jetbrains.kotlin.fir.resolve.transformers.ensureResolvedTypeDeclaration
|
||||
import org.jetbrains.kotlin.fir.symbols.ensureResolved
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.types.AbstractTypeChecker
|
||||
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
|
||||
import org.jetbrains.kotlin.types.model.SimpleTypeMarker
|
||||
|
||||
class FirStandardOverrideChecker(private val session: FirSession) : FirAbstractOverrideChecker() {
|
||||
private val context = session.typeContext
|
||||
|
||||
private fun isEqualTypes(substitutedCandidateType: ConeKotlinType, substitutedBaseType: ConeKotlinType): Boolean {
|
||||
return with(context) {
|
||||
val baseIsFlexible = substitutedBaseType.isFlexible()
|
||||
val candidateIsFlexible = substitutedCandidateType.isFlexible()
|
||||
if (baseIsFlexible == candidateIsFlexible) {
|
||||
return AbstractTypeChecker.equalTypes(context, substitutedCandidateType, substitutedBaseType)
|
||||
}
|
||||
val lowerBound: SimpleTypeMarker
|
||||
val upperBound: SimpleTypeMarker
|
||||
val type: KotlinTypeMarker
|
||||
if (baseIsFlexible) {
|
||||
lowerBound = substitutedBaseType.lowerBoundIfFlexible()
|
||||
upperBound = substitutedBaseType.upperBoundIfFlexible()
|
||||
type = substitutedCandidateType
|
||||
} else {
|
||||
lowerBound = substitutedCandidateType.lowerBoundIfFlexible()
|
||||
upperBound = substitutedCandidateType.upperBoundIfFlexible()
|
||||
type = substitutedBaseType
|
||||
}
|
||||
AbstractTypeChecker.isSubtypeOf(context, lowerBound, type) && AbstractTypeChecker.isSubtypeOf(context, type, upperBound)
|
||||
}
|
||||
}
|
||||
|
||||
private fun isEqualTypes(candidateType: ConeKotlinType, baseType: ConeKotlinType, substitutor: ConeSubstitutor): Boolean {
|
||||
val substitutedCandidateType = substitutor.substituteOrSelf(candidateType)
|
||||
val substitutedBaseType = substitutor.substituteOrSelf(baseType)
|
||||
return isEqualTypes(substitutedCandidateType, substitutedBaseType)
|
||||
}
|
||||
|
||||
fun isEqualTypes(candidateTypeRef: FirTypeRef, baseTypeRef: FirTypeRef, substitutor: ConeSubstitutor): Boolean {
|
||||
candidateTypeRef.ensureResolvedTypeDeclaration(session, requiredPhase = FirResolvePhase.TYPES)
|
||||
baseTypeRef.ensureResolvedTypeDeclaration(session, requiredPhase = FirResolvePhase.TYPES)
|
||||
if (candidateTypeRef is FirErrorTypeRef && baseTypeRef is FirErrorTypeRef) {
|
||||
return maybeEqualErrorTypes(candidateTypeRef, baseTypeRef)
|
||||
}
|
||||
return isEqualTypes(candidateTypeRef.coneType, baseTypeRef.coneType, substitutor)
|
||||
}
|
||||
|
||||
private fun maybeEqualErrorTypes(ref1: FirErrorTypeRef, ref2: FirErrorTypeRef): Boolean {
|
||||
val delegated1 = ref1.delegatedTypeRef as? FirUserTypeRef ?: return false
|
||||
val delegated2 = ref2.delegatedTypeRef as? FirUserTypeRef ?: return false
|
||||
if (delegated1.qualifier.size != delegated2.qualifier.size) return false
|
||||
return delegated1.qualifier.zip(delegated2.qualifier).all { (l, r) -> l.name == r.name }
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Good case complexity is O(1)
|
||||
* Worst case complexity is O(N), where N is number of type-parameter bound's
|
||||
*/
|
||||
private fun isEqualBound(
|
||||
overrideBound: FirTypeRef,
|
||||
baseBound: FirTypeRef,
|
||||
overrideTypeParameter: FirTypeParameter,
|
||||
baseTypeParameter: FirTypeParameter,
|
||||
substitutor: ConeSubstitutor
|
||||
): Boolean {
|
||||
val substitutedOverrideType = substitutor.substituteOrSelf(overrideBound.coneType)
|
||||
val substitutedBaseType = substitutor.substituteOrSelf(baseBound.coneType)
|
||||
|
||||
if (isEqualTypes(substitutedOverrideType, substitutedBaseType)) return true
|
||||
|
||||
return overrideTypeParameter.bounds.any { bound -> isEqualTypes(bound.coneType, substitutedBaseType, substitutor) } &&
|
||||
baseTypeParameter.bounds.any { bound -> isEqualTypes(bound.coneType, substitutedOverrideType, substitutor) }
|
||||
}
|
||||
|
||||
private fun isCompatibleTypeParameters(
|
||||
overrideCandidate: FirTypeParameterRef,
|
||||
baseDeclaration: FirTypeParameterRef,
|
||||
substitutor: ConeSubstitutor
|
||||
): Boolean {
|
||||
if (overrideCandidate.symbol == baseDeclaration.symbol) return true
|
||||
if (overrideCandidate !is FirTypeParameter || baseDeclaration !is FirTypeParameter) return false
|
||||
if (overrideCandidate.bounds.size != baseDeclaration.bounds.size) return false
|
||||
return overrideCandidate.bounds.zip(baseDeclaration.bounds)
|
||||
.all { (aBound, bBound) -> isEqualBound(aBound, bBound, overrideCandidate, baseDeclaration, substitutor) }
|
||||
}
|
||||
|
||||
override fun buildTypeParametersSubstitutorIfCompatible(
|
||||
overrideCandidate: FirCallableDeclaration,
|
||||
baseDeclaration: FirCallableDeclaration
|
||||
): ConeSubstitutor? {
|
||||
overrideCandidate.ensureResolved(FirResolvePhase.TYPES)
|
||||
baseDeclaration.ensureResolved(FirResolvePhase.TYPES)
|
||||
val substitutor = buildSubstitutorForOverridesCheck(overrideCandidate, baseDeclaration, session) ?: return null
|
||||
if (
|
||||
overrideCandidate.typeParameters.isNotEmpty() &&
|
||||
overrideCandidate.typeParameters.zip(baseDeclaration.typeParameters).any { (override, base) ->
|
||||
!isCompatibleTypeParameters(override, base, substitutor)
|
||||
}
|
||||
) return null
|
||||
return substitutor
|
||||
}
|
||||
|
||||
private fun isEqualReceiverTypes(candidateTypeRef: FirTypeRef?, baseTypeRef: FirTypeRef?, substitutor: ConeSubstitutor): Boolean {
|
||||
return when {
|
||||
candidateTypeRef != null && baseTypeRef != null -> isEqualTypes(candidateTypeRef, baseTypeRef, substitutor)
|
||||
else -> candidateTypeRef == null && baseTypeRef == null
|
||||
}
|
||||
}
|
||||
|
||||
override fun isOverriddenFunction(overrideCandidate: FirSimpleFunction, baseDeclaration: FirSimpleFunction): Boolean {
|
||||
if (Visibilities.isPrivate(baseDeclaration.visibility)) return false
|
||||
|
||||
if (overrideCandidate.valueParameters.size != baseDeclaration.valueParameters.size) return false
|
||||
|
||||
val substitutor = buildTypeParametersSubstitutorIfCompatible(overrideCandidate, baseDeclaration) ?: return false
|
||||
|
||||
overrideCandidate.ensureResolved(FirResolvePhase.TYPES)
|
||||
baseDeclaration.ensureResolved(FirResolvePhase.TYPES)
|
||||
if (!isEqualReceiverTypes(overrideCandidate.receiverTypeRef, baseDeclaration.receiverTypeRef, substitutor)) return false
|
||||
|
||||
return overrideCandidate.valueParameters.zip(baseDeclaration.valueParameters).all { (memberParam, selfParam) ->
|
||||
isEqualTypes(memberParam.returnTypeRef, selfParam.returnTypeRef, substitutor)
|
||||
}
|
||||
}
|
||||
|
||||
override fun isOverriddenProperty(
|
||||
overrideCandidate: FirCallableDeclaration,
|
||||
baseDeclaration: FirProperty
|
||||
): Boolean {
|
||||
if (Visibilities.isPrivate(baseDeclaration.visibility)) return false
|
||||
|
||||
if (overrideCandidate !is FirProperty) return false
|
||||
val substitutor = buildTypeParametersSubstitutorIfCompatible(overrideCandidate, baseDeclaration) ?: return false
|
||||
overrideCandidate.ensureResolved(FirResolvePhase.TYPES)
|
||||
baseDeclaration.ensureResolved(FirResolvePhase.TYPES)
|
||||
return isEqualReceiverTypes(overrideCandidate.receiverTypeRef, baseDeclaration.receiverTypeRef, substitutor)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.fir.scopes.impl
|
||||
|
||||
import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration
|
||||
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isStatic
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
||||
import org.jetbrains.kotlin.fir.scopes.FirContainingNamesAwareScope
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassifierSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
class FirStaticScope(private val delegateScope: FirContainingNamesAwareScope) : FirContainingNamesAwareScope() {
|
||||
override fun processClassifiersByNameWithSubstitution(name: Name, processor: (FirClassifierSymbol<*>, ConeSubstitutor) -> Unit) {
|
||||
delegateScope.processClassifiersByNameWithSubstitution(name, processor)
|
||||
}
|
||||
|
||||
override fun processFunctionsByName(name: Name, processor: (FirNamedFunctionSymbol) -> Unit) {
|
||||
delegateScope.processFunctionsByName(name) {
|
||||
if ((it.fir as? FirSimpleFunction)?.isStatic == true) {
|
||||
processor(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun processPropertiesByName(name: Name, processor: (FirVariableSymbol<*>) -> Unit) {
|
||||
delegateScope.processPropertiesByName(name) {
|
||||
if ((it.fir as? FirCallableDeclaration)?.isStatic == true) {
|
||||
processor(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override fun getCallableNames(): Set<Name> {
|
||||
return delegateScope.getCallableNames()
|
||||
}
|
||||
|
||||
override fun getClassifierNames(): Set<Name> {
|
||||
return delegateScope.getClassifierNames()
|
||||
}
|
||||
}
|
||||
+617
@@ -0,0 +1,617 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.fir.scopes.impl
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.descriptors.Visibility
|
||||
import org.jetbrains.kotlin.fir.*
|
||||
import org.jetbrains.kotlin.fir.caches.*
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isExpect
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.modality
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.visibility
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
||||
import org.jetbrains.kotlin.fir.scopes.*
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.name.CallableId
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.types.AbstractTypeChecker
|
||||
|
||||
class FirTypeIntersectionScope private constructor(
|
||||
session: FirSession,
|
||||
overrideChecker: FirOverrideChecker,
|
||||
private val scopes: List<FirTypeScope>,
|
||||
private val dispatchReceiverType: ConeKotlinType,
|
||||
) : AbstractFirOverrideScope(session, overrideChecker) {
|
||||
private val absentFunctions: MutableSet<Name> = mutableSetOf()
|
||||
private val absentProperties: MutableSet<Name> = mutableSetOf()
|
||||
private val absentClassifiers: MutableSet<Name> = mutableSetOf()
|
||||
|
||||
private val typeCheckerState = session.typeContext.newTypeCheckerState(
|
||||
errorTypesEqualToAnything = false,
|
||||
stubTypesEqualToAnything = false
|
||||
)
|
||||
|
||||
private val overriddenSymbols: MutableMap<FirCallableSymbol<*>, Collection<MemberWithBaseScope<FirCallableSymbol<*>>>> = mutableMapOf()
|
||||
|
||||
private val intersectionOverrides =
|
||||
session.intersectionOverrideStorage.cacheByScope.getValue(dispatchReceiverType).intersectionOverrides
|
||||
|
||||
private val callableNamesCached by lazy(LazyThreadSafetyMode.PUBLICATION) {
|
||||
scopes.flatMapTo(mutableSetOf()) { it.getCallableNames() }
|
||||
}
|
||||
|
||||
override fun processFunctionsByName(name: Name, processor: (FirNamedFunctionSymbol) -> Unit) {
|
||||
if (!processCallablesByName(name, processor, absentFunctions, FirScope::processFunctionsByName)) {
|
||||
super.processFunctionsByName(name, processor)
|
||||
}
|
||||
}
|
||||
|
||||
override fun processPropertiesByName(name: Name, processor: (FirVariableSymbol<*>) -> Unit) {
|
||||
if (!processCallablesByName(name, processor, absentProperties, FirScope::processPropertiesByName)) {
|
||||
super.processPropertiesByName(name, processor)
|
||||
}
|
||||
}
|
||||
|
||||
private inline fun <D : FirCallableSymbol<*>> processCallablesByName(
|
||||
name: Name,
|
||||
noinline processor: (D) -> Unit,
|
||||
absentNames: MutableSet<Name>,
|
||||
processCallables: FirScope.(Name, (D) -> Unit) -> Unit
|
||||
): Boolean {
|
||||
if (name in absentNames) {
|
||||
return false
|
||||
}
|
||||
|
||||
val membersByScope = scopes.mapNotNull { scope ->
|
||||
val resultForScope = mutableListOf<D>()
|
||||
scope.processCallables(name) {
|
||||
if (it !is FirConstructorSymbol) {
|
||||
resultForScope.add(it)
|
||||
}
|
||||
}
|
||||
|
||||
resultForScope.takeIf { it.isNotEmpty() }?.let {
|
||||
scope to it
|
||||
}
|
||||
}
|
||||
|
||||
if (membersByScope.isEmpty()) {
|
||||
absentNames.add(name)
|
||||
return false
|
||||
}
|
||||
|
||||
membersByScope.singleOrNull()?.let { (scope, members) ->
|
||||
for (member in members) {
|
||||
overriddenSymbols[member] = listOf(MemberWithBaseScope(member, scope))
|
||||
processor(member)
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
val allMembersWithScope = membersByScope.flatMapTo(linkedSetOf()) { (scope, members) ->
|
||||
members.map { MemberWithBaseScope(it, scope) }
|
||||
}
|
||||
|
||||
while (allMembersWithScope.size > 1) {
|
||||
val maxByVisibility = findMemberWithMaxVisibility(allMembersWithScope)
|
||||
val extractBothWaysWithPrivate = extractBothWaysOverridable(maxByVisibility, allMembersWithScope)
|
||||
val extractedOverrides = extractBothWaysWithPrivate.filterNotTo(mutableListOf()) {
|
||||
Visibilities.isPrivate((it.member.fir as FirMemberDeclaration).visibility)
|
||||
}.takeIf { it.isNotEmpty() } ?: extractBothWaysWithPrivate
|
||||
val baseMembersForIntersection = extractedOverrides.calcBaseMembersForIntersectionOverride()
|
||||
if (baseMembersForIntersection.size > 1) {
|
||||
val (mostSpecific, scopeForMostSpecific) = selectMostSpecificMember(baseMembersForIntersection)
|
||||
val intersectionOverride = intersectionOverrides.getValue(
|
||||
mostSpecific,
|
||||
FirIntersectionOverrideStorage.ContextForIntersectionOverrideConstruction(
|
||||
this,
|
||||
extractedOverrides,
|
||||
scopeForMostSpecific
|
||||
)
|
||||
)
|
||||
overriddenSymbols[intersectionOverride.member] = extractedOverrides
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
processor(intersectionOverride.member as D)
|
||||
} else {
|
||||
val mostSpecific = baseMembersForIntersection.single().member
|
||||
overriddenSymbols[mostSpecific] = extractedOverrides
|
||||
processor(mostSpecific)
|
||||
}
|
||||
}
|
||||
|
||||
if (allMembersWithScope.isNotEmpty()) {
|
||||
val single = allMembersWithScope.single().member
|
||||
overriddenSymbols[single] = allMembersWithScope.toList()
|
||||
processor(single)
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
private inline fun <reified D : FirCallableDeclaration> D.unwrapSubstitutionOverrides(): D {
|
||||
var current = this
|
||||
|
||||
do {
|
||||
val next = current.originalForSubstitutionOverride ?: return current
|
||||
current = next
|
||||
} while (true)
|
||||
}
|
||||
|
||||
fun <D : FirCallableSymbol<*>> createIntersectionOverride(
|
||||
extractedOverrides: List<MemberWithBaseScope<D>>,
|
||||
mostSpecific: D,
|
||||
scopeForMostSpecific: FirTypeScope
|
||||
): MemberWithBaseScope<FirCallableSymbol<*>> {
|
||||
val newModality = chooseIntersectionOverrideModality(extractedOverrides)
|
||||
val newVisibility = chooseIntersectionVisibility(extractedOverrides)
|
||||
val extractedOverridesSymbols = extractedOverrides.map { it.member }
|
||||
return when (mostSpecific) {
|
||||
is FirNamedFunctionSymbol -> createIntersectionOverride(mostSpecific, extractedOverridesSymbols, newModality, newVisibility)
|
||||
is FirPropertySymbol -> createIntersectionOverride(mostSpecific, extractedOverridesSymbols, newModality, newVisibility)
|
||||
else -> throw IllegalStateException("Should not be here")
|
||||
}.withScope(scopeForMostSpecific)
|
||||
}
|
||||
|
||||
private fun <S : FirCallableSymbol<*>>
|
||||
MutableList<MemberWithBaseScope<S>>.calcBaseMembersForIntersectionOverride(): List<MemberWithBaseScope<S>> {
|
||||
if (size == 1) return this
|
||||
val unwrappedMemberSet = mutableSetOf<MemberWithBaseScope<S>>()
|
||||
for ((member, scope) in this) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
unwrappedMemberSet += MemberWithBaseScope(member.fir.unwrapSubstitutionOverrides().symbol as S, scope)
|
||||
}
|
||||
// If in fact extracted overrides are the same symbols,
|
||||
// we should just take most specific member without creating intersection
|
||||
// A typical sample here is inheritance of the same class in different places of hierarchy
|
||||
if (unwrappedMemberSet.size == 1) {
|
||||
return listOf(selectMostSpecificMember(this))
|
||||
}
|
||||
|
||||
val baseMembers = mutableSetOf<S>()
|
||||
for ((member, scope) in this) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
if (member is FirNamedFunctionSymbol) {
|
||||
scope.processOverriddenFunctions(member) {
|
||||
val symbol = it.fir.unwrapSubstitutionOverrides().symbol
|
||||
if (symbol != member.fir.unwrapSubstitutionOverrides().symbol) {
|
||||
baseMembers += symbol as S
|
||||
}
|
||||
ProcessorAction.NEXT
|
||||
}
|
||||
} else if (member is FirPropertySymbol) {
|
||||
scope.processOverriddenProperties(member) {
|
||||
val symbol = it.fir.unwrapSubstitutionOverrides().symbol
|
||||
if (symbol != member.fir.unwrapSubstitutionOverrides().symbol) {
|
||||
baseMembers += symbol as S
|
||||
}
|
||||
ProcessorAction.NEXT
|
||||
}
|
||||
}
|
||||
}
|
||||
removeIf { (member, _) -> member.fir.unwrapSubstitutionOverrides().symbol in baseMembers }
|
||||
return this
|
||||
}
|
||||
|
||||
private fun <D : FirCallableSymbol<*>> chooseIntersectionOverrideModality(
|
||||
extractedOverridden: Collection<MemberWithBaseScope<D>>
|
||||
): Modality? {
|
||||
var hasOpen = false
|
||||
var hasAbstract = false
|
||||
|
||||
for ((member) in extractedOverridden) {
|
||||
when ((member.fir as FirMemberDeclaration).modality) {
|
||||
Modality.FINAL -> return Modality.FINAL
|
||||
Modality.SEALED -> {
|
||||
// Members should not be sealed. But, that will be reported as WRONG_MODIFIER_TARGET, and here we shouldn't raise an
|
||||
// internal error. Instead, let the intersection override have the default modality: null.
|
||||
return null
|
||||
}
|
||||
Modality.OPEN -> {
|
||||
hasOpen = true
|
||||
}
|
||||
Modality.ABSTRACT -> {
|
||||
hasAbstract = true
|
||||
}
|
||||
null -> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hasAbstract && !hasOpen) return Modality.ABSTRACT
|
||||
if (!hasAbstract && hasOpen) return Modality.OPEN
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val processDirectOverridden: ProcessOverriddenWithBaseScope<D> = when (extractedOverridden.first().member) {
|
||||
is FirNamedFunctionSymbol -> FirTypeScope::processDirectOverriddenFunctionsWithBaseScope as ProcessOverriddenWithBaseScope<D>
|
||||
is FirPropertySymbol -> FirTypeScope::processDirectOverriddenPropertiesWithBaseScope as ProcessOverriddenWithBaseScope<D>
|
||||
else -> error("Unexpected callable kind: ${extractedOverridden.first().member}")
|
||||
}
|
||||
|
||||
val realOverridden = extractedOverridden.flatMap { realOverridden(it.member, it.baseScope, processDirectOverridden) }
|
||||
val filteredOverridden = filterOutOverridden(realOverridden, processDirectOverridden)
|
||||
|
||||
return filteredOverridden.minOf { (it.member.fir as FirMemberDeclaration).modality ?: Modality.ABSTRACT }
|
||||
}
|
||||
|
||||
private fun <D : FirCallableSymbol<*>> realOverridden(
|
||||
symbol: D,
|
||||
scope: FirTypeScope,
|
||||
processDirectOverridden: ProcessOverriddenWithBaseScope<D>,
|
||||
): Collection<MemberWithBaseScope<D>> {
|
||||
val result = mutableSetOf<MemberWithBaseScope<D>>()
|
||||
|
||||
collectRealOverridden(symbol, scope, result, mutableSetOf(), processDirectOverridden)
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
private fun <D : FirCallableSymbol<*>> collectRealOverridden(
|
||||
symbol: D,
|
||||
scope: FirTypeScope,
|
||||
result: MutableCollection<MemberWithBaseScope<D>>,
|
||||
visited: MutableSet<D>,
|
||||
processDirectOverridden: FirTypeScope.(D, (D, FirTypeScope) -> ProcessorAction) -> ProcessorAction,
|
||||
) {
|
||||
if (!visited.add(symbol)) return
|
||||
if (!symbol.fir.origin.fromSupertypes) {
|
||||
result.add(MemberWithBaseScope(symbol, scope))
|
||||
return
|
||||
}
|
||||
|
||||
scope.processDirectOverridden(symbol) { overridden, baseScope ->
|
||||
collectRealOverridden(overridden, baseScope, result, visited, processDirectOverridden)
|
||||
ProcessorAction.NEXT
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun <D : FirCallableSymbol<*>> filterOutOverridden(
|
||||
extractedOverridden: Collection<MemberWithBaseScope<D>>,
|
||||
processAllOverridden: ProcessOverriddenWithBaseScope<D>,
|
||||
): Collection<MemberWithBaseScope<D>> {
|
||||
return extractedOverridden.filter { overridden1 ->
|
||||
extractedOverridden.none { overridden2 ->
|
||||
overridden1 !== overridden2 && overrides(
|
||||
overridden2,
|
||||
overridden1,
|
||||
processAllOverridden
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Whether f overrides g
|
||||
private fun <D : FirCallableSymbol<*>> overrides(
|
||||
f: MemberWithBaseScope<D>,
|
||||
g: MemberWithBaseScope<D>,
|
||||
processAllOverridden: ProcessOverriddenWithBaseScope<D>,
|
||||
): Boolean {
|
||||
val (fMember, fScope) = f
|
||||
val (gMember) = g
|
||||
|
||||
var result = false
|
||||
|
||||
fScope.processAllOverridden(fMember) { overridden, _ ->
|
||||
if (overridden == gMember) {
|
||||
result = true
|
||||
ProcessorAction.STOP
|
||||
} else {
|
||||
ProcessorAction.NEXT
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
private fun <D : FirCallableSymbol<*>> chooseIntersectionVisibility(
|
||||
extractedOverrides: Collection<MemberWithBaseScope<D>>
|
||||
): Visibility {
|
||||
var maxVisibility: Visibility = Visibilities.Private
|
||||
for ((override) in extractedOverrides) {
|
||||
val visibility = (override.fir as FirMemberDeclaration).visibility
|
||||
// TODO: There is more complex logic at org.jetbrains.kotlin.resolve.OverridingUtil.resolveUnknownVisibilityForMember
|
||||
// TODO: and org.jetbrains.kotlin.resolve.OverridingUtil.findMaxVisibility
|
||||
val compare = Visibilities.compare(visibility, maxVisibility) ?: return Visibilities.DEFAULT_VISIBILITY
|
||||
if (compare > 0) {
|
||||
maxVisibility = visibility
|
||||
}
|
||||
}
|
||||
return maxVisibility
|
||||
}
|
||||
|
||||
private fun createIntersectionOverride(
|
||||
mostSpecific: FirNamedFunctionSymbol,
|
||||
overrides: Collection<FirCallableSymbol<*>>,
|
||||
newModality: Modality?,
|
||||
newVisibility: Visibility,
|
||||
): FirNamedFunctionSymbol {
|
||||
|
||||
val newSymbol =
|
||||
FirIntersectionOverrideFunctionSymbol(
|
||||
CallableId(
|
||||
dispatchReceiverType.classId ?: mostSpecific.dispatchReceiverClassOrNull()?.classId!!,
|
||||
mostSpecific.fir.name
|
||||
),
|
||||
overrides
|
||||
)
|
||||
val mostSpecificFunction = mostSpecific.fir
|
||||
FirFakeOverrideGenerator.createCopyForFirFunction(
|
||||
newSymbol,
|
||||
mostSpecificFunction, session, FirDeclarationOrigin.IntersectionOverride,
|
||||
mostSpecificFunction.isExpect,
|
||||
newDispatchReceiverType = dispatchReceiverType,
|
||||
newModality = newModality,
|
||||
newVisibility = newVisibility,
|
||||
).apply {
|
||||
originalForIntersectionOverrideAttr = mostSpecific.fir
|
||||
}
|
||||
return newSymbol
|
||||
}
|
||||
|
||||
private fun createIntersectionOverride(
|
||||
mostSpecific: FirPropertySymbol,
|
||||
overrides: Collection<FirCallableSymbol<*>>,
|
||||
newModality: Modality?,
|
||||
newVisibility: Visibility,
|
||||
): FirPropertySymbol {
|
||||
val callableId = CallableId(
|
||||
dispatchReceiverType.classId ?: mostSpecific.dispatchReceiverClassOrNull()?.classId!!,
|
||||
mostSpecific.fir.name
|
||||
)
|
||||
val newSymbol = FirIntersectionOverridePropertySymbol(callableId, overrides)
|
||||
val mostSpecificProperty = mostSpecific.fir
|
||||
FirFakeOverrideGenerator.createCopyForFirProperty(
|
||||
newSymbol, mostSpecificProperty, session, FirDeclarationOrigin.IntersectionOverride,
|
||||
newModality = newModality,
|
||||
newVisibility = newVisibility,
|
||||
newDispatchReceiverType = dispatchReceiverType,
|
||||
).apply {
|
||||
originalForIntersectionOverrideAttr = mostSpecific.fir
|
||||
}
|
||||
return newSymbol
|
||||
}
|
||||
|
||||
private fun <D : FirCallableSymbol<*>> selectMostSpecificMember(overridables: Collection<MemberWithBaseScope<D>>): MemberWithBaseScope<D> {
|
||||
require(overridables.isNotEmpty()) { "Should have at least one overridable symbol" }
|
||||
if (overridables.size == 1) {
|
||||
return overridables.first()
|
||||
}
|
||||
|
||||
val candidates: MutableCollection<MemberWithBaseScope<D>> = ArrayList(2)
|
||||
var transitivelyMostSpecific: MemberWithBaseScope<D> = overridables.first()
|
||||
|
||||
for (candidate in overridables) {
|
||||
if (overridables.all { isMoreSpecific(candidate.member, it.member) }) {
|
||||
candidates.add(candidate)
|
||||
}
|
||||
|
||||
if (isMoreSpecific(candidate.member, transitivelyMostSpecific.member) &&
|
||||
!isMoreSpecific(transitivelyMostSpecific.member, candidate.member)
|
||||
) {
|
||||
transitivelyMostSpecific = candidate
|
||||
}
|
||||
}
|
||||
|
||||
return when {
|
||||
candidates.isEmpty() -> transitivelyMostSpecific
|
||||
candidates.size == 1 -> candidates.first()
|
||||
else -> {
|
||||
candidates.firstOrNull {
|
||||
val type = it.member.fir.returnTypeRef.coneTypeSafe<ConeKotlinType>()
|
||||
type != null && type !is ConeFlexibleType
|
||||
}?.let { return it }
|
||||
candidates.first()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun isMoreSpecific(
|
||||
a: FirCallableSymbol<*>,
|
||||
b: FirCallableSymbol<*>
|
||||
): Boolean {
|
||||
val aFir = a.fir
|
||||
val bFir = b.fir
|
||||
|
||||
val substitutor = buildSubstitutorForOverridesCheck(aFir, bFir, session) ?: return false
|
||||
// NB: these lines throw CCE in modularized tests when changed to just .coneType (FirImplicitTypeRef)
|
||||
val aReturnType = a.fir.returnTypeRef.coneTypeSafe<ConeKotlinType>()?.let(substitutor::substituteOrSelf) ?: return false
|
||||
val bReturnType = b.fir.returnTypeRef.coneTypeSafe<ConeKotlinType>() ?: return false
|
||||
|
||||
if (aFir is FirSimpleFunction) {
|
||||
require(bFir is FirSimpleFunction) { "b is " + b.javaClass }
|
||||
return isTypeMoreSpecific(aReturnType, bReturnType)
|
||||
}
|
||||
if (aFir is FirProperty) {
|
||||
require(bFir is FirProperty) { "b is " + b.javaClass }
|
||||
// TODO: if (!OverridingUtil.isAccessorMoreSpecific(pa.getSetter(), pb.getSetter())) return false
|
||||
return if (aFir.isVar && bFir.isVar) {
|
||||
AbstractTypeChecker.equalTypes(typeCheckerState, aReturnType, bReturnType)
|
||||
} else { // both vals or var vs val: val can't be more specific then var
|
||||
!(!aFir.isVar && bFir.isVar) && isTypeMoreSpecific(aReturnType, bReturnType)
|
||||
}
|
||||
}
|
||||
throw IllegalArgumentException("Unexpected callable: " + a.javaClass)
|
||||
}
|
||||
|
||||
private fun isTypeMoreSpecific(a: ConeKotlinType, b: ConeKotlinType): Boolean =
|
||||
AbstractTypeChecker.isSubtypeOf(typeCheckerState, a, b)
|
||||
|
||||
private fun <D : FirCallableSymbol<*>> findMemberWithMaxVisibility(members: Collection<MemberWithBaseScope<D>>): MemberWithBaseScope<D> {
|
||||
assert(members.isNotEmpty())
|
||||
|
||||
var member: MemberWithBaseScope<D>? = null
|
||||
for (candidate in members) {
|
||||
if (member == null) {
|
||||
member = candidate
|
||||
continue
|
||||
}
|
||||
|
||||
val result = Visibilities.compare(
|
||||
member.member.fir.status.visibility,
|
||||
candidate.member.fir.status.visibility
|
||||
)
|
||||
if (result != null && result < 0) {
|
||||
member = candidate
|
||||
}
|
||||
}
|
||||
return member!!
|
||||
}
|
||||
|
||||
private fun <D : FirCallableSymbol<*>> extractBothWaysOverridable(
|
||||
overrider: MemberWithBaseScope<D>,
|
||||
members: MutableCollection<MemberWithBaseScope<D>>
|
||||
): MutableList<MemberWithBaseScope<D>> {
|
||||
val result = mutableListOf<MemberWithBaseScope<D>>().apply { add(overrider) }
|
||||
|
||||
val iterator = members.iterator()
|
||||
|
||||
val overrideCandidate = overrider.member.fir
|
||||
while (iterator.hasNext()) {
|
||||
val next = iterator.next()
|
||||
if (next == overrider) {
|
||||
iterator.remove()
|
||||
continue
|
||||
}
|
||||
|
||||
if (similarFunctionsOrBothProperties(overrideCandidate, next.member.fir)) {
|
||||
result.add(next)
|
||||
iterator.remove()
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
override fun processClassifiersByNameWithSubstitution(name: Name, processor: (FirClassifierSymbol<*>, ConeSubstitutor) -> Unit) {
|
||||
if (name in absentClassifiers) {
|
||||
return
|
||||
}
|
||||
val accepted = HashSet<FirClassifierSymbol<*>>()
|
||||
val pending = mutableListOf<FirClassifierSymbol<*>>()
|
||||
var empty = true
|
||||
for (scope in scopes) {
|
||||
scope.processClassifiersByNameWithSubstitution(name) { symbol, substitution ->
|
||||
empty = false
|
||||
if (symbol !in accepted) {
|
||||
pending += symbol
|
||||
processor(symbol, substitution)
|
||||
}
|
||||
}
|
||||
accepted += pending
|
||||
pending.clear()
|
||||
}
|
||||
if (empty) {
|
||||
absentClassifiers += name
|
||||
}
|
||||
super.processClassifiersByNameWithSubstitution(name, processor)
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
private fun <S : FirCallableSymbol<*>> getDirectOverriddenSymbols(symbol: S): Collection<MemberWithBaseScope<S>> {
|
||||
val intersectionOverride = intersectionOverrides.getValueIfComputed(symbol)
|
||||
val allDirectOverridden = overriddenSymbols[symbol].orEmpty() + intersectionOverride?.let {
|
||||
overriddenSymbols[it.member]
|
||||
}.orEmpty()
|
||||
return allDirectOverridden as Collection<MemberWithBaseScope<S>>
|
||||
}
|
||||
|
||||
override fun processDirectOverriddenFunctionsWithBaseScope(
|
||||
functionSymbol: FirNamedFunctionSymbol,
|
||||
processor: (FirNamedFunctionSymbol, FirTypeScope) -> ProcessorAction
|
||||
): ProcessorAction =
|
||||
processDirectOverriddenCallablesWithBaseScope(
|
||||
functionSymbol, processor,
|
||||
FirTypeScope::processDirectOverriddenFunctionsWithBaseScope
|
||||
)
|
||||
|
||||
override fun processDirectOverriddenPropertiesWithBaseScope(
|
||||
propertySymbol: FirPropertySymbol,
|
||||
processor: (FirPropertySymbol, FirTypeScope) -> ProcessorAction
|
||||
): ProcessorAction =
|
||||
processDirectOverriddenCallablesWithBaseScope(
|
||||
propertySymbol, processor,
|
||||
FirTypeScope::processDirectOverriddenPropertiesWithBaseScope
|
||||
)
|
||||
|
||||
private fun <D : FirCallableSymbol<*>> processDirectOverriddenCallablesWithBaseScope(
|
||||
callableSymbol: D,
|
||||
processor: (D, FirTypeScope) -> ProcessorAction,
|
||||
processDirectOverriddenInBaseScope: FirTypeScope.(D, ((D, FirTypeScope) -> ProcessorAction)) -> ProcessorAction
|
||||
): ProcessorAction {
|
||||
for ((overridden, baseScope) in getDirectOverriddenSymbols(callableSymbol)) {
|
||||
if (overridden === callableSymbol) {
|
||||
if (!baseScope.processDirectOverriddenInBaseScope(callableSymbol, processor)) return ProcessorAction.STOP
|
||||
} else {
|
||||
if (!processor(overridden, baseScope)) return ProcessorAction.STOP
|
||||
}
|
||||
}
|
||||
|
||||
return ProcessorAction.NEXT
|
||||
}
|
||||
|
||||
override fun getCallableNames(): Set<Name> = callableNamesCached
|
||||
|
||||
override fun getClassifierNames(): Set<Name> {
|
||||
return scopes.flatMapTo(hashSetOf()) { it.getClassifierNames() }
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun prepareIntersectionScope(
|
||||
session: FirSession,
|
||||
overrideChecker: FirOverrideChecker,
|
||||
scopes: List<FirTypeScope>,
|
||||
dispatchReceiverType: ConeKotlinType,
|
||||
): FirTypeScope {
|
||||
scopes.singleOrNull()?.let { return it }
|
||||
if (scopes.isEmpty()) {
|
||||
return Empty
|
||||
}
|
||||
return FirTypeIntersectionScope(session, overrideChecker, scopes, dispatchReceiverType)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class MemberWithBaseScope<out D : FirCallableSymbol<*>>(val member: D, val baseScope: FirTypeScope) {
|
||||
operator fun component1() = member
|
||||
operator fun component2() = baseScope
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
return other is MemberWithBaseScope<*> && member == other.member
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return member.hashCode()
|
||||
}
|
||||
}
|
||||
|
||||
private fun <D : FirCallableSymbol<*>> D.withScope(baseScope: FirTypeScope) = MemberWithBaseScope(this, baseScope)
|
||||
|
||||
class FirIntersectionOverrideStorage(val session: FirSession) : FirSessionComponent {
|
||||
private val cachesFactory = session.firCachesFactory
|
||||
|
||||
class CacheForScope(cachesFactory: FirCachesFactory) {
|
||||
val intersectionOverrides: FirCache<FirCallableSymbol<*>, MemberWithBaseScope<FirCallableSymbol<*>>, ContextForIntersectionOverrideConstruction<*>> =
|
||||
cachesFactory.createCache { mostSpecific, context ->
|
||||
val (intersectionScope, extractedOverrides, scopeForMostSpecific) = context
|
||||
intersectionScope.createIntersectionOverride(extractedOverrides, mostSpecific, scopeForMostSpecific)
|
||||
}
|
||||
}
|
||||
|
||||
data class ContextForIntersectionOverrideConstruction<D : FirCallableSymbol<*>>(
|
||||
val intersectionScope: FirTypeIntersectionScope,
|
||||
val extractedOverrides: List<MemberWithBaseScope<D>>,
|
||||
val scopeForMostSpecific: FirTypeScope
|
||||
)
|
||||
|
||||
val cacheByScope: FirCache<ConeKotlinType, CacheForScope, Nothing?> =
|
||||
cachesFactory.createCache { _ -> CacheForScope(cachesFactory) }
|
||||
}
|
||||
|
||||
private val FirSession.intersectionOverrideStorage: FirIntersectionOverrideStorage by FirSession.sessionComponentAccessor()
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.fir.types
|
||||
|
||||
import org.jetbrains.kotlin.name.StandardClassIds
|
||||
|
||||
val ConeKotlinType.isArrayOrPrimitiveArray: Boolean
|
||||
get() = arrayElementType() != null
|
||||
|
||||
fun ConeKotlinType.createOutArrayType(nullable: Boolean = false, createPrimitiveArrayType: Boolean = true): ConeKotlinType {
|
||||
return ConeKotlinTypeProjectionOut(this).createArrayType(nullable, createPrimitiveArrayType)
|
||||
}
|
||||
|
||||
fun ConeTypeProjection.createArrayType(nullable: Boolean = false, createPrimitiveArrayTypeIfPossible: Boolean = true): ConeClassLikeType {
|
||||
if (this is ConeKotlinTypeProjection && createPrimitiveArrayTypeIfPossible) {
|
||||
val type = type.lowerBoundIfFlexible()
|
||||
if (type is ConeClassLikeType && type.nullability != ConeNullability.NULLABLE) {
|
||||
val classId = type.lookupTag.classId
|
||||
val primitiveArrayId =
|
||||
StandardClassIds.primitiveArrayTypeByElementType[classId] ?: StandardClassIds.unsignedArrayTypeByElementType[classId]
|
||||
if (primitiveArrayId != null) {
|
||||
return primitiveArrayId.constructClassLikeType(emptyArray(), nullable)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return StandardClassIds.Array.constructClassLikeType(arrayOf(this), nullable)
|
||||
}
|
||||
|
||||
fun ConeKotlinType.arrayElementType(): ConeKotlinType? {
|
||||
val type = this.lowerBoundIfFlexible()
|
||||
if (type !is ConeClassLikeType) return null
|
||||
val classId = type.lookupTag.classId
|
||||
if (classId == StandardClassIds.Array)
|
||||
return (type.typeArguments.first() as ConeKotlinTypeProjection).type
|
||||
val elementType = StandardClassIds.elementTypeByPrimitiveArrayType[classId] ?: StandardClassIds.elementTypeByUnsignedArrayType[classId]
|
||||
if (elementType != null) {
|
||||
return elementType.constructClassLikeType(emptyArray(), isNullable = false)
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
fun ConeKotlinType.varargElementType(): ConeKotlinType {
|
||||
return this.arrayElementType() ?: this
|
||||
}
|
||||
|
||||
fun ConeKotlinType?.isPotentiallyArray(): Boolean =
|
||||
this != null && (this.arrayElementType() != null || this is ConeTypeVariableType)
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.fir.types
|
||||
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.StandardClassIds
|
||||
|
||||
object ConeFlexibleTypeBoundsChecker {
|
||||
private val baseTypesToMutableEquivalent = mapOf(
|
||||
StandardClassIds.Iterable to StandardClassIds.MutableIterable,
|
||||
StandardClassIds.Iterator to StandardClassIds.MutableIterator,
|
||||
StandardClassIds.ListIterator to StandardClassIds.MutableListIterator,
|
||||
StandardClassIds.List to StandardClassIds.MutableList,
|
||||
StandardClassIds.Collection to StandardClassIds.MutableCollection,
|
||||
StandardClassIds.Set to StandardClassIds.MutableSet,
|
||||
StandardClassIds.Map to StandardClassIds.MutableMap,
|
||||
StandardClassIds.MapEntry to StandardClassIds.MutableMapEntry
|
||||
)
|
||||
private val mutableToBaseMap = baseTypesToMutableEquivalent.entries.associateBy({ it.value }) { it.key }
|
||||
|
||||
fun areTypesMayBeLowerAndUpperBoundsOfSameFlexibleTypeByMutability(a: ConeKotlinType, b: ConeKotlinType): Boolean {
|
||||
val classId = a.classId ?: return false
|
||||
val possiblePairBound = (baseTypesToMutableEquivalent[classId] ?: mutableToBaseMap[classId]) ?: return false
|
||||
|
||||
return possiblePairBound == b.classId
|
||||
}
|
||||
|
||||
// We consider base bounds as not mutable collections
|
||||
fun getBaseBoundFqNameByMutability(a: ConeKotlinType): ClassId? {
|
||||
val classId = a.classId ?: return null
|
||||
|
||||
if (classId in baseTypesToMutableEquivalent) return classId
|
||||
|
||||
return mutableToBaseMap[classId]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,520 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.fir.types
|
||||
|
||||
import org.jetbrains.kotlin.fir.diagnostics.ConeIntermediateDiagnostic
|
||||
import org.jetbrains.kotlin.fir.isPrimitiveNumberOrUnsignedNumberType
|
||||
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
||||
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider
|
||||
import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.NoSubstitutor
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.createTypeSubstitutorByTypeConstructor
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterLookupTag
|
||||
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
|
||||
import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl
|
||||
import org.jetbrains.kotlin.name.StandardClassIds
|
||||
import org.jetbrains.kotlin.types.AbstractTypeChecker
|
||||
import org.jetbrains.kotlin.types.AbstractTypeRefiner
|
||||
import org.jetbrains.kotlin.types.TypeCheckerState
|
||||
import org.jetbrains.kotlin.types.model.*
|
||||
import org.jetbrains.kotlin.utils.DFS
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.cast
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
interface ConeInferenceContext : TypeSystemInferenceExtensionContext, ConeTypeContext {
|
||||
|
||||
val symbolProvider: FirSymbolProvider get() = session.symbolProvider
|
||||
|
||||
override fun nullableNothingType(): ConeClassLikeType {
|
||||
return session.builtinTypes.nullableNothingType.type
|
||||
}
|
||||
|
||||
override fun nullableAnyType(): ConeClassLikeType {
|
||||
return session.builtinTypes.nullableAnyType.type
|
||||
}
|
||||
|
||||
override fun nothingType(): ConeClassLikeType {
|
||||
return session.builtinTypes.nothingType.type
|
||||
}
|
||||
|
||||
override fun anyType(): ConeClassLikeType {
|
||||
return session.builtinTypes.anyType.type
|
||||
}
|
||||
|
||||
override fun createFlexibleType(lowerBound: SimpleTypeMarker, upperBound: SimpleTypeMarker): KotlinTypeMarker {
|
||||
require(lowerBound is ConeKotlinType)
|
||||
require(upperBound is ConeKotlinType)
|
||||
|
||||
return coneFlexibleOrSimpleType(this, lowerBound, upperBound)
|
||||
}
|
||||
|
||||
override fun createSimpleType(
|
||||
constructor: TypeConstructorMarker,
|
||||
arguments: List<TypeArgumentMarker>,
|
||||
nullable: Boolean,
|
||||
isExtensionFunction: Boolean,
|
||||
annotations: List<AnnotationMarker>?
|
||||
): SimpleTypeMarker {
|
||||
val attributesList = annotations?.filterIsInstanceTo<ConeAttribute<*>, MutableList<ConeAttribute<*>>>(mutableListOf())
|
||||
val attributes: ConeAttributes = if (isExtensionFunction) {
|
||||
require(constructor is ConeClassLikeLookupTag && constructor.isBuiltinFunctionalType())
|
||||
// We don't want to create new instance of ConeAttributes which
|
||||
// contains only CompilerConeAttributes.ExtensionFunctionType
|
||||
// to avoid memory consumption
|
||||
if (attributesList != null) {
|
||||
attributesList += CompilerConeAttributes.ExtensionFunctionType
|
||||
ConeAttributes.create(attributesList)
|
||||
} else {
|
||||
ConeAttributes.WithExtensionFunctionType
|
||||
}
|
||||
} else {
|
||||
attributesList?.let { ConeAttributes.create(it) } ?: ConeAttributes.Empty
|
||||
}
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return when (constructor) {
|
||||
is ConeClassLikeLookupTag -> ConeClassLikeTypeImpl(
|
||||
constructor,
|
||||
(arguments as List<ConeTypeProjection>).toTypedArray(),
|
||||
nullable,
|
||||
attributes,
|
||||
)
|
||||
is ConeTypeParameterLookupTag -> ConeTypeParameterTypeImpl(
|
||||
constructor,
|
||||
nullable,
|
||||
attributes
|
||||
)
|
||||
else -> error("!")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun createTypeArgument(type: KotlinTypeMarker, variance: TypeVariance): TypeArgumentMarker {
|
||||
require(type is ConeKotlinType)
|
||||
return when (variance) {
|
||||
TypeVariance.INV -> type
|
||||
TypeVariance.IN -> ConeKotlinTypeProjectionIn(type)
|
||||
TypeVariance.OUT -> ConeKotlinTypeProjectionOut(type)
|
||||
}
|
||||
}
|
||||
|
||||
override fun createStarProjection(typeParameter: TypeParameterMarker): TypeArgumentMarker {
|
||||
return ConeStarProjection
|
||||
}
|
||||
|
||||
override fun newTypeCheckerState(
|
||||
errorTypesEqualToAnything: Boolean,
|
||||
stubTypesEqualToAnything: Boolean
|
||||
): TypeCheckerState = TypeCheckerState(
|
||||
errorTypesEqualToAnything,
|
||||
stubTypesEqualToAnything,
|
||||
allowedTypeVariable = true,
|
||||
typeSystemContext = this,
|
||||
kotlinTypePreparator = ConeTypePreparator(session),
|
||||
kotlinTypeRefiner = AbstractTypeRefiner.Default
|
||||
)
|
||||
|
||||
override fun KotlinTypeMarker.canHaveUndefinedNullability(): Boolean {
|
||||
require(this is ConeKotlinType)
|
||||
return this is ConeCapturedType || this is ConeTypeVariableType
|
||||
|| this is ConeTypeParameterType
|
||||
}
|
||||
|
||||
override fun SimpleTypeMarker.isExtensionFunction(): Boolean {
|
||||
require(this is ConeKotlinType)
|
||||
return this.isExtensionFunctionType
|
||||
}
|
||||
|
||||
override fun KotlinTypeMarker.typeDepth() = when (this) {
|
||||
is ConeSimpleKotlinType -> typeDepth()
|
||||
is ConeFlexibleType -> maxOf(lowerBound().typeDepth(), upperBound().typeDepth())
|
||||
else -> error("Type should be simple or flexible: $this")
|
||||
}
|
||||
|
||||
override fun SimpleTypeMarker.typeDepth(): Int {
|
||||
require(this is ConeKotlinType)
|
||||
// if (this is TypeUtils.SpecialType) return 0 // TODO: WTF?
|
||||
|
||||
if (this is ConeClassLikeType) {
|
||||
val fullyExpanded = fullyExpandedType(session)
|
||||
if (this !== fullyExpanded) {
|
||||
return fullyExpanded.typeDepth()
|
||||
}
|
||||
}
|
||||
|
||||
var maxArgumentDepth = 0
|
||||
for (arg in typeArguments) {
|
||||
val current = if (arg is ConeStarProjection) 1 else (arg as ConeKotlinTypeProjection).type.typeDepth()
|
||||
if (current > maxArgumentDepth) {
|
||||
maxArgumentDepth = current
|
||||
}
|
||||
}
|
||||
|
||||
return maxArgumentDepth + 1
|
||||
}
|
||||
|
||||
override fun KotlinTypeMarker.contains(predicate: (KotlinTypeMarker) -> Boolean): Boolean {
|
||||
return this.containsInternal(predicate)
|
||||
}
|
||||
|
||||
private fun KotlinTypeMarker?.containsInternal(
|
||||
predicate: (KotlinTypeMarker) -> Boolean,
|
||||
visited: HashSet<KotlinTypeMarker> = hashSetOf()
|
||||
): Boolean {
|
||||
if (this == null) return false
|
||||
if (!visited.add(this)) return false
|
||||
|
||||
if (predicate(this)) return true
|
||||
|
||||
val flexibleType = this as? ConeFlexibleType
|
||||
if (flexibleType != null
|
||||
&& (flexibleType.lowerBound.containsInternal(predicate, visited)
|
||||
|| flexibleType.upperBound.containsInternal(predicate, visited))
|
||||
) {
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
if (this is ConeDefinitelyNotNullType
|
||||
&& this.original.containsInternal(predicate, visited)
|
||||
) {
|
||||
return true
|
||||
}
|
||||
|
||||
if (this is ConeIntersectionType) {
|
||||
return this.intersectedTypes.any { it.containsInternal(predicate, visited) }
|
||||
}
|
||||
|
||||
repeat(argumentsCount()) { index ->
|
||||
val argument = getArgument(index)
|
||||
if (!argument.isStarProjection() && argument.getType().containsInternal(predicate, visited)) return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
override fun TypeConstructorMarker.isUnitTypeConstructor(): Boolean {
|
||||
return this is ConeClassLikeLookupTag && this.classId == StandardClassIds.Unit
|
||||
}
|
||||
|
||||
override fun Collection<KotlinTypeMarker>.singleBestRepresentative(): KotlinTypeMarker? {
|
||||
if (this.size == 1) return this.first()
|
||||
|
||||
val context = newTypeCheckerState(errorTypesEqualToAnything = true, stubTypesEqualToAnything = true)
|
||||
return this.firstOrNull { candidate ->
|
||||
this.all { other ->
|
||||
// We consider error types equal to anything here, so that intersections like
|
||||
// {Array<String>, Array<[ERROR]>} work correctly
|
||||
candidate == other || AbstractTypeChecker.equalTypes(context, candidate, other)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun KotlinTypeMarker.isUnit(): Boolean {
|
||||
require(this is ConeKotlinType)
|
||||
return this.typeConstructor().isUnitTypeConstructor() && !this.isNullable
|
||||
}
|
||||
|
||||
override fun KotlinTypeMarker.isBuiltinFunctionalTypeOrSubtype(): Boolean {
|
||||
require(this is ConeKotlinType)
|
||||
return this.isTypeOrSubtypeOf {
|
||||
(it.lowerBoundIfFlexible() as ConeKotlinType).isBuiltinFunctionalType(session)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override fun KotlinTypeMarker.withNullability(nullable: Boolean): KotlinTypeMarker {
|
||||
require(this is ConeKotlinType)
|
||||
return this.withNullability(ConeNullability.create(nullable), this@ConeInferenceContext)
|
||||
}
|
||||
|
||||
override fun KotlinTypeMarker.makeDefinitelyNotNullOrNotNull(): KotlinTypeMarker {
|
||||
require(this is ConeKotlinType)
|
||||
return makeConeTypeDefinitelyNotNullOrNotNull(this@ConeInferenceContext)
|
||||
}
|
||||
|
||||
override fun SimpleTypeMarker.makeSimpleTypeDefinitelyNotNullOrNotNull(): SimpleTypeMarker {
|
||||
require(this is ConeKotlinType)
|
||||
return makeConeTypeDefinitelyNotNullOrNotNull(this@ConeInferenceContext) as SimpleTypeMarker
|
||||
}
|
||||
|
||||
override fun createCapturedType(
|
||||
constructorProjection: TypeArgumentMarker,
|
||||
constructorSupertypes: List<KotlinTypeMarker>,
|
||||
lowerType: KotlinTypeMarker?,
|
||||
captureStatus: CaptureStatus
|
||||
): CapturedTypeMarker {
|
||||
require(lowerType is ConeKotlinType?)
|
||||
require(constructorProjection is ConeTypeProjection)
|
||||
return ConeCapturedType(
|
||||
captureStatus,
|
||||
lowerType,
|
||||
constructor = ConeCapturedTypeConstructor(constructorProjection, constructorSupertypes.cast())
|
||||
)
|
||||
}
|
||||
|
||||
override fun createStubTypeForBuilderInference(typeVariable: TypeVariableMarker): StubTypeMarker {
|
||||
require(typeVariable is ConeTypeVariable) { "$typeVariable should subtype of ${ConeTypeVariable::class.qualifiedName}" }
|
||||
return ConeStubTypeForBuilderInference(typeVariable, ConeNullability.create(typeVariable.defaultType().isMarkedNullable()))
|
||||
}
|
||||
|
||||
override fun createStubTypeForTypeVariablesInSubtyping(typeVariable: TypeVariableMarker): StubTypeMarker {
|
||||
require(typeVariable is ConeTypeVariable) { "$typeVariable should subtype of ${ConeTypeVariable::class.qualifiedName}" }
|
||||
return ConeStubTypeForTypeVariableInSubtyping(typeVariable, ConeNullability.create(typeVariable.defaultType().isMarkedNullable()))
|
||||
}
|
||||
|
||||
override fun KotlinTypeMarker.removeAnnotations(): KotlinTypeMarker {
|
||||
require(this is ConeKotlinType)
|
||||
return withAttributes(ConeAttributes.Empty, this@ConeInferenceContext)
|
||||
}
|
||||
|
||||
override fun SimpleTypeMarker.replaceArguments(newArguments: List<TypeArgumentMarker>): SimpleTypeMarker {
|
||||
require(this is ConeKotlinType)
|
||||
return this.withArguments(newArguments.cast<List<ConeTypeProjection>>().toTypedArray(), this@ConeInferenceContext)
|
||||
}
|
||||
|
||||
override fun SimpleTypeMarker.replaceArguments(replacement: (TypeArgumentMarker) -> TypeArgumentMarker): SimpleTypeMarker {
|
||||
require(this is ConeKotlinType)
|
||||
return this.withArguments({ replacement(it).cast() }, this@ConeInferenceContext)
|
||||
}
|
||||
|
||||
override fun KotlinTypeMarker.hasExactAnnotation(): Boolean {
|
||||
require(this is ConeKotlinType)
|
||||
return attributes.exact != null
|
||||
}
|
||||
|
||||
override fun KotlinTypeMarker.hasNoInferAnnotation(): Boolean {
|
||||
require(this is ConeKotlinType)
|
||||
return attributes.noInfer != null
|
||||
}
|
||||
|
||||
override fun TypeVariableMarker.freshTypeConstructor(): TypeConstructorMarker {
|
||||
require(this is ConeTypeVariable)
|
||||
return this.typeConstructor
|
||||
}
|
||||
|
||||
override fun CapturedTypeMarker.typeConstructorProjection(): TypeArgumentMarker {
|
||||
require(this is ConeCapturedType)
|
||||
return this.constructor.projection
|
||||
}
|
||||
|
||||
override fun CapturedTypeMarker.typeParameter(): TypeParameterMarker? {
|
||||
require(this is ConeCapturedType)
|
||||
return this.constructor.typeParameterMarker
|
||||
}
|
||||
|
||||
override fun CapturedTypeMarker.withNotNullProjection(): KotlinTypeMarker {
|
||||
require(this is ConeCapturedType)
|
||||
return ConeCapturedType(captureStatus, lowerType, nullability, constructor, attributes, isProjectionNotNull = true)
|
||||
}
|
||||
|
||||
override fun CapturedTypeMarker.isProjectionNotNull(): Boolean {
|
||||
require(this is ConeCapturedType)
|
||||
return isProjectionNotNull
|
||||
}
|
||||
|
||||
override fun DefinitelyNotNullTypeMarker.original(): SimpleTypeMarker {
|
||||
require(this is ConeDefinitelyNotNullType)
|
||||
return this.original as SimpleTypeMarker
|
||||
}
|
||||
|
||||
override fun typeSubstitutorByTypeConstructor(map: Map<TypeConstructorMarker, KotlinTypeMarker>): ConeSubstitutor {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return createTypeSubstitutorByTypeConstructor(map as Map<TypeConstructorMarker, ConeKotlinType>, this)
|
||||
}
|
||||
|
||||
override fun createEmptySubstitutor(): ConeSubstitutor {
|
||||
return ConeSubstitutor.Empty
|
||||
}
|
||||
|
||||
override fun TypeSubstitutorMarker.safeSubstitute(type: KotlinTypeMarker): KotlinTypeMarker {
|
||||
if (this === NoSubstitutor) return type
|
||||
require(this is ConeSubstitutor)
|
||||
require(type is ConeKotlinType)
|
||||
return this.substituteOrSelf(type)
|
||||
}
|
||||
|
||||
override fun TypeVariableMarker.defaultType(): SimpleTypeMarker {
|
||||
require(this is ConeTypeVariable)
|
||||
return this.defaultType
|
||||
}
|
||||
|
||||
override fun KotlinTypeMarker.isSpecial(): Boolean {
|
||||
// Cone type system doesn't have special types
|
||||
return false
|
||||
}
|
||||
|
||||
override fun TypeConstructorMarker.isTypeVariable(): Boolean {
|
||||
return this is ConeTypeVariableTypeConstructor
|
||||
}
|
||||
|
||||
override fun TypeVariableTypeConstructorMarker.isContainedInInvariantOrContravariantPositions(): Boolean {
|
||||
require(this is ConeTypeVariableTypeConstructor)
|
||||
return isContainedInInvariantOrContravariantPositions
|
||||
}
|
||||
|
||||
override fun createErrorType(debugName: String): ConeClassErrorType {
|
||||
return ConeClassErrorType(ConeIntermediateDiagnostic(debugName))
|
||||
}
|
||||
|
||||
override fun createErrorTypeWithCustomConstructor(debugName: String, constructor: TypeConstructorMarker): KotlinTypeMarker {
|
||||
return ConeKotlinErrorType(ConeIntermediateDiagnostic("$debugName c: $constructor"))
|
||||
}
|
||||
|
||||
override fun CapturedTypeMarker.captureStatus(): CaptureStatus {
|
||||
require(this is ConeCapturedType)
|
||||
return this.captureStatus
|
||||
}
|
||||
|
||||
override fun CapturedTypeMarker.isOldCapturedType(): Boolean = false
|
||||
|
||||
override fun TypeConstructorMarker.isCapturedTypeConstructor(): Boolean {
|
||||
return this is ConeCapturedTypeConstructor
|
||||
}
|
||||
|
||||
override fun TypeConstructorMarker.isTypeParameterTypeConstructor(): Boolean {
|
||||
return this.getTypeParameterClassifier() != null
|
||||
}
|
||||
|
||||
override fun KotlinTypeMarker.removeExactAnnotation(): KotlinTypeMarker {
|
||||
require(this is ConeKotlinType)
|
||||
return withAttributes(attributes.remove(CompilerConeAttributes.Exact), this@ConeInferenceContext)
|
||||
}
|
||||
|
||||
override fun TypeConstructorMarker.toErrorType(): SimpleTypeMarker {
|
||||
if (this is ErrorTypeConstructor) return createErrorType(reason)
|
||||
if (this is ConeClassLikeLookupTag) return createErrorType("Not found classifier: $classId")
|
||||
return createErrorType("Unknown reason")
|
||||
}
|
||||
|
||||
override fun findCommonIntegerLiteralTypesSuperType(explicitSupertypes: List<SimpleTypeMarker>): SimpleTypeMarker? {
|
||||
return ConeIntegerLiteralTypeImpl.findCommonSuperType(explicitSupertypes)
|
||||
}
|
||||
|
||||
override fun TypeConstructorMarker.getApproximatedIntegerLiteralType(): KotlinTypeMarker {
|
||||
require(this is ConeIntegerLiteralType)
|
||||
return this.getApproximatedType()
|
||||
}
|
||||
|
||||
override fun KotlinTypeMarker.isSignedOrUnsignedNumberType(): Boolean {
|
||||
require(this is ConeKotlinType)
|
||||
if (this is ConeIntegerLiteralType) return true
|
||||
if (this !is ConeClassLikeType) return false
|
||||
return isPrimitiveNumberOrUnsignedNumberType()
|
||||
}
|
||||
|
||||
override fun KotlinTypeMarker.isFunctionOrKFunctionWithAnySuspendability(): Boolean {
|
||||
require(this is ConeKotlinType)
|
||||
return this.isBuiltinFunctionalType(session)
|
||||
}
|
||||
|
||||
private fun ConeKotlinType.isTypeOrSubtypeOf(predicate: (ConeKotlinType) -> Boolean): Boolean {
|
||||
return predicate(this) || DFS.dfsFromNode(
|
||||
this,
|
||||
{
|
||||
// FIXME supertypes of type constructor contain unsubstituted arguments
|
||||
it.typeConstructor().supertypes()
|
||||
},
|
||||
DFS.VisitedWithSet(),
|
||||
object : DFS.AbstractNodeHandler<ConeKotlinType, Boolean>() {
|
||||
private var result = false
|
||||
|
||||
override fun beforeChildren(current: ConeKotlinType): Boolean {
|
||||
if (predicate(current)) {
|
||||
result = true
|
||||
}
|
||||
return !result
|
||||
}
|
||||
|
||||
override fun result() = result
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
override fun KotlinTypeMarker.isSuspendFunctionTypeOrSubtype(): Boolean {
|
||||
require(this is ConeKotlinType)
|
||||
return isTypeOrSubtypeOf {
|
||||
(it.lowerBoundIfFlexible() as ConeKotlinType).isSuspendFunctionType(session)
|
||||
}
|
||||
}
|
||||
|
||||
override fun KotlinTypeMarker.isExtensionFunctionType(): Boolean {
|
||||
require(this is ConeKotlinType)
|
||||
return this.lowerBoundIfFlexible().safeAs<ConeKotlinType>()?.isExtensionFunctionType(session) == true
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalStdlibApi::class)
|
||||
override fun KotlinTypeMarker.extractArgumentsForFunctionalTypeOrSubtype(): List<KotlinTypeMarker> {
|
||||
val builtInFunctionalType = getFunctionalTypeFromSupertypes().cast<ConeKotlinType>()
|
||||
return buildList {
|
||||
// excluding return type
|
||||
for (index in 0 until builtInFunctionalType.argumentsCount() - 1) {
|
||||
add(builtInFunctionalType.getArgument(index).getType())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun KotlinTypeMarker.getFunctionalTypeFromSupertypes(): KotlinTypeMarker {
|
||||
require(this is ConeKotlinType)
|
||||
assert(this.isBuiltinFunctionalTypeOrSubtype()) {
|
||||
"Not a function type or subtype: ${this.render()}"
|
||||
}
|
||||
|
||||
return fullyExpandedType(session).let {
|
||||
val simpleType = it.lowerBoundIfFlexible()
|
||||
if ((simpleType as ConeKotlinType).isBuiltinFunctionalType(session))
|
||||
this
|
||||
else {
|
||||
var functionalSupertype: KotlinTypeMarker? = null
|
||||
simpleType.anySuperTypeConstructor { typeConstructor ->
|
||||
simpleType.fastCorrespondingSupertypes(typeConstructor)?.any { superType ->
|
||||
val isFunctional = superType.cast<ConeKotlinType>().isBuiltinFunctionalType(session)
|
||||
if (isFunctional)
|
||||
functionalSupertype = superType
|
||||
isFunctional
|
||||
} ?: false
|
||||
}
|
||||
functionalSupertype ?: error("Failed to find functional supertype for $simpleType")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getFunctionTypeConstructor(parametersNumber: Int, isSuspend: Boolean): TypeConstructorMarker {
|
||||
val classId = if (isSuspend) {
|
||||
StandardClassIds.SuspendFunctionN(parametersNumber)
|
||||
} else {
|
||||
StandardClassIds.FunctionN(parametersNumber)
|
||||
}
|
||||
return session.symbolProvider.getClassLikeSymbolByClassId(classId)?.toLookupTag()
|
||||
?: error("Can't find Function type")
|
||||
}
|
||||
|
||||
override fun getKFunctionTypeConstructor(parametersNumber: Int, isSuspend: Boolean): TypeConstructorMarker {
|
||||
val classId = if (isSuspend) {
|
||||
StandardClassIds.KSuspendFunctionN(parametersNumber)
|
||||
} else {
|
||||
StandardClassIds.KFunctionN(parametersNumber)
|
||||
}
|
||||
return session.symbolProvider.getClassLikeSymbolByClassId(classId)?.toLookupTag()
|
||||
?: error("Can't find KFunction type")
|
||||
}
|
||||
|
||||
override fun createTypeWithAlternativeForIntersectionResult(
|
||||
firstCandidate: KotlinTypeMarker,
|
||||
secondCandidate: KotlinTypeMarker
|
||||
): KotlinTypeMarker {
|
||||
require(firstCandidate is ConeKotlinType)
|
||||
require(secondCandidate is ConeKotlinType)
|
||||
val intersectionType = firstCandidate.lowerBoundIfFlexible() as? ConeIntersectionType ?: error {
|
||||
"Expected type is intersection, found $firstCandidate"
|
||||
}
|
||||
return intersectionType.withAlternative(secondCandidate)
|
||||
}
|
||||
|
||||
override fun SimpleTypeMarker.createConstraintPartForLowerBoundAndFlexibleTypeVariable(): KotlinTypeMarker =
|
||||
createFlexibleType(this.makeSimpleTypeDefinitelyNotNullOrNotNull(), this.withNullability(true))
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.fir.types
|
||||
|
||||
import org.jetbrains.kotlin.types.AbstractNullabilityChecker
|
||||
import org.jetbrains.kotlin.types.TypeCheckerState
|
||||
|
||||
object ConeNullabilityChecker {
|
||||
fun isSubtypeOfAny(context: ConeTypeContext, type: ConeKotlinType): Boolean {
|
||||
val actualType = with(context) { type.lowerBoundIfFlexible() }
|
||||
return with(AbstractNullabilityChecker) {
|
||||
context.newTypeCheckerState(errorTypesEqualToAnything = false, stubTypesEqualToAnything = true)
|
||||
.hasNotNullSupertype(actualType, TypeCheckerState.SupertypesPolicy.LowerIfFlexible)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.fir.types
|
||||
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.types.AbstractTypeApproximator
|
||||
import org.jetbrains.kotlin.types.TypeApproximatorConfiguration
|
||||
|
||||
class ConeTypeApproximator(inferenceContext: ConeInferenceContext, languageVersionSettings: LanguageVersionSettings) :
|
||||
AbstractTypeApproximator(inferenceContext, languageVersionSettings) {
|
||||
fun approximateToSuperType(type: ConeKotlinType, conf: TypeApproximatorConfiguration): ConeKotlinType? {
|
||||
return super.approximateToSuperType(type, conf) as ConeKotlinType?
|
||||
}
|
||||
|
||||
fun approximateToSubType(type: ConeKotlinType, conf: TypeApproximatorConfiguration): ConeKotlinType? {
|
||||
return super.approximateToSubType(type, conf) as ConeKotlinType?
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,595 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.fir.types
|
||||
|
||||
import org.jetbrains.kotlin.builtins.PrimitiveType
|
||||
import org.jetbrains.kotlin.builtins.StandardNames
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.*
|
||||
import org.jetbrains.kotlin.fir.expressions.*
|
||||
import org.jetbrains.kotlin.fir.resolve.directExpansionType
|
||||
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap
|
||||
import org.jetbrains.kotlin.fir.resolve.toSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterLookupTag
|
||||
import org.jetbrains.kotlin.fir.symbols.ensureResolved
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.FqNameUnsafe
|
||||
import org.jetbrains.kotlin.name.StandardClassIds
|
||||
import org.jetbrains.kotlin.types.TypeCheckerState
|
||||
import org.jetbrains.kotlin.types.TypeCheckerState.SupertypesPolicy.DoCustomTransform
|
||||
import org.jetbrains.kotlin.types.TypeCheckerState.SupertypesPolicy.LowerIfFlexible
|
||||
import org.jetbrains.kotlin.types.TypeSystemCommonBackendContext
|
||||
import org.jetbrains.kotlin.types.model.*
|
||||
|
||||
class ErrorTypeConstructor(val reason: String) : TypeConstructorMarker {
|
||||
override fun toString(): String = reason
|
||||
}
|
||||
|
||||
interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext, TypeCheckerProviderContext, TypeSystemCommonBackendContext {
|
||||
val session: FirSession
|
||||
|
||||
override fun TypeConstructorMarker.isIntegerLiteralTypeConstructor(): Boolean {
|
||||
return this is ConeIntegerLiteralType
|
||||
}
|
||||
|
||||
override fun TypeConstructorMarker.isLocalType(): Boolean {
|
||||
if (this !is ConeClassLikeLookupTag) return false
|
||||
return classId.isLocal
|
||||
}
|
||||
|
||||
override val TypeVariableTypeConstructorMarker.typeParameter: TypeParameterMarker?
|
||||
get() {
|
||||
require(this is ConeTypeVariableTypeConstructor)
|
||||
return this.originalTypeParameter
|
||||
}
|
||||
|
||||
override fun SimpleTypeMarker.possibleIntegerTypes(): Collection<KotlinTypeMarker> {
|
||||
return (this as? ConeIntegerLiteralType)?.possibleTypes ?: emptyList()
|
||||
}
|
||||
|
||||
override fun SimpleTypeMarker.fastCorrespondingSupertypes(constructor: TypeConstructorMarker): List<SimpleTypeMarker>? {
|
||||
require(this is ConeKotlinType)
|
||||
return session.correspondingSupertypesCache.getCorrespondingSupertypes(this, constructor)
|
||||
}
|
||||
|
||||
override fun SimpleTypeMarker.isIntegerLiteralType(): Boolean {
|
||||
return this is ConeIntegerLiteralType
|
||||
}
|
||||
|
||||
override fun KotlinTypeMarker.asSimpleType(): SimpleTypeMarker? {
|
||||
assert(this is ConeKotlinType)
|
||||
return when (this) {
|
||||
is ConeClassLikeType -> fullyExpandedType(session)
|
||||
is ConeSimpleKotlinType -> this
|
||||
is ConeFlexibleType -> null
|
||||
else -> error("Unknown simpleType: $this")
|
||||
}
|
||||
}
|
||||
|
||||
override fun KotlinTypeMarker.asFlexibleType(): FlexibleTypeMarker? {
|
||||
assert(this is ConeKotlinType)
|
||||
return this as? ConeFlexibleType
|
||||
}
|
||||
|
||||
override fun KotlinTypeMarker.isError(): Boolean {
|
||||
assert(this is ConeKotlinType)
|
||||
return this is ConeClassErrorType || this is ConeKotlinErrorType || this.typeConstructor().isError() ||
|
||||
(this is ConeClassLikeType && this.lookupTag is ConeClassLikeErrorLookupTag)
|
||||
}
|
||||
|
||||
override fun KotlinTypeMarker.isUninferredParameter(): Boolean {
|
||||
assert(this is ConeKotlinType)
|
||||
return this is ConeClassErrorType && this.isUninferredParameter
|
||||
}
|
||||
|
||||
override fun FlexibleTypeMarker.asDynamicType(): DynamicTypeMarker? {
|
||||
assert(this is ConeKotlinType)
|
||||
return null // TODO
|
||||
}
|
||||
|
||||
override fun FlexibleTypeMarker.asRawType(): RawTypeMarker? {
|
||||
require(this is ConeFlexibleType)
|
||||
return this as? ConeRawType
|
||||
}
|
||||
|
||||
override fun FlexibleTypeMarker.upperBound(): SimpleTypeMarker {
|
||||
require(this is ConeFlexibleType)
|
||||
return this.upperBound as SimpleTypeMarker
|
||||
}
|
||||
|
||||
override fun FlexibleTypeMarker.lowerBound(): SimpleTypeMarker {
|
||||
require(this is ConeFlexibleType)
|
||||
return this.lowerBound as SimpleTypeMarker
|
||||
}
|
||||
|
||||
override fun SimpleTypeMarker.asCapturedType(): CapturedTypeMarker? {
|
||||
return this as? ConeCapturedType
|
||||
}
|
||||
|
||||
override fun SimpleTypeMarker.asDefinitelyNotNullType(): DefinitelyNotNullTypeMarker? {
|
||||
require(this is ConeKotlinType)
|
||||
return this as? ConeDefinitelyNotNullType
|
||||
}
|
||||
|
||||
override fun SimpleTypeMarker.isMarkedNullable(): Boolean {
|
||||
require(this is ConeKotlinType)
|
||||
return this.nullability.isNullable
|
||||
}
|
||||
|
||||
override fun SimpleTypeMarker.withNullability(nullable: Boolean): SimpleTypeMarker {
|
||||
require(this is ConeKotlinType)
|
||||
return withNullability(ConeNullability.create(nullable), session.typeContext)
|
||||
}
|
||||
|
||||
override fun SimpleTypeMarker.typeConstructor(): TypeConstructorMarker {
|
||||
return when (this) {
|
||||
is ConeClassLikeType -> lookupTag
|
||||
is ConeTypeParameterType -> lookupTag
|
||||
is ConeCapturedType -> constructor
|
||||
is ConeTypeVariableType -> lookupTag
|
||||
is ConeIntersectionType -> this
|
||||
is ConeStubType -> variable.typeConstructor
|
||||
is ConeDefinitelyNotNullType -> original.typeConstructor()
|
||||
is ConeIntegerLiteralType -> this
|
||||
else -> error("?: $this")
|
||||
}
|
||||
}
|
||||
|
||||
override fun CapturedTypeMarker.typeConstructor(): CapturedTypeConstructorMarker {
|
||||
require(this is ConeCapturedType)
|
||||
return this.constructor
|
||||
}
|
||||
|
||||
override fun CapturedTypeMarker.captureStatus(): CaptureStatus {
|
||||
require(this is ConeCapturedType)
|
||||
return this.captureStatus
|
||||
}
|
||||
|
||||
override fun CapturedTypeMarker.isOldCapturedType(): Boolean = false
|
||||
|
||||
override fun CapturedTypeConstructorMarker.projection(): TypeArgumentMarker {
|
||||
require(this is ConeCapturedTypeConstructor)
|
||||
return this.projection
|
||||
}
|
||||
|
||||
override fun KotlinTypeMarker.argumentsCount(): Int {
|
||||
require(this is ConeKotlinType)
|
||||
return this.typeArguments.size
|
||||
}
|
||||
|
||||
override fun KotlinTypeMarker.getArgument(index: Int): TypeArgumentMarker {
|
||||
require(this is ConeKotlinType)
|
||||
return this.typeArguments.getOrNull(index) ?: ConeStarProjection
|
||||
}
|
||||
|
||||
override fun KotlinTypeMarker.getArguments(): List<TypeArgumentMarker> {
|
||||
require(this is ConeKotlinType)
|
||||
return this.typeArguments.toList()
|
||||
}
|
||||
|
||||
override fun KotlinTypeMarker.asTypeArgument(): TypeArgumentMarker {
|
||||
require(this is ConeKotlinType)
|
||||
return this
|
||||
}
|
||||
|
||||
override fun CapturedTypeMarker.lowerType(): KotlinTypeMarker? {
|
||||
require(this is ConeCapturedType)
|
||||
if (!this.isMarkedNullable) return this.lowerType
|
||||
return this.lowerType?.makeNullable()
|
||||
}
|
||||
|
||||
override fun TypeArgumentMarker.isStarProjection(): Boolean {
|
||||
require(this is ConeTypeProjection)
|
||||
return this is ConeStarProjection
|
||||
}
|
||||
|
||||
override fun TypeArgumentMarker.getVariance(): TypeVariance {
|
||||
require(this is ConeTypeProjection)
|
||||
|
||||
return when (this.kind) {
|
||||
ProjectionKind.STAR -> error("Nekorrektno (c) Stas")
|
||||
ProjectionKind.IN -> TypeVariance.IN
|
||||
ProjectionKind.OUT -> TypeVariance.OUT
|
||||
ProjectionKind.INVARIANT -> TypeVariance.INV
|
||||
}
|
||||
}
|
||||
|
||||
override fun TypeArgumentMarker.getType(): KotlinTypeMarker {
|
||||
require(this is ConeTypeProjection)
|
||||
require(this is ConeKotlinTypeProjection) { "No type for StarProjection" }
|
||||
return this.type
|
||||
}
|
||||
|
||||
override fun TypeConstructorMarker.parametersCount(): Int {
|
||||
return when (this) {
|
||||
is ConeTypeParameterLookupTag,
|
||||
is ConeCapturedTypeConstructor,
|
||||
is ErrorTypeConstructor,
|
||||
is ConeTypeVariableTypeConstructor,
|
||||
is ConeIntersectionType -> 0
|
||||
is ConeClassLikeLookupTag -> {
|
||||
when (val symbol = toSymbol(session)) {
|
||||
is FirAnonymousObjectSymbol -> symbol.fir.typeParameters.size
|
||||
is FirRegularClassSymbol -> symbol.fir.typeParameters.size
|
||||
is FirTypeAliasSymbol -> symbol.fir.typeParameters.size
|
||||
else -> 0
|
||||
}
|
||||
}
|
||||
is ConeIntegerLiteralType -> 0
|
||||
else -> unknownConstructorError()
|
||||
}
|
||||
}
|
||||
|
||||
override fun TypeConstructorMarker.getParameter(index: Int): TypeParameterMarker {
|
||||
return when (val symbol = toClassLikeSymbol()) {
|
||||
is FirAnonymousObjectSymbol -> symbol.fir.typeParameters[index].symbol.toLookupTag()
|
||||
is FirRegularClassSymbol -> symbol.fir.typeParameters[index].symbol.toLookupTag()
|
||||
is FirTypeAliasSymbol -> symbol.fir.typeParameters[index].symbol.toLookupTag()
|
||||
else -> error("Unexpected FirClassLikeSymbol $symbol for ${this::class}, with classId ${(this as? ConeClassLikeLookupTag)?.classId}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun TypeConstructorMarker.getParameters(): List<TypeParameterMarker> {
|
||||
return when (val symbol = toClassLikeSymbol()) {
|
||||
is FirAnonymousObjectSymbol -> symbol.fir.typeParameters.map { it.symbol.toLookupTag() }
|
||||
is FirRegularClassSymbol -> symbol.fir.typeParameters.map { it.symbol.toLookupTag() }
|
||||
is FirTypeAliasSymbol -> symbol.fir.typeParameters.map { it.symbol.toLookupTag() }
|
||||
else -> emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
private fun TypeConstructorMarker.toClassLikeSymbol(): FirClassLikeSymbol<*>? = (this as? ConeClassLikeLookupTag)?.toSymbol(session)
|
||||
|
||||
override fun TypeConstructorMarker.supertypes(): Collection<ConeKotlinType> {
|
||||
if (this is ErrorTypeConstructor) return emptyList()
|
||||
return when (this) {
|
||||
is ConeTypeVariableTypeConstructor -> emptyList()
|
||||
is ConeTypeParameterLookupTag -> symbol.fir.bounds.map { it.coneType }
|
||||
is ConeClassLikeLookupTag -> {
|
||||
when (val symbol = toClassLikeSymbol().also { it?.ensureResolved(FirResolvePhase.TYPES) }) {
|
||||
is FirClassSymbol<*> -> symbol.fir.superConeTypes
|
||||
is FirTypeAliasSymbol -> listOfNotNull(symbol.fir.expandedConeType)
|
||||
else -> listOf(session.builtinTypes.anyType.type)
|
||||
}
|
||||
}
|
||||
is ConeCapturedTypeConstructor -> supertypes!!
|
||||
is ConeIntersectionType -> intersectedTypes
|
||||
is ConeIntegerLiteralType -> supertypes
|
||||
else -> unknownConstructorError()
|
||||
}
|
||||
}
|
||||
|
||||
override fun TypeConstructorMarker.isIntersection(): Boolean {
|
||||
return this is ConeIntersectionType
|
||||
}
|
||||
|
||||
override fun TypeConstructorMarker.isClassTypeConstructor(): Boolean {
|
||||
return this is ConeClassLikeLookupTag
|
||||
}
|
||||
|
||||
override fun TypeConstructorMarker.isInterface(): Boolean {
|
||||
return ((this as? ConeClassLikeLookupTag)?.toClassLikeSymbol()?.fir as? FirClass)?.classKind == ClassKind.INTERFACE
|
||||
}
|
||||
|
||||
override fun TypeParameterMarker.getVariance(): TypeVariance {
|
||||
require(this is ConeTypeParameterLookupTag)
|
||||
return this.symbol.fir.variance.convertVariance()
|
||||
}
|
||||
|
||||
override fun TypeParameterMarker.upperBoundCount(): Int {
|
||||
require(this is ConeTypeParameterLookupTag)
|
||||
return this.symbol.fir.bounds.size
|
||||
}
|
||||
|
||||
override fun TypeParameterMarker.getUpperBound(index: Int): KotlinTypeMarker {
|
||||
require(this is ConeTypeParameterLookupTag)
|
||||
return this.symbol.fir.bounds[index].coneType
|
||||
}
|
||||
|
||||
override fun TypeParameterMarker.getUpperBounds(): List<KotlinTypeMarker> {
|
||||
require(this is ConeTypeParameterLookupTag)
|
||||
return this.symbol.fir.bounds.map { it.coneType }
|
||||
}
|
||||
|
||||
override fun TypeParameterMarker.getTypeConstructor(): TypeConstructorMarker {
|
||||
require(this is ConeTypeParameterLookupTag)
|
||||
return this
|
||||
}
|
||||
|
||||
override fun TypeParameterMarker.hasRecursiveBounds(selfConstructor: TypeConstructorMarker?): Boolean {
|
||||
require(this is ConeTypeParameterLookupTag)
|
||||
return this.typeParameterSymbol.fir.bounds.any { typeRef ->
|
||||
typeRef.coneType.contains { it.typeConstructor() == this.getTypeConstructor() }
|
||||
&& (selfConstructor == null || typeRef.coneType.typeConstructor() == selfConstructor)
|
||||
}
|
||||
}
|
||||
|
||||
override fun areEqualTypeConstructors(c1: TypeConstructorMarker, c2: TypeConstructorMarker): Boolean {
|
||||
if (c1 is ErrorTypeConstructor || c2 is ErrorTypeConstructor) return false
|
||||
return c1 == c2
|
||||
}
|
||||
|
||||
override fun TypeConstructorMarker.isDenotable(): Boolean {
|
||||
return when (this) {
|
||||
is ConeClassLikeLookupTag,
|
||||
is ConeTypeParameterLookupTag -> true
|
||||
|
||||
is ConeCapturedTypeConstructor,
|
||||
is ErrorTypeConstructor,
|
||||
is ConeTypeVariableTypeConstructor,
|
||||
is ConeIntegerLiteralType,
|
||||
is ConeIntersectionType -> false
|
||||
|
||||
else -> unknownConstructorError()
|
||||
}
|
||||
}
|
||||
|
||||
override fun TypeConstructorMarker.isCommonFinalClassConstructor(): Boolean {
|
||||
val symbol = toClassLikeSymbol() ?: return false
|
||||
if (symbol is FirAnonymousObjectSymbol) return true
|
||||
val classSymbol = symbol as? FirRegularClassSymbol ?: return false
|
||||
val fir = classSymbol.fir
|
||||
return fir.modality == Modality.FINAL &&
|
||||
fir.classKind != ClassKind.ENUM_ENTRY &&
|
||||
fir.classKind != ClassKind.ANNOTATION_CLASS
|
||||
}
|
||||
|
||||
override fun captureFromExpression(type: KotlinTypeMarker): KotlinTypeMarker? {
|
||||
require(type is ConeKotlinType)
|
||||
return captureFromExpressionInternal(type)
|
||||
}
|
||||
|
||||
override fun captureFromArguments(type: SimpleTypeMarker, status: CaptureStatus): SimpleTypeMarker? {
|
||||
require(type is ConeKotlinType)
|
||||
return captureFromArgumentsInternal(type, status) as SimpleTypeMarker?
|
||||
}
|
||||
|
||||
override fun SimpleTypeMarker.asArgumentList(): TypeArgumentListMarker {
|
||||
require(this is ConeKotlinType)
|
||||
return this
|
||||
}
|
||||
|
||||
override fun identicalArguments(a: SimpleTypeMarker, b: SimpleTypeMarker): Boolean {
|
||||
require(a is ConeKotlinType)
|
||||
require(b is ConeKotlinType)
|
||||
return a.typeArguments === b.typeArguments
|
||||
}
|
||||
|
||||
override fun TypeConstructorMarker.isAnyConstructor(): Boolean {
|
||||
return this is ConeClassLikeLookupTag && classId == StandardClassIds.Any
|
||||
}
|
||||
|
||||
override fun TypeConstructorMarker.isNothingConstructor(): Boolean {
|
||||
return this is ConeClassLikeLookupTag && classId == StandardClassIds.Nothing
|
||||
}
|
||||
|
||||
override fun SimpleTypeMarker.isSingleClassifierType(): Boolean {
|
||||
if (isError()) return false
|
||||
if (this is ConeCapturedType) return true
|
||||
if (this is ConeTypeVariableType) return false
|
||||
if (this is ConeIntersectionType) return false
|
||||
if (this is ConeIntegerLiteralType) return true
|
||||
if (this is ConeStubType) return true
|
||||
if (this is ConeDefinitelyNotNullType) return true
|
||||
require(this is ConeLookupTagBasedType)
|
||||
val typeConstructor = this.typeConstructor()
|
||||
return typeConstructor is ConeClassLikeLookupTag ||
|
||||
typeConstructor is ConeTypeParameterLookupTag
|
||||
}
|
||||
|
||||
override fun SimpleTypeMarker.isPrimitiveType(): Boolean {
|
||||
if (this is ConeClassLikeType) {
|
||||
return isPrimitive
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override fun KotlinTypeMarker.getAnnotations(): List<AnnotationMarker> {
|
||||
require(this is ConeKotlinType)
|
||||
return attributes.toList()
|
||||
}
|
||||
|
||||
override fun SimpleTypeMarker.isStubType(): Boolean {
|
||||
return this is ConeStubType
|
||||
}
|
||||
|
||||
override fun SimpleTypeMarker.isStubTypeForVariableInSubtyping(): Boolean {
|
||||
return this is ConeStubTypeForTypeVariableInSubtyping
|
||||
}
|
||||
|
||||
override fun SimpleTypeMarker.isStubTypeForBuilderInference(): Boolean {
|
||||
return this is ConeStubTypeForBuilderInference
|
||||
}
|
||||
|
||||
override fun intersectTypes(types: List<SimpleTypeMarker>): SimpleTypeMarker {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return ConeTypeIntersector.intersectTypes(this as ConeInferenceContext, types as List<ConeKotlinType>) as SimpleTypeMarker
|
||||
}
|
||||
|
||||
override fun intersectTypes(types: List<KotlinTypeMarker>): ConeKotlinType {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return ConeTypeIntersector.intersectTypes(this as ConeInferenceContext, types as List<ConeKotlinType>)
|
||||
}
|
||||
|
||||
override fun KotlinTypeMarker.isNullableType(): Boolean {
|
||||
require(this is ConeKotlinType)
|
||||
if (this.isMarkedNullable)
|
||||
return true
|
||||
|
||||
return when (this) {
|
||||
is ConeFlexibleType -> this.upperBound.isNullableType()
|
||||
is ConeTypeParameterType -> lookupTag.symbol.allBoundsAreNullable()
|
||||
is ConeTypeVariableType -> {
|
||||
val symbol = lookupTag.toSymbol(session) ?: return false
|
||||
when (symbol) {
|
||||
is FirClassSymbol -> false
|
||||
is FirTypeAliasSymbol -> symbol.fir.expandedConeType?.isNullableType() ?: false
|
||||
is FirTypeParameterSymbol -> symbol.allBoundsAreNullable()
|
||||
}
|
||||
}
|
||||
is ConeIntersectionType -> intersectedTypes.all { it.isNullableType() }
|
||||
is ConeClassLikeType -> directExpansionType(session)?.isNullableType() ?: false
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
private fun FirTypeParameterSymbol.allBoundsAreNullable(): Boolean {
|
||||
return fir.bounds.all { it.coneType.isNullableType() }
|
||||
}
|
||||
|
||||
private fun TypeConstructorMarker.toFirRegularClass(): FirRegularClass? {
|
||||
return toClassLikeSymbol()?.fir as? FirRegularClass
|
||||
}
|
||||
|
||||
override fun nullableAnyType(): SimpleTypeMarker = session.builtinTypes.nullableAnyType.type
|
||||
|
||||
override fun arrayType(componentType: KotlinTypeMarker): SimpleTypeMarker {
|
||||
require(componentType is ConeKotlinType)
|
||||
return componentType.createArrayType(nullable = false)
|
||||
}
|
||||
|
||||
override fun KotlinTypeMarker.isArrayOrNullableArray(): Boolean {
|
||||
require(this is ConeKotlinType)
|
||||
return this.classId == StandardClassIds.Array
|
||||
}
|
||||
|
||||
override fun TypeConstructorMarker.isFinalClassOrEnumEntryOrAnnotationClassConstructor(): Boolean {
|
||||
val firRegularClass = toFirRegularClass() ?: return false
|
||||
|
||||
return firRegularClass.modality == Modality.FINAL ||
|
||||
firRegularClass.classKind == ClassKind.ENUM_ENTRY ||
|
||||
firRegularClass.classKind == ClassKind.ANNOTATION_CLASS
|
||||
}
|
||||
|
||||
override fun KotlinTypeMarker.hasAnnotation(fqName: FqName): Boolean {
|
||||
require(this is ConeKotlinType)
|
||||
val compilerAttribute = CompilerConeAttributes.compilerAttributeByFqName[fqName]
|
||||
if (compilerAttribute != null) {
|
||||
return compilerAttribute in attributes
|
||||
}
|
||||
val customAnnotations = attributes.customAnnotations
|
||||
return customAnnotations.any {
|
||||
it.typeRef.coneTypeSafe<ConeKotlinType>()?.fullyExpandedType(session)?.classId?.asSingleFqName() == fqName
|
||||
}
|
||||
}
|
||||
|
||||
override fun KotlinTypeMarker.getAnnotationFirstArgumentValue(fqName: FqName): Any? {
|
||||
require(this is ConeKotlinType)
|
||||
// We don't check for compiler attributes because all of them doesn't have parameters
|
||||
val customAnnotations = attributes.customAnnotations
|
||||
val annotationCall = customAnnotations.firstOrNull {
|
||||
it.typeRef.coneTypeSafe<ConeKotlinType>()?.fullyExpandedType(session)?.classId?.asSingleFqName() == fqName
|
||||
} ?: return null
|
||||
val argument = when (val argument = annotationCall.argumentMapping.mapping.values.firstOrNull() ?: return null) {
|
||||
is FirVarargArgumentsExpression -> argument.arguments.firstOrNull()
|
||||
is FirArrayOfCall -> argument.arguments.firstOrNull()
|
||||
is FirNamedArgumentExpression -> argument.expression
|
||||
else -> argument
|
||||
} ?: return null
|
||||
return (argument as? FirConstExpression<*>)?.value
|
||||
}
|
||||
|
||||
override fun TypeConstructorMarker.getTypeParameterClassifier(): TypeParameterMarker? {
|
||||
return this as? ConeTypeParameterLookupTag
|
||||
}
|
||||
|
||||
override fun TypeConstructorMarker.isInlineClass(): Boolean {
|
||||
return toFirRegularClass()?.isInline == true
|
||||
}
|
||||
|
||||
override fun TypeConstructorMarker.isInnerClass(): Boolean {
|
||||
return toFirRegularClass()?.isInner == true
|
||||
}
|
||||
|
||||
override fun TypeParameterMarker.getRepresentativeUpperBound(): KotlinTypeMarker {
|
||||
require(this is ConeTypeParameterLookupTag)
|
||||
return this.symbol.fir.bounds.getOrNull(0)?.coneType
|
||||
?: session.builtinTypes.nullableAnyType.type
|
||||
}
|
||||
|
||||
override fun KotlinTypeMarker.getUnsubstitutedUnderlyingType(): KotlinTypeMarker? {
|
||||
require(this is ConeKotlinType)
|
||||
return unsubstitutedUnderlyingTypeForInlineClass(session)
|
||||
}
|
||||
|
||||
override fun KotlinTypeMarker.getSubstitutedUnderlyingType(): KotlinTypeMarker? {
|
||||
require(this is ConeKotlinType)
|
||||
return substitutedUnderlyingTypeForInlineClass(session, this@ConeTypeContext)
|
||||
}
|
||||
|
||||
override fun TypeConstructorMarker.getPrimitiveType(): PrimitiveType? =
|
||||
getClassFqNameUnsafe()?.let(StandardNames.FqNames.fqNameToPrimitiveType::get)
|
||||
|
||||
override fun TypeConstructorMarker.getPrimitiveArrayType(): PrimitiveType? =
|
||||
getClassFqNameUnsafe()?.let(StandardNames.FqNames.arrayClassFqNameToPrimitiveType::get)
|
||||
|
||||
override fun TypeConstructorMarker.isUnderKotlinPackage(): Boolean =
|
||||
getClassFqNameUnsafe()?.startsWith(StandardClassIds.BASE_KOTLIN_PACKAGE.shortName()) == true
|
||||
|
||||
override fun TypeConstructorMarker.getClassFqNameUnsafe(): FqNameUnsafe? {
|
||||
if (this !is ConeClassLikeLookupTag) return null
|
||||
return classId.asSingleFqName().toUnsafe()
|
||||
}
|
||||
|
||||
override fun TypeParameterMarker.getName() = (this as ConeTypeParameterLookupTag).name
|
||||
|
||||
override fun TypeParameterMarker.isReified(): Boolean {
|
||||
require(this is ConeTypeParameterLookupTag)
|
||||
return typeParameterSymbol.fir.isReified
|
||||
}
|
||||
|
||||
override fun KotlinTypeMarker.isInterfaceOrAnnotationClass(): Boolean {
|
||||
val classKind = typeConstructor().toFirRegularClass()?.classKind ?: return false
|
||||
return classKind == ClassKind.ANNOTATION_CLASS || classKind == ClassKind.INTERFACE
|
||||
}
|
||||
|
||||
override fun TypeConstructorMarker.isError(): Boolean {
|
||||
return this is ErrorTypeConstructor
|
||||
}
|
||||
|
||||
private fun TypeConstructorMarker.unknownConstructorError(): Nothing {
|
||||
error("Unknown type constructor: ${this::class}")
|
||||
}
|
||||
|
||||
override fun substitutionSupertypePolicy(type: SimpleTypeMarker): TypeCheckerState.SupertypesPolicy {
|
||||
if (type.argumentsCount() == 0) return LowerIfFlexible
|
||||
require(type is ConeKotlinType)
|
||||
val declaration = when (type) {
|
||||
is ConeClassLikeType -> type.lookupTag.toSymbol(session)?.fir
|
||||
else -> null
|
||||
}
|
||||
|
||||
val substitutor = if (declaration is FirTypeParameterRefsOwner) {
|
||||
val substitution =
|
||||
declaration.typeParameters.zip(type.typeArguments).associate { (parameter, argument) ->
|
||||
parameter.symbol to ((argument as? ConeKotlinTypeProjection)?.type
|
||||
?: session.builtinTypes.nullableAnyType.type)//StandardClassIds.Any(session.firSymbolProvider).constructType(emptyArray(), isNullable = true))
|
||||
}
|
||||
substitutorByMap(substitution, session)
|
||||
} else {
|
||||
ConeSubstitutor.Empty
|
||||
}
|
||||
return object : DoCustomTransform() {
|
||||
override fun transformType(state: TypeCheckerState, type: KotlinTypeMarker): SimpleTypeMarker {
|
||||
val lowerBound = type.lowerBoundIfFlexible()
|
||||
require(lowerBound is ConeKotlinType)
|
||||
return substitutor.substituteOrSelf(lowerBound) as SimpleTypeMarker
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
override fun KotlinTypeMarker.isTypeVariableType(): Boolean {
|
||||
return this is ConeTypeVariableType
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.fir.types
|
||||
|
||||
import org.jetbrains.kotlin.types.AbstractTypeChecker
|
||||
|
||||
object ConeTypeIntersector {
|
||||
fun intersectTypes(
|
||||
context: ConeInferenceContext,
|
||||
types: List<ConeKotlinType>
|
||||
): ConeKotlinType {
|
||||
when (types.size) {
|
||||
0 -> error("Expected some types")
|
||||
1 -> return types.single()
|
||||
}
|
||||
|
||||
val inputTypes = mutableListOf<ConeKotlinType>()
|
||||
flatIntersectionTypes(types, inputTypes)
|
||||
|
||||
/**
|
||||
* resultNullability. Value description:
|
||||
* ACCEPT_NULL means that all types marked nullable
|
||||
*
|
||||
* NOT_NULL means that there is one type which is subtype of Any => all types can be made definitely not null,
|
||||
* making types definitely not null (not just not null) makes sense when we have intersection of type parameters like {T!! & S}
|
||||
*
|
||||
* UNKNOWN means, that we do not know, i.e. more precisely, all singleClassifier types marked nullable if any,
|
||||
* and other types is captured types or type parameters without not-null upper bound. Example: `String? & T` such types we should leave as is.
|
||||
*/
|
||||
val resultNullability = inputTypes.fold(ResultNullability.START) { nullability, nextType ->
|
||||
nullability.combine(nextType.type, context)
|
||||
}
|
||||
|
||||
val inputTypesWithCorrectNullability = inputTypes.mapTo(LinkedHashSet()) {
|
||||
if (resultNullability == ResultNullability.NOT_NULL) with(context) {
|
||||
it.makeDefinitelyNotNullOrNotNull() as ConeKotlinType
|
||||
} else it
|
||||
}
|
||||
|
||||
return intersectTypesWithoutIntersectionType(context, inputTypesWithCorrectNullability)
|
||||
}
|
||||
|
||||
private fun intersectTypesWithoutIntersectionType(
|
||||
context: ConeTypeContext,
|
||||
inputTypes: Set<ConeKotlinType>
|
||||
): ConeKotlinType {
|
||||
if (inputTypes.size == 1) return inputTypes.single().type
|
||||
|
||||
// Any and Nothing should leave
|
||||
// Note that duplicates should be dropped because we have Set here.
|
||||
val errorMessage = { "This collections cannot be empty! input types: ${inputTypes.joinToString()}" }
|
||||
|
||||
val filteredEqualTypes = filterTypes(inputTypes) { lower, upper ->
|
||||
/*
|
||||
* Here we drop types from intersection set for cases like that:
|
||||
*
|
||||
* interface A
|
||||
* interface B : A
|
||||
*
|
||||
* type = (A & B & ...)
|
||||
*
|
||||
* We want to drop A from that set, because it's useless for type checking. But in case if
|
||||
* A came from inference and B came from smartcast we want to safe both types in intersection
|
||||
*/
|
||||
isStrictSupertype(context, lower, upper)
|
||||
}
|
||||
assert(filteredEqualTypes.isNotEmpty(), errorMessage)
|
||||
|
||||
// TODO
|
||||
// IntegerLiteralTypeConstructor.findIntersectionType(filteredEqualTypes)?.let { return it }
|
||||
|
||||
/*
|
||||
* For the case like it(ft(String..String?), String?), where ft(String..String?) == String?, we prefer to _keep_ flexible type.
|
||||
* When a == b, the former, i.e., the one in the list will be filtered out, and the other one will remain.
|
||||
* So, here, we sort the interim list such that flexible types appear later.
|
||||
*/
|
||||
val sortedEqualTypes = filteredEqualTypes.sortedWith { p0, p1 ->
|
||||
when {
|
||||
p0 is ConeFlexibleType && p1 is ConeFlexibleType -> 0
|
||||
p0 is ConeFlexibleType -> 1
|
||||
p1 is ConeFlexibleType -> -1
|
||||
else -> 0
|
||||
}
|
||||
}
|
||||
val filteredSuperAndEqualTypes = filterTypes(sortedEqualTypes) { a, b ->
|
||||
AbstractTypeChecker.equalTypes(context, a, b)
|
||||
}
|
||||
assert(filteredSuperAndEqualTypes.isNotEmpty(), errorMessage)
|
||||
|
||||
if (filteredSuperAndEqualTypes.size < 2) return filteredSuperAndEqualTypes.single()
|
||||
|
||||
return ConeIntersectionType(filteredSuperAndEqualTypes)
|
||||
}
|
||||
|
||||
private fun filterTypes(
|
||||
inputTypes: Collection<ConeKotlinType>,
|
||||
predicate: (lower: ConeKotlinType, upper: ConeKotlinType) -> Boolean
|
||||
): List<ConeKotlinType> {
|
||||
val filteredTypes = ArrayList(inputTypes)
|
||||
val iterator = filteredTypes.iterator()
|
||||
while (iterator.hasNext()) {
|
||||
val upper = iterator.next()
|
||||
val shouldFilter = filteredTypes.any { lower -> lower !== upper && predicate(lower, upper) }
|
||||
|
||||
if (shouldFilter) iterator.remove()
|
||||
}
|
||||
return filteredTypes
|
||||
}
|
||||
|
||||
private fun isStrictSupertype(context: ConeTypeContext, subtype: ConeKotlinType, supertype: ConeKotlinType): Boolean {
|
||||
return with(AbstractTypeChecker) {
|
||||
isSubtypeOf(context, subtype, supertype) && !isSubtypeOf(context, supertype, subtype)
|
||||
}
|
||||
}
|
||||
|
||||
private fun flatIntersectionTypes(
|
||||
inputTypes: List<ConeKotlinType>,
|
||||
typeCollector: MutableList<ConeKotlinType>
|
||||
) {
|
||||
for (inputType in inputTypes) {
|
||||
if (inputType is ConeIntersectionType) {
|
||||
for (type in inputType.intersectedTypes) {
|
||||
typeCollector += type
|
||||
}
|
||||
} else {
|
||||
typeCollector += inputType
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private enum class ResultNullability {
|
||||
START {
|
||||
override fun combine(nextType: ConeKotlinType, context: ConeTypeContext): ResultNullability =
|
||||
nextType.resultNullability(context)
|
||||
},
|
||||
ACCEPT_NULL {
|
||||
override fun combine(nextType: ConeKotlinType, context: ConeTypeContext): ResultNullability =
|
||||
nextType.resultNullability(context)
|
||||
},
|
||||
|
||||
// example: type parameter without not-null supertype
|
||||
UNKNOWN {
|
||||
override fun combine(nextType: ConeKotlinType, context: ConeTypeContext): ResultNullability =
|
||||
nextType.resultNullability(context).let {
|
||||
if (it == ACCEPT_NULL) this else it
|
||||
}
|
||||
},
|
||||
NOT_NULL {
|
||||
override fun combine(nextType: ConeKotlinType, context: ConeTypeContext): ResultNullability = this
|
||||
};
|
||||
|
||||
abstract fun combine(nextType: ConeKotlinType, context: ConeTypeContext): ResultNullability
|
||||
|
||||
protected fun ConeKotlinType.resultNullability(context: ConeTypeContext): ResultNullability =
|
||||
when {
|
||||
isMarkedNullable -> ACCEPT_NULL
|
||||
this is ConeFlexibleType -> upperBound.resultNullability(context)
|
||||
ConeNullabilityChecker.isSubtypeOfAny(context, this) -> NOT_NULL
|
||||
else -> UNKNOWN
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.fir.types
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
||||
import org.jetbrains.kotlin.types.AbstractTypePreparator
|
||||
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
|
||||
|
||||
class ConeTypePreparator(val session: FirSession) : AbstractTypePreparator() {
|
||||
override fun prepareType(type: KotlinTypeMarker): KotlinTypeMarker {
|
||||
return when (type) {
|
||||
is ConeClassLikeType -> type.fullyExpandedType(session)
|
||||
is ConeFlexibleType -> {
|
||||
val lowerBound = prepareType(type.lowerBound)
|
||||
if (lowerBound === type.lowerBound) return type
|
||||
|
||||
ConeFlexibleType(
|
||||
lowerBound as ConeKotlinType,
|
||||
prepareType(type.upperBound) as ConeKotlinType
|
||||
)
|
||||
}
|
||||
else -> type
|
||||
}
|
||||
}
|
||||
}
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.fir.types
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.FirSessionComponent
|
||||
import org.jetbrains.kotlin.fir.ThreadSafeMutableState
|
||||
import org.jetbrains.kotlin.fir.declarations.FirClassLikeDeclaration
|
||||
import org.jetbrains.kotlin.fir.declarations.FirTypeParameterRefsOwner
|
||||
import org.jetbrains.kotlin.fir.resolve.toSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
|
||||
import org.jetbrains.kotlin.types.TypeCheckerState
|
||||
import org.jetbrains.kotlin.types.model.CaptureStatus
|
||||
import org.jetbrains.kotlin.types.model.SimpleTypeMarker
|
||||
import org.jetbrains.kotlin.types.model.TypeConstructorMarker
|
||||
|
||||
@ThreadSafeMutableState
|
||||
class FirCorrespondingSupertypesCache(private val session: FirSession) : FirSessionComponent {
|
||||
private val cache = HashMap<ConeClassLikeLookupTag, Map<ConeClassLikeLookupTag, List<ConeClassLikeType>>?>(1000, 0.5f)
|
||||
|
||||
fun getCorrespondingSupertypes(
|
||||
type: ConeKotlinType,
|
||||
supertypeConstructor: TypeConstructorMarker
|
||||
): List<ConeClassLikeType>? {
|
||||
if (type !is ConeClassLikeType || supertypeConstructor !is ConeClassLikeLookupTag) return null
|
||||
|
||||
val typeContext = session.typeContext
|
||||
val typeCheckerState = typeContext.newTypeCheckerState(
|
||||
errorTypesEqualToAnything = false,
|
||||
stubTypesEqualToAnything = true
|
||||
)
|
||||
|
||||
val lookupTag = type.lookupTag
|
||||
if (lookupTag == supertypeConstructor) return listOf(captureType(type, typeContext))
|
||||
if (lookupTag !in cache) {
|
||||
cache[lookupTag] = computeSupertypesMap(lookupTag, typeCheckerState)
|
||||
}
|
||||
|
||||
val resultTypes = cache[lookupTag]?.getOrDefault(supertypeConstructor, emptyList()) ?: return null
|
||||
if (type.typeArguments.isEmpty()) return resultTypes
|
||||
|
||||
val capturedType = captureType(type, typeContext)
|
||||
val substitutionSupertypePolicy = typeContext.substitutionSupertypePolicy(capturedType)
|
||||
return resultTypes.map {
|
||||
substitutionSupertypePolicy.transformType(typeCheckerState, it) as ConeClassLikeType
|
||||
}
|
||||
}
|
||||
|
||||
private fun captureType(type: ConeClassLikeType, typeSystemContext: ConeTypeContext): ConeClassLikeType =
|
||||
(typeSystemContext.captureFromArguments(type, CaptureStatus.FOR_SUBTYPING) ?: type) as ConeClassLikeType
|
||||
|
||||
private fun computeSupertypesMap(
|
||||
subtypeLookupTag: ConeClassLikeLookupTag,
|
||||
state: TypeCheckerState
|
||||
): Map<ConeClassLikeLookupTag, List<ConeClassLikeType>>? {
|
||||
val resultingMap = HashMap<ConeClassLikeLookupTag, List<ConeClassLikeType>>()
|
||||
|
||||
val subtypeFirClass: FirClassLikeDeclaration = subtypeLookupTag.toSymbol(session)?.fir ?: return null
|
||||
|
||||
val defaultType = subtypeLookupTag.constructClassType(
|
||||
(subtypeFirClass as? FirTypeParameterRefsOwner)?.typeParameters?.map {
|
||||
it.symbol.toLookupTag().constructType(emptyArray(), isNullable = false)
|
||||
}?.toTypedArray().orEmpty(),
|
||||
isNullable = false
|
||||
)
|
||||
|
||||
if (state.anySupertype(
|
||||
defaultType,
|
||||
{ it !is ConeClassLikeType || it.lookupTag.toSymbol(session) !is FirClassLikeSymbol<*> }
|
||||
) { supertype -> computeSupertypePolicyAndPutInMap(supertype, resultingMap, state) }
|
||||
) {
|
||||
return null
|
||||
}
|
||||
|
||||
return resultingMap.also {
|
||||
it.remove(subtypeLookupTag) // Just optimization: do not preserve mapping from MyClass to MyClas itself
|
||||
}
|
||||
}
|
||||
|
||||
private fun computeSupertypePolicyAndPutInMap(
|
||||
supertype: SimpleTypeMarker,
|
||||
resultingMap: MutableMap<ConeClassLikeLookupTag, List<ConeClassLikeType>>,
|
||||
state: TypeCheckerState
|
||||
): TypeCheckerState.SupertypesPolicy {
|
||||
val supertypeLookupTag = (supertype as ConeClassLikeType).lookupTag
|
||||
val captured =
|
||||
state.typeSystemContext.captureFromArguments(supertype, CaptureStatus.FOR_SUBTYPING) as ConeClassLikeType? ?: supertype
|
||||
|
||||
resultingMap[supertypeLookupTag] = listOf(captured)
|
||||
|
||||
return when {
|
||||
with(state.typeSystemContext) { captured.argumentsCount() } == 0 -> {
|
||||
TypeCheckerState.SupertypesPolicy.LowerIfFlexible
|
||||
}
|
||||
else -> {
|
||||
state.typeSystemContext.substitutionSupertypePolicy(captured)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val FirSession.correspondingSupertypesCache: FirCorrespondingSupertypesCache by FirSession.sessionComponentAccessor()
|
||||
@@ -0,0 +1,243 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.fir.types
|
||||
|
||||
import org.jetbrains.kotlin.builtins.functions.FunctionClassKind
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction
|
||||
import org.jetbrains.kotlin.fir.declarations.FirClass
|
||||
import org.jetbrains.kotlin.fir.originalForSubstitutionOverride
|
||||
import org.jetbrains.kotlin.fir.resolve.ScopeSession
|
||||
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
||||
import org.jetbrains.kotlin.fir.resolve.scope
|
||||
import org.jetbrains.kotlin.fir.resolve.toSymbol
|
||||
import org.jetbrains.kotlin.fir.scopes.FakeOverrideTypeCalculator
|
||||
import org.jetbrains.kotlin.fir.scopes.ProcessorAction
|
||||
import org.jetbrains.kotlin.fir.scopes.processOverriddenFunctions
|
||||
import org.jetbrains.kotlin.fir.scopes.unsubstitutedScope
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.ConeClassLikeLookupTagImpl
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
|
||||
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.StandardClassIds
|
||||
import org.jetbrains.kotlin.types.AbstractTypeChecker
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
import kotlin.contracts.ExperimentalContracts
|
||||
import kotlin.contracts.contract
|
||||
|
||||
@OptIn(ExperimentalContracts::class)
|
||||
private fun ConeKotlinType.classId(session: FirSession): ClassId? {
|
||||
contract {
|
||||
returns(true) implies (this@classId is ConeClassLikeType)
|
||||
}
|
||||
if (this !is ConeClassLikeType) return null
|
||||
return fullyExpandedType(session).lookupTag.classId
|
||||
}
|
||||
|
||||
fun ConeKotlinType.isKMutableProperty(session: FirSession): Boolean {
|
||||
val classId = classId(session) ?: return false
|
||||
return classId.packageFqName == StandardClassIds.BASE_REFLECT_PACKAGE &&
|
||||
classId.shortClassName.identifier.startsWith("KMutableProperty")
|
||||
}
|
||||
|
||||
fun ConeKotlinType.functionClassKind(session: FirSession): FunctionClassKind? {
|
||||
return classId(session)?.toFunctionClassKind()
|
||||
}
|
||||
|
||||
private fun ClassId.toFunctionClassKind(): FunctionClassKind? {
|
||||
return FunctionClassKind.byClassNamePrefix(packageFqName, relativeClassName.asString())
|
||||
}
|
||||
|
||||
// Function, SuspendFunction, KFunction, KSuspendFunction
|
||||
fun ConeKotlinType.isBuiltinFunctionalType(session: FirSession): Boolean {
|
||||
return functionClassKind(session) != null
|
||||
}
|
||||
|
||||
// Function, SuspendFunction, KFunction, KSuspendFunction
|
||||
fun ConeClassLikeLookupTag.isBuiltinFunctionalType(): Boolean {
|
||||
return classId.toFunctionClassKind() != null
|
||||
}
|
||||
|
||||
inline fun ConeKotlinType.isFunctionalType(session: FirSession, predicate: (FunctionClassKind) -> Boolean): Boolean {
|
||||
val kind = functionClassKind(session) ?: return false
|
||||
return predicate(kind)
|
||||
}
|
||||
|
||||
// Function
|
||||
fun ConeKotlinType.isFunctionalType(session: FirSession): Boolean {
|
||||
return isFunctionalType(session) { it == FunctionClassKind.Function }
|
||||
}
|
||||
|
||||
// SuspendFunction, KSuspendFunction
|
||||
fun ConeKotlinType.isSuspendFunctionType(session: FirSession): Boolean {
|
||||
return isFunctionalType(session) { it.isSuspendType }
|
||||
}
|
||||
|
||||
// KFunction, KSuspendFunction
|
||||
fun ConeKotlinType.isKFunctionType(session: FirSession): Boolean {
|
||||
return isFunctionalType(session) { it.isReflectType }
|
||||
}
|
||||
|
||||
fun ConeKotlinType.kFunctionTypeToFunctionType(session: FirSession): ConeClassLikeType {
|
||||
require(this.isKFunctionType(session))
|
||||
val kind =
|
||||
if (isSuspendFunctionType(session)) FunctionClassKind.SuspendFunction
|
||||
else FunctionClassKind.Function
|
||||
val functionalTypeId = ClassId(kind.packageFqName, kind.numberedClassName(typeArguments.size - 1))
|
||||
return ConeClassLikeTypeImpl(ConeClassLikeLookupTagImpl(functionalTypeId), typeArguments, isNullable = false)
|
||||
}
|
||||
|
||||
fun ConeKotlinType.suspendFunctionTypeToFunctionType(session: FirSession): ConeClassLikeType {
|
||||
require(this.isSuspendFunctionType(session))
|
||||
val kind =
|
||||
if (isKFunctionType(session)) FunctionClassKind.KFunction
|
||||
else FunctionClassKind.Function
|
||||
val functionalTypeId = ClassId(kind.packageFqName, kind.numberedClassName(typeArguments.size - 1))
|
||||
return ConeClassLikeTypeImpl(ConeClassLikeLookupTagImpl(functionalTypeId), typeArguments, isNullable = false, attributes = attributes)
|
||||
}
|
||||
|
||||
fun ConeKotlinType.suspendFunctionTypeToFunctionTypeWithContinuation(session: FirSession, continuationClassId: ClassId): ConeClassLikeType {
|
||||
require(this.isSuspendFunctionType(session))
|
||||
val kind =
|
||||
if (isKFunctionType(session)) FunctionClassKind.KFunction
|
||||
else FunctionClassKind.Function
|
||||
val functionalTypeId = ClassId(kind.packageFqName, kind.numberedClassName(typeArguments.size))
|
||||
return ConeClassLikeTypeImpl(
|
||||
ConeClassLikeLookupTagImpl(functionalTypeId),
|
||||
typeArguments = (type.typeArguments.dropLast(1) + ConeClassLikeLookupTagImpl(continuationClassId).constructClassType(
|
||||
arrayOf(type.typeArguments.last()),
|
||||
isNullable = false
|
||||
) + type.typeArguments.last()).toTypedArray(),
|
||||
isNullable = false,
|
||||
attributes = attributes
|
||||
)
|
||||
}
|
||||
|
||||
fun ConeKotlinType.isSubtypeOfFunctionalType(session: FirSession, expectedFunctionalType: ConeClassLikeType): Boolean {
|
||||
require(expectedFunctionalType.isBuiltinFunctionalType(session))
|
||||
return AbstractTypeChecker.isSubtypeOf(session.typeContext, this, expectedFunctionalType.replaceArgumentsWithStarProjections())
|
||||
}
|
||||
|
||||
fun ConeKotlinType.findSubtypeOfNonSuspendFunctionalType(session: FirSession, expectedFunctionalType: ConeClassLikeType): ConeKotlinType? {
|
||||
require(expectedFunctionalType.isBuiltinFunctionalType(session) && !expectedFunctionalType.isSuspendFunctionType(session))
|
||||
return when (this) {
|
||||
is ConeClassLikeType -> {
|
||||
// Expect the argument type is not a suspend functional type.
|
||||
if (isSuspendFunctionType(session) || !isSubtypeOfFunctionalType(session, expectedFunctionalType))
|
||||
null
|
||||
else
|
||||
this
|
||||
}
|
||||
is ConeIntersectionType -> {
|
||||
if (intersectedTypes.any { it.isSuspendFunctionType(session) })
|
||||
null
|
||||
else
|
||||
intersectedTypes.find { it.findSubtypeOfNonSuspendFunctionalType(session, expectedFunctionalType) != null }
|
||||
}
|
||||
is ConeTypeParameterType -> {
|
||||
val bounds = lookupTag.typeParameterSymbol.fir.bounds.map { it.coneType }
|
||||
if (bounds.any { it.isSuspendFunctionType(session) })
|
||||
null
|
||||
else
|
||||
bounds.find { it.findSubtypeOfNonSuspendFunctionalType(session, expectedFunctionalType) != null }
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
fun ConeClassLikeType.findBaseInvokeSymbol(session: FirSession, scopeSession: ScopeSession): FirNamedFunctionSymbol? {
|
||||
require(this.isBuiltinFunctionalType(session))
|
||||
val functionN = (lookupTag.toSymbol(session)?.fir as? FirClass) ?: return null
|
||||
var baseInvokeSymbol: FirNamedFunctionSymbol? = null
|
||||
functionN.unsubstitutedScope(
|
||||
session,
|
||||
scopeSession,
|
||||
withForcedTypeCalculator = false
|
||||
).processFunctionsByName(OperatorNameConventions.INVOKE) { functionSymbol ->
|
||||
baseInvokeSymbol = functionSymbol
|
||||
return@processFunctionsByName
|
||||
}
|
||||
return baseInvokeSymbol
|
||||
}
|
||||
|
||||
fun ConeKotlinType.findContributedInvokeSymbol(
|
||||
session: FirSession,
|
||||
scopeSession: ScopeSession,
|
||||
expectedFunctionalType: ConeClassLikeType,
|
||||
shouldCalculateReturnTypesOfFakeOverrides: Boolean
|
||||
): FirFunctionSymbol<*>? {
|
||||
val baseInvokeSymbol = expectedFunctionalType.findBaseInvokeSymbol(session, scopeSession) ?: return null
|
||||
|
||||
val fakeOverrideTypeCalculator = if (shouldCalculateReturnTypesOfFakeOverrides) {
|
||||
FakeOverrideTypeCalculator.Forced
|
||||
} else {
|
||||
FakeOverrideTypeCalculator.DoNothing
|
||||
}
|
||||
val scope = scope(session, scopeSession, fakeOverrideTypeCalculator) ?: return null
|
||||
var declaredInvoke: FirNamedFunctionSymbol? = null
|
||||
scope.processFunctionsByName(OperatorNameConventions.INVOKE) { functionSymbol ->
|
||||
if (functionSymbol.fir.valueParameters.size == baseInvokeSymbol.fir.valueParameters.size) {
|
||||
declaredInvoke = functionSymbol
|
||||
return@processFunctionsByName
|
||||
}
|
||||
}
|
||||
|
||||
var overriddenInvoke: FirFunctionSymbol<*>? = null
|
||||
if (declaredInvoke != null) {
|
||||
// Make sure the user-contributed or type-substituted invoke we just found above is an override of base invoke.
|
||||
scope.processOverriddenFunctions(declaredInvoke!!) { functionSymbol ->
|
||||
if (functionSymbol == baseInvokeSymbol || functionSymbol.originalForSubstitutionOverride == baseInvokeSymbol) {
|
||||
overriddenInvoke = functionSymbol
|
||||
ProcessorAction.STOP
|
||||
} else {
|
||||
ProcessorAction.NEXT
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return if (overriddenInvoke != null) declaredInvoke else null
|
||||
}
|
||||
|
||||
fun ConeKotlinType.isKClassType(): Boolean {
|
||||
return classId == StandardClassIds.KClass
|
||||
}
|
||||
|
||||
private fun ConeTypeProjection.typeOrDefault(default: ConeKotlinType): ConeKotlinType =
|
||||
when (this) {
|
||||
is ConeKotlinTypeProjection -> type
|
||||
is ConeStarProjection -> default
|
||||
}
|
||||
|
||||
fun ConeKotlinType.receiverType(session: FirSession): ConeKotlinType? {
|
||||
if (!isBuiltinFunctionalType(session) || !isExtensionFunctionType(session)) return null
|
||||
return fullyExpandedType(session).typeArguments.first().typeOrDefault(session.builtinTypes.nothingType.type)
|
||||
}
|
||||
|
||||
fun ConeKotlinType.returnType(session: FirSession): ConeKotlinType {
|
||||
require(this is ConeClassLikeType)
|
||||
return fullyExpandedType(session).typeArguments.last().typeOrDefault(session.builtinTypes.nullableAnyType.type)
|
||||
}
|
||||
|
||||
fun ConeKotlinType.valueParameterTypesIncludingReceiver(session: FirSession): List<ConeKotlinType> {
|
||||
require(this is ConeClassLikeType)
|
||||
return fullyExpandedType(session).typeArguments.dropLast(1).map { it.typeOrDefault(session.builtinTypes.nothingType.type) }
|
||||
}
|
||||
|
||||
val FirAnonymousFunction.returnType: ConeKotlinType? get() = returnTypeRef.coneTypeSafe()
|
||||
val FirAnonymousFunction.receiverType: ConeKotlinType? get() = receiverTypeRef?.coneTypeSafe()
|
||||
|
||||
fun ConeTypeContext.isTypeMismatchDueToNullability(
|
||||
actualType: ConeKotlinType,
|
||||
expectedType: ConeKotlinType
|
||||
): Boolean {
|
||||
return actualType.isNullableType() && !expectedType.isNullableType() && AbstractTypeChecker.isSubtypeOf(
|
||||
this,
|
||||
actualType,
|
||||
expectedType.withNullability(ConeNullability.NULLABLE, this)
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.fir.types
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.FirSessionComponent
|
||||
import org.jetbrains.kotlin.fir.languageVersionSettings
|
||||
|
||||
class TypeComponents(val session: FirSession) : FirSessionComponent {
|
||||
val typeContext: ConeInferenceContext = object : ConeInferenceContext {
|
||||
override val session: FirSession
|
||||
get() = this@TypeComponents.session
|
||||
}
|
||||
|
||||
val typeApproximator: ConeTypeApproximator = ConeTypeApproximator(typeContext, session.languageVersionSettings)
|
||||
}
|
||||
|
||||
private val FirSession.typeComponents: TypeComponents by FirSession.sessionComponentAccessor()
|
||||
|
||||
val FirSession.typeContext: ConeInferenceContext
|
||||
get() = typeComponents.typeContext
|
||||
|
||||
val FirSession.typeApproximator: ConeTypeApproximator
|
||||
get() = typeComponents.typeApproximator
|
||||
@@ -0,0 +1,556 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.fir.types
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.descriptors.Visibility
|
||||
import org.jetbrains.kotlin.fir.*
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.visibility
|
||||
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap
|
||||
import org.jetbrains.kotlin.fir.resolve.toSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterLookupTag
|
||||
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.ConeClassLookupTagWithFixedSymbol
|
||||
import org.jetbrains.kotlin.fir.types.builder.buildErrorTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
|
||||
import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl
|
||||
import org.jetbrains.kotlin.resolve.calls.NewCommonSuperTypeCalculator
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.model.*
|
||||
|
||||
fun ConeInferenceContext.commonSuperTypeOrNull(types: List<ConeKotlinType>): ConeKotlinType? {
|
||||
return when (types.size) {
|
||||
0 -> null
|
||||
1 -> types.first()
|
||||
else -> with(NewCommonSuperTypeCalculator) {
|
||||
commonSuperType(types) as ConeKotlinType
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun ConeInferenceContext.intersectTypesOrNull(types: List<ConeKotlinType>): ConeKotlinType? {
|
||||
return when (types.size) {
|
||||
0 -> null
|
||||
1 -> types.first()
|
||||
else -> ConeTypeIntersector.intersectTypes(this, types)
|
||||
}
|
||||
}
|
||||
|
||||
fun TypeCheckerProviderContext.equalTypes(a: ConeKotlinType, b: ConeKotlinType): Boolean =
|
||||
AbstractTypeChecker.equalTypes(this, a, b)
|
||||
|
||||
private fun ConeTypeContext.makesSenseToBeDefinitelyNotNull(type: ConeKotlinType): Boolean = when (type) {
|
||||
is ConeTypeParameterType -> type.isNullableType()
|
||||
// Actually, this branch should work for type parameters as well, but it breaks some cases. See KT-40114.
|
||||
// Basically, if we have `T : X..X?`, then `T <: Any` but we still have `T` != `T & Any`.
|
||||
is ConeTypeVariableType, is ConeCapturedType ->
|
||||
!AbstractNullabilityChecker.isSubtypeOfAny(
|
||||
newTypeCheckerState(errorTypesEqualToAnything = false, stubTypesEqualToAnything = false), type
|
||||
)
|
||||
// For all other types `T & Any` is the same as `T` without a question mark.
|
||||
// TODO: not true for flexible types.
|
||||
else -> false
|
||||
}
|
||||
|
||||
// TODO: leave only one of `create` and `makeConeTypeDefinitelyNotNullOrNotNull`
|
||||
fun ConeDefinitelyNotNullType.Companion.create(
|
||||
original: ConeKotlinType,
|
||||
typeContext: ConeTypeContext
|
||||
): ConeDefinitelyNotNullType? {
|
||||
return when {
|
||||
original is ConeDefinitelyNotNullType -> original
|
||||
typeContext.makesSenseToBeDefinitelyNotNull(original) -> ConeDefinitelyNotNullType(original)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
fun ConeKotlinType.makeConeTypeDefinitelyNotNullOrNotNull(typeContext: ConeTypeContext): ConeKotlinType {
|
||||
if (this is ConeIntersectionType) {
|
||||
return ConeIntersectionType(intersectedTypes.map { it.makeConeTypeDefinitelyNotNullOrNotNull(typeContext) })
|
||||
}
|
||||
return ConeDefinitelyNotNullType.create(this, typeContext) ?: this.withNullability(ConeNullability.NOT_NULL, typeContext)
|
||||
}
|
||||
|
||||
fun <T : ConeKotlinType> T.withArguments(arguments: Array<out ConeTypeProjection>, typeSystemContext: ConeTypeContext): T {
|
||||
if (this.typeArguments === arguments) {
|
||||
return this
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return when (this) {
|
||||
is ConeClassErrorType -> this
|
||||
is ConeClassLikeTypeImpl -> ConeClassLikeTypeImpl(lookupTag, arguments, nullability.isNullable) as T
|
||||
is ConeDefinitelyNotNullType -> ConeDefinitelyNotNullType(original.withArguments(arguments, typeSystemContext)) as T
|
||||
else -> error("Not supported: $this: ${this.render()}")
|
||||
}
|
||||
}
|
||||
|
||||
fun <T : ConeKotlinType> T.withArguments(replacement: (ConeTypeProjection) -> ConeTypeProjection, typeSystemContext: ConeTypeContext) =
|
||||
withArguments(typeArguments.map(replacement).toTypedArray(), typeSystemContext)
|
||||
|
||||
fun <T : ConeKotlinType> T.withAttributes(attributes: ConeAttributes, typeSystemContext: ConeTypeContext): T {
|
||||
if (this.attributes == attributes) {
|
||||
return this
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return when (this) {
|
||||
is ConeClassErrorType -> this
|
||||
is ConeClassLikeTypeImpl -> ConeClassLikeTypeImpl(lookupTag, typeArguments, nullability.isNullable, attributes)
|
||||
is ConeDefinitelyNotNullType -> ConeDefinitelyNotNullType(original.withAttributes(attributes, typeSystemContext))
|
||||
is ConeTypeParameterTypeImpl -> ConeTypeParameterTypeImpl(lookupTag, nullability.isNullable, attributes)
|
||||
is ConeFlexibleType -> ConeFlexibleType(
|
||||
lowerBound.withAttributes(attributes, typeSystemContext),
|
||||
upperBound.withAttributes(attributes, typeSystemContext)
|
||||
)
|
||||
is ConeTypeVariableType -> ConeTypeVariableType(nullability, lookupTag, attributes)
|
||||
is ConeCapturedType -> ConeCapturedType(
|
||||
captureStatus, lowerType, nullability, constructor, attributes, isProjectionNotNull,
|
||||
)
|
||||
// TODO: Consider correct application of attributes to ConeIntersectionType
|
||||
// Currently, ConeAttributes.union works a bit strange, because it lefts only `other` parts
|
||||
is ConeIntersectionType -> this
|
||||
// Attributes for stub types are not supported, and it's not obvious if it should
|
||||
is ConeStubType -> this
|
||||
else -> error("Not supported: $this: ${this.render()}")
|
||||
} as T
|
||||
}
|
||||
|
||||
fun <T : ConeKotlinType> T.withNullability(
|
||||
nullability: ConeNullability,
|
||||
typeContext: ConeTypeContext,
|
||||
attributes: ConeAttributes = this.attributes,
|
||||
): T {
|
||||
if (this.nullability == nullability && this.attributes == attributes) {
|
||||
return this
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return when (this) {
|
||||
is ConeClassErrorType -> this
|
||||
is ConeClassLikeTypeImpl -> ConeClassLikeTypeImpl(lookupTag, typeArguments, nullability.isNullable, attributes)
|
||||
is ConeTypeParameterTypeImpl -> ConeTypeParameterTypeImpl(lookupTag, nullability.isNullable, attributes)
|
||||
is ConeFlexibleType -> {
|
||||
if (nullability == ConeNullability.UNKNOWN) {
|
||||
if (lowerBound.nullability != upperBound.nullability || lowerBound.nullability == ConeNullability.UNKNOWN) {
|
||||
return this
|
||||
}
|
||||
}
|
||||
coneFlexibleOrSimpleType(
|
||||
typeContext,
|
||||
lowerBound.withNullability(nullability, typeContext),
|
||||
upperBound.withNullability(nullability, typeContext)
|
||||
)
|
||||
}
|
||||
is ConeTypeVariableType -> ConeTypeVariableType(nullability, lookupTag)
|
||||
is ConeCapturedType -> ConeCapturedType(captureStatus, lowerType, nullability, constructor, attributes)
|
||||
is ConeIntersectionType -> when (nullability) {
|
||||
ConeNullability.NULLABLE -> this.mapTypes {
|
||||
it.withNullability(nullability, typeContext)
|
||||
}
|
||||
ConeNullability.UNKNOWN -> this // TODO: is that correct?
|
||||
ConeNullability.NOT_NULL -> this
|
||||
}
|
||||
is ConeStubTypeForBuilderInference -> ConeStubTypeForBuilderInference(variable, nullability)
|
||||
is ConeStubTypeForTypeVariableInSubtyping -> ConeStubTypeForTypeVariableInSubtyping(variable, nullability)
|
||||
is ConeDefinitelyNotNullType -> when (nullability) {
|
||||
ConeNullability.NOT_NULL -> this
|
||||
ConeNullability.NULLABLE -> original.withNullability(nullability, typeContext)
|
||||
ConeNullability.UNKNOWN -> original.withNullability(nullability, typeContext)
|
||||
}
|
||||
is ConeIntegerLiteralType -> ConeIntegerLiteralTypeImpl(value, isUnsigned, nullability)
|
||||
else -> error("sealed: ${this::class}")
|
||||
} as T
|
||||
}
|
||||
|
||||
fun coneFlexibleOrSimpleType(
|
||||
typeContext: ConeTypeContext,
|
||||
lowerBound: ConeKotlinType,
|
||||
upperBound: ConeKotlinType,
|
||||
): ConeKotlinType {
|
||||
if (lowerBound is ConeFlexibleType) {
|
||||
return coneFlexibleOrSimpleType(typeContext, lowerBound.lowerBound, upperBound)
|
||||
}
|
||||
if (upperBound is ConeFlexibleType) {
|
||||
return coneFlexibleOrSimpleType(typeContext, lowerBound, upperBound.upperBound)
|
||||
}
|
||||
return when {
|
||||
AbstractStrictEqualityTypeChecker.strictEqualTypes(typeContext, lowerBound, upperBound) -> lowerBound
|
||||
else -> ConeFlexibleType(lowerBound, upperBound)
|
||||
}
|
||||
}
|
||||
|
||||
fun ConeKotlinType.isExtensionFunctionType(session: FirSession): Boolean {
|
||||
val type = this.lowerBoundIfFlexible().fullyExpandedType(session)
|
||||
return type.attributes.extensionFunctionType != null
|
||||
}
|
||||
|
||||
fun FirTypeRef.isExtensionFunctionType(session: FirSession): Boolean {
|
||||
return coneTypeSafe<ConeKotlinType>()?.isExtensionFunctionType(session) == true
|
||||
}
|
||||
|
||||
fun ConeKotlinType.isUnsafeVarianceType(session: FirSession): Boolean {
|
||||
val type = this.lowerBoundIfFlexible().fullyExpandedType(session)
|
||||
return type.attributes.unsafeVarianceType != null
|
||||
}
|
||||
|
||||
fun ConeKotlinType.toSymbol(session: FirSession): FirBasedSymbol<*>? {
|
||||
return (this as? ConeLookupTagBasedType)?.lookupTag?.toSymbol(session)
|
||||
}
|
||||
|
||||
fun ConeKotlinType.toFirResolvedTypeRef(
|
||||
source: FirSourceElement? = null,
|
||||
delegatedTypeRef: FirTypeRef? = null
|
||||
): FirResolvedTypeRef {
|
||||
return if (this is ConeKotlinErrorType) {
|
||||
buildErrorTypeRef {
|
||||
this.source = source
|
||||
diagnostic = this@toFirResolvedTypeRef.diagnostic
|
||||
this.delegatedTypeRef = delegatedTypeRef
|
||||
}
|
||||
} else {
|
||||
buildResolvedTypeRef {
|
||||
this.source = source
|
||||
type = this@toFirResolvedTypeRef
|
||||
this.delegatedTypeRef = delegatedTypeRef
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun FirTypeRef.isUnsafeVarianceType(session: FirSession): Boolean {
|
||||
return coneTypeSafe<ConeKotlinType>()?.isUnsafeVarianceType(session) == true
|
||||
}
|
||||
|
||||
fun FirTypeRef.hasEnhancedNullability(): Boolean =
|
||||
coneTypeSafe<ConeKotlinType>()?.hasEnhancedNullability == true
|
||||
|
||||
fun FirTypeRef.withoutEnhancedNullability(typeSystemContext: ConeTypeContext): FirTypeRef {
|
||||
require(this is FirResolvedTypeRef)
|
||||
if (!hasEnhancedNullability()) return this
|
||||
return buildResolvedTypeRef {
|
||||
source = this@withoutEnhancedNullability.source
|
||||
type = this@withoutEnhancedNullability.type.withAttributes(
|
||||
ConeAttributes.create(
|
||||
this@withoutEnhancedNullability.type.attributes.filter { it != CompilerConeAttributes.EnhancedNullability }
|
||||
),
|
||||
typeSystemContext,
|
||||
)
|
||||
annotations += this@withoutEnhancedNullability.annotations
|
||||
}
|
||||
}
|
||||
|
||||
// Unlike other cases, return types may be implicit, i.e. unresolved
|
||||
// But in that cases newType should also be `null`
|
||||
fun FirTypeRef.withReplacedReturnType(newType: ConeKotlinType?): FirTypeRef {
|
||||
require(this is FirResolvedTypeRef || newType == null)
|
||||
if (newType == null) return this
|
||||
|
||||
return resolvedTypeFromPrototype(newType)
|
||||
}
|
||||
|
||||
fun FirTypeRef.withReplacedConeType(
|
||||
newType: ConeKotlinType?,
|
||||
firFakeSourceElementKind: FirFakeSourceElementKind? = null
|
||||
): FirResolvedTypeRef {
|
||||
require(this is FirResolvedTypeRef)
|
||||
if (newType == null) return this
|
||||
|
||||
val newSource =
|
||||
if (firFakeSourceElementKind != null)
|
||||
this.source?.fakeElement(firFakeSourceElementKind)
|
||||
else
|
||||
this.source
|
||||
|
||||
return if (newType is ConeKotlinErrorType) {
|
||||
buildErrorTypeRef {
|
||||
source = newSource
|
||||
diagnostic = newType.diagnostic
|
||||
}
|
||||
} else {
|
||||
buildResolvedTypeRef {
|
||||
source = newSource
|
||||
type = newType
|
||||
annotations += this@withReplacedConeType.annotations
|
||||
delegatedTypeRef = this@withReplacedConeType.delegatedTypeRef
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun FirTypeRef.approximated(
|
||||
typeApproximator: ConeTypeApproximator,
|
||||
toSuper: Boolean,
|
||||
): FirTypeRef {
|
||||
val alternativeType = (coneType as? ConeIntersectionType)?.alternativeType ?: coneType
|
||||
if (alternativeType !== coneType && !alternativeType.requiresApproximationInPublicPosition()) {
|
||||
return withReplacedConeType(alternativeType)
|
||||
}
|
||||
val approximatedType = if (toSuper)
|
||||
typeApproximator.approximateToSuperType(alternativeType, TypeApproximatorConfiguration.PublicDeclaration)
|
||||
else
|
||||
typeApproximator.approximateToSubType(alternativeType, TypeApproximatorConfiguration.PublicDeclaration)
|
||||
return withReplacedConeType(approximatedType)
|
||||
}
|
||||
|
||||
fun FirTypeRef.approximatedIfNeededOrSelf(
|
||||
approximator: ConeTypeApproximator,
|
||||
containingCallableVisibility: Visibility?,
|
||||
typeSystemContext: ConeTypeContext,
|
||||
isInlineFunction: Boolean = false,
|
||||
): FirTypeRef {
|
||||
val approximated = if (containingCallableVisibility == Visibilities.Public || containingCallableVisibility == Visibilities.Protected)
|
||||
approximatedForPublicPosition(approximator)
|
||||
else
|
||||
this
|
||||
return approximated.hideLocalTypeIfNeeded(containingCallableVisibility, isInlineFunction).withoutEnhancedNullability(typeSystemContext)
|
||||
}
|
||||
|
||||
fun FirTypeRef.approximatedForPublicPosition(approximator: ConeTypeApproximator): FirTypeRef =
|
||||
if (this is FirResolvedTypeRef && type.requiresApproximationInPublicPosition())
|
||||
this.approximated(approximator, toSuper = true)
|
||||
else
|
||||
this
|
||||
|
||||
private fun ConeKotlinType.requiresApproximationInPublicPosition(): Boolean = contains {
|
||||
it is ConeIntegerLiteralType || it is ConeCapturedType || it is ConeDefinitelyNotNullType || it is ConeIntersectionType
|
||||
}
|
||||
|
||||
/*
|
||||
* Suppose a function without an explicit return type just returns an anonymous object:
|
||||
*
|
||||
* fun foo(...) = object : ObjectSuperType {
|
||||
* override fun ...
|
||||
* }
|
||||
*
|
||||
* Without unwrapping, the return type ended up with that anonymous object (<no name provided>), while the resolved super type, which
|
||||
* acts like an implementing interface, is a better fit. In fact, exposing an anonymous object types is prohibited for certain cases,
|
||||
* e.g., KT-33917. We can also apply this to any local types.
|
||||
*/
|
||||
private fun FirTypeRef.hideLocalTypeIfNeeded(
|
||||
containingCallableVisibility: Visibility?,
|
||||
isInlineFunction: Boolean = false
|
||||
): FirTypeRef {
|
||||
if (!shouldHideLocalType(containingCallableVisibility, isInlineFunction)) return this
|
||||
val firClass =
|
||||
(((this as? FirResolvedTypeRef)
|
||||
?.type as? ConeClassLikeType)
|
||||
?.lookupTag as? ConeClassLookupTagWithFixedSymbol)
|
||||
?.symbol?.fir
|
||||
if (firClass !is FirAnonymousObject) {
|
||||
// NB: local classes are acceptable here, but reported by EXPOSED_* checkers as errors
|
||||
return this
|
||||
}
|
||||
if (firClass.superTypeRefs.size > 1) {
|
||||
// NB: don't approximate so members can be resolved. The error is reported by FirAmbiguousAnonymousTypeChecker.
|
||||
return this
|
||||
}
|
||||
val superType = firClass.superTypeRefs.single()
|
||||
if (superType is FirResolvedTypeRef) {
|
||||
val newKind = source?.kind
|
||||
return if (newKind is FirFakeSourceElementKind) superType.copyWithNewSourceKind(newKind) else superType
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
fun shouldHideLocalType(containingCallableVisibility: Visibility?, isInlineFunction: Boolean): Boolean {
|
||||
if (containingCallableVisibility == null) {
|
||||
return false
|
||||
}
|
||||
// Approximate types for non-private (all but package private or private) members.
|
||||
// Also private inline functions, as per KT-33917.
|
||||
return containingCallableVisibility == Visibilities.Public ||
|
||||
containingCallableVisibility == Visibilities.Protected ||
|
||||
containingCallableVisibility == Visibilities.Internal ||
|
||||
(containingCallableVisibility == Visibilities.Private && isInlineFunction)
|
||||
}
|
||||
|
||||
fun FirDeclaration.visibilityForApproximation(container: FirDeclaration?): Visibility {
|
||||
if (this !is FirMemberDeclaration) return Visibilities.Local
|
||||
val containerVisibility =
|
||||
if (container == null || container is FirFile) Visibilities.Public
|
||||
else (container as? FirRegularClass)?.visibility ?: Visibilities.Local
|
||||
if (containerVisibility == Visibilities.Local || visibility == Visibilities.Local) return Visibilities.Local
|
||||
if (containerVisibility == Visibilities.Private) return Visibilities.Private
|
||||
return visibility
|
||||
}
|
||||
|
||||
|
||||
fun ConeTypeContext.captureFromArgumentsInternal(type: ConeKotlinType, status: CaptureStatus): ConeKotlinType? {
|
||||
val capturedArguments = captureArguments(type, status) ?: return null
|
||||
return if (type is ConeFlexibleType) {
|
||||
ConeFlexibleType(
|
||||
type.lowerBound.withArguments(capturedArguments, this),
|
||||
type.upperBound.withArguments(capturedArguments, this),
|
||||
)
|
||||
} else {
|
||||
type.withArguments(capturedArguments, this)
|
||||
}
|
||||
}
|
||||
|
||||
fun ConeTypeContext.captureArguments(type: ConeKotlinType, status: CaptureStatus): Array<ConeKotlinType>? {
|
||||
val argumentsCount = type.typeArguments.size
|
||||
if (argumentsCount == 0) return null
|
||||
|
||||
val typeConstructor = type.typeConstructor()
|
||||
if (argumentsCount != typeConstructor.parametersCount()) return null
|
||||
|
||||
if (type.typeArguments.all { it !is ConeStarProjection && it.kind == ProjectionKind.INVARIANT }) return null
|
||||
|
||||
val newArguments: Array<ConeKotlinType> = Array(argumentsCount) { index ->
|
||||
val argument = type.typeArguments[index]
|
||||
if (argument !is ConeStarProjection && argument.kind == ProjectionKind.INVARIANT)
|
||||
return@Array argument.type!! // only star projection can return null, but it's guarded above
|
||||
|
||||
val lowerType = if (argument !is ConeStarProjection && argument.getVariance() == TypeVariance.IN) {
|
||||
(argument as ConeKotlinTypeProjection).type
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
ConeCapturedType(status, lowerType, argument, typeConstructor.getParameter(index))
|
||||
}
|
||||
|
||||
val substitution = (0 until argumentsCount).associate { index ->
|
||||
(typeConstructor.getParameter(index) as ConeTypeParameterLookupTag).symbol to (newArguments[index])
|
||||
}
|
||||
val substitutor = substitutorByMap(substitution, session)
|
||||
|
||||
for (index in 0 until argumentsCount) {
|
||||
val oldArgument = type.typeArguments[index]
|
||||
val newArgument = newArguments[index]
|
||||
|
||||
if (oldArgument !is ConeStarProjection && oldArgument.kind == ProjectionKind.INVARIANT) continue
|
||||
|
||||
val parameter = typeConstructor.getParameter(index)
|
||||
val upperBounds = (0 until parameter.upperBoundCount()).mapTo(mutableListOf()) { paramIndex ->
|
||||
substitutor.safeSubstitute(
|
||||
this as TypeSystemInferenceExtensionContext, parameter.getUpperBound(paramIndex)
|
||||
)
|
||||
}
|
||||
|
||||
if (!oldArgument.isStarProjection() && oldArgument.getVariance() == TypeVariance.OUT) {
|
||||
upperBounds += oldArgument.getType()
|
||||
}
|
||||
|
||||
require(newArgument is ConeCapturedType)
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
newArgument.constructor.supertypes = upperBounds as List<ConeKotlinType>
|
||||
}
|
||||
return newArguments
|
||||
}
|
||||
|
||||
fun ConeTypeContext.captureFromExpressionInternal(type: ConeKotlinType): ConeKotlinType? {
|
||||
if (type !is ConeIntersectionType && type !is ConeFlexibleType) {
|
||||
return captureFromArgumentsInternal(type, CaptureStatus.FROM_EXPRESSION)
|
||||
}
|
||||
/*
|
||||
* We capture arguments in the intersection types in specific way:
|
||||
* 1) Firstly, we create captured arguments for all type arguments grouped by a type constructor* and a type argument's type.
|
||||
* It means, that we create only one captured argument for two types `Foo<*>` and `Foo<*>?` within a flexible type, for instance.
|
||||
* * In addition to grouping by type constructors, we look at possibility locating of two types in different bounds of the same flexible type.
|
||||
* This is necessary in order to create the same captured arguments,
|
||||
* for example, for `MutableList` in the lower bound of the flexible type and for `List` in the upper one.
|
||||
* Example: MutableList<*>..List<*>? -> MutableList<Captured1(*)>..List<Captured2(*)>?, Captured1(*) and Captured2(*) are the same.
|
||||
* 2) Secondly, we replace type arguments with captured arguments by given a type constructor and type arguments.
|
||||
*/
|
||||
val capturedArgumentsByComponents = captureArgumentsForIntersectionType(type) ?: return null
|
||||
|
||||
// We reuse `TypeToCapture` for some types, suitability to reuse defines by `isSuitableForType`
|
||||
fun findCorrespondingCapturedArgumentsForType(type: ConeKotlinType) =
|
||||
capturedArgumentsByComponents.find { typeToCapture -> typeToCapture.isSuitableForType(type, this) }?.capturedArguments
|
||||
|
||||
fun replaceArgumentsWithCapturedArgumentsByIntersectionComponents(typeToReplace: ConeKotlinType): List<ConeKotlinType> {
|
||||
return if (typeToReplace is ConeIntersectionType) {
|
||||
typeToReplace.intersectedTypes.map { componentType ->
|
||||
val capturedArguments = findCorrespondingCapturedArgumentsForType(componentType)
|
||||
?: return@map componentType
|
||||
componentType.withArguments(capturedArguments, this)
|
||||
}
|
||||
} else {
|
||||
val capturedArguments = findCorrespondingCapturedArgumentsForType(typeToReplace)
|
||||
?: return listOf(typeToReplace)
|
||||
listOf(typeToReplace.withArguments(capturedArguments, this))
|
||||
}
|
||||
}
|
||||
|
||||
return if (type is ConeFlexibleType) {
|
||||
val lowerIntersectedType = intersectTypes(replaceArgumentsWithCapturedArgumentsByIntersectionComponents(type.lowerBound))
|
||||
.withNullability(type.lowerBound.isMarkedNullable) as ConeKotlinType
|
||||
val upperIntersectedType = intersectTypes(replaceArgumentsWithCapturedArgumentsByIntersectionComponents(type.upperBound))
|
||||
.withNullability(type.upperBound.isMarkedNullable) as ConeKotlinType
|
||||
|
||||
ConeFlexibleType(lowerIntersectedType, upperIntersectedType)
|
||||
} else {
|
||||
intersectTypes(replaceArgumentsWithCapturedArgumentsByIntersectionComponents(type)).withNullability(type.isMarkedNullable) as ConeKotlinType
|
||||
}
|
||||
}
|
||||
|
||||
private fun ConeTypeContext.captureArgumentsForIntersectionType(type: ConeKotlinType): List<CapturedArguments>? {
|
||||
// It's possible to have one of the bounds as non-intersection type
|
||||
fun getTypesToCapture(type: ConeKotlinType) =
|
||||
if (type is ConeIntersectionType) type.intersectedTypes else listOf(type)
|
||||
|
||||
val filteredTypesToCapture =
|
||||
when (type) {
|
||||
is ConeFlexibleType -> {
|
||||
val typesToCapture = getTypesToCapture(type.lowerBound) + getTypesToCapture(type.upperBound)
|
||||
typesToCapture.distinctBy {
|
||||
(ConeFlexibleTypeBoundsChecker.getBaseBoundFqNameByMutability(it) ?: it.typeConstructor(this)) to it.typeArguments
|
||||
}
|
||||
}
|
||||
is ConeIntersectionType -> type.intersectedTypes
|
||||
else -> error("Should not be here")
|
||||
}
|
||||
|
||||
var changed = false
|
||||
|
||||
val capturedArgumentsByTypes = filteredTypesToCapture.mapNotNull { typeToCapture ->
|
||||
val capturedArguments = captureArguments(typeToCapture, CaptureStatus.FROM_EXPRESSION)
|
||||
?: return@mapNotNull null
|
||||
changed = true
|
||||
CapturedArguments(capturedArguments, originalType = typeToCapture)
|
||||
}
|
||||
|
||||
if (!changed) return null
|
||||
|
||||
return capturedArgumentsByTypes
|
||||
}
|
||||
|
||||
private class CapturedArguments(val capturedArguments: Array<out ConeTypeProjection>, private val originalType: ConeKotlinType) {
|
||||
fun isSuitableForType(type: ConeKotlinType, context: ConeTypeContext): Boolean {
|
||||
val areArgumentsMatched = type.typeArguments.withIndex().all { (i, typeArgumentsType) ->
|
||||
originalType.typeArguments.size > i && typeArgumentsType == originalType.typeArguments[i]
|
||||
}
|
||||
|
||||
if (!areArgumentsMatched) return false
|
||||
|
||||
val areConstructorsMatched = originalType.typeConstructor(context) == type.typeConstructor(context)
|
||||
|| ConeFlexibleTypeBoundsChecker.areTypesMayBeLowerAndUpperBoundsOfSameFlexibleTypeByMutability(originalType, type)
|
||||
|
||||
if (!areConstructorsMatched) return false
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
fun ConeKotlinType.isSubtypeOf(superType: ConeKotlinType, session: FirSession): Boolean =
|
||||
AbstractTypeChecker.isSubtypeOf(
|
||||
session.typeContext.newTypeCheckerState(errorTypesEqualToAnything = false, stubTypesEqualToAnything = false),
|
||||
this, superType,
|
||||
)
|
||||
|
||||
fun FirTypedDeclaration.isSubtypeOf(
|
||||
other: FirTypedDeclaration,
|
||||
typeCheckerContext: TypeCheckerState
|
||||
): Boolean {
|
||||
return AbstractTypeChecker.isSubtypeOf(
|
||||
typeCheckerContext,
|
||||
returnTypeRef.coneType,
|
||||
other.returnTypeRef.coneType
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user