K2: implement correct check for ctors mapped from java

so the check is functionally the same as in K1.
#KT-57064 fixed
#KT-57065 fixed
One of the tests introduced here (javaMappedCtors) revealed an
additional issue, filed as KT-57368
This commit is contained in:
Ilya Chernikov
2023-03-09 11:05:22 +01:00
committed by Space Team
parent 730502638a
commit 0e77b67170
10 changed files with 165 additions and 57 deletions
@@ -8,7 +8,9 @@ package org.jetbrains.kotlin.fir.scopes.jvm
import org.jetbrains.kotlin.builtins.jvm.JvmBuiltInsSignatures
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirClass
import org.jetbrains.kotlin.fir.declarations.FirConstructor
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.constructors
import org.jetbrains.kotlin.fir.declarations.utils.classId
import org.jetbrains.kotlin.fir.resolve.defaultType
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
@@ -17,11 +19,12 @@ import org.jetbrains.kotlin.fir.scopes.FirContainingNamesAwareScope
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.impl.FirStandardOverrideChecker
import org.jetbrains.kotlin.fir.scopes.impl.buildSubstitutorForOverridesCheck
import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterLookupTag
import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.types.coneType
import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl
import org.jetbrains.kotlin.load.kotlin.SignatureBuildingComponents.inJavaLang
import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.name.Name
@@ -37,6 +40,8 @@ class JvmMappedScope(
private val constructorsCache = mutableMapOf<FirConstructorSymbol, FirConstructorSymbol>()
private val overrideChecker = FirStandardOverrideChecker(session)
private val substitutor = ConeSubstitutorByMap(
firJavaClass.typeParameters.zip(firKotlinClass.typeParameters).associate { (javaParameter, kotlinParameter) ->
javaParameter.symbol to ConeTypeParameterTypeImpl(ConeTypeParameterLookupTag(kotlinParameter.symbol), isNullable = false)
@@ -96,19 +101,40 @@ class JvmMappedScope(
processor: (FirNamedFunctionSymbol, FirTypeScope) -> ProcessorAction
) = ProcessorAction.NONE
private val firKotlinClassConstructors by lazy(LazyThreadSafetyMode.PUBLICATION) {
firKotlinClass.constructors(session)
}
override fun processDeclaredConstructors(processor: (FirConstructorSymbol) -> Unit) {
val hiddenConstructors = signatures.hiddenConstructors
if (hiddenConstructors.isNotEmpty()) {
javaMappedClassUseSiteScope.processDeclaredConstructors { symbol ->
val jvmSignature = symbol.fir.computeJvmDescriptor()
if (jvmSignature !in hiddenConstructors) {
val newSymbol = getOrCreateCopy(symbol)
processor(newSymbol)
javaMappedClassUseSiteScope.processDeclaredConstructors { javaCtorSymbol ->
fun FirConstructor.isShadowedBy(ctorFromKotlin: FirConstructorSymbol): Boolean {
// assuming already checked for visibility
val valueParams = valueParameters
val valueParamsFromKotlin = ctorFromKotlin.fir.valueParameters
if (valueParams.size != valueParamsFromKotlin.size) return false
val substitutor = buildSubstitutorForOverridesCheck(ctorFromKotlin.fir, this@isShadowedBy, session) ?: return false
return valueParamsFromKotlin.zip(valueParams).all { (kotlinCtorParam, javaCtorParam) ->
overrideChecker.isEqualTypes(kotlinCtorParam.returnTypeRef, javaCtorParam.returnTypeRef, substitutor)
}
}
} else {
javaMappedClassUseSiteScope.processDeclaredConstructors { symbol ->
val newSymbol = getOrCreateCopy(symbol)
fun FirConstructor.isTrivialCopyConstructor(): Boolean =
valueParameters.singleOrNull()?.let {
val type = substitutor.substituteOrSelf(it.returnTypeRef.coneType)
type == firKotlinClass.defaultType()
} ?: false
// In K1 it is handled by JvmBuiltInsCustomizer.getConstructors
// Here the logic is generally the same, but simplified for performance by reordering checks and avoiding checking
// for the impossible combinations
val javaCtor = javaCtorSymbol.fir
if (javaCtor.status.visibility.isPublicAPI &&
javaCtor.computeJvmDescriptor() !in signatures.hiddenConstructors &&
!javaCtor.isTrivialCopyConstructor() &&
firKotlinClassConstructors.none { javaCtor.isShadowedBy(it) }
) {
val newSymbol = getOrCreateCopy(javaCtorSymbol)
processor(newSymbol)
}
}