[FIR] Provide implementation of ExpectActualMatchingContext for FIR

^KT-58578
This commit is contained in:
Dmitriy Novozhilov
2023-05-11 13:26:49 +03:00
committed by Space Team
parent 8338370fbd
commit b19116d3af
11 changed files with 370 additions and 609 deletions
@@ -0,0 +1,284 @@
/*
* Copyright 2010-2023 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.mpp
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.descriptors.isEnumClass
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.utils.*
import org.jetbrains.kotlin.fir.isSubstitutionOrIntersectionOverride
import org.jetbrains.kotlin.fir.resolve.*
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
import org.jetbrains.kotlin.fir.scopes.*
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.mpp.*
import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.calls.mpp.ExpectActualMatchingContext
import org.jetbrains.kotlin.types.AbstractTypeChecker
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
import org.jetbrains.kotlin.types.model.SimpleTypeMarker
import org.jetbrains.kotlin.types.model.TypeSubstitutorMarker
import org.jetbrains.kotlin.types.model.TypeSystemInferenceExtensionContext
import org.jetbrains.kotlin.utils.addIfNotNull
import org.jetbrains.kotlin.utils.addToStdlib.UnsafeCastFunction
import org.jetbrains.kotlin.utils.addToStdlib.castAll
class FirExpectActualMatchingContext(
private val actualSession: FirSession,
private val scopeSession: ScopeSession
) : ExpectActualMatchingContext<FirBasedSymbol<*>>, TypeSystemInferenceExtensionContext by actualSession.typeContext {
override val shouldCheckReturnTypesOfCallables: Boolean
get() = false
private fun CallableSymbolMarker.asSymbol(): FirCallableSymbol<*> = this as FirCallableSymbol<*>
private fun FunctionSymbolMarker.asSymbol(): FirFunctionSymbol<*> = this as FirFunctionSymbol<*>
private fun PropertySymbolMarker.asSymbol(): FirPropertySymbol = this as FirPropertySymbol
private fun ValueParameterSymbolMarker.asSymbol(): FirValueParameterSymbol = this as FirValueParameterSymbol
private fun TypeParameterSymbolMarker.asSymbol(): FirTypeParameterSymbol = this as FirTypeParameterSymbol
private fun ClassLikeSymbolMarker.asSymbol(): FirClassLikeSymbol<*> = this as FirClassLikeSymbol<*>
private fun RegularClassSymbolMarker.asSymbol(): FirRegularClassSymbol = this as FirRegularClassSymbol
private fun TypeAliasSymbolMarker.asSymbol(): FirTypeAliasSymbol = this as FirTypeAliasSymbol
override val RegularClassSymbolMarker.classId: ClassId
get() = asSymbol().classId
override val TypeAliasSymbolMarker.classId: ClassId
get() = asSymbol().classId
override val CallableSymbolMarker.callableId: CallableId
get() = asSymbol().callableId
override val TypeParameterSymbolMarker.parameterName: Name
get() = asSymbol().name
override val ValueParameterSymbolMarker.parameterName: Name
get() = asSymbol().name
override fun TypeAliasSymbolMarker.expandToRegularClass(): RegularClassSymbolMarker? {
return asSymbol()
.resolvedExpandedTypeRef
.coneType
.fullyExpandedType(actualSession)
.toSymbol(actualSession) as? FirRegularClassSymbol
}
override val RegularClassSymbolMarker.classKind: ClassKind
get() = asSymbol().classKind
override val RegularClassSymbolMarker.isCompanion: Boolean
get() = asSymbol().resolvedStatus.isCompanion
override val RegularClassSymbolMarker.isInner: Boolean
get() = asSymbol().resolvedStatus.isInner
override val RegularClassSymbolMarker.isInline: Boolean
get() = asSymbol().resolvedStatus.isInline
override val RegularClassSymbolMarker.isValue: Boolean
get() = asSymbol().resolvedStatus.isInline
override val RegularClassSymbolMarker.isFun: Boolean
get() = asSymbol().resolvedStatus.isFun
override val ClassLikeSymbolMarker.typeParameters: List<TypeParameterSymbolMarker>
get() = asSymbol().typeParameterSymbols
override val ClassLikeSymbolMarker.modality: Modality?
get() = asSymbol().resolvedStatus.modality
override val ClassLikeSymbolMarker.visibility: Visibility
get() = asSymbol().resolvedStatus.visibility
override val CallableSymbolMarker.modality: Modality?
get() = asSymbol().resolvedStatus.modality
override val CallableSymbolMarker.visibility: Visibility
get() = asSymbol().resolvedStatus.visibility
override val CallableSymbolMarker.isExpect: Boolean
get() = asSymbol().resolvedStatus.isExpect
override val CallableSymbolMarker.isInline: Boolean
get() = asSymbol().resolvedStatus.isInline
override val CallableSymbolMarker.isSuspend: Boolean
get() = asSymbol().resolvedStatus.isSuspend
override val CallableSymbolMarker.isExternal: Boolean
get() = asSymbol().resolvedStatus.isExternal
override val CallableSymbolMarker.isInfix: Boolean
get() = asSymbol().resolvedStatus.isInfix
override val CallableSymbolMarker.isOperator: Boolean
get() = asSymbol().resolvedStatus.isOperator
override val CallableSymbolMarker.isTailrec: Boolean
get() = asSymbol().resolvedStatus.isTailRec
override val PropertySymbolMarker.isVar: Boolean
get() = asSymbol().isVar
override val PropertySymbolMarker.isLateinit: Boolean
get() = asSymbol().resolvedStatus.isLateInit
override val PropertySymbolMarker.isConst: Boolean
get() = asSymbol().resolvedStatus.isConst
override val PropertySymbolMarker.setter: FunctionSymbolMarker?
get() = asSymbol().setterSymbol
@OptIn(UnsafeCastFunction::class)
override fun createExpectActualTypeParameterSubstitutor(
expectTypeParameters: List<TypeParameterSymbolMarker>,
actualTypeParameters: List<TypeParameterSymbolMarker>,
parentSubstitutor: TypeSubstitutorMarker?,
): TypeSubstitutorMarker {
return createExpectActualTypeParameterSubstitutor(
expectTypeParameters.castAll<FirTypeParameterSymbol>(),
actualTypeParameters.castAll<FirTypeParameterSymbol>(),
actualSession,
parentSubstitutor as ConeSubstitutor?
)
}
override val RegularClassSymbolMarker.superTypes: List<KotlinTypeMarker>
get() = asSymbol().resolvedSuperTypes
override fun RegularClassSymbolMarker.collectAllMembers(isActualDeclaration: Boolean): List<FirBasedSymbol<*>> {
val symbol = asSymbol()
val session = when (isActualDeclaration) {
true -> actualSession
false -> symbol.moduleData.session
}
val scope = symbol.defaultType()
.scope(useSiteSession = session, scopeSession, FakeOverrideTypeCalculator.DoNothing, requiredPhase = FirResolvePhase.STATUS)
?: return emptyList()
return mutableListOf<FirBasedSymbol<*>>().apply {
for (name in scope.getCallableNames()) {
scope.getMembersTo(this, name)
}
// TODO: replace with scope lookup
for (name in symbol.declarationSymbols.mapNotNull { (it as? FirRegularClassSymbol)?.classId?.shortClassName }) {
addIfNotNull(scope.getSingleClassifier(name) as? FirRegularClassSymbol)
}
getConstructorsTo(this, scope)
}
}
override fun RegularClassSymbolMarker.getMembersForExpectClass(name: Name): List<FirCallableSymbol<*>> {
val symbol = asSymbol()
val scope = symbol.defaultType()
.scope(
useSiteSession = symbol.moduleData.session,
scopeSession,
FakeOverrideTypeCalculator.DoNothing,
requiredPhase = FirResolvePhase.STATUS
)
?: return emptyList()
return mutableListOf<FirCallableSymbol<*>>().apply {
scope.getMembersTo(this, name)
}
}
fun FirClassSymbol<*>.getConstructors(
scopeSession: ScopeSession,
session: FirSession = moduleData.session
): Collection<FirConstructorSymbol> = mutableListOf<FirConstructorSymbol>().apply {
getConstructorsTo(
this,
unsubstitutedScope(
session,
scopeSession,
withForcedTypeCalculator = false,
memberRequiredPhase = FirResolvePhase.STATUS,
)
)
}
private fun getConstructorsTo(destination: MutableList<in FirConstructorSymbol>, scope: FirTypeScope) {
scope.getDeclaredConstructors().mapTo(destination) { it }
}
private fun FirTypeScope.getMembersTo(destination: MutableList<in FirCallableSymbol<*>>, name: Name) {
processFunctionsByName(name) { destination.add(it) }
processPropertiesByName(name) { destination.add(it) }
}
override fun RegularClassSymbolMarker.collectEnumEntryNames(): List<Name> {
return asSymbol().fir.collectEnumEntries().map { it.name }
}
override val CallableSymbolMarker.dispatchReceiverType: SimpleTypeMarker?
get() = asSymbol().dispatchReceiverType
override val CallableSymbolMarker.extensionReceiverType: KotlinTypeMarker?
get() = asSymbol().resolvedReceiverTypeRef?.coneType
override val CallableSymbolMarker.returnType: KotlinTypeMarker
get() = asSymbol().resolvedReturnType.type
override val CallableSymbolMarker.typeParameters: List<TypeParameterSymbolMarker>
get() = asSymbol().typeParameterSymbols
override val FunctionSymbolMarker.valueParameters: List<ValueParameterSymbolMarker>
get() = asSymbol().valueParameterSymbols
override val ValueParameterSymbolMarker.isVararg: Boolean
get() = asSymbol().isVararg
override val ValueParameterSymbolMarker.isNoinline: Boolean
get() = asSymbol().isNoinline
override val ValueParameterSymbolMarker.isCrossinline: Boolean
get() = asSymbol().isCrossinline
override val ValueParameterSymbolMarker.hasDefaultValue: Boolean
get() = asSymbol().hasDefaultValue
override fun CallableSymbolMarker.isAnnotationConstructor(): Boolean {
val symbol = asSymbol()
return symbol.isAnnotationConstructor(symbol.moduleData.session)
}
override val TypeParameterSymbolMarker.bounds: List<KotlinTypeMarker>
get() = asSymbol().resolvedBounds.map { it.coneType }
override val TypeParameterSymbolMarker.variance: Variance
get() = asSymbol().variance
override val TypeParameterSymbolMarker.isReified: Boolean
get() = asSymbol().isReified
override fun areCompatibleExpectActualTypes(
expectType: KotlinTypeMarker?,
actualType: KotlinTypeMarker?,
): Boolean {
if (expectType == null) return actualType == null
if (actualType == null) return false
return AbstractTypeChecker.equalTypes(
actualSession.typeContext.newTypeCheckerState(errorTypesEqualToAnything = true, stubTypesEqualToAnything = false),
expectType,
actualType
)
}
override fun RegularClassSymbolMarker.isNotSamInterface(): Boolean {
val type = asSymbol().defaultType()
val isSam = FirSamResolver(actualSession, scopeSession).isSamType(type)
return !isSam
}
override fun CallableSymbolMarker.shouldSkipMatching(containingExpectClass: RegularClassSymbolMarker): Boolean {
val symbol = asSymbol()
val classSymbol = containingExpectClass.asSymbol()
val isConstructor = symbol is FirConstructorSymbol
if (isConstructor && classSymbol.classKind.isEnumClass) {
/*
* Expect enums in FIR have (expect) constructors, but actually there is no need to map them
*/
return true
}
if (!isConstructor && symbol.dispatchReceiverType?.classId != classSymbol.classId) {
// Skip fake overrides
return true
}
return symbol.isSubstitutionOrIntersectionOverride // Skip fake overrides
|| !symbol.isExpect // Skip non-expect declarations like equals, hashCode, toString and any inherited declarations from non-expect super types
}
override val CallableSymbolMarker.hasStableParameterNames: Boolean
get() = when (asSymbol().origin) {
is FirDeclarationOrigin.Java,
FirDeclarationOrigin.Enhancement,
FirDeclarationOrigin.DynamicScope -> false
else -> true
}
}
@@ -5,30 +5,18 @@
package org.jetbrains.kotlin.fir.resolve.transformers.mpp package org.jetbrains.kotlin.fir.resolve.transformers.mpp
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Modality.*
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.utils.*
import org.jetbrains.kotlin.fir.resolve.* import org.jetbrains.kotlin.fir.resolve.*
import org.jetbrains.kotlin.fir.resolve.providers.dependenciesSymbolProvider import org.jetbrains.kotlin.fir.resolve.providers.dependenciesSymbolProvider
import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
import org.jetbrains.kotlin.fir.scopes.*
import org.jetbrains.kotlin.fir.scopes.impl.FirPackageMemberScope import org.jetbrains.kotlin.fir.scopes.impl.FirPackageMemberScope
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.* import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.calls.mpp.AbstractExpectActualCompatibilityChecker
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility import org.jetbrains.kotlin.mpp.CallableSymbolMarker
import org.jetbrains.kotlin.utils.SmartList
import org.jetbrains.kotlin.utils.addIfNotNull
import org.jetbrains.kotlin.utils.addToStdlib.enumMapOf
import org.jetbrains.kotlin.utils.addToStdlib.enumSetOf
import org.jetbrains.kotlin.utils.keysToMap
import java.util.*
object FirExpectActualResolver { object FirExpectActualResolver {
fun findExpectForActual( fun findExpectForActual(
@@ -36,593 +24,70 @@ object FirExpectActualResolver {
useSiteSession: FirSession, useSiteSession: FirSession,
scopeSession: ScopeSession scopeSession: ScopeSession
): ExpectForActualData? { ): ExpectForActualData? {
return when (actualSymbol) { val context = FirExpectActualMatchingContext(useSiteSession, scopeSession)
is FirCallableSymbol<*> -> { with(context) {
val callableId = actualSymbol.callableId val result = when (actualSymbol) {
val classId = callableId.classId is FirCallableSymbol<*> -> {
var parentSubstitutor: ConeSubstitutor? = null val callableId = actualSymbol.callableId
var expectContainingClass: FirRegularClassSymbol? = null val classId = callableId.classId
var actualContainingClass: FirRegularClassSymbol? = null var parentSubstitutor: ConeSubstitutor? = null
val candidates = when { var expectContainingClass: FirRegularClassSymbol? = null
classId != null -> { var actualContainingClass: FirRegularClassSymbol? = null
expectContainingClass = useSiteSession.dependenciesSymbolProvider.getClassLikeSymbolByClassId(classId)?.let { val candidates = when {
it.fullyExpandedClass(it.moduleData.session) classId != null -> {
expectContainingClass = useSiteSession.dependenciesSymbolProvider.getClassLikeSymbolByClassId(classId)?.let {
it.fullyExpandedClass(it.moduleData.session)
}
actualContainingClass = useSiteSession.symbolProvider.getClassLikeSymbolByClassId(classId)
?.fullyExpandedClass(useSiteSession)
val expectTypeParameters = expectContainingClass?.typeParameterSymbols.orEmpty()
val actualTypeParameters = actualContainingClass
?.typeParameterSymbols
.orEmpty()
parentSubstitutor = createExpectActualTypeParameterSubstitutor(
expectTypeParameters,
actualTypeParameters,
useSiteSession,
)
when (actualSymbol) {
is FirConstructorSymbol -> expectContainingClass?.getConstructors(scopeSession)
else -> expectContainingClass?.getMembersForExpectClass(actualSymbol.name)
}.orEmpty()
} }
actualContainingClass = useSiteSession.symbolProvider.getClassLikeSymbolByClassId(classId) callableId.isLocal -> return null
?.fullyExpandedClass(useSiteSession) else -> {
val scope = FirPackageMemberScope(callableId.packageName, useSiteSession, useSiteSession.dependenciesSymbolProvider)
val expectTypeParameters = expectContainingClass?.typeParameterSymbols.orEmpty() mutableListOf<FirCallableSymbol<*>>().apply {
val actualTypeParameters = actualContainingClass scope.processFunctionsByName(callableId.callableName) { add(it) }
?.typeParameterSymbols scope.processPropertiesByName(callableId.callableName) { add(it) }
.orEmpty() }
parentSubstitutor = createExpectActualTypeParameterSubstitutor(
expectTypeParameters,
actualTypeParameters,
useSiteSession,
)
when (actualSymbol) {
is FirConstructorSymbol -> expectContainingClass?.getConstructors(scopeSession)
else -> expectContainingClass?.getMembers(callableId.callableName, scopeSession)
}.orEmpty()
}
callableId.isLocal -> return null
else -> {
val scope = FirPackageMemberScope(callableId.packageName, useSiteSession, useSiteSession.dependenciesSymbolProvider)
mutableListOf<FirCallableSymbol<*>>().apply {
scope.processFunctionsByName(callableId.callableName) { add(it) }
scope.processPropertiesByName(callableId.callableName) { add(it) }
} }
} }
} candidates.filter { expectSymbol ->
candidates.filter { expectSymbol -> actualSymbol != expectSymbol && expectSymbol.isExpect
actualSymbol != expectSymbol && expectSymbol.isExpect }.groupBy { expectDeclaration ->
}.groupBy { expectDeclaration -> AbstractExpectActualCompatibilityChecker.areCompatibleCallables(
areCompatibleCallables( expectDeclaration,
expectDeclaration, actualSymbol as CallableSymbolMarker,
actualSymbol, parentSubstitutor,
useSiteSession, expectContainingClass,
parentSubstitutor, actualContainingClass,
expectContainingClass, context
actualContainingClass
)
}
}
is FirClassLikeSymbol<*> -> {
val expectClassSymbol = useSiteSession.dependenciesSymbolProvider
.getClassLikeSymbolByClassId(actualSymbol.classId) as? FirRegularClassSymbol ?: return null
val compatibility = areCompatibleClassifiers(expectClassSymbol, actualSymbol, useSiteSession, scopeSession)
mapOf(compatibility to listOf(expectClassSymbol))
}
else -> null
}
}
private fun areCompatibleClassifiers(
expectClassSymbol: FirRegularClassSymbol,
actualClassLikeSymbol: FirClassLikeSymbol<*>,
actualSession: FirSession,
scopeSession: ScopeSession
): ExpectActualCompatibility<FirBasedSymbol<*>> {
// Can't check FQ names here because nested expected class may be implemented via actual typealias's expansion with the other FQ name
assert(expectClassSymbol.classId.shortClassName == actualClassLikeSymbol.classId.shortClassName) {
"This function should be invoked only for declarations with the same name: $expectClassSymbol, $actualClassLikeSymbol"
}
val actualClass = when (actualClassLikeSymbol) {
is FirRegularClassSymbol -> actualClassLikeSymbol
is FirTypeAliasSymbol -> actualClassLikeSymbol.resolvedExpandedTypeRef.coneType.fullyExpandedType(actualSession)
.toSymbol(actualSession) as? FirRegularClassSymbol
?: return ExpectActualCompatibility.Compatible // do not report extra error on erroneous typealias
else -> throw IllegalArgumentException("Incorrect actual classifier for $expectClassSymbol: $actualClassLikeSymbol")
}
if (expectClassSymbol.classKind != actualClass.classKind) return ExpectActualCompatibility.Incompatible.ClassKind
if (!equalBy(expectClassSymbol, actualClass) { listOf(it.isCompanion, it.isInner, it.isInline /*|| it.isValue*/) }) {
return ExpectActualCompatibility.Incompatible.ClassModifiers
}
if (expectClassSymbol.isFun && !actualClass.isFun) {
return ExpectActualCompatibility.Incompatible.FunInterfaceModifier
}
val expectTypeParameterSymbols = expectClassSymbol.typeParameterSymbols
val actualTypeParameterSymbols = actualClass.typeParameterSymbols
if (expectTypeParameterSymbols.size != actualTypeParameterSymbols.size) {
return ExpectActualCompatibility.Incompatible.TypeParameterCount
}
if (!areCompatibleModalities(expectClassSymbol.modality, actualClass.modality)) {
return ExpectActualCompatibility.Incompatible.Modality
}
if (expectClassSymbol.visibility != actualClass.visibility) {
return ExpectActualCompatibility.Incompatible.Visibility
}
val substitutor = createExpectActualTypeParameterSubstitutor(expectTypeParameterSymbols, actualTypeParameterSymbols, actualSession)
areCompatibleTypeParameters(expectTypeParameterSymbols, actualTypeParameterSymbols, actualSession, substitutor).let {
if (it != ExpectActualCompatibility.Compatible) {
return it
}
}
// Subtract kotlin.Any from supertypes because it's implicitly added if no explicit supertype is specified,
// and not added if an explicit supertype _is_ specified
val expectSupertypes = expectClassSymbol.resolvedSuperTypes.filterNot { it.classId == actualSession.builtinTypes.anyType.id }
val actualSupertypes = actualClass.resolvedSuperTypes.filterNot { it.classId == actualSession.builtinTypes.anyType.id }
if (
expectSupertypes.map(substitutor::substituteOrSelf).any { expectSupertype ->
actualSupertypes.none { actualSupertype ->
areCompatibleExpectActualTypes(expectSupertype, actualSupertype, actualSession)
}
}
) {
return ExpectActualCompatibility.Incompatible.Supertypes
}
areCompatibleClassScopes(expectClassSymbol, actualClass, actualSession, scopeSession, substitutor).let {
if (it != ExpectActualCompatibility.Compatible) {
return it
}
}
return ExpectActualCompatibility.Compatible
}
private fun areCompatibleClassScopes(
expectClassSymbol: FirRegularClassSymbol,
actualClassSymbol: FirRegularClassSymbol,
actualSession: FirSession,
scopeSession: ScopeSession,
substitutor: ConeSubstitutor
): ExpectActualCompatibility<FirBasedSymbol<*>> {
val unfulfilled =
mutableListOf<Pair<FirBasedSymbol<*>, Map<ExpectActualCompatibility.Incompatible<FirBasedSymbol<*>>, MutableCollection<FirBasedSymbol<*>>>>>()
val allActualMembers = actualClassSymbol.getMembers(scopeSession, actualSession)
val actualMembersByName = allActualMembers.groupBy { it.name }
val actualConstructors = allActualMembers.filterIsInstance<FirConstructorSymbol>()
outer@ for (expectMember in expectClassSymbol.getMembers(scopeSession)) {
// if (expectMember is CallableMemberDescriptor && !expectMember.kind.isReal) continue
// Skip non-expect declarations like equals, hashCode, toString and any inherited declarations from non-expect super types.
if (expectMember is FirCallableSymbol && !expectMember.isExpect) continue
val actualMembers = when (expectMember) {
is FirConstructorSymbol -> actualConstructors
else -> actualMembersByName[expectMember.name]?.filter { actualMember ->
expectMember is FirRegularClassSymbol && actualMember is FirRegularClassSymbol ||
expectMember is FirCallableSymbol<*> && actualMember is FirCallableSymbol<*>
}.orEmpty()
}
val mapping = actualMembers.keysToMap { actualMember ->
when (expectMember) {
is FirCallableSymbol<*> ->
areCompatibleCallables(
expectMember,
actualMember as FirCallableSymbol<*>,
actualSession,
substitutor,
expectClassSymbol,
actualClassSymbol
) )
is FirRegularClassSymbol -> }
areCompatibleClassifiers(expectMember, actualMember as FirRegularClassSymbol, actualSession, scopeSession)
else -> throw UnsupportedOperationException("Unsupported declaration: $expectMember ($actualMembers)")
} }
} is FirClassLikeSymbol<*> -> {
if (mapping.values.any { it == ExpectActualCompatibility.Compatible }) continue val expectClassSymbol = useSiteSession.dependenciesSymbolProvider
.getClassLikeSymbolByClassId(actualSymbol.classId) as? FirRegularClassSymbol ?: return null
val incompatibilityMap = val compatibility = AbstractExpectActualCompatibilityChecker.areCompatibleClassifiers(expectClassSymbol, actualSymbol, context)
mutableMapOf<ExpectActualCompatibility.Incompatible<FirBasedSymbol<*>>, MutableCollection<FirBasedSymbol<*>>>() mapOf(compatibility to listOf(expectClassSymbol))
for ((declaration, compatibility) in mapping) {
when (compatibility) {
ExpectActualCompatibility.Compatible -> continue@outer
is ExpectActualCompatibility.Incompatible -> incompatibilityMap.getOrPut(compatibility) { SmartList() }.add(declaration)
} }
else -> null
} }
return result
unfulfilled.add(expectMember to incompatibilityMap)
}
if (expectClassSymbol.classKind == ClassKind.ENUM_CLASS) {
val expectEntries = expectClassSymbol.fir.collectEnumEntries().map { it.name }
val actualEntries = actualClassSymbol.fir.collectEnumEntries().map { it.name }
if (!actualEntries.containsAll(expectEntries)) {
return ExpectActualCompatibility.Incompatible.EnumEntries
}
}
// TODO: check static scope?
if (unfulfilled.isEmpty()) return ExpectActualCompatibility.Compatible
return ExpectActualCompatibility.Incompatible.ClassScopes(unfulfilled)
}
private fun areCompatibleCallables(
expectDeclaration: FirCallableSymbol<*>,
actualDeclaration: FirCallableSymbol<*>,
actualSession: FirSession,
parentSubstitutor: ConeSubstitutor?,
expectContainingClass: FirRegularClassSymbol?,
actualContainingClass: FirRegularClassSymbol?,
): ExpectActualCompatibility<FirBasedSymbol<*>> {
assert(
(expectDeclaration is FirConstructorSymbol && actualDeclaration is FirConstructorSymbol) ||
expectDeclaration.callableId.callableName == actualDeclaration.callableId.callableName
) {
"This function should be invoked only for declarations with the same name: $expectDeclaration, $actualDeclaration"
}
assert((expectDeclaration.dispatchReceiverType == null) == (actualDeclaration.dispatchReceiverType == null)) {
"This function should be invoked only for declarations in the same kind of container (both members or both top level): $expectDeclaration, $actualDeclaration"
}
if (
expectDeclaration is FirConstructorSymbol &&
actualDeclaration is FirConstructorSymbol &&
expectContainingClass?.classKind == ClassKind.ENUM_CLASS &&
actualContainingClass?.classKind == ClassKind.ENUM_CLASS
) {
return ExpectActualCompatibility.Compatible
}
if (expectDeclaration is FirNamedFunctionSymbol != actualDeclaration is FirNamedFunctionSymbol) {
return ExpectActualCompatibility.Incompatible.CallableKind
}
val expectedReceiverType = expectDeclaration.resolvedReceiverTypeRef
val actualReceiverType = actualDeclaration.resolvedReceiverTypeRef
if ((expectedReceiverType != null) != (actualReceiverType != null)) {
return ExpectActualCompatibility.Incompatible.ParameterShape
}
val expectedValueParameters = expectDeclaration.valueParameterSymbols
val actualValueParameters = actualDeclaration.valueParameterSymbols
if (!valueParametersCountCompatible(expectDeclaration, actualDeclaration, expectedValueParameters, actualValueParameters)) {
return ExpectActualCompatibility.Incompatible.ParameterCount
}
val expectedTypeParameters = expectDeclaration.typeParameterSymbols
val actualTypeParameters = actualDeclaration.typeParameterSymbols
if (expectedTypeParameters.size != actualTypeParameters.size) {
return ExpectActualCompatibility.Incompatible.TypeParameterCount
}
val substitutor = createExpectActualTypeParameterSubstitutor(
expectedTypeParameters,
actualTypeParameters,
actualSession,
parentSubstitutor,
)
if (
!areCompatibleTypeLists(
expectedValueParameters.toTypeList(substitutor),
actualValueParameters.toTypeList(ConeSubstitutor.Empty),
actualSession
) ||
!areCompatibleExpectActualTypes(
expectedReceiverType?.coneType?.let { substitutor.substituteOrSelf(it) },
actualReceiverType?.coneType,
actualSession
)
) {
return ExpectActualCompatibility.Incompatible.ParameterTypes
}
// TODO: implement hasStableParameterNames calculation
// if (actualDeclaration.hasStableParameterNames() && !equalsBy(expectedValueParameters, actualValueParameters, ValueParameterDescriptor::getName)) return Incompatible.ParameterNames
if (!equalsBy(expectedTypeParameters, actualTypeParameters) { it.name }) {
return ExpectActualCompatibility.Incompatible.TypeParameterNames
}
if (
!areCompatibleModalities(
expectDeclaration.modality,
actualDeclaration.modality,
expectContainingClass?.modality,
actualContainingClass?.modality
)
) {
if (expectDeclaration.dispatchReceiverType?.isAny != true) {
return ExpectActualCompatibility.Incompatible.Modality
}
}
if (!areDeclarationsWithCompatibleVisibilities(expectDeclaration.resolvedStatus, actualDeclaration.resolvedStatus)) {
return ExpectActualCompatibility.Incompatible.Visibility
}
areCompatibleTypeParameters(expectedTypeParameters, actualTypeParameters, actualSession, substitutor).let {
if (it != ExpectActualCompatibility.Compatible) {
return it
}
}
if (!equalsBy(expectedValueParameters, actualValueParameters) { it.isVararg }) {
return ExpectActualCompatibility.Incompatible.ValueParameterVararg
}
// Adding noinline/crossinline to parameters is disallowed, except if the expected declaration was not inline at all
if (expectDeclaration is FirNamedFunctionSymbol && expectDeclaration.isInline) {
if (expectedValueParameters.indices.any { i -> !expectedValueParameters[i].isNoinline && actualValueParameters[i].isNoinline }) {
return ExpectActualCompatibility.Incompatible.ValueParameterNoinline
}
if (expectedValueParameters.indices.any { i -> !expectedValueParameters[i].isCrossinline && actualValueParameters[i].isCrossinline }) {
return ExpectActualCompatibility.Incompatible.ValueParameterCrossinline
}
}
when {
expectDeclaration is FirNamedFunctionSymbol && actualDeclaration is FirNamedFunctionSymbol -> areCompatibleFunctions(
expectDeclaration,
actualDeclaration
).let { if (it != ExpectActualCompatibility.Compatible) return it }
expectDeclaration is FirConstructorSymbol && actualDeclaration is FirConstructorSymbol -> areCompatibleFunctions(
expectDeclaration,
actualDeclaration
).let { if (it != ExpectActualCompatibility.Compatible) return it }
expectDeclaration is FirPropertySymbol && actualDeclaration is FirPropertySymbol -> areCompatibleProperties(
expectDeclaration,
actualDeclaration
).let { if (it != ExpectActualCompatibility.Compatible) return it }
else -> throw AssertionError("Unsupported declarations: $expectDeclaration, $actualDeclaration")
}
return ExpectActualCompatibility.Compatible
}
private fun valueParametersCountCompatible(
expectDeclaration: FirCallableSymbol<*>,
actualDeclaration: FirCallableSymbol<*>,
expectValueParameters: List<FirValueParameterSymbol>,
actualValueParameters: List<FirValueParameterSymbol>
): Boolean {
if (expectValueParameters.size == actualValueParameters.size) return true
return if (
expectDeclaration.isAnnotationConstructor(expectDeclaration.moduleData.session) &&
actualDeclaration.isAnnotationConstructor(actualDeclaration.moduleData.session)
) {
expectValueParameters.isEmpty() && actualValueParameters.all { it.hasDefaultValue }
} else {
false
} }
} }
private fun areCompatibleTypeLists(
expectedTypes: List<ConeKotlinType?>,
actualTypes: List<ConeKotlinType?>,
actualSession: FirSession
): Boolean {
for (i in expectedTypes.indices) {
if (!areCompatibleExpectActualTypes(expectedTypes[i], actualTypes[i], actualSession)) {
return false
}
}
return true
}
private fun areCompatibleModalities(
expectModality: Modality?,
actualModality: Modality?,
expectContainingClassModality: Modality? = null,
actualContainingClassModality: Modality? = null
): Boolean {
val expectEffectiveModality = effectiveModality(expectModality, expectContainingClassModality)
val actualEffectiveModality = effectiveModality(actualModality, actualContainingClassModality)
val result = actualEffectiveModality in compatibleModalityMap.getValue(expectEffectiveModality)
return result
}
/*
* If containing class is final then all declarations in it effectively final
*/
private fun effectiveModality(declarationModality: Modality?, containingClassModality: Modality?): Modality? {
return when (containingClassModality) {
FINAL -> FINAL
else -> declarationModality
}
}
/*
* Key is expect modality, value is a set of compatible actual modalities
*/
private val compatibleModalityMap: EnumMap<Modality, EnumSet<Modality>> = enumMapOf(
ABSTRACT to enumSetOf(ABSTRACT, OPEN),
OPEN to enumSetOf(OPEN),
FINAL to enumSetOf(ABSTRACT, OPEN, FINAL),
SEALED to enumSetOf(SEALED),
)
private fun areDeclarationsWithCompatibleVisibilities(
expectStatus: FirDeclarationStatus,
actualStatus: FirDeclarationStatus
): Boolean {
val compare = Visibilities.compare(expectStatus.visibility, actualStatus.visibility)
return if (expectStatus.modality != FINAL) {
// For overridable declarations visibility should match precisely, see KT-19664
compare == 0
} else {
// For non-overridable declarations actuals are allowed to have more permissive visibility
compare != null && compare <= 0
}
}
private fun areCompatibleTypeParameters(
expectTypeParameterSymbols: List<FirTypeParameterSymbol>,
actualTypeParameterSymbols: List<FirTypeParameterSymbol>,
actualSession: FirSession,
substitutor: ConeSubstitutor
): ExpectActualCompatibility<FirBasedSymbol<*>> {
for (i in expectTypeParameterSymbols.indices) {
val expectBounds = expectTypeParameterSymbols[i].resolvedBounds.map { it.coneType }
val actualBounds = actualTypeParameterSymbols[i].resolvedBounds.map { it.coneType }
if (
expectBounds.size != actualBounds.size ||
!areCompatibleTypeLists(expectBounds.map(substitutor::substituteOrSelf), actualBounds, actualSession)
) {
return ExpectActualCompatibility.Incompatible.TypeParameterUpperBounds
}
}
if (!equalsBy(expectTypeParameterSymbols, actualTypeParameterSymbols) { it.variance }) {
return ExpectActualCompatibility.Incompatible.TypeParameterVariance
}
// Removing "reified" from an expected function's type parameter is fine
if (
expectTypeParameterSymbols.indices.any { i ->
!expectTypeParameterSymbols[i].isReified && actualTypeParameterSymbols[i].isReified
}
) {
return ExpectActualCompatibility.Incompatible.TypeParameterReified
}
return ExpectActualCompatibility.Compatible
}
private fun areCompatibleFunctions(
expectFunction: FirCallableSymbol<*>,
actualFunction: FirCallableSymbol<*>
): ExpectActualCompatibility<FirBasedSymbol<*>> {
if (!equalBy(expectFunction, actualFunction) { f -> f.isSuspend }) {
return ExpectActualCompatibility.Incompatible.FunctionModifiersDifferent
}
if (
expectFunction.isExternal && !actualFunction.isExternal ||
expectFunction.isInfix && !actualFunction.isInfix ||
expectFunction.isInline && !actualFunction.isInline ||
expectFunction.isOperator && !actualFunction.isOperator ||
expectFunction.isTailRec && !actualFunction.isTailRec
) {
return ExpectActualCompatibility.Incompatible.FunctionModifiersNotSubset
}
return ExpectActualCompatibility.Compatible
}
private fun areCompatibleProperties(
expected: FirPropertySymbol,
actual: FirPropertySymbol,
): ExpectActualCompatibility<FirBasedSymbol<*>> {
return when {
!equalBy(expected, actual) { p -> p.isVar } -> ExpectActualCompatibility.Incompatible.PropertyKind
!equalBy(expected, actual) { p -> p.isLateInit } -> ExpectActualCompatibility.Incompatible.PropertyLateinitModifier
expected.isConst && !actual.isConst -> ExpectActualCompatibility.Incompatible.PropertyConstModifier
!arePropertySettersWithCompatibleVisibilities(expected, actual) -> ExpectActualCompatibility.Incompatible.PropertySetterVisibility
else -> ExpectActualCompatibility.Compatible
}
}
private fun arePropertySettersWithCompatibleVisibilities(
expected: FirPropertySymbol,
actual: FirPropertySymbol,
): Boolean {
val expectedSetterStatus = expected.setterSymbol?.resolvedStatus
val actualSetterStatus = actual.setterSymbol?.resolvedStatus
if (expectedSetterStatus == null || actualSetterStatus == null) {
return true
}
return areDeclarationsWithCompatibleVisibilities(expectedSetterStatus, actualSetterStatus)
}
// ---------------------------------------- Utils ----------------------------------------
private fun List<FirValueParameterSymbol>.toTypeList(substitutor: ConeSubstitutor): List<ConeKotlinType> {
return this.map { substitutor.substituteOrSelf(it.resolvedReturnTypeRef.coneType) }
}
private val FirCallableSymbol<*>.valueParameterSymbols: List<FirValueParameterSymbol>
get() = (this as? FirFunctionSymbol<*>)?.valueParameterSymbols ?: emptyList()
private inline fun <T, K> equalsBy(first: List<T>, second: List<T>, selector: (T) -> K): Boolean {
for (i in first.indices) {
if (selector(first[i]) != selector(second[i])) return false
}
return true
}
private inline fun <T, K> equalBy(first: T, second: T, selector: (T) -> K): Boolean =
selector(first) == selector(second)
private fun FirClassSymbol<*>.getMembers(
scopeSession: ScopeSession,
session: FirSession = moduleData.session
): Collection<FirBasedSymbol<*>> {
val scope = defaultType()
.scope(useSiteSession = session, scopeSession, FakeOverrideTypeCalculator.DoNothing, requiredPhase = FirResolvePhase.STATUS)
?: return emptyList()
return mutableListOf<FirBasedSymbol<*>>().apply {
for (name in scope.getCallableNames()) {
scope.getMembersTo(this, name)
}
for (name in declarationSymbols.mapNotNull { (it as? FirRegularClassSymbol)?.classId?.shortClassName }) {
addIfNotNull(scope.getSingleClassifier(name) as? FirRegularClassSymbol)
}
getConstructorsTo(this, scope)
}
}
private fun FirClassSymbol<*>.getConstructors(
scopeSession: ScopeSession,
session: FirSession = moduleData.session
): Collection<FirConstructorSymbol> = mutableListOf<FirConstructorSymbol>().apply {
getConstructorsTo(
this,
unsubstitutedScope(
session,
scopeSession,
withForcedTypeCalculator = false,
memberRequiredPhase = FirResolvePhase.STATUS,
)
)
}
private fun getConstructorsTo(destination: MutableList<in FirConstructorSymbol>, scope: FirTypeScope) {
scope.getDeclaredConstructors().mapTo(destination) { it }
}
private fun FirClassSymbol<*>.getMembers(name: Name, scopeSession: ScopeSession): Collection<FirCallableSymbol<*>> {
val scope = defaultType()
.scope(
useSiteSession = moduleData.session,
scopeSession,
FakeOverrideTypeCalculator.DoNothing,
requiredPhase = FirResolvePhase.STATUS
)
?: return emptyList()
return mutableListOf<FirCallableSymbol<*>>().apply {
scope.getMembersTo(this, name)
}
}
private fun FirTypeScope.getMembersTo(
destination: MutableList<in FirCallableSymbol<*>>,
name: Name,
) {
processFunctionsByName(name) { destination.add(it) }
processPropertiesByName(name) { destination.add(it) }
}
private val FirBasedSymbol<*>.name: Name
get() = when (this) {
is FirCallableSymbol<*> -> name
is FirRegularClassSymbol -> classId.shortClassName
else -> error("Should not be here")
}
} }
@@ -17,9 +17,10 @@ import org.jetbrains.kotlin.fir.expressions.arguments
import org.jetbrains.kotlin.fir.symbols.impl.FirBackingFieldSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirBackingFieldSymbol
import org.jetbrains.kotlin.fir.types.ConeClassLikeType import org.jetbrains.kotlin.fir.types.ConeClassLikeType
import org.jetbrains.kotlin.fir.types.coneType import org.jetbrains.kotlin.fir.types.coneType
import org.jetbrains.kotlin.mpp.DeclarationSymbolMarker
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
abstract class FirBasedSymbol<E : FirDeclaration> { abstract class FirBasedSymbol<E : FirDeclaration> : DeclarationSymbolMarker {
private var _fir: E? = null private var _fir: E? = null
@SymbolInternals @SymbolInternals
@@ -10,10 +10,11 @@ import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase
import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.mpp.CallableSymbolMarker
import org.jetbrains.kotlin.name.CallableId import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
abstract class FirCallableSymbol<D : FirCallableDeclaration> : FirBasedSymbol<D>() { abstract class FirCallableSymbol<D : FirCallableDeclaration> : FirBasedSymbol<D>(), CallableSymbolMarker {
abstract val callableId: CallableId abstract val callableId: CallableId
val resolvedReturnTypeRef: FirResolvedTypeRef val resolvedReturnTypeRef: FirResolvedTypeRef
@@ -15,13 +15,16 @@ import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
import org.jetbrains.kotlin.fir.types.coneType import org.jetbrains.kotlin.fir.types.coneType
import org.jetbrains.kotlin.fir.types.toLookupTag import org.jetbrains.kotlin.fir.types.toLookupTag
import org.jetbrains.kotlin.mpp.ClassLikeSymbolMarker
import org.jetbrains.kotlin.mpp.RegularClassSymbolMarker
import org.jetbrains.kotlin.mpp.TypeAliasSymbolMarker
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.SpecialNames import org.jetbrains.kotlin.name.SpecialNames
sealed class FirClassLikeSymbol<D : FirClassLikeDeclaration>( sealed class FirClassLikeSymbol<D : FirClassLikeDeclaration>(
val classId: ClassId, val classId: ClassId,
) : FirClassifierSymbol<D>() { ) : FirClassifierSymbol<D>(), ClassLikeSymbolMarker {
abstract override fun toLookupTag(): ConeClassLikeLookupTag abstract override fun toLookupTag(): ConeClassLikeLookupTag
val name get() = classId.shortClassName val name get() = classId.shortClassName
@@ -68,7 +71,7 @@ sealed class FirClassSymbol<C : FirClass>(classId: ClassId) : FirClassLikeSymbol
get() = fir.classKind get() = fir.classKind
} }
class FirRegularClassSymbol(classId: ClassId) : FirClassSymbol<FirRegularClass>(classId) { class FirRegularClassSymbol(classId: ClassId) : FirClassSymbol<FirRegularClass>(classId), RegularClassSymbolMarker {
val companionObjectSymbol: FirRegularClassSymbol? val companionObjectSymbol: FirRegularClassSymbol?
get() = fir.companionObjectSymbol get() = fir.companionObjectSymbol
@@ -84,7 +87,7 @@ val ANONYMOUS_CLASS_ID = ClassId(FqName.ROOT, FqName.topLevel(SpecialNames.ANONY
class FirAnonymousObjectSymbol : FirClassSymbol<FirAnonymousObject>(ANONYMOUS_CLASS_ID) class FirAnonymousObjectSymbol : FirClassSymbol<FirAnonymousObject>(ANONYMOUS_CLASS_ID)
class FirTypeAliasSymbol(classId: ClassId) : FirClassLikeSymbol<FirTypeAlias>(classId) { class FirTypeAliasSymbol(classId: ClassId) : FirClassLikeSymbol<FirTypeAlias>(classId), TypeAliasSymbolMarker {
override fun toLookupTag(): ConeClassLikeLookupTag = classId.toLookupTag() override fun toLookupTag(): ConeClassLikeLookupTag = classId.toLookupTag()
val resolvedExpandedTypeRef: FirResolvedTypeRef val resolvedExpandedTypeRef: FirResolvedTypeRef
@@ -8,7 +8,8 @@ package org.jetbrains.kotlin.fir.symbols.impl
import org.jetbrains.kotlin.fir.declarations.FirDeclaration import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.symbols.ConeClassifierLookupTag import org.jetbrains.kotlin.fir.symbols.ConeClassifierLookupTag
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.mpp.ClassifierSymbolMarker
sealed class FirClassifierSymbol<E : FirDeclaration> : FirBasedSymbol<E>() { sealed class FirClassifierSymbol<E : FirDeclaration> : FirBasedSymbol<E>(), ClassifierSymbolMarker {
abstract fun toLookupTag(): ConeClassifierLookupTag abstract fun toLookupTag(): ConeClassifierLookupTag
} }
@@ -12,9 +12,12 @@ import org.jetbrains.kotlin.fir.expressions.FirDelegatedConstructorCall
import org.jetbrains.kotlin.fir.references.FirControlFlowGraphReference import org.jetbrains.kotlin.fir.references.FirControlFlowGraphReference
import org.jetbrains.kotlin.fir.references.toResolvedConstructorSymbol import org.jetbrains.kotlin.fir.references.toResolvedConstructorSymbol
import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase
import org.jetbrains.kotlin.mpp.ConstructorSymbolMarker
import org.jetbrains.kotlin.mpp.FunctionSymbolMarker
import org.jetbrains.kotlin.mpp.SimpleFunctionSymbolMarker
import org.jetbrains.kotlin.name.* import org.jetbrains.kotlin.name.*
sealed class FirFunctionSymbol<D : FirFunction>(override val callableId: CallableId) : FirCallableSymbol<D>() { sealed class FirFunctionSymbol<D : FirFunction>(override val callableId: CallableId) : FirCallableSymbol<D>(), FunctionSymbolMarker {
val valueParameterSymbols: List<FirValueParameterSymbol> val valueParameterSymbols: List<FirValueParameterSymbol>
get() = fir.valueParameters.map { it.symbol } get() = fir.valueParameters.map { it.symbol }
@@ -37,7 +40,7 @@ sealed class FirFunctionSymbol<D : FirFunction>(override val callableId: Callabl
// ------------------------ named ------------------------ // ------------------------ named ------------------------
open class FirNamedFunctionSymbol(callableId: CallableId) : FirFunctionSymbol<FirSimpleFunction>(callableId) open class FirNamedFunctionSymbol(callableId: CallableId) : FirFunctionSymbol<FirSimpleFunction>(callableId), SimpleFunctionSymbolMarker
interface FirIntersectionCallableSymbol { interface FirIntersectionCallableSymbol {
val intersections: Collection<FirCallableSymbol<*>> val intersections: Collection<FirCallableSymbol<*>>
@@ -48,7 +51,7 @@ class FirIntersectionOverrideFunctionSymbol(
override val intersections: Collection<FirCallableSymbol<*>>, override val intersections: Collection<FirCallableSymbol<*>>,
) : FirNamedFunctionSymbol(callableId), FirIntersectionCallableSymbol ) : FirNamedFunctionSymbol(callableId), FirIntersectionCallableSymbol
class FirConstructorSymbol(callableId: CallableId) : FirFunctionSymbol<FirConstructor>(callableId) { class FirConstructorSymbol(callableId: CallableId) : FirFunctionSymbol<FirConstructor>(callableId), ConstructorSymbolMarker {
constructor(classId: ClassId) : this(classId.callableIdForConstructor()) constructor(classId: ClassId) : this(classId.callableIdForConstructor())
val isPrimary: Boolean val isPrimary: Boolean
@@ -11,10 +11,11 @@ import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterLookupTag
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
import org.jetbrains.kotlin.mpp.TypeParameterSymbolMarker
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.types.Variance import org.jetbrains.kotlin.types.Variance
class FirTypeParameterSymbol : FirClassifierSymbol<FirTypeParameter>() { class FirTypeParameterSymbol : FirClassifierSymbol<FirTypeParameter>(), TypeParameterSymbolMarker {
val name: Name val name: Name
get() = fir.name get() = fir.name
@@ -11,15 +11,15 @@ import org.jetbrains.kotlin.fir.expressions.FirAnonymousObjectExpression
import org.jetbrains.kotlin.fir.expressions.FirExpression import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.references.FirControlFlowGraphReference import org.jetbrains.kotlin.fir.references.FirControlFlowGraphReference
import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase
import org.jetbrains.kotlin.mpp.PropertySymbolMarker
import org.jetbrains.kotlin.mpp.ValueParameterSymbolMarker
import org.jetbrains.kotlin.name.CallableId import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
sealed class FirVariableSymbol<E : FirVariable>(override val callableId: CallableId) : FirCallableSymbol<E>() sealed class FirVariableSymbol<E : FirVariable>(override val callableId: CallableId) : FirCallableSymbol<E>()
open class FirPropertySymbol( open class FirPropertySymbol(callableId: CallableId, ) : FirVariableSymbol<FirProperty>(callableId), PropertySymbolMarker {
callableId: CallableId,
) : FirVariableSymbol<FirProperty>(callableId) {
// TODO: should we use this constructor for local variables? // TODO: should we use this constructor for local variables?
constructor(name: Name) : this(CallableId(name)) constructor(name: Name) : this(CallableId(name))
@@ -108,7 +108,7 @@ class FirEnumEntrySymbol(callableId: CallableId) : FirVariableSymbol<FirEnumEntr
get() = (fir.initializer as? FirAnonymousObjectExpression)?.anonymousObject?.symbol get() = (fir.initializer as? FirAnonymousObjectExpression)?.anonymousObject?.symbol
} }
class FirValueParameterSymbol(name: Name) : FirVariableSymbol<FirValueParameter>(CallableId(name)) { class FirValueParameterSymbol(name: Name) : FirVariableSymbol<FirValueParameter>(CallableId(name)), ValueParameterSymbolMarker {
val hasDefaultValue: Boolean val hasDefaultValue: Boolean
get() = fir.defaultValue != null get() = fir.defaultValue != null
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.ir.generator.model
import org.jetbrains.kotlin.ir.generator.config.* import org.jetbrains.kotlin.ir.generator.config.*
import org.jetbrains.kotlin.ir.generator.elementBaseType import org.jetbrains.kotlin.ir.generator.elementBaseType
import org.jetbrains.kotlin.ir.generator.util.* import org.jetbrains.kotlin.ir.generator.util.*
import org.jetbrains.kotlin.utils.addToStdlib.UnsafeCastFunction
import org.jetbrains.kotlin.utils.addToStdlib.castAll import org.jetbrains.kotlin.utils.addToStdlib.castAll
import org.jetbrains.kotlin.utils.addToStdlib.partitionIsInstance import org.jetbrains.kotlin.utils.addToStdlib.partitionIsInstance
@@ -82,6 +83,7 @@ fun config2model(config: Config): Model {
return Model(elements, rootElement) return Model(elements, rootElement)
} }
@OptIn(UnsafeCastFunction::class)
private fun replaceElementRefs(config: Config, mapping: Map<ElementConfig, Element>): Element { private fun replaceElementRefs(config: Config, mapping: Map<ElementConfig, Element>): Element {
val visited = mutableMapOf<TypeRef, TypeRef>() val visited = mutableMapOf<TypeRef, TypeRef>()
@@ -9,7 +9,7 @@ expect class Foo {
// MODULE: m2-jvm()()(m1-common) // MODULE: m2-jvm()()(m1-common)
// FILE: jvm.kt // FILE: jvm.kt
actual class Foo { actual class <!NO_ACTUAL_CLASS_MEMBER_FOR_EXPECTED_CLASS!>Foo<!> {
fun bar(): String = "bar" fun bar(): String = "bar"
fun bas(g: Int) {} fun bas(g: Int) {}
} }