FIR: Rework loading overrides of special built-in methods from Java
Some of the changed data is correct, but some diagnostics are incorrect Corner cases like having both contains(Object) and contains(String) within implementation of Collection<String> is not supported
This commit is contained in:
@@ -43,6 +43,9 @@ import org.jetbrains.kotlin.util.OperatorNameConventions.ITERATOR
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions.NEXT
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions.SET
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions.UNARY_OPERATION_NAMES
|
||||
import kotlin.contracts.ExperimentalContracts
|
||||
import kotlin.contracts.InvocationKind
|
||||
import kotlin.contracts.contract
|
||||
import kotlin.properties.Delegates
|
||||
|
||||
@OptIn(FirImplementationDetail::class)
|
||||
@@ -227,3 +230,29 @@ class FirJavaMethodBuilder : FirFunctionBuilder, FirTypeParametersOwnerBuilder,
|
||||
inline fun buildJavaMethod(init: FirJavaMethodBuilder.() -> Unit): FirJavaMethod {
|
||||
return FirJavaMethodBuilder().apply(init).build()
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalContracts::class)
|
||||
inline fun buildJavaMethodCopy(original: FirSimpleFunction, init: FirJavaMethodBuilder.() -> Unit): FirJavaMethod {
|
||||
contract {
|
||||
callsInPlace(init, InvocationKind.EXACTLY_ONCE)
|
||||
}
|
||||
val copyBuilder = FirJavaMethodBuilder()
|
||||
copyBuilder.source = original.source
|
||||
copyBuilder.session = original.session
|
||||
copyBuilder.resolvePhase = original.resolvePhase
|
||||
copyBuilder.attributes = original.attributes.copy()
|
||||
copyBuilder.returnTypeRef = original.returnTypeRef
|
||||
copyBuilder.valueParameters.addAll(original.valueParameters)
|
||||
copyBuilder.body = original.body
|
||||
copyBuilder.status = original.status
|
||||
copyBuilder.dispatchReceiverType = original.dispatchReceiverType
|
||||
copyBuilder.name = original.name
|
||||
copyBuilder.symbol = original.symbol
|
||||
copyBuilder.annotations.addAll(original.annotations)
|
||||
copyBuilder.typeParameters.addAll(original.typeParameters)
|
||||
val annotations = original.annotations
|
||||
copyBuilder.annotationBuilder = { annotations }
|
||||
return copyBuilder
|
||||
.apply(init)
|
||||
.build()
|
||||
}
|
||||
|
||||
+21
@@ -20,6 +20,9 @@ import org.jetbrains.kotlin.fir.visitors.FirTransformer
|
||||
import org.jetbrains.kotlin.fir.visitors.FirVisitor
|
||||
import org.jetbrains.kotlin.fir.visitors.transformSingle
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import kotlin.contracts.ExperimentalContracts
|
||||
import kotlin.contracts.InvocationKind
|
||||
import kotlin.contracts.contract
|
||||
|
||||
@OptIn(FirImplementationDetail::class)
|
||||
class FirJavaValueParameter @FirImplementationDetail constructor(
|
||||
@@ -174,3 +177,21 @@ class FirJavaValueParameterBuilder {
|
||||
inline fun buildJavaValueParameter(init: FirJavaValueParameterBuilder.() -> Unit): FirJavaValueParameter {
|
||||
return FirJavaValueParameterBuilder().apply(init).build()
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalContracts::class)
|
||||
inline fun buildJavaValueParameterCopy(original: FirValueParameter, init: FirJavaValueParameterBuilder.() -> Unit): FirValueParameter {
|
||||
contract {
|
||||
callsInPlace(init, InvocationKind.EXACTLY_ONCE)
|
||||
}
|
||||
val copyBuilder = FirJavaValueParameterBuilder()
|
||||
copyBuilder.source = original.source
|
||||
copyBuilder.session = original.session
|
||||
copyBuilder.attributes = original.attributes.copy()
|
||||
copyBuilder.returnTypeRef = original.returnTypeRef
|
||||
copyBuilder.name = original.name
|
||||
val annotations = original.annotations
|
||||
copyBuilder.annotationBuilder = { annotations }
|
||||
copyBuilder.defaultValue = original.defaultValue
|
||||
copyBuilder.isVararg = original.isVararg
|
||||
return copyBuilder.apply(init).build()
|
||||
}
|
||||
|
||||
+8
-1
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.fir.declarations.synthetic.buildSyntheticProperty
|
||||
import org.jetbrains.kotlin.fir.initialSignatureAttr
|
||||
import org.jetbrains.kotlin.fir.java.JavaTypeParameterStack
|
||||
import org.jetbrains.kotlin.fir.java.declarations.*
|
||||
import org.jetbrains.kotlin.fir.java.toConeKotlinTypeProbablyFlexible
|
||||
import org.jetbrains.kotlin.fir.render
|
||||
import org.jetbrains.kotlin.fir.scopes.jvm.computeJvmDescriptor
|
||||
import org.jetbrains.kotlin.fir.symbols.CallableId
|
||||
@@ -165,7 +166,10 @@ class FirSignatureEnhancement(
|
||||
val memberContext = context.copyWithNewDefaultTypeQualifiers(typeQualifierResolver, jsr305State, firMethod.annotations)
|
||||
|
||||
val predefinedEnhancementInfo =
|
||||
SignatureBuildingComponents.signature(owner.symbol.classId, firMethod.computeJvmDescriptor()).let { signature ->
|
||||
SignatureBuildingComponents.signature(
|
||||
owner.symbol.classId,
|
||||
firMethod.computeJvmDescriptor { it.toConeKotlinTypeProbablyFlexible(session, javaTypeParameterStack) }
|
||||
).let { signature ->
|
||||
PREDEFINED_FUNCTION_ENHANCEMENT_INFO_BY_SIGNATURE[signature]
|
||||
}
|
||||
|
||||
@@ -308,6 +312,9 @@ class FirSignatureEnhancement(
|
||||
ownerParameter: FirJavaValueParameter,
|
||||
index: Int
|
||||
): FirResolvedTypeRef {
|
||||
if (ownerParameter.returnTypeRef is FirResolvedTypeRef) {
|
||||
return ownerParameter.returnTypeRef as FirResolvedTypeRef
|
||||
}
|
||||
val signatureParts = ownerFunction.partsForValueParameter(
|
||||
typeQualifierResolver,
|
||||
overriddenMembers,
|
||||
|
||||
+1
-97
@@ -5,31 +5,17 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.java.scopes
|
||||
|
||||
import org.jetbrains.kotlin.builtins.StandardNames
|
||||
import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.FirCallableMemberDeclaration
|
||||
import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
|
||||
import org.jetbrains.kotlin.fir.declarations.FirProperty
|
||||
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
|
||||
import org.jetbrains.kotlin.fir.java.enhancement.FirSignatureEnhancement
|
||||
import org.jetbrains.kotlin.fir.resolve.lookupSuperTypes
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
||||
import org.jetbrains.kotlin.fir.scopes.FirTypeScope
|
||||
import org.jetbrains.kotlin.fir.scopes.ProcessorAction
|
||||
import org.jetbrains.kotlin.fir.scopes.impl.FirFakeOverrideGenerator
|
||||
import org.jetbrains.kotlin.fir.scopes.jvm.computeJvmDescriptorReplacingKotlinToJava
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterLookupTag
|
||||
import org.jetbrains.kotlin.fir.symbols.StandardClassIds
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.load.java.SpecialGenericSignatures
|
||||
import org.jetbrains.kotlin.load.java.SpecialGenericSignatures.Companion.ERASED_COLLECTION_PARAMETER_SIGNATURES
|
||||
import org.jetbrains.kotlin.load.java.SpecialGenericSignatures.Companion.ERASED_VALUE_PARAMETERS_SHORT_NAMES
|
||||
import org.jetbrains.kotlin.load.java.SpecialGenericSignatures.Companion.ERASED_VALUE_PARAMETERS_SIGNATURES
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
class JavaClassMembersEnhancementScope(
|
||||
session: FirSession,
|
||||
@@ -62,91 +48,10 @@ class JavaClassMembersEnhancementScope(
|
||||
return super.processPropertiesByName(name, processor)
|
||||
}
|
||||
|
||||
private fun FirSimpleFunction.changeSignatureIfErasedValueParameter(): FirSimpleFunction {
|
||||
val typeParameters = owner.fir.typeParameters
|
||||
if (typeParameters.isEmpty() || name !in ERASED_VALUE_PARAMETERS_SHORT_NAMES) {
|
||||
return this
|
||||
}
|
||||
val jvmDescriptor = this.computeJvmDescriptorReplacingKotlinToJava().replace(
|
||||
"kotlin/collections/Collection",
|
||||
"java/util/Collection"
|
||||
)
|
||||
if (ERASED_VALUE_PARAMETERS_SIGNATURES.none { it.endsWith(jvmDescriptor) }) {
|
||||
return this
|
||||
}
|
||||
val superClassIds = listOfNotNull(symbol.callableId.classId) +
|
||||
lookupSuperTypes(owner, lookupInterfaces = true, deep = true, useSiteSession = session).map { it.lookupTag.classId }
|
||||
for (superClassId in superClassIds) {
|
||||
val javaClassId = JavaToKotlinClassMap.mapKotlinToJava(superClassId.asSingleFqName().toUnsafe()) ?: superClassId
|
||||
val newParameterTypes: List<ConeKotlinType?> = when (val fqJvmDescriptor = "${javaClassId.asString()}.$jvmDescriptor") {
|
||||
in ERASED_COLLECTION_PARAMETER_SIGNATURES -> {
|
||||
valueParameters.map {
|
||||
val typeParameter = typeParameters.first()
|
||||
ConeClassLikeLookupTagImpl(ClassId.topLevel(StandardNames.FqNames.collection)).constructClassType(
|
||||
arrayOf(
|
||||
ConeTypeParameterLookupTag(typeParameter.symbol).constructType(emptyArray(), isNullable = false)
|
||||
), isNullable = false
|
||||
)
|
||||
}
|
||||
}
|
||||
in ERASED_VALUE_PARAMETERS_SIGNATURES -> {
|
||||
val specialSignatureInfo = SpecialGenericSignatures.getSpecialSignatureInfo(fqJvmDescriptor)
|
||||
if (!specialSignatureInfo.isObjectReplacedWithTypeParameter) {
|
||||
return this
|
||||
}
|
||||
valueParameters.mapIndexed { i, valueParameter ->
|
||||
val classLikeType =
|
||||
valueParameter.returnTypeRef.coneTypeSafe<ConeKotlinType>()?.lowerBoundIfFlexible().safeAs<ConeClassLikeType>()
|
||||
if (classLikeType?.lookupTag?.classId == StandardClassIds.Any) {
|
||||
val typeParameterIndex = if (name.asString() == "containsValue") 1 else i
|
||||
val typeParameter = typeParameters.getOrNull(typeParameterIndex) ?: typeParameters.first()
|
||||
val type = ConeTypeParameterLookupTag(typeParameter.symbol).constructType(
|
||||
emptyArray(), valueParameter.returnTypeRef.isMarkedNullable == true
|
||||
)
|
||||
if (valueParameter.returnTypeRef.coneType is ConeFlexibleType) {
|
||||
ConeFlexibleType(
|
||||
type.withAttributes(
|
||||
type.attributes.withFlexibleUnless {
|
||||
it.hasEnhancedNullability
|
||||
}
|
||||
),
|
||||
type.withNullability(ConeNullability.NULLABLE)
|
||||
)
|
||||
} else {
|
||||
type
|
||||
}
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if (newParameterTypes.none { it != null }) {
|
||||
return this
|
||||
}
|
||||
|
||||
return FirFakeOverrideGenerator.createCopyForFirFunction(
|
||||
FirNamedFunctionSymbol(symbol.callableId),
|
||||
this,
|
||||
session,
|
||||
FirDeclarationOrigin.Enhancement,
|
||||
newParameterTypes = valueParameters.zip(newParameterTypes).map { (valueParameter, newType) ->
|
||||
newType ?: valueParameter.returnTypeRef.coneType
|
||||
},
|
||||
newDispatchReceiverType = dispatchReceiverType,
|
||||
)
|
||||
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
override fun processFunctionsByName(name: Name, processor: (FirNamedFunctionSymbol) -> Unit) {
|
||||
useSiteMemberScope.processFunctionsByName(name) process@{ original ->
|
||||
val symbol = signatureEnhancement.enhancedFunction(original, name)
|
||||
val enhancedFunction = (symbol.fir as? FirSimpleFunction)?.changeSignatureIfErasedValueParameter()
|
||||
val enhancedFunction = (symbol.fir as? FirSimpleFunction)
|
||||
val enhancedFunctionSymbol = enhancedFunction?.symbol ?: symbol
|
||||
|
||||
if (enhancedFunctionSymbol is FirNamedFunctionSymbol) {
|
||||
@@ -162,7 +67,6 @@ class JavaClassMembersEnhancementScope(
|
||||
|
||||
private fun FirCallableMemberDeclaration<*>.overriddenMembers(name: Name): List<FirCallableMemberDeclaration<*>> {
|
||||
val backMap = overrideBindCache.getOrPut(name) {
|
||||
useSiteMemberScope.bindOverrides(name)
|
||||
useSiteMemberScope
|
||||
.overrideByBase
|
||||
.toList()
|
||||
|
||||
+374
-98
@@ -5,26 +5,30 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.java.scopes
|
||||
|
||||
import com.intellij.lang.jvm.types.JvmPrimitiveTypeKind
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.*
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.declarations.synthetic.FirSyntheticProperty
|
||||
import org.jetbrains.kotlin.fir.declarations.synthetic.buildSyntheticProperty
|
||||
import org.jetbrains.kotlin.fir.java.declarations.*
|
||||
import org.jetbrains.kotlin.fir.resolve.FirJavaSyntheticNamesProvider
|
||||
import org.jetbrains.kotlin.fir.resolve.calls.syntheticNamesProvider
|
||||
import org.jetbrains.kotlin.fir.scopes.FirScope
|
||||
import org.jetbrains.kotlin.fir.scopes.FirTypeScope
|
||||
import org.jetbrains.kotlin.fir.scopes.getContainingCallableNamesIfPresent
|
||||
import org.jetbrains.kotlin.fir.scopes.getContainingClassifierNamesIfPresent
|
||||
import org.jetbrains.kotlin.fir.java.toConeKotlinTypeProbablyFlexible
|
||||
import org.jetbrains.kotlin.fir.resolve.toSymbol
|
||||
import org.jetbrains.kotlin.fir.scopes.*
|
||||
import org.jetbrains.kotlin.fir.scopes.impl.AbstractFirUseSiteMemberScope
|
||||
import org.jetbrains.kotlin.fir.scopes.jvm.computeJvmDescriptor
|
||||
import org.jetbrains.kotlin.fir.scopes.jvm.computeJvmSignature
|
||||
import org.jetbrains.kotlin.fir.symbols.CallableId
|
||||
import org.jetbrains.kotlin.fir.symbols.StandardClassIds
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||
import org.jetbrains.kotlin.fir.types.isUnit
|
||||
import org.jetbrains.kotlin.fir.types.jvm.FirJavaTypeRef
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaPrimitiveType
|
||||
import org.jetbrains.kotlin.load.java.structure.impl.JavaPrimitiveTypeImpl
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.load.java.BuiltinSpecialProperties
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||
import org.jetbrains.kotlin.load.java.SpecialGenericSignatures
|
||||
import org.jetbrains.kotlin.load.java.SpecialGenericSignatures.Companion.ERASED_COLLECTION_PARAMETER_NAMES
|
||||
import org.jetbrains.kotlin.load.java.SpecialGenericSignatures.Companion.sameAsBuiltinMethodWithErasedValueParameters
|
||||
import org.jetbrains.kotlin.load.java.getPropertyNamesCandidatesByAccessorName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.types.AbstractTypeChecker
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
|
||||
|
||||
class JavaClassUseSiteMemberScope(
|
||||
klass: FirJavaClass,
|
||||
@@ -37,15 +41,8 @@ class JavaClassUseSiteMemberScope(
|
||||
superTypesScope,
|
||||
declaredMemberScope
|
||||
) {
|
||||
internal fun bindOverrides(name: Name) {
|
||||
val overrideCandidates = mutableSetOf<FirNamedFunctionSymbol>()
|
||||
declaredMemberScope.processFunctionsByName(name) {
|
||||
overrideCandidates += it
|
||||
}
|
||||
superTypesScope.processFunctionsByName(name) {
|
||||
it.getOverridden(overrideCandidates)
|
||||
}
|
||||
}
|
||||
private val typeParameterStack = klass.javaTypeParameterStack
|
||||
private val specialFunctions = hashMapOf<Name, Collection<FirNamedFunctionSymbol>>()
|
||||
|
||||
override fun getCallableNames(): Set<Name> {
|
||||
return declaredMemberScope.getContainingCallableNamesIfPresent() + superTypesScope.getCallableNames()
|
||||
@@ -72,99 +69,378 @@ class JavaClassUseSiteMemberScope(
|
||||
}.symbol
|
||||
}
|
||||
|
||||
private fun processAccessorFunctionsAndPropertiesByName(
|
||||
propertyName: Name,
|
||||
getterNames: List<Name>,
|
||||
processor: (FirVariableSymbol<*>) -> Unit
|
||||
) {
|
||||
val overrideCandidates = mutableSetOf<FirCallableSymbol<*>>()
|
||||
declaredMemberScope.processPropertiesByName(propertyName) { variableSymbol ->
|
||||
if (variableSymbol.isStatic) return@processPropertiesByName
|
||||
overrideCandidates += variableSymbol
|
||||
override fun processPropertiesByName(name: Name, processor: (FirVariableSymbol<*>) -> Unit) {
|
||||
val fields = mutableSetOf<FirCallableSymbol<*>>()
|
||||
val fieldNames = mutableSetOf<Name>()
|
||||
|
||||
// fields
|
||||
declaredMemberScope.processPropertiesByName(name) processor@{ variableSymbol ->
|
||||
if (variableSymbol.isStatic) return@processor
|
||||
fields += variableSymbol
|
||||
fieldNames += variableSymbol.fir.name
|
||||
processor(variableSymbol)
|
||||
}
|
||||
|
||||
for (getterName in getterNames) {
|
||||
var getterSymbol: FirNamedFunctionSymbol? = null
|
||||
var setterSymbol: FirNamedFunctionSymbol? = null
|
||||
declaredMemberScope.processFunctionsByName(getterName) { functionSymbol ->
|
||||
if (getterSymbol == null) {
|
||||
val function = functionSymbol.fir
|
||||
if (!function.isStatic && function.valueParameters.isEmpty()) {
|
||||
getterSymbol = functionSymbol
|
||||
}
|
||||
}
|
||||
}
|
||||
val setterName = session.syntheticNamesProvider.setterNameByGetterName(getterName)
|
||||
if (getterSymbol != null && setterName != null) {
|
||||
declaredMemberScope.processFunctionsByName(setterName) { functionSymbol ->
|
||||
if (setterSymbol == null) {
|
||||
val function = functionSymbol.fir
|
||||
if (!function.isStatic && function.valueParameters.size == 1) {
|
||||
val returnTypeRef = function.returnTypeRef
|
||||
if (returnTypeRef.isUnit) {
|
||||
// Unit return type
|
||||
setterSymbol = functionSymbol
|
||||
} else if (returnTypeRef is FirJavaTypeRef) {
|
||||
// Void/void return type
|
||||
when (val returnType = returnTypeRef.type) {
|
||||
is JavaPrimitiveTypeImpl ->
|
||||
if (returnType.psi.kind == JvmPrimitiveTypeKind.VOID) {
|
||||
setterSymbol = functionSymbol
|
||||
}
|
||||
is JavaPrimitiveType ->
|
||||
if (returnType.type == null) {
|
||||
setterSymbol = functionSymbol
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
val accessorSymbol = generateAccessorSymbol(getterSymbol!!, setterSymbol, propertyName)
|
||||
overrideCandidates += accessorSymbol
|
||||
}
|
||||
}
|
||||
val fromSupertypes = superTypesScope.getProperties(name)
|
||||
|
||||
superTypesScope.processPropertiesByName(propertyName) {
|
||||
when (val overriddenBy = it.getOverridden(overrideCandidates)) {
|
||||
null -> processor(it)
|
||||
is FirAccessorSymbol -> processor(overriddenBy)
|
||||
is FirPropertySymbol -> if (it is FirPropertySymbol) {
|
||||
directOverriddenProperties.getOrPut(overriddenBy) { mutableListOf() }.add(it)
|
||||
for (propertyFromSupertype in fromSupertypes) {
|
||||
if (propertyFromSupertype is FirFieldSymbol) {
|
||||
if (propertyFromSupertype.fir.name !in fieldNames) {
|
||||
processor(propertyFromSupertype)
|
||||
}
|
||||
continue
|
||||
}
|
||||
if (propertyFromSupertype !is FirPropertySymbol) continue
|
||||
val overrideInClass = propertyFromSupertype.createOverridePropertyIfExists(declaredMemberScope)
|
||||
when {
|
||||
overrideInClass != null -> {
|
||||
directOverriddenProperties.getOrPut(overrideInClass) { mutableListOf() }.add(propertyFromSupertype)
|
||||
overrideByBase[propertyFromSupertype] = overrideInClass
|
||||
processor(overrideInClass)
|
||||
}
|
||||
else -> processor(propertyFromSupertype)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun processPropertiesByName(name: Name, processor: (FirVariableSymbol<*>) -> Unit) {
|
||||
val getterNames = FirJavaSyntheticNamesProvider.possibleGetterNamesByPropertyName(name)
|
||||
return processAccessorFunctionsAndPropertiesByName(name, getterNames, processor)
|
||||
private fun FirVariableSymbol<*>.createOverridePropertyIfExists(scope: FirScope): FirPropertySymbol? {
|
||||
if (this !is FirPropertySymbol || !doesClassOverridesProperty(this, scope)) return null
|
||||
|
||||
val getterSymbol = this.findGetterOverride(scope)!!
|
||||
val setterSymbol =
|
||||
if (this.fir.isVar)
|
||||
this.findSetterOverride(scope)!!
|
||||
else
|
||||
null
|
||||
|
||||
return generateAccessorSymbol(getterSymbol, setterSymbol, fir.name)
|
||||
}
|
||||
|
||||
private fun doesClassOverridesProperty(
|
||||
propertySymbolFromSupertype: FirPropertySymbol,
|
||||
scope: FirScope,
|
||||
): Boolean {
|
||||
val getter = propertySymbolFromSupertype.findGetterOverride(scope)
|
||||
val setter = propertySymbolFromSupertype.findSetterOverride(scope)
|
||||
|
||||
if (getter == null) return false
|
||||
if (!propertySymbolFromSupertype.fir.isVar) return true
|
||||
|
||||
return setter != null && setter.fir.modality == getter.fir.modality
|
||||
}
|
||||
|
||||
private fun FirPropertySymbol.findGetterOverride(
|
||||
scope: FirScope,
|
||||
): FirNamedFunctionSymbol? {
|
||||
val specialGetterName = getBuiltinSpecialPropertyGetterName()
|
||||
if (specialGetterName != null) {
|
||||
return findGetterByName(specialGetterName.asString(), scope)
|
||||
}
|
||||
|
||||
return findGetterByName(JvmAbi.getterName(fir.name.asString()), scope)
|
||||
}
|
||||
|
||||
private fun FirPropertySymbol.findGetterByName(
|
||||
getterName: String,
|
||||
scope: FirScope,
|
||||
): FirNamedFunctionSymbol? {
|
||||
val propertyFromSupertype = fir
|
||||
val expectedReturnType = propertyFromSupertype.returnTypeRef.coneTypeSafe<ConeKotlinType>()
|
||||
return scope.getFunctions(Name.identifier(getterName)).firstNotNullResult factory@{ candidateSymbol ->
|
||||
val candidate = candidateSymbol.fir
|
||||
if (candidate.valueParameters.isNotEmpty()) return@factory null
|
||||
|
||||
val candidateReturnType = candidate.returnTypeRef.toConeKotlinTypeProbablyFlexible(session, typeParameterStack)
|
||||
|
||||
candidateSymbol.takeIf {
|
||||
// TODO: Decide something for the case when property type is not computed yet
|
||||
expectedReturnType == null || AbstractTypeChecker.isSubtypeOf(session.typeContext, candidateReturnType, expectedReturnType)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun FirPropertySymbol.findSetterOverride(
|
||||
scope: FirScope,
|
||||
): FirNamedFunctionSymbol? {
|
||||
val propertyType = fir.returnTypeRef.coneTypeSafe<ConeKotlinType>() ?: return null
|
||||
return scope.getFunctions(Name.identifier(JvmAbi.setterName(fir.name.asString()))).firstNotNullResult factory@{ candidateSymbol ->
|
||||
val candidate = candidateSymbol.fir
|
||||
if (candidate.valueParameters.size != 1) return@factory null
|
||||
|
||||
if (!candidate.returnTypeRef.toConeKotlinTypeProbablyFlexible(session, typeParameterStack).isUnit) return@factory null
|
||||
|
||||
val parameterType =
|
||||
candidate.valueParameters.single().returnTypeRef.toConeKotlinTypeProbablyFlexible(session, typeParameterStack)
|
||||
|
||||
candidateSymbol.takeIf {
|
||||
AbstractTypeChecker.equalTypes(session.typeContext, parameterType, propertyType)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun FirPropertySymbol.getBuiltinSpecialPropertyGetterName(): Name? {
|
||||
var result: Name? = null
|
||||
|
||||
superTypesScope.processOverriddenPropertiesAndSelf(this) { overridden ->
|
||||
val fqName = overridden.fir.containingClass()?.classId?.asSingleFqName()?.child(overridden.fir.name)
|
||||
|
||||
BuiltinSpecialProperties.PROPERTY_FQ_NAME_TO_JVM_GETTER_NAME_MAP[fqName]?.let { name ->
|
||||
result = name
|
||||
return@processOverriddenPropertiesAndSelf ProcessorAction.STOP
|
||||
}
|
||||
|
||||
ProcessorAction.NEXT
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
override fun processFunctionsByName(name: Name, processor: (FirNamedFunctionSymbol) -> Unit) {
|
||||
val potentialPropertyNames = session.syntheticNamesProvider.possiblePropertyNamesByAccessorName(name)
|
||||
val accessors = mutableListOf<FirAccessorSymbol>()
|
||||
val getterName by lazy { session.syntheticNamesProvider.getterNameBySetterName(name) ?: name }
|
||||
for (potentialPropertyName in potentialPropertyNames) {
|
||||
processAccessorFunctionsAndPropertiesByName(potentialPropertyName, listOf(getterName)) {
|
||||
if (it is FirAccessorSymbol) {
|
||||
accessors += it
|
||||
}
|
||||
}
|
||||
}
|
||||
if (accessors.isEmpty()) {
|
||||
val potentialPropertyNames = getPropertyNamesCandidatesByAccessorName(name)
|
||||
|
||||
val renamedSpecialBuiltInNames = SpecialGenericSignatures.getBuiltinFunctionNamesByJvmName(name)
|
||||
|
||||
if (potentialPropertyNames.isEmpty() && renamedSpecialBuiltInNames.isEmpty() &&
|
||||
!name.sameAsBuiltinMethodWithErasedValueParameters
|
||||
) {
|
||||
return super.processFunctionsByName(name, processor)
|
||||
}
|
||||
super.processFunctionsByName(name) { functionSymbol ->
|
||||
if (accessors.none { accessorSymbol ->
|
||||
val syntheticProperty = accessorSymbol.fir as FirSyntheticProperty
|
||||
syntheticProperty.getter.delegate === functionSymbol.fir ||
|
||||
syntheticProperty.setter?.delegate === functionSymbol.fir
|
||||
}
|
||||
|
||||
val overriddenProperties = potentialPropertyNames.flatMap(this::getProperties).filterIsInstance<FirPropertySymbol>()
|
||||
|
||||
specialFunctions.getOrPut(name) {
|
||||
doProcessSpecialFunctions(name, overriddenProperties, renamedSpecialBuiltInNames)
|
||||
}.forEach {
|
||||
processor(it)
|
||||
}
|
||||
}
|
||||
|
||||
private fun doProcessSpecialFunctions(
|
||||
name: Name,
|
||||
overriddenProperties: List<FirPropertySymbol>,
|
||||
renamedSpecialBuiltInNames: List<Name>
|
||||
): List<FirNamedFunctionSymbol> {
|
||||
val result = mutableListOf<FirNamedFunctionSymbol>()
|
||||
|
||||
declaredMemberScope.processFunctionsByName(name) { functionSymbol ->
|
||||
if (functionSymbol.isStatic) return@processFunctionsByName
|
||||
if (overriddenProperties.none { it.isOverriddenInClassBy(functionSymbol) } &&
|
||||
!functionSymbol.doesOverrideRenamedBuiltins(renamedSpecialBuiltInNames) &&
|
||||
!functionSymbol.shouldBeVisibleAsOverrideOfBuiltInWithErasedValueParameters()
|
||||
) {
|
||||
processor(functionSymbol)
|
||||
result += functionSymbol
|
||||
}
|
||||
}
|
||||
|
||||
addOverriddenSpecialMethods(name, result, declaredMemberScope)
|
||||
|
||||
val overrideCandidates = result.toMutableSet()
|
||||
|
||||
superTypesScope.processFunctionsByName(name) {
|
||||
val overriddenBy = it.getOverridden(overrideCandidates)
|
||||
if (overriddenBy == null) {
|
||||
result += it
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
private fun FirPropertySymbol.isOverriddenInClassBy(functionSymbol: FirNamedFunctionSymbol): Boolean {
|
||||
val fir = fir as? FirSyntheticProperty ?: return false
|
||||
|
||||
return fir.getter.delegate.symbol == functionSymbol || fir.setter?.delegate?.symbol == functionSymbol
|
||||
}
|
||||
|
||||
private fun addOverriddenSpecialMethods(
|
||||
name: Name,
|
||||
result: MutableList<FirNamedFunctionSymbol>,
|
||||
scope: FirScope,
|
||||
) {
|
||||
superTypesScope.processFunctionsByName(name) { fromSupertype ->
|
||||
obtainOverrideForBuiltinWithDifferentJvmName(fromSupertype, scope, name)?.let {
|
||||
directOverriddenFunctions[it] = listOf(fromSupertype)
|
||||
overrideByBase[fromSupertype] = it
|
||||
result += it
|
||||
}
|
||||
|
||||
obtainOverrideForBuiltInWithErasedValueParametersInJava(fromSupertype, scope)?.let {
|
||||
directOverriddenFunctions[it] = listOf(fromSupertype)
|
||||
overrideByBase[fromSupertype] = it
|
||||
result += it
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun obtainOverrideForBuiltinWithDifferentJvmName(
|
||||
symbol: FirNamedFunctionSymbol,
|
||||
scope: FirScope,
|
||||
name: Name,
|
||||
): FirNamedFunctionSymbol? {
|
||||
val overriddenBuiltin = symbol.getOverriddenBuiltinWithDifferentJvmName() ?: return null
|
||||
|
||||
val nameInJava =
|
||||
SpecialGenericSignatures.SIGNATURE_TO_JVM_REPRESENTATION_NAME[overriddenBuiltin.fir.computeJvmSignature() ?: return null]
|
||||
?: return null
|
||||
|
||||
for (candidateSymbol in scope.getFunctions(nameInJava)) {
|
||||
val candidateFir = candidateSymbol.fir
|
||||
val renamedCopy = buildJavaMethodCopy(candidateFir) {
|
||||
this.name = name
|
||||
this.symbol = FirNamedFunctionSymbol(CallableId(candidateFir.symbol.callableId.classId!!, name))
|
||||
}.apply {
|
||||
initialSignatureAttr = candidateFir
|
||||
}
|
||||
|
||||
if (overrideChecker.isOverriddenFunction(renamedCopy, overriddenBuiltin.fir)) {
|
||||
return renamedCopy.symbol
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
private fun obtainOverrideForBuiltInWithErasedValueParametersInJava(
|
||||
symbol: FirNamedFunctionSymbol,
|
||||
scope: FirScope,
|
||||
): FirNamedFunctionSymbol? {
|
||||
val overriddenBuiltin =
|
||||
symbol.getOverriddenBuiltinFunctionWithErasedValueParametersInJava()
|
||||
?: return null
|
||||
|
||||
return createOverrideForBuiltinFunctionWithErasedParameterIfNeeded(symbol, overriddenBuiltin, scope)
|
||||
}
|
||||
|
||||
private fun createOverrideForBuiltinFunctionWithErasedParameterIfNeeded(
|
||||
fromSupertype: FirNamedFunctionSymbol,
|
||||
overriddenBuiltin: FirNamedFunctionSymbol,
|
||||
scope: FirScope,
|
||||
): FirNamedFunctionSymbol? {
|
||||
return scope.getFunctions(overriddenBuiltin.fir.name).firstOrNull { candidateOverride ->
|
||||
candidateOverride.fir.computeJvmDescriptor() == overriddenBuiltin.fir.computeJvmDescriptor() &&
|
||||
candidateOverride.hasErasedParameters()
|
||||
}?.let { override ->
|
||||
buildJavaMethodCopy(override.fir) {
|
||||
this.valueParameters.clear()
|
||||
override.fir.valueParameters.zip(fromSupertype.fir.valueParameters)
|
||||
.mapTo(this.valueParameters) { (overrideParameter, parameterFromSupertype) ->
|
||||
buildJavaValueParameterCopy(overrideParameter) {
|
||||
this@buildJavaValueParameterCopy.returnTypeRef = parameterFromSupertype.returnTypeRef
|
||||
}
|
||||
}
|
||||
|
||||
symbol = FirNamedFunctionSymbol(override.callableId)
|
||||
}.apply {
|
||||
initialSignatureAttr = override.fir
|
||||
}.symbol
|
||||
}
|
||||
}
|
||||
|
||||
// It's either overrides Collection.contains(Object) or Collection.containsAll(Collection<?>) or similar methods
|
||||
private fun FirNamedFunctionSymbol.hasErasedParameters(): Boolean {
|
||||
val valueParameter = fir.valueParameters.first()
|
||||
val parameterType = valueParameter.returnTypeRef.toConeKotlinTypeProbablyFlexible(session, typeParameterStack)
|
||||
val upperBound = parameterType.upperBoundIfFlexible()
|
||||
if (upperBound !is ConeClassLikeType) return false
|
||||
|
||||
if (fir.name.asString() in ERASED_COLLECTION_PARAMETER_NAMES) {
|
||||
require(upperBound.lookupTag.classId == StandardClassIds.Collection) {
|
||||
"Unexpected type: ${upperBound.lookupTag.classId}"
|
||||
}
|
||||
|
||||
return upperBound.typeArguments.singleOrNull() is ConeStarProjection
|
||||
}
|
||||
|
||||
return upperBound.classId == StandardClassIds.Any
|
||||
}
|
||||
|
||||
private fun FirNamedFunctionSymbol.doesOverrideRenamedBuiltins(renamedSpecialBuiltInNames: List<Name>): Boolean {
|
||||
return renamedSpecialBuiltInNames.any {
|
||||
// e.g. 'removeAt' or 'toInt'
|
||||
builtinName ->
|
||||
val builtinSpecialFromSuperTypes =
|
||||
getFunctionsFromSupertypes(builtinName).filter { it.getOverriddenBuiltinWithDifferentJvmName() != null }
|
||||
if (builtinSpecialFromSuperTypes.isEmpty()) return@any false
|
||||
|
||||
val currentJvmDescriptor = fir.computeJvmDescriptor(customName = builtinName.asString())
|
||||
|
||||
builtinSpecialFromSuperTypes.any { builtinSpecial ->
|
||||
builtinSpecial.fir.computeJvmDescriptor() == currentJvmDescriptor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun FirFunction<*>.computeJvmSignature(): String? {
|
||||
return computeJvmSignature { it.toConeKotlinTypeProbablyFlexible(session, typeParameterStack) }
|
||||
}
|
||||
|
||||
private fun FirFunction<*>.computeJvmDescriptor(customName: String? = null, includeReturnType: Boolean = false): String {
|
||||
return computeJvmDescriptor(customName, includeReturnType) {
|
||||
it.toConeKotlinTypeProbablyFlexible(
|
||||
session,
|
||||
typeParameterStack
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getFunctionsFromSupertypes(name: Name): List<FirNamedFunctionSymbol> {
|
||||
val result = mutableListOf<FirNamedFunctionSymbol>()
|
||||
superTypesScope.processFunctionsByName(name) {
|
||||
result += it
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
private fun FirNamedFunctionSymbol.getOverriddenBuiltinWithDifferentJvmName(): FirNamedFunctionSymbol? {
|
||||
var result: FirNamedFunctionSymbol? = null
|
||||
|
||||
superTypesScope.processOverriddenFunctions(this) {
|
||||
if (!it.isFromBuiltInClass(session)) return@processOverriddenFunctions ProcessorAction.NEXT
|
||||
if (SpecialGenericSignatures.SIGNATURE_TO_JVM_REPRESENTATION_NAME.containsKey(
|
||||
it.fir.computeJvmSignature()
|
||||
)
|
||||
) {
|
||||
result = it
|
||||
return@processOverriddenFunctions ProcessorAction.STOP
|
||||
}
|
||||
|
||||
ProcessorAction.NEXT
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
private fun FirNamedFunctionSymbol.shouldBeVisibleAsOverrideOfBuiltInWithErasedValueParameters(): Boolean {
|
||||
val name = fir.name
|
||||
if (!name.sameAsBuiltinMethodWithErasedValueParameters) return false
|
||||
val candidatesToOverride =
|
||||
getFunctionsFromSupertypes(name).mapNotNull {
|
||||
it.getOverriddenBuiltinFunctionWithErasedValueParametersInJava()
|
||||
}
|
||||
|
||||
val jvmDescriptor = fir.computeJvmDescriptor()
|
||||
|
||||
return candidatesToOverride.any { candidate ->
|
||||
candidate.fir.computeJvmDescriptor() == jvmDescriptor && this.hasErasedParameters()
|
||||
}
|
||||
}
|
||||
|
||||
private fun FirNamedFunctionSymbol.getOverriddenBuiltinFunctionWithErasedValueParametersInJava(): FirNamedFunctionSymbol? {
|
||||
var result: FirNamedFunctionSymbol? = null
|
||||
|
||||
superTypesScope.processOverriddenFunctionsAndSelf(this) {
|
||||
if (it.fir.computeJvmSignature() in SpecialGenericSignatures.ERASED_VALUE_PARAMETERS_SIGNATURES) {
|
||||
result = it
|
||||
return@processOverriddenFunctionsAndSelf ProcessorAction.STOP
|
||||
}
|
||||
|
||||
ProcessorAction.NEXT
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
private fun FirCallableSymbol<*>.isFromBuiltInClass(session: FirSession) =
|
||||
dispatchReceiverClassOrNull()?.toSymbol(session)?.fir?.origin == FirDeclarationOrigin.BuiltIns
|
||||
|
||||
@@ -15,11 +15,9 @@ import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap
|
||||
import org.jetbrains.kotlin.fir.scopes.impl.FirAbstractOverrideChecker
|
||||
import org.jetbrains.kotlin.fir.scopes.jvm.computeJvmDescriptor
|
||||
import org.jetbrains.kotlin.fir.symbols.StandardClassIds
|
||||
import org.jetbrains.kotlin.fir.typeContext
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.load.java.SpecialGenericSignatures
|
||||
|
||||
class JavaOverrideChecker internal constructor(
|
||||
private val session: FirSession,
|
||||
@@ -30,11 +28,10 @@ class JavaOverrideChecker internal constructor(
|
||||
private fun isEqualTypes(
|
||||
candidateType: ConeKotlinType,
|
||||
baseType: ConeKotlinType,
|
||||
substitutor: ConeSubstitutor,
|
||||
mayBeSpecialBuiltIn: Boolean
|
||||
substitutor: ConeSubstitutor
|
||||
): Boolean {
|
||||
if (candidateType is ConeFlexibleType) return isEqualTypes(candidateType.lowerBound, baseType, substitutor, mayBeSpecialBuiltIn)
|
||||
if (baseType is ConeFlexibleType) return isEqualTypes(candidateType, baseType.lowerBound, substitutor, mayBeSpecialBuiltIn)
|
||||
if (candidateType is ConeFlexibleType) return isEqualTypes(candidateType.lowerBound, baseType, substitutor)
|
||||
if (baseType is ConeFlexibleType) return isEqualTypes(candidateType, baseType.lowerBound, substitutor)
|
||||
if (candidateType is ConeClassLikeType && baseType is ConeClassLikeType) {
|
||||
val candidateTypeClassId = candidateType.fullyExpandedType(session).lookupTag.classId.let { it.readOnlyToMutable() ?: it }
|
||||
val baseTypeClassId = baseType.fullyExpandedType(session).lookupTag.classId.let { it.readOnlyToMutable() ?: it }
|
||||
@@ -49,22 +46,11 @@ class JavaOverrideChecker internal constructor(
|
||||
return isEqualArrayElementTypeProjections(
|
||||
candidateType.typeArguments.single(),
|
||||
baseType.typeArguments.single(),
|
||||
substitutor,
|
||||
mayBeSpecialBuiltIn
|
||||
substitutor
|
||||
)
|
||||
}
|
||||
return true
|
||||
}
|
||||
// TODO: handle the situation in more proper way
|
||||
// Typical case: class EnumMap<K extends Enum, V> implements Map<K, V>
|
||||
// We have containsKey(Object) in Map which is enhanced to containsKey(K) in supertype scope
|
||||
// In EnumMap we have overridden containsKey(Object) which is not yet enhanced
|
||||
// K may be substituted but after that we will get containsKey(Enum) from supertype, which still does not match...
|
||||
if (mayBeSpecialBuiltIn && baseType is ConeTypeParameterType &&
|
||||
candidateType is ConeClassLikeType && candidateType.classId == StandardClassIds.Any
|
||||
) {
|
||||
return true
|
||||
}
|
||||
return with(context) {
|
||||
areEqualTypeConstructors(
|
||||
substitutor.substituteOrSelf(candidateType).typeConstructor(),
|
||||
@@ -76,25 +62,22 @@ class JavaOverrideChecker internal constructor(
|
||||
private fun isEqualTypes(
|
||||
candidateTypeRef: FirTypeRef,
|
||||
baseTypeRef: FirTypeRef,
|
||||
substitutor: ConeSubstitutor,
|
||||
mayBeSpecialBuiltIn: Boolean = false
|
||||
substitutor: ConeSubstitutor
|
||||
) = isEqualTypes(
|
||||
candidateTypeRef.toConeKotlinTypeProbablyFlexible(session, javaTypeParameterStack),
|
||||
baseTypeRef.toConeKotlinTypeProbablyFlexible(session, javaTypeParameterStack),
|
||||
substitutor,
|
||||
mayBeSpecialBuiltIn
|
||||
substitutor
|
||||
)
|
||||
|
||||
private fun isEqualArrayElementTypeProjections(
|
||||
candidateTypeProjection: ConeTypeProjection,
|
||||
baseTypeProjection: ConeTypeProjection,
|
||||
substitutor: ConeSubstitutor,
|
||||
mayBeSpecialBuiltIn: Boolean
|
||||
substitutor: ConeSubstitutor
|
||||
): Boolean =
|
||||
when {
|
||||
candidateTypeProjection is ConeKotlinTypeProjection && baseTypeProjection is ConeKotlinTypeProjection ->
|
||||
candidateTypeProjection.kind == baseTypeProjection.kind &&
|
||||
isEqualTypes(candidateTypeProjection.type, baseTypeProjection.type, substitutor, mayBeSpecialBuiltIn)
|
||||
isEqualTypes(candidateTypeProjection.type, baseTypeProjection.type, substitutor)
|
||||
candidateTypeProjection is ConeStarProjection && baseTypeProjection is ConeStarProjection -> true
|
||||
else -> false
|
||||
}
|
||||
@@ -169,13 +152,8 @@ class JavaOverrideChecker internal constructor(
|
||||
|
||||
if (overrideCandidate.valueParameters.size != baseParameterTypes.size) return false
|
||||
val substitutor = buildTypeParametersSubstitutorIfCompatible(overrideCandidate, baseDeclaration) ?: return false
|
||||
|
||||
val jvmDescriptor by lazy { baseDeclaration.computeJvmDescriptor() }
|
||||
val mayBeSpecialBuiltIn =
|
||||
baseDeclaration.name in SpecialGenericSignatures.ERASED_VALUE_PARAMETERS_SHORT_NAMES &&
|
||||
SpecialGenericSignatures.ERASED_VALUE_PARAMETERS_SIGNATURES.any { it.endsWith(jvmDescriptor) }
|
||||
return overrideCandidate.valueParameters.zip(baseParameterTypes).all { (paramFromJava, baseType) ->
|
||||
isEqualTypes(paramFromJava.returnTypeRef, baseType, substitutor, mayBeSpecialBuiltIn)
|
||||
isEqualTypes(paramFromJava.returnTypeRef, baseType, substitutor)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user