[FIR Java] Soften rules for matching types for may-be-special-builtins
This commit is workaround for cases like MyJavaMap<KK : Bound, V> : java.util.Map<K, V>. After signature changing and substitution we have MyJavaMap.get(Object) declared and MyJavaMap.get(KK) from supertype, which can't be otherwise matched as overriding one another.
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
// FULL_JDK
|
||||
|
||||
import java.util.EnumMap
|
||||
|
||||
typealias SomeEnumMap = EnumMap<String, String?>
|
||||
|
||||
fun test(map: SomeEnumMap, qualifier: String?) {
|
||||
val result = map[qualifier]
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
FILE: EnumMapGet.kt
|
||||
public final typealias SomeEnumMap = R|java/util/EnumMap<kotlin/String, kotlin/String?>|
|
||||
public final fun test(map: R|SomeEnumMap|, qualifier: R|kotlin/String?|): R|kotlin/Unit| {
|
||||
lval result: R|kotlin/String?| = R|<local>/map|.R|FakeOverride<java/util/EnumMap.get: R|kotlin/String?|>|(R|<local>/qualifier|)
|
||||
}
|
||||
+5
@@ -1199,6 +1199,11 @@ public class FirDiagnosticsWithStdlibTestGenerated extends AbstractFirDiagnostic
|
||||
runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/problems/DeepCopyIrTree.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("EnumMapGet.kt")
|
||||
public void testEnumMapGet() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/problems/EnumMapGet.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("invokePriority.kt")
|
||||
public void testInvokePriority() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/problems/invokePriority.kt");
|
||||
|
||||
@@ -14,8 +14,11 @@ import org.jetbrains.kotlin.fir.java.toConeKotlinTypeProbablyFlexible
|
||||
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,
|
||||
@@ -23,11 +26,27 @@ class JavaOverrideChecker internal constructor(
|
||||
) : FirAbstractOverrideChecker() {
|
||||
private val context: ConeTypeContext = session.typeContext
|
||||
|
||||
private fun isEqualTypes(candidateType: ConeKotlinType, baseType: ConeKotlinType, substitutor: ConeSubstitutor): Boolean {
|
||||
if (candidateType is ConeFlexibleType) return isEqualTypes(candidateType.lowerBound, baseType, substitutor)
|
||||
if (baseType is ConeFlexibleType) return isEqualTypes(candidateType, baseType.lowerBound, substitutor)
|
||||
private fun isEqualTypes(
|
||||
candidateType: ConeKotlinType,
|
||||
baseType: ConeKotlinType,
|
||||
substitutor: ConeSubstitutor,
|
||||
mayBeSpecialBuiltIn: Boolean
|
||||
): 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 ConeClassLikeType && baseType is ConeClassLikeType) {
|
||||
return candidateType.lookupTag.classId.let { it.readOnlyToMutable() ?: it } == baseType.lookupTag.classId.let { it.readOnlyToMutable() ?: it }
|
||||
return candidateType.lookupTag.classId.let { it.readOnlyToMutable() ?: it } ==
|
||||
baseType.lookupTag.classId.let { it.readOnlyToMutable() ?: it }
|
||||
}
|
||||
// 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(
|
||||
@@ -37,12 +56,17 @@ class JavaOverrideChecker internal constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private fun isEqualTypes(candidateTypeRef: FirTypeRef, baseTypeRef: FirTypeRef, substitutor: ConeSubstitutor) =
|
||||
isEqualTypes(
|
||||
candidateTypeRef.toConeKotlinTypeProbablyFlexible(session, javaTypeParameterStack),
|
||||
baseTypeRef.toConeKotlinTypeProbablyFlexible(session, javaTypeParameterStack),
|
||||
substitutor
|
||||
)
|
||||
private fun isEqualTypes(
|
||||
candidateTypeRef: FirTypeRef,
|
||||
baseTypeRef: FirTypeRef,
|
||||
substitutor: ConeSubstitutor,
|
||||
mayBeSpecialBuiltIn: Boolean = false
|
||||
) = isEqualTypes(
|
||||
candidateTypeRef.toConeKotlinTypeProbablyFlexible(session, javaTypeParameterStack),
|
||||
baseTypeRef.toConeKotlinTypeProbablyFlexible(session, javaTypeParameterStack),
|
||||
substitutor,
|
||||
mayBeSpecialBuiltIn
|
||||
)
|
||||
|
||||
private fun Collection<FirTypeParameterRef>.buildErasure() = associate {
|
||||
val symbol = it.symbol
|
||||
@@ -97,8 +121,12 @@ 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)
|
||||
isEqualTypes(paramFromJava.returnTypeRef, baseType, substitutor, mayBeSpecialBuiltIn)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user