FIR Java: bind overrides properly

This commit is contained in:
Simon Ogorodnik
2019-04-23 04:22:48 +03:00
committed by Mikhail Glukhikh
parent d19a250cbe
commit 2f7ced2a8e
2 changed files with 58 additions and 45 deletions
@@ -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 {
@@ -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) {