[FIR] Fix scope of Java classes that inherit multiple properties with the same name
Use the receiver and context receiver types in addition to the property name as cache keys for the synthetic property generation. Also, fix logic that searches for accessor overrides by comparing receiver and context receiver types. Finally, let synthetic properties delegate their receiverParameter and contextReceivers to their accessors. #KT-65464 Fixed #KT-66195
This commit is contained in:
committed by
Space Team
parent
89ecb92551
commit
0889770ccd
+8
-1
@@ -15,9 +15,16 @@ import org.jetbrains.kotlin.fir.java.scopes.JavaClassUseSiteMemberScope
|
|||||||
import org.jetbrains.kotlin.fir.scopes.impl.FirTypeIntersectionScopeContext.ResultOfIntersection
|
import org.jetbrains.kotlin.fir.scopes.impl.FirTypeIntersectionScopeContext.ResultOfIntersection
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirSyntheticPropertySymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirSyntheticPropertySymbol
|
||||||
|
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
|
||||||
typealias SyntheticPropertiesCache = FirCache<Name, FirSyntheticPropertySymbol?, Pair<JavaClassUseSiteMemberScope, ResultOfIntersection<FirPropertySymbol>>>
|
data class SyntheticPropertiesCacheKey(
|
||||||
|
val name: Name,
|
||||||
|
val receiverParameterType: ConeKotlinType?,
|
||||||
|
val contextReceiverTypes: List<ConeKotlinType>
|
||||||
|
)
|
||||||
|
|
||||||
|
typealias SyntheticPropertiesCache = FirCache<SyntheticPropertiesCacheKey, FirSyntheticPropertySymbol?, Pair<JavaClassUseSiteMemberScope, ResultOfIntersection<FirPropertySymbol>>>
|
||||||
|
|
||||||
class FirSyntheticPropertiesStorage(session: FirSession) : FirSessionComponent {
|
class FirSyntheticPropertiesStorage(session: FirSession) : FirSessionComponent {
|
||||||
private val cachesFactory = session.firCachesFactory
|
private val cachesFactory = session.firCachesFactory
|
||||||
|
|||||||
+2
@@ -268,6 +268,8 @@ class FirSignatureEnhancement(
|
|||||||
|
|
||||||
val defaultQualifiers = firMethod.computeDefaultQualifiers()
|
val defaultQualifiers = firMethod.computeDefaultQualifiers()
|
||||||
val overriddenMembers = precomputedOverridden ?: (firMethod as? FirSimpleFunction)?.overridden().orEmpty()
|
val overriddenMembers = precomputedOverridden ?: (firMethod as? FirSimpleFunction)?.overridden().orEmpty()
|
||||||
|
|
||||||
|
// TODO(KT-66195) handle context receivers
|
||||||
val hasReceiver = overriddenMembers.any { it.receiverParameter != null }
|
val hasReceiver = overriddenMembers.any { it.receiverParameter != null }
|
||||||
|
|
||||||
val newReceiverTypeRef = if (firMethod is FirSimpleFunction && hasReceiver) {
|
val newReceiverTypeRef = if (firMethod is FirSimpleFunction && hasReceiver) {
|
||||||
|
|||||||
+37
-6
@@ -18,6 +18,7 @@ import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertySetter
|
|||||||
import org.jetbrains.kotlin.fir.declarations.synthetic.FirSyntheticProperty
|
import org.jetbrains.kotlin.fir.declarations.synthetic.FirSyntheticProperty
|
||||||
import org.jetbrains.kotlin.fir.declarations.synthetic.buildSyntheticProperty
|
import org.jetbrains.kotlin.fir.declarations.synthetic.buildSyntheticProperty
|
||||||
import org.jetbrains.kotlin.fir.declarations.utils.*
|
import org.jetbrains.kotlin.fir.declarations.utils.*
|
||||||
|
import org.jetbrains.kotlin.fir.java.SyntheticPropertiesCacheKey
|
||||||
import org.jetbrains.kotlin.fir.java.declarations.FirJavaClass
|
import org.jetbrains.kotlin.fir.java.declarations.FirJavaClass
|
||||||
import org.jetbrains.kotlin.fir.java.declarations.FirJavaMethod
|
import org.jetbrains.kotlin.fir.java.declarations.FirJavaMethod
|
||||||
import org.jetbrains.kotlin.fir.java.declarations.buildJavaMethodCopy
|
import org.jetbrains.kotlin.fir.java.declarations.buildJavaMethodCopy
|
||||||
@@ -35,6 +36,7 @@ import org.jetbrains.kotlin.fir.scopes.impl.MembersByScope
|
|||||||
import org.jetbrains.kotlin.fir.scopes.impl.isIntersectionOverride
|
import org.jetbrains.kotlin.fir.scopes.impl.isIntersectionOverride
|
||||||
import org.jetbrains.kotlin.fir.scopes.impl.similarFunctionsOrBothProperties
|
import org.jetbrains.kotlin.fir.scopes.impl.similarFunctionsOrBothProperties
|
||||||
import org.jetbrains.kotlin.fir.scopes.jvm.computeJvmDescriptor
|
import org.jetbrains.kotlin.fir.scopes.jvm.computeJvmDescriptor
|
||||||
|
import org.jetbrains.kotlin.fir.scopes.jvm.computeJvmDescriptorRepresentation
|
||||||
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.fir.types.builder.buildResolvedTypeRef
|
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
|
||||||
@@ -47,6 +49,7 @@ import org.jetbrains.kotlin.name.CallableId
|
|||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.name.StandardClassIds
|
import org.jetbrains.kotlin.name.StandardClassIds
|
||||||
import org.jetbrains.kotlin.types.AbstractTypeChecker
|
import org.jetbrains.kotlin.types.AbstractTypeChecker
|
||||||
|
import org.jetbrains.kotlin.utils.addToStdlib.ifNotEmpty
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.runIf
|
import org.jetbrains.kotlin.utils.addToStdlib.runIf
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -163,7 +166,12 @@ class JavaClassUseSiteMemberScope(
|
|||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
for (overriddenProperty in propertiesFromSupertypes as List<ResultOfIntersection<FirPropertySymbol>>) {
|
for (overriddenProperty in propertiesFromSupertypes as List<ResultOfIntersection<FirPropertySymbol>>) {
|
||||||
val overrideInClass = syntheticPropertyCache.getValue(name, this to overriddenProperty)
|
val key = SyntheticPropertiesCacheKey(
|
||||||
|
name,
|
||||||
|
overriddenProperty.chosenSymbol.receiverParameter?.typeRef?.coneType,
|
||||||
|
overriddenProperty.chosenSymbol.resolvedContextReceivers.ifNotEmpty { map { it.typeRef.coneType } } ?: emptyList()
|
||||||
|
)
|
||||||
|
val overrideInClass = syntheticPropertyCache.getValue(key, this to overriddenProperty)
|
||||||
|
|
||||||
val chosenSymbol = overrideInClass ?: overriddenProperty.chosenSymbol
|
val chosenSymbol = overrideInClass ?: overriddenProperty.chosenSymbol
|
||||||
directOverriddenProperties[chosenSymbol] = listOf(overriddenProperty)
|
directOverriddenProperties[chosenSymbol] = listOf(overriddenProperty)
|
||||||
@@ -208,18 +216,20 @@ class JavaClassUseSiteMemberScope(
|
|||||||
): FirNamedFunctionSymbol? {
|
): FirNamedFunctionSymbol? {
|
||||||
val specialGetterName = if (canUseSpecialGetters) getBuiltinSpecialPropertyGetterName() else null
|
val specialGetterName = if (canUseSpecialGetters) getBuiltinSpecialPropertyGetterName() else null
|
||||||
val name = specialGetterName?.asString() ?: JvmAbi.getterName(fir.name.asString())
|
val name = specialGetterName?.asString() ?: JvmAbi.getterName(fir.name.asString())
|
||||||
return findGetterByName(name, scope)
|
return findGetterOverride(name, scope)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun FirPropertySymbol.findGetterByName(
|
private fun FirPropertySymbol.findGetterOverride(
|
||||||
getterName: String,
|
getterName: String,
|
||||||
scope: FirScope,
|
scope: FirScope,
|
||||||
): FirNamedFunctionSymbol? {
|
): FirNamedFunctionSymbol? {
|
||||||
val propertyFromSupertype = fir
|
val propertyFromSupertype = fir
|
||||||
val expectedReturnType = propertyFromSupertype.returnTypeRef.coneTypeSafe<ConeKotlinType>()
|
val expectedReturnType = propertyFromSupertype.returnTypeRef.coneTypeSafe<ConeKotlinType>()
|
||||||
|
val receiverCount = (if (receiverParameter != null) 1 else 0) + resolvedContextReceivers.size
|
||||||
return scope.getFunctions(Name.identifier(getterName)).firstNotNullOfOrNull factory@{ candidateSymbol ->
|
return scope.getFunctions(Name.identifier(getterName)).firstNotNullOfOrNull factory@{ candidateSymbol ->
|
||||||
val candidate = candidateSymbol.fir
|
val candidate = candidateSymbol.fir
|
||||||
if (candidate.valueParameters.isNotEmpty()) return@factory null
|
if (candidate.valueParameters.size != receiverCount) return@factory null
|
||||||
|
if (!checkValueParameters(candidate)) return@factory null
|
||||||
|
|
||||||
val candidateReturnType = candidate.returnTypeRef.toConeKotlinTypeProbablyFlexible(session, typeParameterStack)
|
val candidateReturnType = candidate.returnTypeRef.toConeKotlinTypeProbablyFlexible(session, typeParameterStack)
|
||||||
|
|
||||||
@@ -239,14 +249,18 @@ class JavaClassUseSiteMemberScope(
|
|||||||
scope: FirScope,
|
scope: FirScope,
|
||||||
): FirNamedFunctionSymbol? {
|
): FirNamedFunctionSymbol? {
|
||||||
val propertyType = fir.returnTypeRef.coneTypeSafe<ConeKotlinType>() ?: return null
|
val propertyType = fir.returnTypeRef.coneTypeSafe<ConeKotlinType>() ?: return null
|
||||||
|
val receiverCount = (if (receiverParameter != null) 1 else 0) + resolvedContextReceivers.size
|
||||||
|
|
||||||
return scope.getFunctions(Name.identifier(JvmAbi.setterName(fir.name.asString()))).firstNotNullOfOrNull factory@{ candidateSymbol ->
|
return scope.getFunctions(Name.identifier(JvmAbi.setterName(fir.name.asString()))).firstNotNullOfOrNull factory@{ candidateSymbol ->
|
||||||
val candidate = candidateSymbol.fir
|
val candidate = candidateSymbol.fir
|
||||||
if (candidate.valueParameters.size != 1) return@factory null
|
|
||||||
|
if (candidate.valueParameters.size != receiverCount + 1) return@factory null
|
||||||
|
if (!checkValueParameters(candidate)) return@factory null
|
||||||
|
|
||||||
if (!candidate.returnTypeRef.toConeKotlinTypeProbablyFlexible(session, typeParameterStack).isUnit) return@factory null
|
if (!candidate.returnTypeRef.toConeKotlinTypeProbablyFlexible(session, typeParameterStack).isUnit) return@factory null
|
||||||
|
|
||||||
val parameterType =
|
val parameterType =
|
||||||
candidate.valueParameters.single().returnTypeRef.toConeKotlinTypeProbablyFlexible(session, typeParameterStack)
|
candidate.valueParameters.last().returnTypeRef.toConeKotlinTypeProbablyFlexible(session, typeParameterStack)
|
||||||
|
|
||||||
candidateSymbol.takeIf {
|
candidateSymbol.takeIf {
|
||||||
candidate.isAcceptableAsAccessorOverride() && AbstractTypeChecker.equalTypes(
|
candidate.isAcceptableAsAccessorOverride() && AbstractTypeChecker.equalTypes(
|
||||||
@@ -256,6 +270,23 @@ class JavaClassUseSiteMemberScope(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun FirPropertySymbol.checkValueParameters(candidate: FirSimpleFunction): Boolean {
|
||||||
|
var parameterIndex = 0
|
||||||
|
for (contextReceiver in this.resolvedContextReceivers) {
|
||||||
|
if (contextReceiver.typeRef.coneType.computeJvmDescriptorRepresentation() !=
|
||||||
|
candidate.valueParameters[parameterIndex++].returnTypeRef.toConeKotlinTypeProbablyFlexible(session, typeParameterStack)
|
||||||
|
.computeJvmDescriptorRepresentation()
|
||||||
|
) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return receiverParameter == null ||
|
||||||
|
receiverParameter!!.typeRef.coneType.computeJvmDescriptorRepresentation() ==
|
||||||
|
candidate.valueParameters[parameterIndex].returnTypeRef.toConeKotlinTypeProbablyFlexible(session, typeParameterStack)
|
||||||
|
.computeJvmDescriptorRepresentation()
|
||||||
|
}
|
||||||
|
|
||||||
private fun FirSimpleFunction.isAcceptableAsAccessorOverride(): Boolean {
|
private fun FirSimpleFunction.isAcceptableAsAccessorOverride(): Boolean {
|
||||||
// We don't accept here accessors with type parameters from Kotlin to avoid strange cases like KT-59038
|
// We don't accept here accessors with type parameters from Kotlin to avoid strange cases like KT-59038
|
||||||
// However, we (temporarily, see below) accept accessors from Kotlin in general to keep K1 compatibility in cases like KT-59550
|
// However, we (temporarily, see below) accept accessors from Kotlin in general to keep K1 compatibility in cases like KT-59550
|
||||||
|
|||||||
+2
-2
@@ -62,7 +62,7 @@ class FirSyntheticProperty @FirImplementationDetail internal constructor(
|
|||||||
get() = false
|
get() = false
|
||||||
|
|
||||||
override val receiverParameter: FirReceiverParameter?
|
override val receiverParameter: FirReceiverParameter?
|
||||||
get() = null
|
get() = getter.receiverParameter
|
||||||
|
|
||||||
override val isVal: Boolean
|
override val isVal: Boolean
|
||||||
get() = !isVar
|
get() = !isVar
|
||||||
@@ -84,7 +84,7 @@ class FirSyntheticProperty @FirImplementationDetail internal constructor(
|
|||||||
get() = FirPropertyBodyResolveState.ALL_BODIES_RESOLVED
|
get() = FirPropertyBodyResolveState.ALL_BODIES_RESOLVED
|
||||||
|
|
||||||
override val contextReceivers: List<FirContextReceiver>
|
override val contextReceivers: List<FirContextReceiver>
|
||||||
get() = emptyList()
|
get() = getter.contextReceivers
|
||||||
|
|
||||||
override fun <R, D> acceptChildren(visitor: FirVisitor<R, D>, data: D) {
|
override fun <R, D> acceptChildren(visitor: FirVisitor<R, D>, data: D) {
|
||||||
returnTypeRef.accept(visitor, data)
|
returnTypeRef.accept(visitor, data)
|
||||||
|
|||||||
+2
-2
@@ -47,7 +47,7 @@ class FirSyntheticPropertyAccessor @FirImplementationDetail internal constructor
|
|||||||
get() = delegate.dispatchReceiverType
|
get() = delegate.dispatchReceiverType
|
||||||
|
|
||||||
override val receiverParameter: FirReceiverParameter?
|
override val receiverParameter: FirReceiverParameter?
|
||||||
get() = null
|
get() = delegate.receiverParameter
|
||||||
|
|
||||||
override val deprecationsProvider: DeprecationsProvider
|
override val deprecationsProvider: DeprecationsProvider
|
||||||
get() = delegate.deprecationsProvider
|
get() = delegate.deprecationsProvider
|
||||||
@@ -75,7 +75,7 @@ class FirSyntheticPropertyAccessor @FirImplementationDetail internal constructor
|
|||||||
}
|
}
|
||||||
|
|
||||||
override val contextReceivers: List<FirContextReceiver>
|
override val contextReceivers: List<FirContextReceiver>
|
||||||
get() = emptyList()
|
get() = delegate.contextReceivers
|
||||||
|
|
||||||
override val controlFlowGraphReference: FirControlFlowGraphReference? = null
|
override val controlFlowGraphReference: FirControlFlowGraphReference? = null
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -51,7 +51,7 @@ class F : J() {
|
|||||||
class F2 : JOverridesRegular() {
|
class F2 : JOverridesRegular() {
|
||||||
fun test() {
|
fun test() {
|
||||||
a
|
a
|
||||||
"".<!UNRESOLVED_REFERENCE!>a<!>
|
"".a
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,6 +65,6 @@ class F3 : JOverridesExtension() {
|
|||||||
class F4 : JOVerridesBoth() {
|
class F4 : JOVerridesBoth() {
|
||||||
fun test() {
|
fun test() {
|
||||||
a
|
a
|
||||||
"".<!UNRESOLVED_REFERENCE!>a<!>
|
"".a
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user