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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.scopes.jvm
|
||||
|
||||
import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap
|
||||
import org.jetbrains.kotlin.fir.containingClass
|
||||
import org.jetbrains.kotlin.fir.declarations.FirCallableMemberDeclaration
|
||||
import org.jetbrains.kotlin.fir.declarations.FirFunction
|
||||
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
|
||||
import org.jetbrains.kotlin.fir.symbols.StandardClassIds
|
||||
@@ -12,68 +15,44 @@ import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.fir.types.impl.FirImplicitAnyTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.impl.FirImplicitNullableAnyTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.jvm.FirJavaTypeRef
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaClass
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaClassifierType
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaPrimitiveType
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaTypeParameter
|
||||
import org.jetbrains.kotlin.load.kotlin.SignatureBuildingComponents
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
|
||||
fun FirFunction<*>.computeJvmDescriptorReplacingKotlinToJava(): String =
|
||||
computeJvmDescriptor()
|
||||
.replace("kotlin/Any", "java/lang/Object")
|
||||
.replace("kotlin/String", "java/lang/String")
|
||||
.replace("kotlin/Throwable", "java/lang/Throwable")
|
||||
fun FirFunction<*>.computeJvmSignature(typeConversion: (FirTypeRef) -> ConeKotlinType? = FirTypeRef::coneTypeSafe): String? {
|
||||
if (this !is FirCallableMemberDeclaration<*>) return null
|
||||
val containingClass = containingClass() ?: return null
|
||||
|
||||
fun FirFunction<*>.computeJvmDescriptor(): String = buildString {
|
||||
if (this@computeJvmDescriptor is FirSimpleFunction) {
|
||||
append(name.asString())
|
||||
return SignatureBuildingComponents.signature(containingClass.classId, computeJvmDescriptor(typeConversion = typeConversion))
|
||||
}
|
||||
|
||||
fun FirFunction<*>.computeJvmDescriptor(
|
||||
customName: String? = null,
|
||||
includeReturnType: Boolean = true,
|
||||
typeConversion: (FirTypeRef) -> ConeKotlinType? = FirTypeRef::coneTypeSafe
|
||||
): String = buildString {
|
||||
if (customName != null) {
|
||||
append(customName)
|
||||
} else {
|
||||
append("<init>")
|
||||
if (this@computeJvmDescriptor is FirSimpleFunction) {
|
||||
append(name.asString())
|
||||
} else {
|
||||
append("<init>")
|
||||
}
|
||||
}
|
||||
|
||||
append("(")
|
||||
for (parameter in valueParameters) {
|
||||
appendErasedType(parameter.returnTypeRef)
|
||||
typeConversion(parameter.returnTypeRef)?.let(this::appendConeType)
|
||||
}
|
||||
append(")")
|
||||
|
||||
if (this@computeJvmDescriptor !is FirSimpleFunction || returnTypeRef.isVoid()) {
|
||||
append("V")
|
||||
} else {
|
||||
appendErasedType(returnTypeRef)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: primitive types, arrays, etc.
|
||||
private fun StringBuilder.appendErasedType(typeRef: FirTypeRef) {
|
||||
fun appendClass(klass: JavaClass) {
|
||||
klass.fqName?.let {
|
||||
append("L")
|
||||
append(it.asString().replace(".", "/"))
|
||||
append(";")
|
||||
}
|
||||
}
|
||||
|
||||
when (typeRef) {
|
||||
is FirResolvedTypeRef -> appendConeType(typeRef.type)
|
||||
is FirJavaTypeRef -> {
|
||||
when (val javaType = typeRef.type) {
|
||||
is JavaClassifierType -> {
|
||||
when (val classifier = javaType.classifier) {
|
||||
is JavaClass -> appendClass(classifier)
|
||||
is JavaTypeParameter -> {
|
||||
val representative = classifier.upperBounds.firstOrNull { it.classifier is JavaClass }
|
||||
if (representative == null) {
|
||||
append("Ljava/lang/Object;")
|
||||
} else {
|
||||
appendClass(representative.classifier as JavaClass)
|
||||
}
|
||||
}
|
||||
else -> return
|
||||
}
|
||||
}
|
||||
}
|
||||
if (includeReturnType) {
|
||||
if (this@computeJvmDescriptor !is FirSimpleFunction || returnTypeRef.isVoid()) {
|
||||
append("V")
|
||||
} else {
|
||||
typeConversion(returnTypeRef)?.let(this::appendConeType)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -101,7 +80,8 @@ private fun StringBuilder.appendConeType(coneType: ConeKotlinType) {
|
||||
}
|
||||
|
||||
fun appendClassLikeType(type: ConeClassLikeType) {
|
||||
val classId = type.lookupTag.classId
|
||||
val baseClassId = type.lookupTag.classId
|
||||
val classId = JavaToKotlinClassMap.mapKotlinToJava(baseClassId.asSingleFqName().toUnsafe()) ?: baseClassId
|
||||
if (classId == StandardClassIds.Array) {
|
||||
append("[")
|
||||
type.typeArguments.forEach { typeArg ->
|
||||
|
||||
@@ -29,11 +29,11 @@ class JvmMappedScope(
|
||||
}
|
||||
|
||||
val declaredSignatures by lazy {
|
||||
declared.mapTo(mutableSetOf()) { it.fir.computeJvmDescriptorReplacingKotlinToJava() }
|
||||
declared.mapTo(mutableSetOf()) { it.fir.computeJvmDescriptor() }
|
||||
}
|
||||
|
||||
javaMappedClassUseSiteScope.processFunctionsByName(name) { symbol ->
|
||||
val jvmSignature = symbol.fir.computeJvmDescriptorReplacingKotlinToJava()
|
||||
val jvmSignature = symbol.fir.computeJvmDescriptor()
|
||||
if (jvmSignature in visibleMethods && jvmSignature !in declaredSignatures) {
|
||||
processor(symbol)
|
||||
}
|
||||
@@ -49,7 +49,7 @@ class JvmMappedScope(
|
||||
val hiddenConstructors = signatures.hiddenConstructors
|
||||
if (hiddenConstructors.isNotEmpty()) {
|
||||
javaMappedClassUseSiteScope.processDeclaredConstructors { symbol ->
|
||||
val jvmSignature = symbol.fir.computeJvmDescriptorReplacingKotlinToJava()
|
||||
val jvmSignature = symbol.fir.computeJvmDescriptor()
|
||||
if (jvmSignature !in hiddenConstructors) {
|
||||
processor(symbol)
|
||||
}
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@ abstract class AbstractFirUseSiteMemberScope(
|
||||
) : AbstractFirOverrideScope(session, overrideChecker) {
|
||||
|
||||
private val functions = hashMapOf<Name, Collection<FirNamedFunctionSymbol>>()
|
||||
private val directOverriddenFunctions = hashMapOf<FirNamedFunctionSymbol, Collection<FirNamedFunctionSymbol>>()
|
||||
protected val directOverriddenFunctions = hashMapOf<FirNamedFunctionSymbol, Collection<FirNamedFunctionSymbol>>()
|
||||
protected val directOverriddenProperties = hashMapOf<FirPropertySymbol, MutableList<FirPropertySymbol>>()
|
||||
|
||||
override fun processFunctionsByName(name: Name, processor: (FirNamedFunctionSymbol) -> Unit) {
|
||||
|
||||
@@ -61,6 +61,15 @@ fun FirTypeScope.processOverriddenFunctionsAndSelf(
|
||||
return processOverriddenFunctions(functionSymbol, processor)
|
||||
}
|
||||
|
||||
fun FirTypeScope.processOverriddenPropertiesAndSelf(
|
||||
propertySymbol: FirPropertySymbol,
|
||||
processor: (FirPropertySymbol) -> ProcessorAction
|
||||
): ProcessorAction {
|
||||
if (!processor(propertySymbol)) return ProcessorAction.STOP
|
||||
|
||||
return processOverriddenProperties(propertySymbol, processor)
|
||||
}
|
||||
|
||||
enum class ProcessorAction {
|
||||
STOP,
|
||||
NEXT,
|
||||
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
// FILE: CollectionStringImpl.java
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
|
||||
public class CollectionStringImpl implements Collection<String> {
|
||||
@Override
|
||||
public int size() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object o) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Iterator<String> iterator() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Object[] toArray() {
|
||||
return new Object[0];
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public <T> T[] toArray(T[] a) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(String s) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Object o) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsAll(Collection<?> c) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(Collection<? extends String> c) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeAll(Collection<?> c) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean retainAll(Collection<?> c) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
|
||||
}
|
||||
|
||||
public boolean contains(String o) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// FILE: main.kt
|
||||
|
||||
fun test(x: CollectionStringImpl) {
|
||||
x.<!AMBIGUITY!>contains<!>("")
|
||||
(x as Collection<String>).contains("")
|
||||
}
|
||||
-1
@@ -1,4 +1,3 @@
|
||||
// FIR_IDENTICAL
|
||||
// FILE: CollectionStringImpl.java
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
+6
-6
@@ -40,14 +40,14 @@ fun foo(
|
||||
1 <!INAPPLICABLE_CANDIDATE!>in<!> a
|
||||
|
||||
b.contains("")
|
||||
b.contains(1)
|
||||
b.<!INAPPLICABLE_CANDIDATE!>contains<!>(1)
|
||||
"" in b
|
||||
1 in b
|
||||
1 <!INAPPLICABLE_CANDIDATE!>in<!> b
|
||||
|
||||
ic.contains("")
|
||||
ic.contains(1)
|
||||
ic.<!INAPPLICABLE_CANDIDATE!>contains<!>(1)
|
||||
"" in ic
|
||||
1 in ic
|
||||
1 <!INAPPLICABLE_CANDIDATE!>in<!> ic
|
||||
|
||||
ka.contains("")
|
||||
ka.<!INAPPLICABLE_CANDIDATE!>contains<!>(1)
|
||||
@@ -55,9 +55,9 @@ fun foo(
|
||||
1 <!INAPPLICABLE_CANDIDATE!>in<!> ka
|
||||
|
||||
kb.contains("")
|
||||
kb.contains(1)
|
||||
kb.<!INAPPLICABLE_CANDIDATE!>contains<!>(1)
|
||||
"" in kb
|
||||
1 in kb
|
||||
1 <!INAPPLICABLE_CANDIDATE!>in<!> kb
|
||||
|
||||
al.contains("")
|
||||
al.<!INAPPLICABLE_CANDIDATE!>contains<!>(1)
|
||||
|
||||
+3
-3
@@ -40,16 +40,16 @@ fun foo(
|
||||
a.<!INAPPLICABLE_CANDIDATE!>containsAll<!>(ca)
|
||||
|
||||
b.containsAll(cs)
|
||||
b.containsAll(ca)
|
||||
b.<!INAPPLICABLE_CANDIDATE!>containsAll<!>(ca)
|
||||
|
||||
ic.containsAll(cs)
|
||||
ic.containsAll(ca)
|
||||
ic.<!INAPPLICABLE_CANDIDATE!>containsAll<!>(ca)
|
||||
|
||||
ka.containsAll(cs)
|
||||
ka.<!INAPPLICABLE_CANDIDATE!>containsAll<!>(ca)
|
||||
|
||||
kb.containsAll(cs)
|
||||
kb.containsAll(ca)
|
||||
kb.<!INAPPLICABLE_CANDIDATE!>containsAll<!>(ca)
|
||||
|
||||
al.containsAll(cs)
|
||||
al.<!INAPPLICABLE_CANDIDATE!>containsAll<!>(ca)
|
||||
|
||||
+6
-6
@@ -12,13 +12,13 @@ abstract class KA : A() {
|
||||
}
|
||||
|
||||
fun foo(a: A, ka: KA) {
|
||||
a.contains("")
|
||||
a.contains(1)
|
||||
"" in a
|
||||
1 in a
|
||||
a.<!AMBIGUITY!>contains<!>("")
|
||||
a.<!NONE_APPLICABLE!>contains<!>(1)
|
||||
"" <!AMBIGUITY!>in<!> a
|
||||
1 <!NONE_APPLICABLE!>in<!> a
|
||||
|
||||
ka.contains("")
|
||||
ka.contains(1)
|
||||
ka.<!INAPPLICABLE_CANDIDATE!>contains<!>(1)
|
||||
"" in ka
|
||||
1 in ka
|
||||
1 <!INAPPLICABLE_CANDIDATE!>in<!> ka
|
||||
}
|
||||
|
||||
Vendored
+19
@@ -0,0 +1,19 @@
|
||||
// FILE: Dict.java
|
||||
|
||||
public abstract class Dict<K, V> {
|
||||
abstract public V get(Object key);
|
||||
}
|
||||
|
||||
// FILE: MHashtable.java
|
||||
|
||||
abstract public class MHashtable<X, Y> extends Dict<X, Y> implements java.util.Map<X, Y> {
|
||||
public V get(Object key) { return null; }
|
||||
}
|
||||
|
||||
// FILE: main.kt
|
||||
|
||||
abstract class C1 : MHashtable<String, Int>()
|
||||
|
||||
abstract class C2 : MHashtable<String, Int>() {
|
||||
override fun <!RETURN_TYPE_MISMATCH_ON_OVERRIDE!>get<!>(key: String) = 1
|
||||
}
|
||||
-1
@@ -1,4 +1,3 @@
|
||||
// FIR_IDENTICAL
|
||||
// FILE: Dict.java
|
||||
|
||||
public abstract class Dict<K, V> {
|
||||
|
||||
-32
@@ -1,32 +0,0 @@
|
||||
// JAVAC_EXPECTED_FILE
|
||||
// FILE: A.java
|
||||
abstract public class A extends B {
|
||||
public Integer removeAt(int x) { }
|
||||
public boolean remove(Integer x) { }
|
||||
}
|
||||
|
||||
// FILE: main.kt
|
||||
import java.util.*;
|
||||
|
||||
abstract class B : MutableList<Int>, AbstractList<Int>() {
|
||||
override fun removeAt(index: Int): Int = null!!
|
||||
override fun remove(element: Int): <!RETURN_TYPE_MISMATCH_ON_OVERRIDE!>Boolean<!> = null!!
|
||||
}
|
||||
|
||||
abstract class D : AbstractList<Int>() {
|
||||
// removeAt() doesn't exist in java/util/AbstractList, it's a
|
||||
// fake override of the method from kotlin/collections/MutableList
|
||||
override fun removeAt(index: Int): Int = null!!
|
||||
// AbstractList::remove() should return Int here. No fake overrides created.
|
||||
// This may be a bug because the old compiler doesn't report a diagnostic here.
|
||||
override fun remove(element: Int): <!RETURN_TYPE_MISMATCH_ON_OVERRIDE!>Boolean<!> = null!!
|
||||
}
|
||||
|
||||
fun main(a: A, b: B, c: ArrayList<Int>) {
|
||||
a.remove(1)
|
||||
a.removeAt(0)
|
||||
b.remove(1)
|
||||
b.removeAt(0)
|
||||
c.remove(1)
|
||||
c.removeAt(0)
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// JAVAC_EXPECTED_FILE
|
||||
// FILE: A.java
|
||||
abstract public class A extends B {
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
// JAVAC_EXPECTED_FILE
|
||||
// FILE: A.java
|
||||
|
||||
abstract public class A extends java.util.ArrayList<String> {
|
||||
public final int size() { return 0; }
|
||||
}
|
||||
|
||||
// FILE: main.kt
|
||||
|
||||
class B : A() {
|
||||
override val size: Int = 1
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// JAVAC_EXPECTED_FILE
|
||||
// FILE: A.java
|
||||
|
||||
|
||||
+113
@@ -0,0 +1,113 @@
|
||||
// FILE: AbstractSpecializedMap.java
|
||||
public abstract class AbstractSpecializedMap implements java.util.Map<Integer, Double> {
|
||||
public abstract double put(int x, double y);
|
||||
public abstract double remove(int k);
|
||||
public abstract double get(int k);
|
||||
|
||||
public abstract boolean containsKey(int k);
|
||||
public boolean containsKey(Object x) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public abstract boolean containsValue(double v);
|
||||
public boolean containsValue(Object x) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// FILE: SpecializedMap.java
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class SpecializedMap extends AbstractSpecializedMap {
|
||||
public double put(int x, double y) {
|
||||
return 123.0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double get(Object key) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double put(Integer key, Double value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public double remove(int k) {
|
||||
return 456.0;
|
||||
}
|
||||
|
||||
|
||||
public Double remove(Object ok) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public double get(int k) {
|
||||
return 789.0;
|
||||
}
|
||||
|
||||
public boolean containsKey(int k) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean containsValue(double v) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(Map<? extends Integer, ? extends Double> m) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Set<Integer> keySet() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Collection<Double> values() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Set<Entry<Integer, Double>> entrySet() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// FILE: main.kt
|
||||
fun foo(x: SpecializedMap) {
|
||||
x.containsKey(1)
|
||||
x.<!INAPPLICABLE_CANDIDATE!>containsKey<!>(null)
|
||||
|
||||
x.<!AMBIGUITY!>get<!>(2)
|
||||
x.<!NONE_APPLICABLE!>get<!>(null)
|
||||
|
||||
x.<!AMBIGUITY!>remove<!>(3)
|
||||
x.<!NONE_APPLICABLE!>remove<!>(null)
|
||||
|
||||
x.put(4, 5.0)
|
||||
x.put(4, null)
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
// FIR_IDENTICAL
|
||||
// FILE: AbstractSpecializedMap.java
|
||||
public abstract class AbstractSpecializedMap implements java.util.Map<Integer, Double> {
|
||||
public abstract double put(int x, double y);
|
||||
|
||||
-2
@@ -1,8 +1,6 @@
|
||||
public open class ModalityOfFakeOverrides : R|java/util/AbstractList<ft<@FlexibleNullability kotlin/String, kotlin/String?>!>| {
|
||||
@R|java/lang/Override|() @R|org/jetbrains/annotations/NotNull|() public open operator fun get(index: R|kotlin/Int|): R|@EnhancedNullability kotlin/String|
|
||||
|
||||
@R|java/lang/Override|() public open fun size(): R|kotlin/Int|
|
||||
|
||||
public constructor(): R|test/ModalityOfFakeOverrides|
|
||||
|
||||
}
|
||||
|
||||
@@ -52,46 +52,25 @@ KtFirJavaFieldSymbol:
|
||||
symbolKind: MEMBER
|
||||
visibility: PRIVATE
|
||||
|
||||
KtFirFunctionSymbol:
|
||||
KtFirSyntheticJavaPropertySymbol:
|
||||
annotatedType: [] kotlin/Int
|
||||
annotationClassIds: []
|
||||
annotations: []
|
||||
callableIdIfNonLocal: java.lang.String.length
|
||||
dispatchType: java/lang/String
|
||||
isExtension: false
|
||||
isExternal: false
|
||||
isInline: false
|
||||
isOperator: false
|
||||
isOverride: false
|
||||
isSuspend: false
|
||||
modality: OPEN
|
||||
name: length
|
||||
origin: JAVA
|
||||
receiverType: null
|
||||
symbolKind: MEMBER
|
||||
typeParameters: []
|
||||
valueParameters: []
|
||||
visibility: PUBLIC
|
||||
|
||||
KtFirKotlinPropertySymbol:
|
||||
annotatedType: [] kotlin/Int
|
||||
annotationClassIds: []
|
||||
annotations: []
|
||||
callableIdIfNonLocal: kotlin.CharSequence.length
|
||||
dispatchType: kotlin/CharSequence
|
||||
getter: KtFirPropertyGetterSymbol(<getter>)
|
||||
hasBackingField: false
|
||||
hasBackingField: true
|
||||
hasGetter: true
|
||||
hasSetter: false
|
||||
initializer: null
|
||||
isConst: false
|
||||
isExtension: false
|
||||
isLateInit: false
|
||||
isOverride: false
|
||||
isVal: true
|
||||
modality: ABSTRACT
|
||||
javaGetterName: length
|
||||
javaSetterName: null
|
||||
modality: OPEN
|
||||
name: length
|
||||
origin: LIBRARY
|
||||
origin: JAVA_SYNTHETIC_PROPERTY
|
||||
receiverType: null
|
||||
setter: null
|
||||
symbolKind: MEMBER
|
||||
|
||||
Reference in New Issue
Block a user