FIR Java: bind overrides properly
This commit is contained in:
committed by
Mikhail Glukhikh
parent
d19a250cbe
commit
2f7ced2a8e
+9
-17
@@ -18,6 +18,7 @@ import org.jetbrains.kotlin.fir.java.enhancement.EnhancementSignatureParts
|
|||||||
import org.jetbrains.kotlin.fir.java.toNotNullConeKotlinType
|
import org.jetbrains.kotlin.fir.java.toNotNullConeKotlinType
|
||||||
import org.jetbrains.kotlin.fir.java.types.FirJavaTypeRef
|
import org.jetbrains.kotlin.fir.java.types.FirJavaTypeRef
|
||||||
import org.jetbrains.kotlin.fir.render
|
import org.jetbrains.kotlin.fir.render
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.transformers.firUnsafe
|
||||||
import org.jetbrains.kotlin.fir.scopes.FirScope
|
import org.jetbrains.kotlin.fir.scopes.FirScope
|
||||||
import org.jetbrains.kotlin.fir.scopes.ProcessorAction
|
import org.jetbrains.kotlin.fir.scopes.ProcessorAction
|
||||||
import org.jetbrains.kotlin.fir.symbols.*
|
import org.jetbrains.kotlin.fir.symbols.*
|
||||||
@@ -316,26 +317,17 @@ class JavaClassEnhancementScope(
|
|||||||
return signatureParts.type
|
return signatureParts.type
|
||||||
}
|
}
|
||||||
|
|
||||||
private val overriddenMemberCache = mutableMapOf<FirCallableMemberDeclaration, List<FirCallableMemberDeclaration>>()
|
private val overrideBindCache = mutableMapOf<Name, Map<ConeFunctionSymbol?, List<ConeCallableSymbol>>>()
|
||||||
|
|
||||||
private fun FirCallableMemberDeclaration.overriddenMembers(): List<FirCallableMemberDeclaration> {
|
private fun FirCallableMemberDeclaration.overriddenMembers(): List<FirCallableMemberDeclaration> {
|
||||||
return overriddenMemberCache.getOrPut(this) {
|
val backMap = overrideBindCache.getOrPut(this.name) {
|
||||||
val result = mutableListOf<FirCallableMemberDeclaration>()
|
useSiteScope.bindOverrides(this.name)
|
||||||
if (this is FirNamedFunction) {
|
useSiteScope
|
||||||
val superTypesScope = useSiteScope.superTypesScope
|
.overriddenByBase
|
||||||
superTypesScope.processFunctionsByName(this.name) { basicFunctionSymbol ->
|
.toList()
|
||||||
val overriddenBy = with(useSiteScope) {
|
.groupBy({ (_, key) -> key }, { (value) -> value })
|
||||||
basicFunctionSymbol.getOverridden(setOf(this@overriddenMembers.symbol as ConeFunctionSymbol))
|
|
||||||
}
|
|
||||||
val overriddenByFir = (overriddenBy as? FirFunctionSymbol)?.fir
|
|
||||||
if (overriddenByFir === this@overriddenMembers) {
|
|
||||||
result += (basicFunctionSymbol as FirFunctionSymbol).fir as FirCallableMemberDeclaration
|
|
||||||
}
|
|
||||||
ProcessorAction.NEXT
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result
|
|
||||||
}
|
}
|
||||||
|
return backMap[this.symbol]?.map { it.firUnsafe() } ?: emptyList()
|
||||||
}
|
}
|
||||||
|
|
||||||
private sealed class TypeInSignature {
|
private sealed class TypeInSignature {
|
||||||
|
|||||||
+49
-28
@@ -5,13 +5,14 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.fir.java.scopes
|
package org.jetbrains.kotlin.fir.java.scopes
|
||||||
|
|
||||||
import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap
|
|
||||||
import org.jetbrains.kotlin.descriptors.Modality
|
import org.jetbrains.kotlin.descriptors.Modality
|
||||||
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.java.JavaTypeParameterStack
|
import org.jetbrains.kotlin.fir.java.JavaTypeParameterStack
|
||||||
import org.jetbrains.kotlin.fir.java.declarations.FirJavaClass
|
import org.jetbrains.kotlin.fir.java.declarations.FirJavaClass
|
||||||
import org.jetbrains.kotlin.fir.java.toNotNullConeKotlinType
|
import org.jetbrains.kotlin.fir.java.toNotNullConeKotlinType
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutorByMap
|
||||||
import org.jetbrains.kotlin.fir.resolve.transformers.firUnsafe
|
import org.jetbrains.kotlin.fir.resolve.transformers.firUnsafe
|
||||||
import org.jetbrains.kotlin.fir.scopes.FirScope
|
import org.jetbrains.kotlin.fir.scopes.FirScope
|
||||||
import org.jetbrains.kotlin.fir.scopes.ProcessorAction
|
import org.jetbrains.kotlin.fir.scopes.ProcessorAction
|
||||||
@@ -25,6 +26,7 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
|
|||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
|
||||||
import org.jetbrains.kotlin.fir.typeContext
|
import org.jetbrains.kotlin.fir.typeContext
|
||||||
import org.jetbrains.kotlin.fir.types.*
|
import org.jetbrains.kotlin.fir.types.*
|
||||||
|
import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
|
||||||
class JavaClassUseSiteScope(
|
class JavaClassUseSiteScope(
|
||||||
@@ -39,45 +41,50 @@ class JavaClassUseSiteScope(
|
|||||||
if (klass is FirJavaClass) klass.javaTypeParameterStack else JavaTypeParameterStack.EMPTY
|
if (klass is FirJavaClass) klass.javaTypeParameterStack else JavaTypeParameterStack.EMPTY
|
||||||
|
|
||||||
//base symbol as key, overridden as value
|
//base symbol as key, overridden as value
|
||||||
private val overriddenByBase = mutableMapOf<ConeCallableSymbol, ConeFunctionSymbol?>()
|
internal val overriddenByBase = mutableMapOf<ConeCallableSymbol, ConeFunctionSymbol?>()
|
||||||
|
|
||||||
private val context: ConeTypeContext = session.typeContext
|
private val context: ConeTypeContext = session.typeContext
|
||||||
|
|
||||||
private fun isEqualTypes(a: ConeKotlinType, b: ConeKotlinType): Boolean {
|
private fun isEqualTypes(a: ConeKotlinType, b: ConeKotlinType, substitutor: ConeSubstitutor): Boolean {
|
||||||
if (a is ConeFlexibleType) return isEqualTypes(a.lowerBound, b)
|
if (a is ConeFlexibleType) return isEqualTypes(a.lowerBound, b, substitutor)
|
||||||
if (b is ConeFlexibleType) return isEqualTypes(a, b.lowerBound)
|
if (b is ConeFlexibleType) return isEqualTypes(a, b.lowerBound, substitutor)
|
||||||
with(context) {
|
with(context) {
|
||||||
if (a is ConeClassLikeType && b is ConeClassLikeType) {
|
return isEqualTypeConstructors(
|
||||||
val aId = a.lookupTag.classId
|
substitutor.substituteOrSelf(a).typeConstructor(),
|
||||||
val bId = b.lookupTag.classId
|
substitutor.substituteOrSelf(b).typeConstructor()
|
||||||
val aMapped = JavaToKotlinClassMap.mapJavaToKotlin(aId.asSingleFqName()) ?: aId
|
)
|
||||||
val bMapped = JavaToKotlinClassMap.mapJavaToKotlin(bId.asSingleFqName()) ?: bId
|
|
||||||
return aMapped == bMapped
|
|
||||||
}
|
|
||||||
return isEqualTypeConstructors(a.typeConstructor(), b.typeConstructor())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun isEqualTypes(a: FirTypeRef, b: FirTypeRef) =
|
private fun isEqualTypes(a: FirTypeRef, b: FirTypeRef, substitutor: ConeSubstitutor) =
|
||||||
isEqualTypes(
|
isEqualTypes(
|
||||||
a.toNotNullConeKotlinType(session, javaTypeParameterStack),
|
a.toNotNullConeKotlinType(session, javaTypeParameterStack),
|
||||||
b.toNotNullConeKotlinType(session, javaTypeParameterStack)
|
b.toNotNullConeKotlinType(session, javaTypeParameterStack),
|
||||||
|
substitutor
|
||||||
)
|
)
|
||||||
|
|
||||||
private fun isOverriddenFunCheck(overriddenInJava: FirFunction, base: FirFunction): Boolean {
|
private fun isOverriddenFunCheck(overriddenInJava: FirFunction, base: FirFunction): Boolean {
|
||||||
|
overriddenInJava as FirCallableMemberDeclaration
|
||||||
val receiverTypeRef = (base as FirCallableMemberDeclaration).receiverTypeRef
|
val receiverTypeRef = (base as FirCallableMemberDeclaration).receiverTypeRef
|
||||||
if (receiverTypeRef == null) {
|
val baseParameterTypes = listOfNotNull(receiverTypeRef) + base.valueParameters.map { it.returnTypeRef }
|
||||||
return overriddenInJava.valueParameters.size == base.valueParameters.size &&
|
|
||||||
overriddenInJava.valueParameters.zip(base.valueParameters).all { (memberParam, selfParam) ->
|
if (overriddenInJava.valueParameters.size != baseParameterTypes.size) return false
|
||||||
isEqualTypes(memberParam.returnTypeRef, selfParam.returnTypeRef)
|
if (overriddenInJava.typeParameters.size != base.typeParameters.size) return false
|
||||||
}
|
|
||||||
} else {
|
val types = base.typeParameters.map {
|
||||||
if (overriddenInJava.valueParameters.size != base.valueParameters.size + 1) return false
|
ConeTypeParameterTypeImpl(it.symbol, false)
|
||||||
val baseParameterTypes = listOf(receiverTypeRef) + base.valueParameters.map { it.returnTypeRef }
|
}
|
||||||
val javaParameterTypes = overriddenInJava.valueParameters.map { it.returnTypeRef }
|
val substitution = ConeSubstitutorByMap(overriddenInJava.typeParameters.map { it.symbol }.zip(types).toMap())
|
||||||
return baseParameterTypes.zip(javaParameterTypes).all { (baseType, typeFromJava) ->
|
if (!overriddenInJava.typeParameters.zip(base.typeParameters).all { (a, b) ->
|
||||||
isEqualTypes(baseType, typeFromJava)
|
a.bounds.size == b.bounds.size && a.bounds.zip(b.bounds).all { (aBound, bBound) ->
|
||||||
|
isEqualTypes(aBound, bBound, substitution)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
) return false
|
||||||
|
|
||||||
|
|
||||||
|
return overriddenInJava.valueParameters.zip(baseParameterTypes).all { (paramFromJava, baseType) ->
|
||||||
|
isEqualTypes(paramFromJava.returnTypeRef, baseType, substitution)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,11 +95,25 @@ class JavaClassUseSiteScope(
|
|||||||
return overriddenInJava.valueParameters.isEmpty()
|
return overriddenInJava.valueParameters.isEmpty()
|
||||||
} else {
|
} else {
|
||||||
if (overriddenInJava.valueParameters.size != 1) return false
|
if (overriddenInJava.valueParameters.size != 1) return false
|
||||||
return isEqualTypes(receiverTypeRef, overriddenInJava.valueParameters.single().returnTypeRef)
|
return isEqualTypes(receiverTypeRef, overriddenInJava.valueParameters.single().returnTypeRef, ConeSubstitutor.Empty)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun ConeCallableSymbol.getOverridden(candidates: Set<ConeFunctionSymbol>): ConeCallableSymbol? {
|
internal fun bindOverrides(name: Name) {
|
||||||
|
val overrideCandidates = mutableSetOf<ConeFunctionSymbol>()
|
||||||
|
declaredMemberScope.processFunctionsByName(name) {
|
||||||
|
overrideCandidates += it
|
||||||
|
ProcessorAction.NEXT
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
superTypesScope.processFunctionsByName(name) {
|
||||||
|
it.getOverridden(overrideCandidates)
|
||||||
|
ProcessorAction.NEXT
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun ConeCallableSymbol.getOverridden(candidates: Set<ConeFunctionSymbol>): ConeCallableSymbol? {
|
||||||
if (overriddenByBase.containsKey(this)) return overriddenByBase[this]
|
if (overriddenByBase.containsKey(this)) return overriddenByBase[this]
|
||||||
|
|
||||||
val overriding = when (this) {
|
val overriding = when (this) {
|
||||||
|
|||||||
Reference in New Issue
Block a user