[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) private val ideDeclarationTransformer = LLFirDeclarationTransformer(designation)
override val declarationsTransformer: FirDeclarationsResolveTransformer = object : FirDeclarationsContractResolveTransformer(this) { override val contractDeclarationsTransformer: FirDeclarationsContractResolveTransformer
override fun transformDeclarationContent(firClass: FirClass, data: ResolutionMode) { get() = object : FirDeclarationsContractResolveTransformer() {
ideDeclarationTransformer.transformDeclarationContent(this, firClass, data) { override fun transformDeclarationContent(firClass: FirClass, data: ResolutionMode) {
super.transformDeclarationContent(firClass, data) ideDeclarationTransformer.transformDeclarationContent(this, firClass, data) {
firClass super.transformDeclarationContent(firClass, data)
firClass
}
} }
} }
}
override fun transformDeclarationContent(declaration: FirDeclaration, data: ResolutionMode): FirDeclaration = override fun transformDeclarationContent(declaration: FirDeclaration, data: ResolutionMode): FirDeclaration =
ideDeclarationTransformer.transformDeclarationContent(this, declaration, data) { ideDeclarationTransformer.transformDeclarationContent(this, declaration, data) {
@@ -48,6 +48,14 @@ abstract class FirAbstractContractResolveTransformerDispatcher(
final override val expressionsTransformer: FirExpressionsResolveTransformer = final override val expressionsTransformer: FirExpressionsResolveTransformer =
FirExpressionsResolveTransformer(this) 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 { override fun transformAnnotation(annotation: FirAnnotation, data: ResolutionMode): FirStatement {
return annotation return annotation
} }
@@ -56,9 +64,8 @@ abstract class FirAbstractContractResolveTransformerDispatcher(
return annotationCall return annotationCall
} }
protected open class FirDeclarationsContractResolveTransformer( protected open inner class FirDeclarationsContractResolveTransformer :
transformer: FirAbstractBodyResolveTransformerDispatcher FirDeclarationsResolveTransformer(this@FirAbstractContractResolveTransformerDispatcher) {
) : FirDeclarationsResolveTransformer(transformer) {
override fun transformSimpleFunction( override fun transformSimpleFunction(
simpleFunction: FirSimpleFunction, simpleFunction: FirSimpleFunction,
data: ResolutionMode data: ResolutionMode
@@ -136,7 +143,12 @@ abstract class FirAbstractContractResolveTransformerDispatcher(
for (valueParameter in valueParameters) { for (valueParameter in valueParameters) {
context.storeVariable(valueParameter, session) 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) val resolvedId = contractCall.toResolvedCallableSymbol()?.callableId ?: return transformOwnerWithUnresolvedContract(owner)
if (resolvedId != FirContractsDslNames.CONTRACT) return transformOwnerWithUnresolvedContract(owner) if (resolvedId != FirContractsDslNames.CONTRACT) return transformOwnerWithUnresolvedContract(owner)
if (contractCall.arguments.size != 1) return transformOwnerOfErrorContract(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.ScopeSession
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.* import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.*
open class FirContractResolveTransformer( class FirContractResolveTransformer(
session: FirSession, session: FirSession,
scopeSession: ScopeSession, scopeSession: ScopeSession,
outerBodyResolveContext: BodyResolveContext? = null outerBodyResolveContext: BodyResolveContext? = null
@@ -18,6 +18,6 @@ open class FirContractResolveTransformer(
scopeSession, scopeSession,
outerBodyResolveContext, outerBodyResolveContext,
) { ) {
final override val declarationsTransformer: FirDeclarationsResolveTransformer = override val contractDeclarationsTransformer: FirDeclarationsContractResolveTransformer
FirDeclarationsContractResolveTransformer(this) get() = FirDeclarationsContractResolveTransformer()
} }
@@ -25,7 +25,7 @@ fun whenInContract(x: Any?, boolean: Boolean) {
fun forInContract(x: Any?) { fun forInContract(x: Any?) {
contract { contract {
for (i in <!HAS_NEXT_MISSING!>0..1<!>) { for (i in 0..1) {
returns() implies (x is String) 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 // !OPT_IN: kotlin.contracts.ExperimentalContracts
// !LANGUAGE: +UseReturnsEffect // !LANGUAGE: +UseReturnsEffect
// Issue: KT-26386 // Issue: KT-26386