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:
Denis.Zharkov
2021-02-17 18:31:57 +03:00
parent 4b0aeb7105
commit 45018ea468
25 changed files with 725 additions and 372 deletions
@@ -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()
}
@@ -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()
}
@@ -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,
@@ -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()
@@ -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)
}
@@ -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,
@@ -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,4 +1,3 @@
// FIR_IDENTICAL
// FILE: CollectionStringImpl.java
import java.util.Collection;
@@ -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)
@@ -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)
@@ -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
}
@@ -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,4 +1,3 @@
// FIR_IDENTICAL
// FILE: Dict.java
public abstract class Dict<K, V> {
@@ -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
@@ -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);
@@ -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