FIR: avoid resolve loop between accessor and other members

#KT-48634 Fixed
This commit is contained in:
Mikhail Glukhikh
2021-08-23 18:08:31 +03:00
committed by teamcityserver
parent 72fa330576
commit 19a75b31f9
16 changed files with 186 additions and 29 deletions
@@ -0,0 +1,73 @@
FILE: accessInSetter.kt
public final class DrawableGrid : R|kotlin/Any| {
public constructor(isEnabled: R|kotlin/Boolean|): R|DrawableGrid| {
super<R|kotlin/Any|>()
}
public final var isEnabled: R|kotlin/Boolean| = R|<local>/isEnabled|
public get(): R|kotlin/Boolean|
public set(value: R|kotlin/Boolean|): R|kotlin/Unit|
}
public final class My : R|kotlin/Any| {
public constructor(): R|My| {
super<R|kotlin/Any|>()
}
private final val drawableGrid: R|DrawableGrid| = this@R|/My|.R|/My.createDrawableGrid|()
private get(): R|DrawableGrid|
private final var useAll: R|kotlin/Boolean| = Boolean(false)
private get(): R|kotlin/Boolean|
private set(value: R|kotlin/Boolean|): R|kotlin/Unit| {
this@R|/My|.R|/My.drawableGrid|.R|/DrawableGrid.isEnabled| = R|<local>/value|.R|kotlin/Boolean.not|()
}
private final fun createDrawableGrid(): R|DrawableGrid| {
^createDrawableGrid R|/DrawableGrid.DrawableGrid|(Boolean(false)).R|kotlin/apply|<R|DrawableGrid|>(<L> = apply@fun R|DrawableGrid|.<anonymous>(): R|kotlin/Unit| <inline=Inline, kind=EXACTLY_ONCE> {
when () {
this@R|/My|.R|/My.useAll| -> {
Int(-1)
}
else -> {
Int(0)
}
}
}
)
}
}
public final class Your : R|kotlin/Any| {
public constructor(): R|Your| {
super<R|kotlin/Any|>()
}
private final val drawableGrid: R|DrawableGrid| = this@R|/Your|.R|/Your.createDrawableGrid|()
private get(): R|DrawableGrid|
private final var useAll: R|kotlin/Boolean|
private get(): R|kotlin/Boolean| {
^ Boolean(false)
}
private set(value: R|kotlin/Boolean|): R|kotlin/Unit| {
this@R|/Your|.R|/Your.drawableGrid|.R|/DrawableGrid.isEnabled| = R|<local>/value|.R|kotlin/Boolean.not|()
}
private final fun createDrawableGrid(): R|DrawableGrid| {
^createDrawableGrid R|/DrawableGrid.DrawableGrid|(Boolean(false)).R|kotlin/apply|<R|DrawableGrid|>(<L> = apply@fun R|DrawableGrid|.<anonymous>(): R|kotlin/Unit| <inline=Inline, kind=EXACTLY_ONCE> {
when () {
this@R|/Your|.R|/Your.useAll| -> {
Int(-1)
}
else -> {
Int(0)
}
}
}
)
}
}
@@ -0,0 +1,28 @@
class DrawableGrid(var isEnabled: Boolean)
class My {
private val drawableGrid = createDrawableGrid()
private var useAll = false
set(value) {
drawableGrid.isEnabled = !value
}
private fun createDrawableGrid() = DrawableGrid(false).apply {
if (useAll) -1 else 0
}
}
class Your {
private val drawableGrid = createDrawableGrid()
private var useAll
get() = false
set(value) {
drawableGrid.isEnabled = !value
}
private fun createDrawableGrid() = DrawableGrid(false).apply {
if (useAll) -1 else 0
}
}
@@ -5034,6 +5034,12 @@ public class FirDiagnosticTestGenerated extends AbstractFirDiagnosticTest {
@TestMetadata("compiler/fir/analysis-tests/testData/resolveWithStdlib/intellij")
@TestDataPath("$PROJECT_ROOT")
public class Intellij {
@Test
@TestMetadata("accessInSetter.kt")
public void testAccessInSetter() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/intellij/accessInSetter.kt");
}
@Test
public void testAllFilesPresentInIntellij() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolveWithStdlib/intellij"), Pattern.compile("^([^.]+)\\.kt$"), null, true);
@@ -5034,6 +5034,12 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos
@TestMetadata("compiler/fir/analysis-tests/testData/resolveWithStdlib/intellij")
@TestDataPath("$PROJECT_ROOT")
public class Intellij {
@Test
@TestMetadata("accessInSetter.kt")
public void testAccessInSetter() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/intellij/accessInSetter.kt");
}
@Test
public void testAllFilesPresentInIntellij() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolveWithStdlib/intellij"), Pattern.compile("^([^.]+)\\.kt$"), null, true);
@@ -47,7 +47,6 @@ import org.jetbrains.kotlin.fir.visitors.FirDefaultTransformer
import org.jetbrains.kotlin.fir.visitors.FirTransformer
import org.jetbrains.kotlin.fir.visitors.transformSingle
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.SpecialNames
open class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransformer) : FirPartialBodyResolveTransformer(transformer) {
private val statusResolver: FirStatusResolver = FirStatusResolver(session, scopeSession)
@@ -126,17 +125,23 @@ open class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransfor
}
val returnTypeRef = property.returnTypeRef
if (property.initializerAndAccessorsAreResolved) return property
val bodyResolveState = property.bodyResolveState
if (bodyResolveState == FirPropertyBodyResolveState.EVERYTHING_RESOLVED) return property
if (returnTypeRef !is FirImplicitTypeRef && implicitTypeOnly) return property
property.transformReceiverTypeRef(transformer, ResolutionMode.ContextIndependent)
dataFlowAnalyzer.enterProperty(property)
doTransformTypeParameters(property)
val shouldResolveEverything = !implicitTypeOnly
return withFullBodyResolve {
val initializerIsAlreadyResolved = bodyResolveState >= FirPropertyBodyResolveState.INITIALIZER_RESOLVED
context.withProperty(property) {
context.forPropertyInitializer {
property.transformDelegate(transformer, ResolutionMode.ContextDependentDelegate)
property.transformChildrenWithoutAccessors(returnTypeRef)
if (!initializerIsAlreadyResolved) {
property.transformChildrenWithoutAccessors(returnTypeRef)
property.replaceBodyResolveState(FirPropertyBodyResolveState.INITIALIZER_RESOLVED)
}
if (property.initializer != null) {
storeVariableReturnType(property)
}
@@ -147,14 +152,26 @@ open class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransfor
if (property.delegateFieldSymbol != null) {
replacePropertyReferenceTypeInDelegateAccessors(property)
}
property.replaceBodyResolveState(FirPropertyBodyResolveState.EVERYTHING_RESOLVED)
} else {
property.transformAccessors()
val hasNonDefaultAccessors = property.getter != null && property.getter !is FirDefaultPropertyAccessor ||
property.setter != null && property.setter !is FirDefaultPropertyAccessor
val mayResolveSetter = shouldResolveEverything || !hasNonDefaultAccessors
val mayResolveGetter = mayResolveSetter || property.initializer == null
if (mayResolveGetter) {
property.transformAccessors(mayResolveSetter)
property.replaceBodyResolveState(
if (mayResolveSetter) FirPropertyBodyResolveState.EVERYTHING_RESOLVED
else FirPropertyBodyResolveState.INITIALIZER_AND_GETTER_RESOLVED
)
}
}
}
dataFlowAnalyzer.exitProperty(property)?.let {
property.replaceControlFlowGraphReference(FirControlFlowGraphReferenceImpl(it))
if (!initializerIsAlreadyResolved) {
dataFlowAnalyzer.exitProperty(property)?.let {
property.replaceControlFlowGraphReference(FirControlFlowGraphReferenceImpl(it))
}
}
property.replaceInitializerAndAccessorsAreResolved(true)
property
}
}
@@ -293,10 +310,12 @@ open class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransfor
.transformOtherChildren(transformer, data)
}
private fun FirProperty.transformAccessors() {
private fun FirProperty.transformAccessors(mayResolveSetter: Boolean = true) {
var enhancedTypeRef = returnTypeRef
getter?.let {
transformAccessor(it, enhancedTypeRef, this)
if (bodyResolveState < FirPropertyBodyResolveState.INITIALIZER_AND_GETTER_RESOLVED) {
getter?.let {
transformAccessor(it, enhancedTypeRef, this)
}
}
if (returnTypeRef is FirImplicitTypeRef) {
storeVariableReturnType(this)
@@ -304,11 +323,13 @@ open class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransfor
// We need update type of getter for case when its type was approximated
getter?.replaceReturnTypeRef(enhancedTypeRef)
}
setter?.let {
if (it.valueParameters[0].returnTypeRef is FirImplicitTypeRef) {
it.valueParameters[0].transformReturnTypeRef(StoreType, enhancedTypeRef)
if (mayResolveSetter) {
setter?.let {
if (it.valueParameters[0].returnTypeRef is FirImplicitTypeRef) {
it.valueParameters[0].transformReturnTypeRef(StoreType, enhancedTypeRef)
}
transformAccessor(it, enhancedTypeRef, this)
}
transformAccessor(it, enhancedTypeRef, this)
}
}
@@ -50,7 +50,7 @@ abstract class FirProperty : FirVariable(), FirTypeParametersOwner, FirControlFl
abstract val backingFieldSymbol: FirBackingFieldSymbol
abstract val delegateFieldSymbol: FirDelegateFieldSymbol?
abstract val isLocal: Boolean
abstract val initializerAndAccessorsAreResolved: Boolean
abstract val bodyResolveState: FirPropertyBodyResolveState
abstract override val typeParameters: List<FirTypeParameter>
override fun <R, D> accept(visitor: FirVisitor<R, D>, data: D): R = visitor.visitProperty(this, data)
@@ -71,7 +71,7 @@ abstract class FirProperty : FirVariable(), FirTypeParametersOwner, FirControlFl
abstract override fun replaceControlFlowGraphReference(newControlFlowGraphReference: FirControlFlowGraphReference?)
abstract fun replaceInitializerAndAccessorsAreResolved(newInitializerAndAccessorsAreResolved: Boolean)
abstract fun replaceBodyResolveState(newBodyResolveState: FirPropertyBodyResolveState)
abstract override fun <D> transformReturnTypeRef(transformer: FirTransformer<D>, data: D): FirProperty
@@ -16,6 +16,7 @@ import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
import org.jetbrains.kotlin.fir.declarations.FirDeclarationStatus
import org.jetbrains.kotlin.fir.declarations.FirProperty
import org.jetbrains.kotlin.fir.declarations.FirPropertyAccessor
import org.jetbrains.kotlin.fir.declarations.FirPropertyBodyResolveState
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.declarations.FirTypeParameter
import org.jetbrains.kotlin.fir.declarations.builder.FirDeclarationBuilder
@@ -61,7 +62,7 @@ class FirPropertyBuilder : FirDeclarationBuilder, FirTypeParametersOwnerBuilder,
lateinit var symbol: FirPropertySymbol
var delegateFieldSymbol: FirDelegateFieldSymbol? = null
var isLocal: Boolean by kotlin.properties.Delegates.notNull<Boolean>()
var initializerAndAccessorsAreResolved: Boolean = false
var bodyResolveState: FirPropertyBodyResolveState = FirPropertyBodyResolveState.NOTHING_RESOLVED
override val typeParameters: MutableList<FirTypeParameter> = mutableListOf()
override fun build(): FirProperty {
@@ -87,7 +88,7 @@ class FirPropertyBuilder : FirDeclarationBuilder, FirTypeParametersOwnerBuilder,
symbol,
delegateFieldSymbol,
isLocal,
initializerAndAccessorsAreResolved,
bodyResolveState,
typeParameters,
)
}
@@ -129,7 +130,7 @@ inline fun buildPropertyCopy(original: FirProperty, init: FirPropertyBuilder.()
copyBuilder.symbol = original.symbol
copyBuilder.delegateFieldSymbol = original.delegateFieldSymbol
copyBuilder.isLocal = original.isLocal
copyBuilder.initializerAndAccessorsAreResolved = original.initializerAndAccessorsAreResolved
copyBuilder.bodyResolveState = original.bodyResolveState
copyBuilder.typeParameters.addAll(original.typeParameters)
return copyBuilder.apply(init).build()
}
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
import org.jetbrains.kotlin.fir.declarations.FirDeclarationStatus
import org.jetbrains.kotlin.fir.declarations.FirProperty
import org.jetbrains.kotlin.fir.declarations.FirPropertyAccessor
import org.jetbrains.kotlin.fir.declarations.FirPropertyBodyResolveState
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.declarations.FirTypeParameter
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
@@ -55,7 +56,7 @@ internal class FirPropertyImpl(
override val symbol: FirPropertySymbol,
override val delegateFieldSymbol: FirDelegateFieldSymbol?,
override val isLocal: Boolean,
override var initializerAndAccessorsAreResolved: Boolean,
override var bodyResolveState: FirPropertyBodyResolveState,
override val typeParameters: MutableList<FirTypeParameter>,
) : FirProperty() {
override val isVal: Boolean get() = !isVar
@@ -169,7 +170,7 @@ internal class FirPropertyImpl(
controlFlowGraphReference = newControlFlowGraphReference
}
override fun replaceInitializerAndAccessorsAreResolved(newInitializerAndAccessorsAreResolved: Boolean) {
initializerAndAccessorsAreResolved = newInitializerAndAccessorsAreResolved
override fun replaceBodyResolveState(newBodyResolveState: FirPropertyBodyResolveState) {
bodyResolveState = newBodyResolveState
}
}
@@ -0,0 +1,14 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.declarations
// Semantically all states here are parts of FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE and just BODY_RESOLVE
enum class FirPropertyBodyResolveState {
NOTHING_RESOLVED,
INITIALIZER_RESOLVED,
INITIALIZER_AND_GETTER_RESOLVED,
EVERYTHING_RESOLVED
}
@@ -82,8 +82,8 @@ class FirSyntheticProperty(
// ???
override val backingFieldSymbol: FirBackingFieldSymbol = FirBackingFieldSymbol(symbol.callableId)
override val initializerAndAccessorsAreResolved: Boolean
get() = true
override val bodyResolveState: FirPropertyBodyResolveState
get() = FirPropertyBodyResolveState.EVERYTHING_RESOLVED
override fun <R, D> acceptChildren(visitor: FirVisitor<R, D>, data: D) {
returnTypeRef.accept(visitor, data)
@@ -158,7 +158,7 @@ class FirSyntheticProperty(
throw AssertionError("Mutation of synthetic property isn't supported")
}
override fun replaceInitializerAndAccessorsAreResolved(newInitializerAndAccessorsAreResolved: Boolean) {
override fun replaceBodyResolveState(newBodyResolveState: FirPropertyBodyResolveState) {
throw AssertionError("Mutation of synthetic property isn't supported")
}
}
@@ -202,7 +202,7 @@ object BuilderConfigurator : AbstractBuilderConfigurator<FirTreeBuilder>(FirTree
parents += typeParametersOwnerBuilder
defaultNull("getter", "setter", "containerSource", "delegateFieldSymbol")
default("resolvePhase", "FirResolvePhase.RAW_FIR")
defaultFalse("initializerAndAccessorsAreResolved")
default("bodyResolveState", "FirPropertyBodyResolveState.NOTHING_RESOLVED")
withCopy()
}
@@ -318,7 +318,7 @@ object NodeConfigurator : AbstractFieldConfigurator<FirTreeBuilder>(FirTreeBuild
+field("backingFieldSymbol", backingFieldSymbolType)
+field("delegateFieldSymbol", delegateFieldSymbolType, nullable = true)
+booleanField("isLocal")
+booleanField("initializerAndAccessorsAreResolved", withReplace = true)
+field("bodyResolveState", propertyBodyResolveStateType, withReplace = true)
+typeParameters
}
@@ -61,6 +61,7 @@ val implicitNothingTypeRefType = generatedType("types.impl", "FirImplicitNothing
val implicitStringTypeRefType = generatedType("types.impl", "FirImplicitStringTypeRef")
val implicitUnitTypeRefType = generatedType("types.impl", "FirImplicitUnitTypeRef")
val resolvePhaseType = type("fir.declarations", "FirResolvePhase")
val propertyBodyResolveStateType = type("fir.declarations", "FirPropertyBodyResolveState")
val stubReferenceType = generatedType("references.impl", "FirStubReference")
val firBasedSymbolType = type("fir.symbols", "FirBasedSymbol")
@@ -60,7 +60,7 @@ internal object DeclarationCopyBuilder {
setter = copySetter
if (propertyResolvePhase < FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE) {
initializerAndAccessorsAreResolved = false
bodyResolveState = FirPropertyBodyResolveState.NOTHING_RESOLVED
}
initDeclaration(this@withBodyFrom, propertyWithBody)
@@ -200,7 +200,7 @@ internal class ReanalyzablePropertyStructureElement(
getter?.replaceResolvePhase(upgradedPhase)
setter?.replaceResolvePhase(upgradedPhase)
replaceResolvePhase(upgradedPhase)
replaceInitializerAndAccessorsAreResolved(false)
replaceBodyResolveState(FirPropertyBodyResolveState.NOTHING_RESOLVED)
}
val resolvedDeclaration = firLazyDeclarationResolver.lazyResolveDeclaration(
@@ -5034,6 +5034,12 @@ public class DiagnosisCompilerFirTestdataTestGenerated extends AbstractDiagnosis
@TestMetadata("compiler/fir/analysis-tests/testData/resolveWithStdlib/intellij")
@TestDataPath("$PROJECT_ROOT")
public class Intellij {
@Test
@TestMetadata("accessInSetter.kt")
public void testAccessInSetter() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/intellij/accessInSetter.kt");
}
@Test
public void testAllFilesPresentInIntellij() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolveWithStdlib/intellij"), Pattern.compile("^([^.]+)\\.kt$"), null, true);