[FIR] Create intersection overrides for fields in intersection type scope

^KT-56820 Fixed
This commit is contained in:
Dmitriy Novozhilov
2023-03-01 13:16:00 +02:00
committed by Space Team
parent 4e56079c59
commit 8c6d4a6f4b
13 changed files with 325 additions and 70 deletions
@@ -379,6 +379,42 @@ object FirFakeOverrideGenerator {
}
}
fun createCopyForFirField(
newSymbol: FirFieldSymbol,
baseField: FirField,
derivedClassLookupTag: ConeClassLikeLookupTag?,
session: FirSession,
origin: FirDeclarationOrigin,
isExpect: Boolean = baseField.isExpect,
newDispatchReceiverType: ConeSimpleKotlinType?,
newReceiverType: ConeKotlinType? = null,
newContextReceiverTypes: List<ConeKotlinType?>? = null,
newReturnType: ConeKotlinType? = null,
newModality: Modality? = null,
newVisibility: Visibility? = null,
fakeOverrideSubstitution: FakeOverrideSubstitution? = null
): FirField {
return buildField {
source = baseField.source
moduleData = session.moduleData
this.origin = origin
name = baseField.name
isVar = baseField.isVar
this.symbol = newSymbol
status = baseField.status.copy(newVisibility, newModality, isExpect = isExpect)
resolvePhase = baseField.resolvePhase
dispatchReceiverType = newDispatchReceiverType
attributes = baseField.attributes.copy()
configureAnnotationsAndSignature(
baseField, newReceiverType, newContextReceiverTypes, newReturnType, fakeOverrideSubstitution, updateReceiver = false
)
deprecationsProvider = baseField.deprecationsProvider
}.apply {
containingClassForStaticMemberAttr = derivedClassLookupTag.takeIf { shouldOverrideSetContainingClass(baseField) }
}
}
private fun FirPropertyBuilder.configureAnnotationsTypeParametersAndSignature(
useSiteSession: FirSession,
baseProperty: FirProperty,
@@ -452,35 +488,38 @@ object FirFakeOverrideGenerator {
return Triple(copiedReceiverType, copiedContextReceiverTypes, Maybe.Value(copiedReturnType))
}
private fun FirPropertyBuilder.configureAnnotationsAndSignature(
baseProperty: FirProperty,
private fun FirVariableBuilder.configureAnnotationsAndSignature(
baseVariable: FirVariable,
newReceiverType: ConeKotlinType?,
newContextReceiverTypes: List<ConeKotlinType?>?,
newReturnType: ConeKotlinType?,
fakeOverrideSubstitution: FakeOverrideSubstitution?
fakeOverrideSubstitution: FakeOverrideSubstitution?,
updateReceiver: Boolean = true
) {
annotations += baseProperty.annotations
annotations += baseVariable.annotations
@Suppress("NAME_SHADOWING")
val fakeOverrideSubstitution = fakeOverrideSubstitution ?: runIf(baseProperty.returnTypeRef is FirImplicitTypeRef) {
FakeOverrideSubstitution(ConeSubstitutor.Empty, baseProperty.symbol)
val fakeOverrideSubstitution = fakeOverrideSubstitution ?: runIf(baseVariable.returnTypeRef is FirImplicitTypeRef) {
FakeOverrideSubstitution(ConeSubstitutor.Empty, baseVariable.symbol)
}
if (fakeOverrideSubstitution != null) {
returnTypeRef = buildImplicitTypeRef()
attributes.fakeOverrideSubstitution = fakeOverrideSubstitution
} else {
returnTypeRef = baseProperty.returnTypeRef.withReplacedReturnType(newReturnType)
returnTypeRef = baseVariable.returnTypeRef.withReplacedReturnType(newReturnType)
}
receiverParameter = baseProperty.receiverParameter?.let { receiverParameter ->
buildReceiverParameterCopy(receiverParameter) {
typeRef = receiverParameter.typeRef.withReplacedConeType(newReceiverType)
if (updateReceiver) {
receiverParameter = baseVariable.receiverParameter?.let { receiverParameter ->
buildReceiverParameterCopy(receiverParameter) {
typeRef = receiverParameter.typeRef.withReplacedConeType(newReceiverType)
}
}
}
contextReceivers += baseProperty.contextReceivers.zip(
newContextReceiverTypes ?: List(baseProperty.contextReceivers.size) { null }
contextReceivers += baseVariable.contextReceivers.zip(
newContextReceiverTypes ?: List(baseVariable.contextReceivers.size) { null }
) { contextReceiver, newType ->
buildContextReceiverCopy(contextReceiver) {
typeRef = contextReceiver.typeRef.withReplacedConeType(newType)
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.fir.caches.*
import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration
import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
import org.jetbrains.kotlin.fir.declarations.FirVariable
import org.jetbrains.kotlin.fir.declarations.utils.isExpect
import org.jetbrains.kotlin.fir.declarations.utils.modality
import org.jetbrains.kotlin.fir.declarations.utils.visibility
@@ -24,6 +25,7 @@ import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.utils.addToStdlib.runIf
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.contract
@@ -104,7 +106,6 @@ class FirTypeIntersectionScopeContext(
return collectIntersectionResultsForCallables(name, FirScope::processFunctionsByName)
}
@OptIn(PrivateForInline::class)
inline fun <D : FirCallableSymbol<*>> collectMembersGroupedByScope(
name: Name,
processCallables: FirScope.(Name, (D) -> Unit) -> Unit
@@ -123,7 +124,6 @@ class FirTypeIntersectionScopeContext(
}
}
@OptIn(PrivateForInline::class)
inline fun <D : FirCallableSymbol<*>> collectIntersectionResultsForCallables(
name: Name,
processCallables: FirScope.(Name, (D) -> Unit) -> Unit
@@ -200,7 +200,12 @@ class FirTypeIntersectionScopeContext(
is FirPropertySymbol ->
createIntersectionOverrideProperty(mostSpecificSymbols, extractedOverridesSymbols, newModality, newVisibility)
else -> throw IllegalStateException("Should not be here")
is FirFieldSymbol -> {
if (forClassUseSiteScope) error("Can not create intersection override in class scope for field ${key.member}")
createIntersectionOverrideField(mostSpecificSymbols, extractedOverridesSymbols, newModality, newVisibility)
}
else -> error("Unsupported symbol type for creating intersection overrides: ${key.member}")
}.withScope(key.baseScope)
}
@@ -372,26 +377,62 @@ class FirTypeIntersectionScopeContext(
newModality: Modality?,
newVisibility: Visibility,
): FirPropertySymbol {
val key = mostSpecific.first() as FirPropertySymbol
return createIntersectionOverrideVariable<FirPropertySymbol, _>(
mostSpecific,
overrides,
::FirIntersectionOverridePropertySymbol,
) { symbol, fir, returnType ->
FirFakeOverrideGenerator.createCopyForFirProperty(
symbol, fir, derivedClassLookupTag = null, session,
FirDeclarationOrigin.IntersectionOverride,
newModality = newModality,
newVisibility = newVisibility,
newDispatchReceiverType = dispatchReceiverType,
// If any of the properties are vars and the types are not equal, these declarations are conflicting
// anyway and their uses should result in an overload resolution error.
newReturnType = returnType
)
}
}
private fun createIntersectionOverrideField(
mostSpecific: Collection<FirCallableSymbol<*>>,
overrides: Collection<FirCallableSymbol<*>>,
newModality: Modality?,
newVisibility: Visibility,
): FirFieldSymbol {
return createIntersectionOverrideVariable<FirFieldSymbol, _>(
mostSpecific,
overrides,
::FirIntersectionOverrideFieldSymbol
) { symbol, fir, returnType ->
FirFakeOverrideGenerator.createCopyForFirField(
symbol, fir, derivedClassLookupTag = null, session,
FirDeclarationOrigin.IntersectionOverride,
newModality = newModality,
newVisibility = newVisibility,
newDispatchReceiverType = dispatchReceiverType,
// If any of the properties are vars and the types are not equal, these declarations are conflicting
// anyway and their uses should result in an overload resolution error.
newReturnType = returnType
)
}
}
private inline fun <reified S : FirVariableSymbol<F>, F : FirVariable> createIntersectionOverrideVariable(
mostSpecific: Collection<FirCallableSymbol<*>>,
overrides: Collection<FirCallableSymbol<*>>,
createIntersectionOverrideSymbol: (CallableId, Collection<FirCallableSymbol<*>>) -> S,
createCopy: (S, F, returnType: ConeKotlinType?) -> F
): S {
val key = mostSpecific.first() as S
val keyFir = key.fir
val callableId = CallableId(
dispatchReceiverType.classId ?: keyFir.dispatchReceiverClassLookupTagOrNull()?.classId!!,
keyFir.name
)
val newSymbol = FirIntersectionOverridePropertySymbol(callableId, overrides)
FirFakeOverrideGenerator.createCopyForFirProperty(
newSymbol, keyFir, derivedClassLookupTag = null, session,
FirDeclarationOrigin.IntersectionOverride,
newModality = newModality,
newVisibility = newVisibility,
newDispatchReceiverType = dispatchReceiverType,
// If any of the properties are vars and the types are not equal, these declarations are conflicting
// anyway and their uses should result in an overload resolution error.
newReturnType = if (!forClassUseSiteScope && !mostSpecific.any { (it as FirPropertySymbol).fir.isVar })
intersectReturnTypes(mostSpecific)
else
null,
).apply {
val callableId = CallableId(dispatchReceiverType.classId ?: keyFir.dispatchReceiverClassLookupTagOrNull()?.classId!!, keyFir.name)
val newSymbol = createIntersectionOverrideSymbol(callableId, overrides)
val newReturnType = runIf(!forClassUseSiteScope && mostSpecific.none { (it as FirVariableSymbol<*>).fir.isVar }) {
intersectReturnTypes(mostSpecific)
}
createCopy(newSymbol, keyFir, newReturnType).apply {
originalForIntersectionOverrideAttr = keyFir
}
return newSymbol