[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:
committed by
Space Team
parent
6aef11704b
commit
9b89759755
+18
@@ -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 {
|
||||
|
||||
+18
@@ -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 {
|
||||
|
||||
+18
@@ -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
|
||||
|
||||
+2
-1
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+9
-4
@@ -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
|
||||
}
|
||||
|
||||
+5
-2
@@ -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 {
|
||||
|
||||
+22
@@ -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<!>
|
||||
}
|
||||
Generated
+18
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user