[FIR] Properly resolve declarations inside contract calls on CONTRACT phase

This commit is contained in:
Dmitriy Novozhilov
2022-11-11 17:34:14 +02:00
committed by Space Team
parent 01c6c7dc59
commit 9b7b517f43
6 changed files with 29 additions and 54 deletions
@@ -29,14 +29,15 @@ internal class LLFirDesignatedContractsResolveTransformer(
private val ideDeclarationTransformer = LLFirDeclarationTransformer(designation)
override val declarationsTransformer: FirDeclarationsResolveTransformer = object : FirDeclarationsContractResolveTransformer(this) {
override fun transformDeclarationContent(firClass: FirClass, data: ResolutionMode) {
ideDeclarationTransformer.transformDeclarationContent(this, firClass, data) {
super.transformDeclarationContent(firClass, data)
firClass
override val contractDeclarationsTransformer: FirDeclarationsContractResolveTransformer
get() = object : FirDeclarationsContractResolveTransformer() {
override fun transformDeclarationContent(firClass: FirClass, data: ResolutionMode) {
ideDeclarationTransformer.transformDeclarationContent(this, firClass, data) {
super.transformDeclarationContent(firClass, data)
firClass
}
}
}
}
override fun transformDeclarationContent(declaration: FirDeclaration, data: ResolutionMode): FirDeclaration =
ideDeclarationTransformer.transformDeclarationContent(this, declaration, data) {
@@ -48,6 +48,14 @@ abstract class FirAbstractContractResolveTransformerDispatcher(
final override val expressionsTransformer: FirExpressionsResolveTransformer =
FirExpressionsResolveTransformer(this)
final override val declarationsTransformer: FirDeclarationsResolveTransformer
get() = if (contractMode) contractDeclarationsTransformer else regularDeclarationsTransformer
protected abstract val contractDeclarationsTransformer: FirDeclarationsContractResolveTransformer
private val regularDeclarationsTransformer = FirDeclarationsResolveTransformer(this)
private var contractMode = true
override fun transformAnnotation(annotation: FirAnnotation, data: ResolutionMode): FirStatement {
return annotation
}
@@ -56,9 +64,8 @@ abstract class FirAbstractContractResolveTransformerDispatcher(
return annotationCall
}
protected open class FirDeclarationsContractResolveTransformer(
transformer: FirAbstractBodyResolveTransformerDispatcher
) : FirDeclarationsResolveTransformer(transformer) {
protected open inner class FirDeclarationsContractResolveTransformer :
FirDeclarationsResolveTransformer(this@FirAbstractContractResolveTransformerDispatcher) {
override fun transformSimpleFunction(
simpleFunction: FirSimpleFunction,
data: ResolutionMode
@@ -136,7 +143,12 @@ abstract class FirAbstractContractResolveTransformerDispatcher(
for (valueParameter in valueParameters) {
context.storeVariable(valueParameter, session)
}
val contractCall = contractDescription.contractCall.transformSingle(transformer, ResolutionMode.ContextIndependent)
val contractCall = try {
contractMode = false
contractDescription.contractCall.transformSingle(transformer, ResolutionMode.ContextIndependent)
} finally {
contractMode = true
}
val resolvedId = contractCall.toResolvedCallableSymbol()?.callableId ?: return transformOwnerWithUnresolvedContract(owner)
if (resolvedId != FirContractsDslNames.CONTRACT) return transformOwnerWithUnresolvedContract(owner)
if (contractCall.arguments.size != 1) return transformOwnerOfErrorContract(owner)
@@ -9,7 +9,7 @@ import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.*
open class FirContractResolveTransformer(
class FirContractResolveTransformer(
session: FirSession,
scopeSession: ScopeSession,
outerBodyResolveContext: BodyResolveContext? = null
@@ -18,6 +18,6 @@ open class FirContractResolveTransformer(
scopeSession,
outerBodyResolveContext,
) {
final override val declarationsTransformer: FirDeclarationsResolveTransformer =
FirDeclarationsContractResolveTransformer(this)
override val contractDeclarationsTransformer: FirDeclarationsContractResolveTransformer
get() = FirDeclarationsContractResolveTransformer()
}
@@ -25,7 +25,7 @@ fun whenInContract(x: Any?, boolean: Boolean) {
fun forInContract(x: Any?) {
contract {
for (i in <!HAS_NEXT_MISSING!>0..1<!>) {
for (i in 0..1) {
returns() implies (x is String)
}
}
@@ -52,4 +52,4 @@ fun localValInContract(x: Any?) {
<!ERROR_IN_CONTRACT_DESCRIPTION!>val y: Int = 42<!>
returns() implies (x is String)
}<!>
}
}
@@ -1,39 +0,0 @@
// !OPT_IN: kotlin.contracts.ExperimentalContracts
// !LANGUAGE: +UseReturnsEffect
// Issue: KT-26386
fun myRun(block: () -> Unit) {
block()
}
fun contract(block: () -> Unit) {
block()
}
fun case_1(): Boolean? {
contract { case_1() }
return null
}
fun case_2(): Boolean? {
contract { case_3() }
return null
}
fun case_3(): Boolean? {
contract { case_2() }
return null
}
fun case4() {
contract {
myRun {
val s: String
run {
<!UNRESOLVED_REFERENCE!>s<!> = "hello"
}
<!UNRESOLVED_REFERENCE!>s<!>.length
}
}
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// !OPT_IN: kotlin.contracts.ExperimentalContracts
// !LANGUAGE: +UseReturnsEffect
// Issue: KT-26386