[FIR] Add contract description blocks support to "lightTree2FIR" conversion
This commit is contained in:
+10
@@ -113,6 +113,16 @@ open class BaseConverter(
|
||||
return kidsRef.get()
|
||||
}
|
||||
|
||||
fun LighterASTNode?.getFirstChild(): LighterASTNode? {
|
||||
val firstChild: LighterASTNode?
|
||||
try {
|
||||
firstChild = getChildrenAsArray()[0]
|
||||
} catch (e: ArrayIndexOutOfBoundsException) {
|
||||
return null
|
||||
}
|
||||
return firstChild
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalContracts::class)
|
||||
protected inline fun LighterASTNode.forEachChildren(vararg skipTokens: KtToken, f: (LighterASTNode) -> Unit) {
|
||||
val kidsArray = this.getChildrenAsArray()
|
||||
|
||||
+53
-7
@@ -17,6 +17,7 @@ import org.jetbrains.kotlin.fir.builder.Context
|
||||
import org.jetbrains.kotlin.fir.builder.extractContractDescriptionIfPossible
|
||||
import org.jetbrains.kotlin.fir.builder.generateAccessorsByDelegate
|
||||
import org.jetbrains.kotlin.fir.contracts.FirContractDescription
|
||||
import org.jetbrains.kotlin.fir.contracts.builder.buildRawContractDescription
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.declarations.builder.*
|
||||
import org.jetbrains.kotlin.fir.declarations.impl.FirDeclarationStatusImpl
|
||||
@@ -1083,6 +1084,7 @@ class DeclarationsConverter(
|
||||
}
|
||||
var block: LighterASTNode? = null
|
||||
var expression: LighterASTNode? = null
|
||||
var outerContractDescription: FirContractDescription? = null
|
||||
getterOrSetter.forEachChildren {
|
||||
if (it.asText == "set") isGetter = false
|
||||
when (it.tokenType) {
|
||||
@@ -1090,6 +1092,7 @@ class DeclarationsConverter(
|
||||
MODIFIER_LIST -> modifiers = convertModifierList(it)
|
||||
TYPE_REFERENCE -> returnType = convertType(it)
|
||||
VALUE_PARAMETER_LIST -> firValueParameters = convertSetterParameter(it, propertyTypeRef)
|
||||
CONTRACT_EFFECT_LIST -> outerContractDescription = obtainContractDescription(it)
|
||||
BLOCK -> block = it
|
||||
else -> if (it.isExpression()) expression = it
|
||||
}
|
||||
@@ -1137,10 +1140,12 @@ class DeclarationsConverter(
|
||||
valueParameters += firValueParameters
|
||||
}
|
||||
|
||||
val (body, contractDescription) = convertFunctionBody(block, expression)
|
||||
this.body = body
|
||||
val hasContractEffectList = outerContractDescription != null
|
||||
val bodyWithContractDescription = convertFunctionBody(block, expression, hasContractEffectList)
|
||||
this.body = bodyWithContractDescription.first
|
||||
val contractDescription = outerContractDescription ?: bodyWithContractDescription.second
|
||||
contractDescription?.let {
|
||||
this.contractDescription = contractDescription
|
||||
this.contractDescription = it
|
||||
}
|
||||
context.firFunctionTargets.removeLast()
|
||||
}.also {
|
||||
@@ -1148,6 +1153,31 @@ class DeclarationsConverter(
|
||||
}
|
||||
}
|
||||
|
||||
private fun obtainContractDescription(rawContractDescription: LighterASTNode): FirContractDescription? =
|
||||
buildRawContractDescription {
|
||||
source = rawContractDescription.toFirSourceElement()
|
||||
extractRawEffects(rawContractDescription, rawEffects)
|
||||
}
|
||||
|
||||
private fun extractRawEffects(rawContractDescription: LighterASTNode, destination: MutableList<FirExpression>) {
|
||||
rawContractDescription.forEachChildren {
|
||||
val errorReason = "The contract effect is not an expression"
|
||||
when (it.tokenType) {
|
||||
CONTRACT_EFFECT -> {
|
||||
val effect = it.getFirstChild()
|
||||
if (effect == null) {
|
||||
val errorExpression = buildErrorExpression(null, ConeSimpleDiagnostic(errorReason, DiagnosticKind.ExpressionRequired))
|
||||
destination.add(errorExpression)
|
||||
} else {
|
||||
val expression = expressionConverter.convertExpression(effect, errorReason)
|
||||
destination.add(expression as FirExpression)
|
||||
}
|
||||
}
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* this is just a VALUE_PARAMETER_LIST
|
||||
*
|
||||
@@ -1195,6 +1225,7 @@ class DeclarationsConverter(
|
||||
var expression: LighterASTNode? = null
|
||||
var hasEqToken = false
|
||||
var typeParameterList: LighterASTNode? = null
|
||||
var outerContractDescription: FirContractDescription? = null
|
||||
functionDeclaration.forEachChildren {
|
||||
when (it.tokenType) {
|
||||
MODIFIER_LIST -> modifiers = convertModifierList(it)
|
||||
@@ -1204,6 +1235,7 @@ class DeclarationsConverter(
|
||||
COLON -> isReturnType = true
|
||||
TYPE_REFERENCE -> if (isReturnType) returnType = convertType(it) else receiverType = convertType(it)
|
||||
TYPE_CONSTRAINT_LIST -> typeConstraints += convertTypeConstraints(it)
|
||||
CONTRACT_EFFECT_LIST -> outerContractDescription = obtainContractDescription(it)
|
||||
BLOCK -> block = it
|
||||
EQ -> hasEqToken = true
|
||||
else -> if (it.isExpression()) expression = it
|
||||
@@ -1269,8 +1301,11 @@ class DeclarationsConverter(
|
||||
addCapturedTypeParameters(typeParameters)
|
||||
}
|
||||
valueParametersList?.let { list -> valueParameters += convertValueParameters(list).map { it.firValueParameter } }
|
||||
val (body, contractDescription) = convertFunctionBody(block, expression)
|
||||
this.body = body
|
||||
|
||||
val hasContractEffectList = outerContractDescription != null
|
||||
val bodyWithContractDescription = convertFunctionBody(block, expression, hasContractEffectList)
|
||||
this.body = bodyWithContractDescription.first
|
||||
val contractDescription = outerContractDescription ?: bodyWithContractDescription.second
|
||||
contractDescription?.let {
|
||||
// TODO: add error reporting for contracts on lambdas
|
||||
if (this is FirSimpleFunctionBuilder) {
|
||||
@@ -1288,9 +1323,20 @@ class DeclarationsConverter(
|
||||
* @see org.jetbrains.kotlin.parsing.KotlinParsing.parseFunctionBody
|
||||
* @see org.jetbrains.kotlin.fir.builder.RawFirBuilder.Visitor.buildFirBody
|
||||
*/
|
||||
private fun convertFunctionBody(blockNode: LighterASTNode?, expression: LighterASTNode?): Pair<FirBlock?, FirContractDescription?> {
|
||||
private fun convertFunctionBody(
|
||||
blockNode: LighterASTNode?,
|
||||
expression: LighterASTNode?,
|
||||
hasContractEffectList: Boolean = false
|
||||
): Pair<FirBlock?, FirContractDescription?> {
|
||||
return when {
|
||||
blockNode != null -> convertBlock(blockNode).extractContractDescriptionIfPossible()
|
||||
blockNode != null -> {
|
||||
val block = convertBlock(blockNode)
|
||||
if (hasContractEffectList) {
|
||||
block to null
|
||||
} else {
|
||||
block.extractContractDescriptionIfPossible()
|
||||
}
|
||||
}
|
||||
expression != null -> FirSingleExpressionBlock(
|
||||
expressionConverter.getAsFirExpression<FirExpression>(expression, "Function has no body (but should)").toReturn()
|
||||
) to null
|
||||
|
||||
Reference in New Issue
Block a user