From b19116d3aff9f82d43906a33678407e2c7df5cbe Mon Sep 17 00:00:00 2001 From: Dmitriy Novozhilov Date: Thu, 11 May 2023 13:26:49 +0300 Subject: [PATCH] [FIR] Provide implementation of ExpectActualMatchingContext for FIR ^KT-58578 --- .../mpp/FirExpectActualMatchingContext.kt | 284 ++++++++ .../mpp/FirExpectActualResolver.kt | 653 ++---------------- .../kotlin/fir/symbols/FirBasedSymbol.kt | 3 +- .../fir/symbols/impl/FirCallableSymbol.kt | 3 +- .../fir/symbols/impl/FirClassLikeSymbol.kt | 9 +- .../fir/symbols/impl/FirClassifierSymbol.kt | 3 +- .../fir/symbols/impl/FirFunctionSymbol.kt | 9 +- .../symbols/impl/FirTypeParameterSymbol.kt | 3 +- .../fir/symbols/impl/FirVariableSymbol.kt | 8 +- .../ir/generator/model/Transformations.kt | 2 + .../headerClass/noImplKeywordOnMember.fir.kt | 2 +- 11 files changed, 370 insertions(+), 609 deletions(-) create mode 100644 compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/mpp/FirExpectActualMatchingContext.kt diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/mpp/FirExpectActualMatchingContext.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/mpp/FirExpectActualMatchingContext.kt new file mode 100644 index 00000000000..40c94482855 --- /dev/null +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/mpp/FirExpectActualMatchingContext.kt @@ -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>, 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 + 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, + actualTypeParameters: List, + parentSubstitutor: TypeSubstitutorMarker?, + ): TypeSubstitutorMarker { + return createExpectActualTypeParameterSubstitutor( + expectTypeParameters.castAll(), + actualTypeParameters.castAll(), + actualSession, + parentSubstitutor as ConeSubstitutor? + ) + } + + override val RegularClassSymbolMarker.superTypes: List + get() = asSymbol().resolvedSuperTypes + + override fun RegularClassSymbolMarker.collectAllMembers(isActualDeclaration: Boolean): List> { + 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>().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> { + val symbol = asSymbol() + val scope = symbol.defaultType() + .scope( + useSiteSession = symbol.moduleData.session, + scopeSession, + FakeOverrideTypeCalculator.DoNothing, + requiredPhase = FirResolvePhase.STATUS + ) + ?: return emptyList() + return mutableListOf>().apply { + scope.getMembersTo(this, name) + } + } + + fun FirClassSymbol<*>.getConstructors( + scopeSession: ScopeSession, + session: FirSession = moduleData.session + ): Collection = mutableListOf().apply { + getConstructorsTo( + this, + unsubstitutedScope( + session, + scopeSession, + withForcedTypeCalculator = false, + memberRequiredPhase = FirResolvePhase.STATUS, + ) + ) + } + + + private fun getConstructorsTo(destination: MutableList, scope: FirTypeScope) { + scope.getDeclaredConstructors().mapTo(destination) { it } + } + + private fun FirTypeScope.getMembersTo(destination: MutableList>, name: Name) { + processFunctionsByName(name) { destination.add(it) } + processPropertiesByName(name) { destination.add(it) } + } + + override fun RegularClassSymbolMarker.collectEnumEntryNames(): List { + 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 + get() = asSymbol().typeParameterSymbols + override val FunctionSymbolMarker.valueParameters: List + 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 + 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 + } +} diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/mpp/FirExpectActualResolver.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/mpp/FirExpectActualResolver.kt index 5f9b8c79000..1be63b78c03 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/mpp/FirExpectActualResolver.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/mpp/FirExpectActualResolver.kt @@ -5,30 +5,18 @@ 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.declarations.* -import org.jetbrains.kotlin.fir.declarations.utils.* import org.jetbrains.kotlin.fir.resolve.* import org.jetbrains.kotlin.fir.resolve.providers.dependenciesSymbolProvider import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider 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.symbols.FirBasedSymbol import org.jetbrains.kotlin.fir.symbols.impl.* import org.jetbrains.kotlin.fir.types.* -import org.jetbrains.kotlin.name.Name -import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility -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.* +import org.jetbrains.kotlin.resolve.calls.mpp.AbstractExpectActualCompatibilityChecker +import org.jetbrains.kotlin.mpp.CallableSymbolMarker object FirExpectActualResolver { fun findExpectForActual( @@ -36,593 +24,70 @@ object FirExpectActualResolver { useSiteSession: FirSession, scopeSession: ScopeSession ): ExpectForActualData? { - return when (actualSymbol) { - is FirCallableSymbol<*> -> { - val callableId = actualSymbol.callableId - val classId = callableId.classId - var parentSubstitutor: ConeSubstitutor? = null - var expectContainingClass: FirRegularClassSymbol? = null - var actualContainingClass: FirRegularClassSymbol? = null - val candidates = when { - classId != null -> { - expectContainingClass = useSiteSession.dependenciesSymbolProvider.getClassLikeSymbolByClassId(classId)?.let { - it.fullyExpandedClass(it.moduleData.session) + val context = FirExpectActualMatchingContext(useSiteSession, scopeSession) + with(context) { + val result = when (actualSymbol) { + is FirCallableSymbol<*> -> { + val callableId = actualSymbol.callableId + val classId = callableId.classId + var parentSubstitutor: ConeSubstitutor? = null + var expectContainingClass: FirRegularClassSymbol? = null + var actualContainingClass: FirRegularClassSymbol? = null + val candidates = when { + 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) - ?.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?.getMembers(callableId.callableName, scopeSession) - }.orEmpty() - } - callableId.isLocal -> return null - else -> { - val scope = FirPackageMemberScope(callableId.packageName, useSiteSession, useSiteSession.dependenciesSymbolProvider) - mutableListOf>().apply { - scope.processFunctionsByName(callableId.callableName) { add(it) } - scope.processPropertiesByName(callableId.callableName) { add(it) } + callableId.isLocal -> return null + else -> { + val scope = FirPackageMemberScope(callableId.packageName, useSiteSession, useSiteSession.dependenciesSymbolProvider) + mutableListOf>().apply { + scope.processFunctionsByName(callableId.callableName) { add(it) } + scope.processPropertiesByName(callableId.callableName) { add(it) } + } } } - } - candidates.filter { expectSymbol -> - actualSymbol != expectSymbol && expectSymbol.isExpect - }.groupBy { expectDeclaration -> - areCompatibleCallables( - expectDeclaration, - actualSymbol, - useSiteSession, - parentSubstitutor, - expectContainingClass, - 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> { - // 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> { - val unfulfilled = - mutableListOf, Map>, MutableCollection>>>>() - - val allActualMembers = actualClassSymbol.getMembers(scopeSession, actualSession) - val actualMembersByName = allActualMembers.groupBy { it.name } - val actualConstructors = allActualMembers.filterIsInstance() - - 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 + candidates.filter { expectSymbol -> + actualSymbol != expectSymbol && expectSymbol.isExpect + }.groupBy { expectDeclaration -> + AbstractExpectActualCompatibilityChecker.areCompatibleCallables( + expectDeclaration, + actualSymbol as CallableSymbolMarker, + parentSubstitutor, + expectContainingClass, + actualContainingClass, + context ) - is FirRegularClassSymbol -> - areCompatibleClassifiers(expectMember, actualMember as FirRegularClassSymbol, actualSession, scopeSession) - else -> throw UnsupportedOperationException("Unsupported declaration: $expectMember ($actualMembers)") + } } - } - if (mapping.values.any { it == ExpectActualCompatibility.Compatible }) continue - - val incompatibilityMap = - mutableMapOf>, MutableCollection>>() - for ((declaration, compatibility) in mapping) { - when (compatibility) { - ExpectActualCompatibility.Compatible -> continue@outer - is ExpectActualCompatibility.Incompatible -> incompatibilityMap.getOrPut(compatibility) { SmartList() }.add(declaration) + is FirClassLikeSymbol<*> -> { + val expectClassSymbol = useSiteSession.dependenciesSymbolProvider + .getClassLikeSymbolByClassId(actualSymbol.classId) as? FirRegularClassSymbol ?: return null + val compatibility = AbstractExpectActualCompatibilityChecker.areCompatibleClassifiers(expectClassSymbol, actualSymbol, context) + mapOf(compatibility to listOf(expectClassSymbol)) } + else -> null } - - 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> { - 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, - actualValueParameters: List - ): 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 + return result } } - - private fun areCompatibleTypeLists( - expectedTypes: List, - actualTypes: List, - 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> = 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, - actualTypeParameterSymbols: List, - actualSession: FirSession, - substitutor: ConeSubstitutor - ): ExpectActualCompatibility> { - 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> { - 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> { - 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.toTypeList(substitutor: ConeSubstitutor): List { - return this.map { substitutor.substituteOrSelf(it.resolvedReturnTypeRef.coneType) } - } - - private val FirCallableSymbol<*>.valueParameterSymbols: List - get() = (this as? FirFunctionSymbol<*>)?.valueParameterSymbols ?: emptyList() - - private inline fun equalsBy(first: List, second: List, selector: (T) -> K): Boolean { - for (i in first.indices) { - if (selector(first[i]) != selector(second[i])) return false - } - - return true - } - - private inline fun equalBy(first: T, second: T, selector: (T) -> K): Boolean = - selector(first) == selector(second) - - private fun FirClassSymbol<*>.getMembers( - scopeSession: ScopeSession, - session: FirSession = moduleData.session - ): Collection> { - val scope = defaultType() - .scope(useSiteSession = session, scopeSession, FakeOverrideTypeCalculator.DoNothing, requiredPhase = FirResolvePhase.STATUS) - ?: return emptyList() - return mutableListOf>().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 = mutableListOf().apply { - getConstructorsTo( - this, - unsubstitutedScope( - session, - scopeSession, - withForcedTypeCalculator = false, - memberRequiredPhase = FirResolvePhase.STATUS, - ) - ) - } - - private fun getConstructorsTo(destination: MutableList, scope: FirTypeScope) { - scope.getDeclaredConstructors().mapTo(destination) { it } - } - - private fun FirClassSymbol<*>.getMembers(name: Name, scopeSession: ScopeSession): Collection> { - val scope = defaultType() - .scope( - useSiteSession = moduleData.session, - scopeSession, - FakeOverrideTypeCalculator.DoNothing, - requiredPhase = FirResolvePhase.STATUS - ) - ?: return emptyList() - return mutableListOf>().apply { - scope.getMembersTo(this, name) - } - } - - private fun FirTypeScope.getMembersTo( - destination: MutableList>, - 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") - } } diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/FirBasedSymbol.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/FirBasedSymbol.kt index 8f2d831add7..0dbb24254e5 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/FirBasedSymbol.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/FirBasedSymbol.kt @@ -17,9 +17,10 @@ import org.jetbrains.kotlin.fir.expressions.arguments import org.jetbrains.kotlin.fir.symbols.impl.FirBackingFieldSymbol import org.jetbrains.kotlin.fir.types.ConeClassLikeType import org.jetbrains.kotlin.fir.types.coneType +import org.jetbrains.kotlin.mpp.DeclarationSymbolMarker import org.jetbrains.kotlin.name.ClassId -abstract class FirBasedSymbol { +abstract class FirBasedSymbol : DeclarationSymbolMarker { private var _fir: E? = null @SymbolInternals diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/impl/FirCallableSymbol.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/impl/FirCallableSymbol.kt index 9dca29715ff..eff8345987b 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/impl/FirCallableSymbol.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/impl/FirCallableSymbol.kt @@ -10,10 +10,11 @@ import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase import org.jetbrains.kotlin.fir.types.* +import org.jetbrains.kotlin.mpp.CallableSymbolMarker import org.jetbrains.kotlin.name.CallableId import org.jetbrains.kotlin.name.Name -abstract class FirCallableSymbol : FirBasedSymbol() { +abstract class FirCallableSymbol : FirBasedSymbol(), CallableSymbolMarker { abstract val callableId: CallableId val resolvedReturnTypeRef: FirResolvedTypeRef diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/impl/FirClassLikeSymbol.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/impl/FirClassLikeSymbol.kt index 8d226bf4130..9733f16f47b 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/impl/FirClassLikeSymbol.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/impl/FirClassLikeSymbol.kt @@ -15,13 +15,16 @@ import org.jetbrains.kotlin.fir.types.ConeKotlinType import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef import org.jetbrains.kotlin.fir.types.coneType 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.FqName import org.jetbrains.kotlin.name.SpecialNames sealed class FirClassLikeSymbol( val classId: ClassId, -) : FirClassifierSymbol() { +) : FirClassifierSymbol(), ClassLikeSymbolMarker { abstract override fun toLookupTag(): ConeClassLikeLookupTag val name get() = classId.shortClassName @@ -68,7 +71,7 @@ sealed class FirClassSymbol(classId: ClassId) : FirClassLikeSymbol get() = fir.classKind } -class FirRegularClassSymbol(classId: ClassId) : FirClassSymbol(classId) { +class FirRegularClassSymbol(classId: ClassId) : FirClassSymbol(classId), RegularClassSymbolMarker { val companionObjectSymbol: FirRegularClassSymbol? get() = fir.companionObjectSymbol @@ -84,7 +87,7 @@ val ANONYMOUS_CLASS_ID = ClassId(FqName.ROOT, FqName.topLevel(SpecialNames.ANONY class FirAnonymousObjectSymbol : FirClassSymbol(ANONYMOUS_CLASS_ID) -class FirTypeAliasSymbol(classId: ClassId) : FirClassLikeSymbol(classId) { +class FirTypeAliasSymbol(classId: ClassId) : FirClassLikeSymbol(classId), TypeAliasSymbolMarker { override fun toLookupTag(): ConeClassLikeLookupTag = classId.toLookupTag() val resolvedExpandedTypeRef: FirResolvedTypeRef diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/impl/FirClassifierSymbol.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/impl/FirClassifierSymbol.kt index 66fb291a07c..c0a91ac75f8 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/impl/FirClassifierSymbol.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/impl/FirClassifierSymbol.kt @@ -8,7 +8,8 @@ package org.jetbrains.kotlin.fir.symbols.impl import org.jetbrains.kotlin.fir.declarations.FirDeclaration import org.jetbrains.kotlin.fir.symbols.ConeClassifierLookupTag import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol +import org.jetbrains.kotlin.mpp.ClassifierSymbolMarker -sealed class FirClassifierSymbol : FirBasedSymbol() { +sealed class FirClassifierSymbol : FirBasedSymbol(), ClassifierSymbolMarker { abstract fun toLookupTag(): ConeClassifierLookupTag } diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/impl/FirFunctionSymbol.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/impl/FirFunctionSymbol.kt index 1aa319af686..43193b27f60 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/impl/FirFunctionSymbol.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/impl/FirFunctionSymbol.kt @@ -12,9 +12,12 @@ import org.jetbrains.kotlin.fir.expressions.FirDelegatedConstructorCall import org.jetbrains.kotlin.fir.references.FirControlFlowGraphReference import org.jetbrains.kotlin.fir.references.toResolvedConstructorSymbol 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.* -sealed class FirFunctionSymbol(override val callableId: CallableId) : FirCallableSymbol() { +sealed class FirFunctionSymbol(override val callableId: CallableId) : FirCallableSymbol(), FunctionSymbolMarker { val valueParameterSymbols: List get() = fir.valueParameters.map { it.symbol } @@ -37,7 +40,7 @@ sealed class FirFunctionSymbol(override val callableId: Callabl // ------------------------ named ------------------------ -open class FirNamedFunctionSymbol(callableId: CallableId) : FirFunctionSymbol(callableId) +open class FirNamedFunctionSymbol(callableId: CallableId) : FirFunctionSymbol(callableId), SimpleFunctionSymbolMarker interface FirIntersectionCallableSymbol { val intersections: Collection> @@ -48,7 +51,7 @@ class FirIntersectionOverrideFunctionSymbol( override val intersections: Collection>, ) : FirNamedFunctionSymbol(callableId), FirIntersectionCallableSymbol -class FirConstructorSymbol(callableId: CallableId) : FirFunctionSymbol(callableId) { +class FirConstructorSymbol(callableId: CallableId) : FirFunctionSymbol(callableId), ConstructorSymbolMarker { constructor(classId: ClassId) : this(classId.callableIdForConstructor()) val isPrimary: Boolean diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/impl/FirTypeParameterSymbol.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/impl/FirTypeParameterSymbol.kt index dc90c59a279..e3585fe2534 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/impl/FirTypeParameterSymbol.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/impl/FirTypeParameterSymbol.kt @@ -11,10 +11,11 @@ import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterLookupTag import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef +import org.jetbrains.kotlin.mpp.TypeParameterSymbolMarker import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.types.Variance -class FirTypeParameterSymbol : FirClassifierSymbol() { +class FirTypeParameterSymbol : FirClassifierSymbol(), TypeParameterSymbolMarker { val name: Name get() = fir.name diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/impl/FirVariableSymbol.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/impl/FirVariableSymbol.kt index 3fbaeedf6ce..60fd72ec588 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/impl/FirVariableSymbol.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/impl/FirVariableSymbol.kt @@ -11,15 +11,15 @@ import org.jetbrains.kotlin.fir.expressions.FirAnonymousObjectExpression import org.jetbrains.kotlin.fir.expressions.FirExpression import org.jetbrains.kotlin.fir.references.FirControlFlowGraphReference 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.FqName import org.jetbrains.kotlin.name.Name sealed class FirVariableSymbol(override val callableId: CallableId) : FirCallableSymbol() -open class FirPropertySymbol( - callableId: CallableId, -) : FirVariableSymbol(callableId) { +open class FirPropertySymbol(callableId: CallableId, ) : FirVariableSymbol(callableId), PropertySymbolMarker { // TODO: should we use this constructor for local variables? constructor(name: Name) : this(CallableId(name)) @@ -108,7 +108,7 @@ class FirEnumEntrySymbol(callableId: CallableId) : FirVariableSymbol(CallableId(name)) { +class FirValueParameterSymbol(name: Name) : FirVariableSymbol(CallableId(name)), ValueParameterSymbolMarker { val hasDefaultValue: Boolean get() = fir.defaultValue != null diff --git a/compiler/ir/ir.tree/tree-generator/src/org/jetbrains/kotlin/ir/generator/model/Transformations.kt b/compiler/ir/ir.tree/tree-generator/src/org/jetbrains/kotlin/ir/generator/model/Transformations.kt index 92254722fe6..4c07a5a99f9 100644 --- a/compiler/ir/ir.tree/tree-generator/src/org/jetbrains/kotlin/ir/generator/model/Transformations.kt +++ b/compiler/ir/ir.tree/tree-generator/src/org/jetbrains/kotlin/ir/generator/model/Transformations.kt @@ -8,6 +8,7 @@ package org.jetbrains.kotlin.ir.generator.model import org.jetbrains.kotlin.ir.generator.config.* import org.jetbrains.kotlin.ir.generator.elementBaseType 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.partitionIsInstance @@ -82,6 +83,7 @@ fun config2model(config: Config): Model { return Model(elements, rootElement) } +@OptIn(UnsafeCastFunction::class) private fun replaceElementRefs(config: Config, mapping: Map): Element { val visited = mutableMapOf() diff --git a/compiler/testData/diagnostics/tests/multiplatform/headerClass/noImplKeywordOnMember.fir.kt b/compiler/testData/diagnostics/tests/multiplatform/headerClass/noImplKeywordOnMember.fir.kt index ab6d7684384..bd34df5eb05 100644 --- a/compiler/testData/diagnostics/tests/multiplatform/headerClass/noImplKeywordOnMember.fir.kt +++ b/compiler/testData/diagnostics/tests/multiplatform/headerClass/noImplKeywordOnMember.fir.kt @@ -9,7 +9,7 @@ expect class Foo { // MODULE: m2-jvm()()(m1-common) // FILE: jvm.kt -actual class Foo { +actual class Foo { fun bar(): String = "bar" fun bas(g: Int) {} }