[FIR] Add contracts resolve for property accessors
This commit is contained in:
+30
@@ -0,0 +1,30 @@
|
||||
import kotlin.contracts.*
|
||||
|
||||
interface A {
|
||||
fun foo()
|
||||
}
|
||||
|
||||
var Any?.isNotNull: Boolean
|
||||
get() {
|
||||
contract {
|
||||
returns(true) implies (this@isNotNull != null)
|
||||
}
|
||||
return this != null
|
||||
}
|
||||
set(value) {
|
||||
contract {
|
||||
returns() implies (this@isNotNull != null)
|
||||
require(this != null)
|
||||
}
|
||||
}
|
||||
|
||||
fun test_1(a: A?) {
|
||||
if (a.isNotNull) {
|
||||
a.<!INAPPLICABLE_CANDIDATE!>foo<!>()
|
||||
}
|
||||
}
|
||||
|
||||
fun test_2(a: A?) {
|
||||
a.isNotNull = true
|
||||
a.<!INAPPLICABLE_CANDIDATE!>foo<!>()
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
FILE: propertyAccessors.kt
|
||||
public abstract interface A : R|kotlin/Any| {
|
||||
public abstract fun foo(): R|kotlin/Unit|
|
||||
|
||||
}
|
||||
public final var R|kotlin/Any?|.isNotNull: R|kotlin/Boolean|
|
||||
public get(): R|kotlin/Boolean|
|
||||
[R|Contract description]
|
||||
<
|
||||
Returns(TRUE) -> this != null
|
||||
>
|
||||
{
|
||||
[StubStatement]
|
||||
^ !=(this@R|/isNotNull|, Null(null))
|
||||
}
|
||||
public set(value: R|kotlin/Boolean|): R|kotlin/Unit|
|
||||
[R|Contract description]
|
||||
<
|
||||
Returns(WILDCARD) -> this != null
|
||||
>
|
||||
{
|
||||
[StubStatement]
|
||||
}
|
||||
public final fun test_1(a: R|A?|): R|kotlin/Unit| {
|
||||
when () {
|
||||
R|<local>/a|.R|/isNotNull| -> {
|
||||
R|<local>/a|.<Inapplicable(WRONG_RECEIVER): [/A.foo]>#()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
public final fun test_2(a: R|A?|): R|kotlin/Unit| {
|
||||
R|<local>/a|.R|/isNotNull| = Boolean(true)
|
||||
R|<local>/a|.<Inapplicable(WRONG_RECEIVER): [/A.foo]>#()
|
||||
}
|
||||
+5
@@ -593,6 +593,11 @@ public class FirDiagnosticsWithStdlibTestGenerated extends AbstractFirDiagnostic
|
||||
runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/good/returnsImplies/eqNotEq.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("propertyAccessors.kt")
|
||||
public void testPropertyAccessors() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/good/returnsImplies/propertyAccessors.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("receivers.kt")
|
||||
public void testReceivers() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/good/returnsImplies/receivers.kt");
|
||||
|
||||
+49
-2
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.fir.contracts.builder.buildResolvedContractDescripti
|
||||
import org.jetbrains.kotlin.fir.contracts.description.ConeEffectDeclaration
|
||||
import org.jetbrains.kotlin.fir.contracts.impl.FirEmptyContractDescription
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.declarations.synthetic.FirSyntheticProperty
|
||||
import org.jetbrains.kotlin.fir.errorTypeFromPrototype
|
||||
import org.jetbrains.kotlin.fir.expressions.*
|
||||
import org.jetbrains.kotlin.fir.resolve.ResolutionMode
|
||||
@@ -38,12 +39,12 @@ class FirContractResolveTransformer(session: FirSession, scopeSession: ScopeSess
|
||||
data: ResolutionMode
|
||||
): CompositeTransformResult<FirSimpleFunction> {
|
||||
if (!simpleFunction.hasContractToResolve) {
|
||||
simpleFunction.replaceResolvePhase(FirResolvePhase.CONTRACTS)
|
||||
simpleFunction.updatePhase()
|
||||
return simpleFunction.compose()
|
||||
}
|
||||
val containingDeclaration = context.containerIfAny
|
||||
if (containingDeclaration != null && containingDeclaration !is FirClass<*>) {
|
||||
simpleFunction.replaceResolvePhase(FirResolvePhase.CONTRACTS)
|
||||
simpleFunction.updatePhase()
|
||||
simpleFunction.replaceReturnTypeRef(
|
||||
simpleFunction.returnTypeRef.errorTypeFromPrototype(
|
||||
ConeContractDescriptionError("Local function can not be used in contract description")
|
||||
@@ -64,6 +65,48 @@ class FirContractResolveTransformer(session: FirSession, scopeSession: ScopeSess
|
||||
}
|
||||
}
|
||||
|
||||
override fun transformProperty(property: FirProperty, data: ResolutionMode): CompositeTransformResult<FirProperty> {
|
||||
if (
|
||||
property.getter?.hasContractToResolve != true && property.setter?.hasContractToResolve != true ||
|
||||
property.isLocal || property.delegate != null
|
||||
) {
|
||||
property.updatePhase()
|
||||
return property.compose()
|
||||
}
|
||||
if (property is FirSyntheticProperty) {
|
||||
transformSimpleFunction(property.getter.delegate, data)
|
||||
return property.compose()
|
||||
}
|
||||
withTypeParametersOf(property) {
|
||||
withLocalScopeCleanup {
|
||||
context.withContainer(property) {
|
||||
property.getter?.let { transformPropertyAccessor(it, property) }
|
||||
property.setter?.let { transformPropertyAccessor(it, property) }
|
||||
}
|
||||
}
|
||||
}
|
||||
property.updatePhase()
|
||||
return property.compose()
|
||||
}
|
||||
|
||||
private fun transformPropertyAccessor(
|
||||
propertyAccessor: FirPropertyAccessor,
|
||||
owner: FirProperty
|
||||
): CompositeTransformResult<FirStatement> {
|
||||
if (!propertyAccessor.hasContractToResolve) {
|
||||
propertyAccessor.updatePhase()
|
||||
return propertyAccessor.compose()
|
||||
}
|
||||
val receiverTypeRef = owner.receiverTypeRef
|
||||
return if (receiverTypeRef != null) {
|
||||
withLabelAndReceiverType(owner.name, propertyAccessor, receiverTypeRef.coneTypeUnsafe()) {
|
||||
transformContractDescriptionOwner(propertyAccessor)
|
||||
}
|
||||
} else {
|
||||
transformContractDescriptionOwner(propertyAccessor)
|
||||
}
|
||||
}
|
||||
|
||||
private fun <T : FirContractDescriptionOwner> transformContractDescriptionOwner(
|
||||
owner: T
|
||||
): CompositeTransformResult<T> {
|
||||
@@ -119,6 +162,10 @@ class FirContractResolveTransformer(session: FirSession, scopeSession: ScopeSess
|
||||
|
||||
private val FirContractDescriptionOwner.hasContractToResolve: Boolean
|
||||
get() = contractDescription is FirRawContractDescription
|
||||
|
||||
private fun FirDeclaration.updatePhase() {
|
||||
replaceResolvePhase(FirResolvePhase.CONTRACTS)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user