[FIR] Explicitly resolve synthetic property return type if necessary

During implicit body resolve phase, we can encounter a reference to a
not yet resolved Kotlin class that inherits a synthetic property from a
Java class. In that case, resolve the return type in
FirSyntheticPropertiesScope.

#KT-57166 Fixed
This commit is contained in:
Kirill Rakhman
2023-03-08 14:08:01 +01:00
committed by Space Team
parent 6aef11704b
commit 9b89759755
12 changed files with 218 additions and 12 deletions
@@ -19570,6 +19570,24 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag
runTest("compiler/testData/diagnostics/tests/j+k/supertypeUsesNested.kt");
}
@Test
@TestMetadata("syntheticAssignmentInLambdaExpressionBody.kt")
public void testSyntheticAssignmentInLambdaExpressionBody() throws Exception {
runTest("compiler/testData/diagnostics/tests/j+k/syntheticAssignmentInLambdaExpressionBody.kt");
}
@Test
@TestMetadata("syntheticPropertyOverridden.kt")
public void testSyntheticPropertyOverridden() throws Exception {
runTest("compiler/testData/diagnostics/tests/j+k/syntheticPropertyOverridden.kt");
}
@Test
@TestMetadata("syntheticPropertyOverridden2.kt")
public void testSyntheticPropertyOverridden2() throws Exception {
runTest("compiler/testData/diagnostics/tests/j+k/syntheticPropertyOverridden2.kt");
}
@Test
@TestMetadata("traitDefaultCall.kt")
public void testTraitDefaultCall() throws Exception {
@@ -19570,6 +19570,24 @@ public class FirLightTreeOldFrontendDiagnosticsTestGenerated extends AbstractFir
runTest("compiler/testData/diagnostics/tests/j+k/supertypeUsesNested.kt");
}
@Test
@TestMetadata("syntheticAssignmentInLambdaExpressionBody.kt")
public void testSyntheticAssignmentInLambdaExpressionBody() throws Exception {
runTest("compiler/testData/diagnostics/tests/j+k/syntheticAssignmentInLambdaExpressionBody.kt");
}
@Test
@TestMetadata("syntheticPropertyOverridden.kt")
public void testSyntheticPropertyOverridden() throws Exception {
runTest("compiler/testData/diagnostics/tests/j+k/syntheticPropertyOverridden.kt");
}
@Test
@TestMetadata("syntheticPropertyOverridden2.kt")
public void testSyntheticPropertyOverridden2() throws Exception {
runTest("compiler/testData/diagnostics/tests/j+k/syntheticPropertyOverridden2.kt");
}
@Test
@TestMetadata("traitDefaultCall.kt")
public void testTraitDefaultCall() throws Exception {
@@ -19576,6 +19576,24 @@ public class FirPsiOldFrontendDiagnosticsTestGenerated extends AbstractFirPsiDia
runTest("compiler/testData/diagnostics/tests/j+k/supertypeUsesNested.kt");
}
@Test
@TestMetadata("syntheticAssignmentInLambdaExpressionBody.kt")
public void testSyntheticAssignmentInLambdaExpressionBody() throws Exception {
runTest("compiler/testData/diagnostics/tests/j+k/syntheticAssignmentInLambdaExpressionBody.kt");
}
@Test
@TestMetadata("syntheticPropertyOverridden.kt")
public void testSyntheticPropertyOverridden() throws Exception {
runTest("compiler/testData/diagnostics/tests/j+k/syntheticPropertyOverridden.kt");
}
@Test
@TestMetadata("syntheticPropertyOverridden2.kt")
public void testSyntheticPropertyOverridden2() throws Exception {
runTest("compiler/testData/diagnostics/tests/j+k/syntheticPropertyOverridden2.kt");
}
@Test
@TestMetadata("traitDefaultCall.kt")
public void testTraitDefaultCall() throws Exception {
@@ -10,6 +10,7 @@ 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.declarations.utils.isStatic
import org.jetbrains.kotlin.fir.resolve.transformers.ReturnTypeCalculator
import org.jetbrains.kotlin.fir.scopes.*
import org.jetbrains.kotlin.fir.symbols.SyntheticSymbol
import org.jetbrains.kotlin.fir.symbols.impl.*
@@ -40,20 +41,23 @@ class FirSyntheticPropertiesScope private constructor(
val session: FirSession,
private val baseScope: FirTypeScope,
private val dispatchReceiverType: ConeKotlinType,
private val syntheticNamesProvider: FirSyntheticNamesProvider
private val syntheticNamesProvider: FirSyntheticNamesProvider,
private val returnTypeCalculator: ReturnTypeCalculator?,
) : FirContainingNamesAwareScope() {
companion object {
fun createIfSyntheticNamesProviderIsDefined(
session: FirSession,
dispatchReceiverType: ConeKotlinType,
baseScope: FirTypeScope
baseScope: FirTypeScope,
returnTypeCalculator: ReturnTypeCalculator? = null,
): FirSyntheticPropertiesScope? {
val syntheticNamesProvider = session.syntheticNamesProvider ?: return null
return FirSyntheticPropertiesScope(
session,
baseScope,
dispatchReceiverType,
syntheticNamesProvider
syntheticNamesProvider,
returnTypeCalculator,
)
}
}
@@ -104,7 +108,14 @@ class FirSyntheticPropertiesScope private constructor(
if (getter.typeParameters.isNotEmpty()) return
if (getter.valueParameters.isNotEmpty()) return
if (getter.isStatic) return
val getterReturnType = (getter.returnTypeRef as? FirResolvedTypeRef)?.type
var getterReturnType = (getter.returnTypeRef as? FirResolvedTypeRef)?.type
if (getterReturnType == null && needCheckForSetter) {
// During implicit body resolve phase, we can encounter a reference to a not yet resolved Kotlin class that inherits a
// synthetic property from a Java class. In that case, resolve the return type here, ignoring error types (e.g. cycles).
getterReturnType = returnTypeCalculator?.tryCalculateReturnTypeOrNull(getter)?.type?.takeUnless { it is ConeErrorType }
}
if ((getterReturnType as? ConeClassLikeType)?.lookupTag?.classId == StandardClassIds.Unit) return
if (!getterSymbol.hasJavaOverridden()) return
@@ -195,7 +206,7 @@ class FirSyntheticPropertiesScope private constructor(
baseScope.processDirectOverriddenFunctionsWithBaseScope(symbolToStart) l@{ symbol, scope ->
if (hasMatchingSetter) return@l ProcessorAction.STOP
val baseDispatchReceiverType = symbol.dispatchReceiverType ?: return@l ProcessorAction.NEXT
val syntheticScope = FirSyntheticPropertiesScope(session, scope, baseDispatchReceiverType, syntheticNamesProvider)
val syntheticScope = FirSyntheticPropertiesScope(session, scope, baseDispatchReceiverType, syntheticNamesProvider, returnTypeCalculator)
val baseProperties = syntheticScope.getProperties(propertyName)
val propertyFound = baseProperties.any {
val baseProperty = it.fir
@@ -105,7 +105,8 @@ internal class FirInvokeResolveTowerExtension(
towerDataElementsForName = towerDataElementsForName,
invokeBuiltinExtensionMode = true
) {
it.runResolverForNoReceiver(invokeReceiverVariableWithNoReceiverInfo)
// Synthetic properties can never have an extension function type
it.runResolverForNoReceiver(invokeReceiverVariableWithNoReceiverInfo, skipSynthetics = true)
}
}
@@ -121,9 +121,11 @@ internal abstract class FirBaseTowerResolveTask(
protected fun ReceiverValue.toMemberScopeTowerLevel(
extensionReceiver: ReceiverValue? = null,
contextReceiverGroup: ContextReceiverGroup? = null,
skipSynthetics: Boolean = false,
) = MemberScopeTowerLevel(
components, this,
givenExtensionReceiverOptions = contextReceiverGroup ?: listOfNotNull(extensionReceiver),
skipSynthetics = skipSynthetics,
)
protected fun ContextReceiverGroup.toMemberScopeTowerLevel(
@@ -315,7 +317,8 @@ internal open class FirTowerResolveTask(
}
suspend fun runResolverForNoReceiver(
info: CallInfo
info: CallInfo,
skipSynthetics: Boolean = false,
) {
val emptyScopes = mutableSetOf<FirScope>()
val implicitReceiverValuesWithEmptyScopes = mutableSetOf<ImplicitReceiverValue<*>>()
@@ -342,7 +345,8 @@ internal open class FirTowerResolveTask(
info,
group,
implicitReceiverValuesWithEmptyScopes,
emptyScopes
emptyScopes,
skipSynthetics,
)
},
onContextReceiverGroup = { contextReceiverGroup, towerGroup ->
@@ -401,7 +405,8 @@ internal open class FirTowerResolveTask(
info: CallInfo,
parentGroup: TowerGroup,
implicitReceiverValuesWithEmptyScopes: MutableSet<ImplicitReceiverValue<*>>,
emptyScopes: MutableSet<FirScope>
emptyScopes: MutableSet<FirScope>,
skipSynthetics: Boolean,
) {
processExtensionsThatHideMembers(
info, receiver, TowerGroup.EmptyRoot,
@@ -409,7 +414,7 @@ internal open class FirTowerResolveTask(
)
processLevel(
receiver.toMemberScopeTowerLevel(), info, parentGroup.Member,
receiver.toMemberScopeTowerLevel(skipSynthetics = skipSynthetics), info, parentGroup.Member,
onEmptyLevel = {
implicitReceiverValuesWithEmptyScopes += receiver
}
@@ -74,6 +74,7 @@ class MemberScopeTowerLevel(
private val bodyResolveComponents: BodyResolveComponents,
val dispatchReceiverValue: ReceiverValue,
private val givenExtensionReceiverOptions: List<ReceiverValue>,
private val skipSynthetics: Boolean,
) : TowerScopeLevel() {
private val scopeSession: ScopeSession get() = bodyResolveComponents.scopeSession
private val session: FirSession get() = bodyResolveComponents.session
@@ -117,7 +118,7 @@ class MemberScopeTowerLevel(
)
}
if (givenExtensionReceiverOptions.isEmpty()) {
if (givenExtensionReceiverOptions.isEmpty() && !skipSynthetics) {
val dispatchReceiverType = dispatchReceiverValue.type
val useSiteForSyntheticScope: FirTypeScope
@@ -148,7 +149,9 @@ class MemberScopeTowerLevel(
session,
typeForSyntheticScope,
useSiteForSyntheticScope,
bodyResolveComponents.returnTypeCalculator,
)
withSynthetic?.processScopeMembers { symbol ->
empty = false
output.consumeCandidate(
@@ -291,7 +294,7 @@ class ContextReceiverGroupMemberScopeTowerLevel(
givenExtensionReceiverOptions: List<ReceiverValue> = emptyList(),
) : TowerScopeLevel() {
private val memberScopeLevels = contextReceiverGroup.map {
MemberScopeTowerLevel(bodyResolveComponents, it, givenExtensionReceiverOptions)
MemberScopeTowerLevel(bodyResolveComponents, it, givenExtensionReceiverOptions, false)
}
override fun processFunctionsByName(info: CallInfo, processor: TowerScopeLevelProcessor<FirFunctionSymbol<*>>): ProcessResult {
@@ -0,0 +1,22 @@
// FIR_IDENTICAL
// ISSUE: KT-57166
// File order is important.
// FILE: InstanceObject.java
public interface InstanceObject {
long getDeallocTime();
void setDeallocTime(long deallocTime);
}
// FILE: LiveAllocationCaptureObject.kt
class LiveAllocationCaptureObject {
private fun queryJavaInstanceDelta() = run {
LiveAllocationInstanceObject().deallocTime = 42L
}
}
// FILE: LiveAllocationInstanceObject.kt
class LiveAllocationInstanceObject: InstanceObject {
override fun getDeallocTime() = 42L
override fun setDeallocTime(deallocTime: Long) {}
}
@@ -0,0 +1,26 @@
// FIR_IDENTICAL
// ISSUE: KT-57166
// FILE: PsiType.java
public abstract class PsiType {
}
// FILE: JavaCodeFragment.java
public interface JavaCodeFragment {
PsiType getThisType();
void setThisType(PsiType psiType);
}
// FILE: KtCodeFragment.kt
abstract class KtCodeFragment : JavaCodeFragment {
private var thisType: PsiType? = null
override fun getThisType() = thisType
override fun setThisType(psiType: PsiType?) {
thisType = psiType
}
}
@@ -0,0 +1,33 @@
// ISSUE: KT-57166
// FILE: Modality.kt
enum class Modality {
FINAL
}
// FILE: ClassDescriptor.java
public interface ClassDescriptor {
@NotNull
Modality getModality();
}
// FILE: DeserializedClassDescriptor.kt
object ProtoEnumFlags {
fun modality(): Modality = Modality.FINAL
}
class DeserializedClassDescriptor : ClassDescriptor {
private val modality = ProtoEnumFlags.modality()
override fun getModality() = modality
}
fun modality(): Modality = Modality.FINAL
class DeserializedClassDescriptor2 : ClassDescriptor {
private val modality = modality()
override fun getModality() = <!TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM!>modality<!>
}
@@ -0,0 +1,33 @@
// ISSUE: KT-57166
// FILE: Modality.kt
enum class Modality {
FINAL
}
// FILE: ClassDescriptor.java
public interface ClassDescriptor {
@NotNull
Modality getModality();
}
// FILE: DeserializedClassDescriptor.kt
object ProtoEnumFlags {
fun modality(): Modality = Modality.FINAL
}
class DeserializedClassDescriptor : ClassDescriptor {
private val modality = ProtoEnumFlags.modality()
override fun getModality() = modality
}
fun modality(): Modality = Modality.FINAL
class DeserializedClassDescriptor2 : ClassDescriptor {
private val modality = <!TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM_ERROR!><!DEBUG_INFO_MISSING_UNRESOLVED!>modality<!>()<!>
override fun getModality() = <!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>modality<!>
}
@@ -19576,6 +19576,24 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
runTest("compiler/testData/diagnostics/tests/j+k/supertypeUsesNested.kt");
}
@Test
@TestMetadata("syntheticAssignmentInLambdaExpressionBody.kt")
public void testSyntheticAssignmentInLambdaExpressionBody() throws Exception {
runTest("compiler/testData/diagnostics/tests/j+k/syntheticAssignmentInLambdaExpressionBody.kt");
}
@Test
@TestMetadata("syntheticPropertyOverridden.kt")
public void testSyntheticPropertyOverridden() throws Exception {
runTest("compiler/testData/diagnostics/tests/j+k/syntheticPropertyOverridden.kt");
}
@Test
@TestMetadata("syntheticPropertyOverridden2.kt")
public void testSyntheticPropertyOverridden2() throws Exception {
runTest("compiler/testData/diagnostics/tests/j+k/syntheticPropertyOverridden2.kt");
}
@Test
@TestMetadata("traitDefaultCall.kt")
public void testTraitDefaultCall() throws Exception {