FIR: add a resolution mode for property delegates

Like function arguments, they are context-dependent, but unlike function
arguments, callable references should be resolved eagerly as if they are
explicit receivers.
This commit is contained in:
pyos
2020-11-17 14:02:35 +01:00
committed by Mikhail Glukhikh
parent 0a5b899aab
commit 7327c20200
15 changed files with 75 additions and 32 deletions
@@ -6,12 +6,12 @@
package org.jetbrains.kotlin.fir.backend.generators
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.fir.FirFakeSourceElementKind
import org.jetbrains.kotlin.fir.backend.*
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.dispatchReceiverClassOrNull
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.expressions.impl.FirNoReceiverExpression
import org.jetbrains.kotlin.fir.psi
import org.jetbrains.kotlin.fir.references.FirDelegateFieldReference
import org.jetbrains.kotlin.fir.references.FirReference
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
@@ -35,7 +35,6 @@ import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.psi.KtPropertyDelegate
import org.jetbrains.kotlin.psi2ir.generators.hasNoSideEffects
import org.jetbrains.kotlin.types.AbstractTypeApproximator
@@ -59,11 +58,12 @@ class CallAndReferenceGenerator(
val symbol =
callableReferenceAccess.calleeReference.toSymbolForCall(session, classifierStorage, declarationStorage, conversionScope)
val type = callableReferenceAccess.typeRef.toIrType()
fun propertyOrigin(): IrStatementOrigin? =
when (callableReferenceAccess.source?.psi?.parent) {
is KtPropertyDelegate -> IrStatementOrigin.PROPERTY_REFERENCE_FOR_DELEGATE
else -> null
}
// val x by y ->
// val `x$delegate` = y
// val x get() = `x$delegate`.getValue(this, ::x)
// The reference here (like the rest of the accessor) has DefaultAccessor source kind.
val isForDelegate = callableReferenceAccess.source?.kind == FirFakeSourceElementKind.DefaultAccessor
val origin = if (isForDelegate) IrStatementOrigin.PROPERTY_REFERENCE_FOR_DELEGATE else null
return callableReferenceAccess.convertWithOffsets { startOffset, endOffset ->
when (symbol) {
is IrPropertySymbol -> {
@@ -82,7 +82,7 @@ class CallAndReferenceGenerator(
field = backingFieldSymbol,
getter = referencedPropertyGetter?.symbol,
setter = referencedPropertySetterSymbol,
propertyOrigin()
origin = origin
)
}
is IrLocalDelegatedPropertySymbol -> {
@@ -91,7 +91,7 @@ class CallAndReferenceGenerator(
delegate = symbol.owner.delegate.symbol,
getter = symbol.owner.getter.symbol,
setter = symbol.owner.setter?.symbol,
IrStatementOrigin.PROPERTY_REFERENCE_FOR_DELEGATE
origin = origin
)
}
is IrFieldSymbol -> {
@@ -111,7 +111,7 @@ class CallAndReferenceGenerator(
field = symbol,
getter = if (referencedField.isStatic) null else propertySymbol.owner.getter?.symbol,
setter = if (referencedField.isStatic) null else propertySymbol.owner.setter?.symbol,
propertyOrigin()
origin
)
}
is IrConstructorSymbol -> {
@@ -10028,6 +10028,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/delegatedProperty/delegateForExtPropertyInClass.kt");
}
@TestMetadata("delegateToAnother.kt")
public void testDelegateToAnother() throws Exception {
runTest("compiler/testData/codegen/box/delegatedProperty/delegateToAnother.kt");
}
@TestMetadata("delegateWithPrivateSet.kt")
public void testDelegateWithPrivateSet() throws Exception {
runTest("compiler/testData/codegen/box/delegatedProperty/delegateWithPrivateSet.kt");
@@ -292,6 +292,7 @@ fun FirPropertyBuilder.generateAccessorsByDelegate(
else -> null
}
val isMember = ownerSymbol != null
val fakeSource = delegateBuilder.source?.fakeElement(FirFakeSourceElementKind.DefaultAccessor)
/*
* If we have delegation with provide delegate then we generate call like
@@ -310,7 +311,7 @@ fun FirPropertyBuilder.generateAccessorsByDelegate(
fun thisRef(isForDelegateProviderCall: Boolean = false): FirExpression =
when {
ownerSymbol != null -> buildThisReceiverExpression {
source = delegateBuilder.source
source = fakeSource
calleeReference = buildImplicitThisReference {
boundSymbol = ownerSymbol
}
@@ -320,7 +321,7 @@ fun FirPropertyBuilder.generateAccessorsByDelegate(
}
}
isExtension && !isForDelegateProviderCall -> buildThisReceiverExpression {
source = delegateBuilder.source
source = fakeSource
calleeReference = buildImplicitThisReference {
boundSymbol = this@generateAccessorsByDelegate.symbol
}
@@ -329,7 +330,7 @@ fun FirPropertyBuilder.generateAccessorsByDelegate(
}
fun delegateAccess() = buildQualifiedAccessExpression {
source = delegateBuilder.source
source = fakeSource
calleeReference = buildDelegateFieldReference {
resolvedSymbol = delegateFieldSymbol
}
@@ -340,9 +341,9 @@ fun FirPropertyBuilder.generateAccessorsByDelegate(
val isVar = this@generateAccessorsByDelegate.isVar
fun propertyRef() = buildCallableReferenceAccess {
source = delegateBuilder.source
source = fakeSource
calleeReference = buildResolvedNamedReference {
source = delegateBuilder.source
source = fakeSource
name = this@generateAccessorsByDelegate.name
resolvedSymbol = this@generateAccessorsByDelegate.symbol
}
@@ -368,7 +369,7 @@ fun FirPropertyBuilder.generateAccessorsByDelegate(
delegateBuilder.delegateProvider = if (stubMode) buildExpressionStub() else buildFunctionCall {
explicitReceiver = receiver
calleeReference = buildSimpleNamedReference {
source = delegateBuilder.source
source = fakeSource
name = PROVIDE_DELEGATE
}
argumentList = buildBinaryArgumentList(thisRef(isForDelegateProviderCall = true), propertyRef())
@@ -379,7 +380,7 @@ fun FirPropertyBuilder.generateAccessorsByDelegate(
val annotations = getter?.annotations
val returnTarget = FirFunctionTarget(null, isLambda = false)
getter = buildPropertyAccessor {
this.source = delegateBuilder.source
this.source = fakeSource
this.session = session
origin = FirDeclarationOrigin.Source
returnTypeRef = buildImplicitTypeRef()
@@ -390,10 +391,10 @@ fun FirPropertyBuilder.generateAccessorsByDelegate(
body = FirSingleExpressionBlock(
buildReturnExpression {
result = buildFunctionCall {
source = delegateBuilder.source
source = fakeSource
explicitReceiver = delegateAccess()
calleeReference = buildSimpleNamedReference {
source = delegateBuilder.source
source = fakeSource
name = GET_VALUE
}
argumentList = buildBinaryArgumentList(thisRef(), propertyRef())
@@ -411,14 +412,14 @@ fun FirPropertyBuilder.generateAccessorsByDelegate(
if (isVar && (setter == null || setter is FirDefaultPropertyAccessor)) {
val annotations = setter?.annotations
setter = buildPropertyAccessor {
this.source = delegateBuilder.source
this.source = fakeSource
this.session = session
origin = FirDeclarationOrigin.Source
returnTypeRef = session.builtinTypes.unitType
isGetter = false
status = FirDeclarationStatusImpl(Visibilities.Unknown, Modality.FINAL)
val parameter = buildValueParameter {
source = delegateBuilder.source
source = fakeSource
this.session = session
origin = FirDeclarationOrigin.Source
returnTypeRef = buildImplicitTypeRef()
@@ -432,7 +433,7 @@ fun FirPropertyBuilder.generateAccessorsByDelegate(
symbol = FirPropertyAccessorSymbol()
body = FirSingleExpressionBlock(
buildFunctionCall {
source = delegateBuilder.source
source = fakeSource
explicitReceiver = delegateAccess()
calleeReference = buildSimpleNamedReference {
name = SET_VALUE
@@ -442,7 +443,7 @@ fun FirPropertyBuilder.generateAccessorsByDelegate(
arguments += propertyRef()
arguments += buildQualifiedAccessExpression {
calleeReference = buildResolvedNamedReference {
source = delegateBuilder.source
source = fakeSource
name = DELEGATED_SETTER_PARAM
resolvedSymbol = parameter.symbol
}
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
sealed class ResolutionMode {
object ContextDependent : ResolutionMode()
object ContextDependentDelegate : ResolutionMode()
object ContextIndependent : ResolutionMode()
// TODO: it's better not to use WithExpectedType(FirImplicitTypeRef)
class WithExpectedType(val expectedTypeRef: FirTypeRef) : ResolutionMode()
@@ -192,7 +192,7 @@ open class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransfor
}
private fun transformPropertyWithDelegate(property: FirProperty) {
property.transformDelegate(transformer, ResolutionMode.ContextDependent)
property.transformDelegate(transformer, ResolutionMode.ContextDependentDelegate)
val delegateExpression = property.delegate!!
@@ -230,7 +230,7 @@ open class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransfor
): CompositeTransformResult<FirStatement> {
dataFlowAnalyzer.enterDelegateExpression()
try {
val delegateProvider = wrappedDelegateExpression.delegateProvider.transformSingle(transformer, ResolutionMode.ContextDependent)
val delegateProvider = wrappedDelegateExpression.delegateProvider.transformSingle(transformer, data)
when (val calleeReference = (delegateProvider as FirResolvable).calleeReference) {
is FirResolvedNamedReference -> return delegateProvider.compose()
is FirNamedReferenceWithCandidate -> {
@@ -243,7 +243,7 @@ open class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransfor
(delegateProvider as? FirFunctionCall)?.let { dataFlowAnalyzer.dropSubgraphFromCall(it) }
return wrappedDelegateExpression.expression
.transformSingle(transformer, ResolutionMode.ContextDependent)
.transformSingle(transformer, data)
.approximateIfIsIntegerConst()
.compose()
} finally {
@@ -669,7 +669,7 @@ open class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransfor
context.saveContextForAnonymousFunction(anonymousFunction)
}
return when (data) {
ResolutionMode.ContextDependent -> {
is ResolutionMode.ContextDependent, is ResolutionMode.ContextDependentDelegate -> {
dataFlowAnalyzer.visitPostponedAnonymousFunction(anonymousFunction)
anonymousFunction.addReturn().compose()
}
@@ -33,7 +33,6 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.types.builder.*
import org.jetbrains.kotlin.fir.visitors.*
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.calls.tower.CandidateApplicability
import org.jetbrains.kotlin.types.TypeApproximatorConfiguration
@@ -612,7 +611,7 @@ open class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransform
else
callableReferenceAccess
if (data !is ResolutionMode.ContextDependent) {
if (data !is ResolutionMode.ContextDependent /* ContextDependentDelegate is Ok here */) {
val resolvedReference =
components.syntheticCallGenerator.resolveCallableReferenceWithSyntheticOuterCall(
callableReferenceAccess, data.expectedType, resolutionContext,
@@ -0,0 +1,9 @@
// WITH_REFLECT
// WITH_RUNTIME
class C(val x: String)
val x = "O"
val y by ::x
val z by C("K")::x
fun box(): String = y + z
@@ -1,2 +0,0 @@
Failures detected in FirBodyResolveTransformerAdapter, file: /provideDelegateOnFunctionalTypeWithThis.fir.kt
Cause: java.lang.ClassCastException: org.jetbrains.kotlin.fir.types.impl.FirImplicitTypeRefImpl cannot be cast to org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
@@ -13,7 +13,7 @@ fun wrong(arg: Wrong) {}
class Wrong
class Right {
val prop: () -> Unit by <!DELEGATE_SPECIAL_FUNCTION_MISSING, DELEGATE_SPECIAL_FUNCTION_NONE_APPLICABLE!>::wrong<!>
val prop: () -> Unit by <!UNRESOLVED_REFERENCE!>::wrong<!>
}
fun box(): String {
@@ -11428,6 +11428,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/delegatedProperty/delegateForExtPropertyInClass.kt");
}
@TestMetadata("delegateToAnother.kt")
public void testDelegateToAnother() throws Exception {
runTest("compiler/testData/codegen/box/delegatedProperty/delegateToAnother.kt");
}
@TestMetadata("delegateWithPrivateSet.kt")
public void testDelegateWithPrivateSet() throws Exception {
runTest("compiler/testData/codegen/box/delegatedProperty/delegateWithPrivateSet.kt");
@@ -11433,6 +11433,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/delegatedProperty/delegateForExtPropertyInClass.kt");
}
@TestMetadata("delegateToAnother.kt")
public void testDelegateToAnother() throws Exception {
runTest("compiler/testData/codegen/box/delegatedProperty/delegateToAnother.kt");
}
@TestMetadata("delegateWithPrivateSet.kt")
public void testDelegateWithPrivateSet() throws Exception {
runTest("compiler/testData/codegen/box/delegatedProperty/delegateWithPrivateSet.kt");
@@ -10028,6 +10028,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/delegatedProperty/delegateForExtPropertyInClass.kt");
}
@TestMetadata("delegateToAnother.kt")
public void testDelegateToAnother() throws Exception {
runTest("compiler/testData/codegen/box/delegatedProperty/delegateToAnother.kt");
}
@TestMetadata("delegateWithPrivateSet.kt")
public void testDelegateWithPrivateSet() throws Exception {
runTest("compiler/testData/codegen/box/delegatedProperty/delegateWithPrivateSet.kt");
@@ -8543,6 +8543,11 @@ public class IrJsCodegenBoxES6TestGenerated extends AbstractIrJsCodegenBoxES6Tes
runTest("compiler/testData/codegen/box/delegatedProperty/delegateForExtPropertyInClass.kt");
}
@TestMetadata("delegateToAnother.kt")
public void testDelegateToAnother() throws Exception {
runTest("compiler/testData/codegen/box/delegatedProperty/delegateToAnother.kt");
}
@TestMetadata("delegateWithPrivateSet.kt")
public void testDelegateWithPrivateSet() throws Exception {
runTest("compiler/testData/codegen/box/delegatedProperty/delegateWithPrivateSet.kt");
@@ -8543,6 +8543,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/delegatedProperty/delegateForExtPropertyInClass.kt");
}
@TestMetadata("delegateToAnother.kt")
public void testDelegateToAnother() throws Exception {
runTest("compiler/testData/codegen/box/delegatedProperty/delegateToAnother.kt");
}
@TestMetadata("delegateWithPrivateSet.kt")
public void testDelegateWithPrivateSet() throws Exception {
runTest("compiler/testData/codegen/box/delegatedProperty/delegateWithPrivateSet.kt");
@@ -8543,6 +8543,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/delegatedProperty/delegateForExtPropertyInClass.kt");
}
@TestMetadata("delegateToAnother.kt")
public void testDelegateToAnother() throws Exception {
runTest("compiler/testData/codegen/box/delegatedProperty/delegateToAnother.kt");
}
@TestMetadata("delegateWithPrivateSet.kt")
public void testDelegateWithPrivateSet() throws Exception {
runTest("compiler/testData/codegen/box/delegatedProperty/delegateWithPrivateSet.kt");