FIR: get rid of ANDAND / OROR by replacing with when

This commit is contained in:
Mikhail Glukhikh
2019-04-02 16:49:07 +03:00
parent 395651a21e
commit eb86c9e540
6 changed files with 115 additions and 74 deletions
@@ -18,6 +18,7 @@ import org.jetbrains.kotlin.fir.references.FirExplicitThisReference
import org.jetbrains.kotlin.fir.references.FirSimpleNamedReference
import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol
import org.jetbrains.kotlin.fir.types.FirTypeRef
import org.jetbrains.kotlin.fir.types.impl.FirImplicitBooleanTypeRef
import org.jetbrains.kotlin.fir.types.impl.FirImplicitTypeRefImpl
import org.jetbrains.kotlin.ir.expressions.IrConstKind
import org.jetbrains.kotlin.lexer.KtTokens
@@ -158,8 +159,6 @@ internal fun IElementType.toFirOperation(): FirOperation =
KtTokens.EXCLEQ -> FirOperation.NOT_EQ
KtTokens.EQEQEQ -> FirOperation.IDENTITY
KtTokens.EXCLEQEQEQ -> FirOperation.NOT_IDENTITY
KtTokens.ANDAND -> FirOperation.AND
KtTokens.OROR -> FirOperation.OR
KtTokens.IN_KEYWORD -> FirOperation.IN
KtTokens.NOT_IN -> FirOperation.NOT_IN
KtTokens.RANGE -> FirOperation.RANGE
@@ -201,6 +200,85 @@ internal fun FirExpression.generateNotNullOrOther(
}
}
internal fun FirExpression.generateLazyLogicalOperation(
session: FirSession, other: FirExpression, isAnd: Boolean, basePsi: KtElement
): FirWhenExpression {
val terminalExpression = FirConstExpressionImpl(session, psi, IrConstKind.Boolean, !isAnd)
val terminalBlock = FirSingleExpressionBlock(session, terminalExpression)
val otherBlock = FirSingleExpressionBlock(session, other)
return FirWhenExpressionImpl(session, basePsi).apply {
branches += FirWhenBranchImpl(
session, psi, this@generateLazyLogicalOperation,
if (isAnd) otherBlock else terminalBlock
)
branches += FirWhenBranchImpl(
session, other.psi, FirElseIfTrueCondition(session, psi),
if (isAnd) terminalBlock else otherBlock
)
typeRef = FirImplicitBooleanTypeRef(session, basePsi)
}
}
internal fun KtWhenCondition.toFirWhenCondition(
session: FirSession,
convert: KtExpression?.(String) -> FirExpression,
toFirOrErrorTypeRef: KtTypeReference?.() -> FirTypeRef
): FirExpression {
val firSubjectExpression = FirWhenSubjectExpression(session, this)
return when (this) {
is KtWhenConditionWithExpression -> {
FirOperatorCallImpl(
session,
expression,
FirOperation.EQ
).apply {
arguments += firSubjectExpression
arguments += expression.convert("No expression in condition with expression")
}
}
is KtWhenConditionInRange -> {
FirOperatorCallImpl(
session,
rangeExpression,
if (isNegated) FirOperation.NOT_IN else FirOperation.IN
).apply {
arguments += firSubjectExpression
arguments += rangeExpression.convert("No range in condition with range")
}
}
is KtWhenConditionIsPattern -> {
FirTypeOperatorCallImpl(
session, typeReference, if (isNegated) FirOperation.NOT_IS else FirOperation.IS,
typeReference.toFirOrErrorTypeRef()
).apply {
arguments += firSubjectExpression
}
}
else -> {
FirErrorExpressionImpl(session, this, "Unsupported when condition: ${this.javaClass}")
}
}
}
internal fun Array<KtWhenCondition>.toFirWhenCondition(
session: FirSession,
basePsi: KtElement,
convert: KtExpression?.(String) -> FirExpression,
toFirOrErrorTypeRef: KtTypeReference?.() -> FirTypeRef
): FirExpression {
var firCondition: FirExpression? = null
for (condition in this) {
val firConditionElement = condition.toFirWhenCondition(session, convert, toFirOrErrorTypeRef)
firCondition = when (firCondition) {
null -> firConditionElement
else -> firCondition.generateLazyLogicalOperation(
session, firConditionElement, false, basePsi
)
}
}
return firCondition!!
}
internal fun generateIncrementOrDecrementBlock(
session: FirSession,
baseExpression: KtUnaryExpression,
@@ -989,42 +989,6 @@ class RawFirBuilder(val session: FirSession, val stubMode: Boolean) {
}
}
private fun KtWhenCondition.toFirWhenCondition(firSubjectExpression: FirExpression): FirExpression {
return when (this) {
is KtWhenConditionWithExpression -> {
FirOperatorCallImpl(
session,
expression,
FirOperation.EQ
).apply {
arguments += firSubjectExpression
arguments += expression.toFirExpression("No expression in condition with expression")
}
}
is KtWhenConditionInRange -> {
FirOperatorCallImpl(
session,
rangeExpression,
if (isNegated) FirOperation.NOT_IN else FirOperation.IN
).apply {
arguments += firSubjectExpression
arguments += rangeExpression.toFirExpression("No range in condition with range")
}
}
is KtWhenConditionIsPattern -> {
FirTypeOperatorCallImpl(
session, typeReference, if (isNegated) FirOperation.NOT_IS else FirOperation.IS,
typeReference.toFirOrErrorType()
).apply {
arguments += firSubjectExpression
}
}
else -> {
FirErrorExpressionImpl(session, this, "Unsupported when condition: ${this.javaClass}")
}
}
}
override fun visitWhenExpression(expression: KtWhenExpression, data: Unit): FirElement {
val subjectExpression = expression.subjectExpression
val subject = when (subjectExpression) {
@@ -1050,25 +1014,13 @@ class RawFirBuilder(val session: FirSession, val stubMode: Boolean) {
val branch = entry.expression.toFirBlock()
branches += if (!entry.isElse) {
if (hasSubject) {
var firCondition: FirExpression? = null
for (condition in entry.conditions) {
val firConditionElement = condition.toFirWhenCondition(
FirWhenSubjectExpression(this@RawFirBuilder.session, condition)
)
when {
firCondition == null -> firCondition = firConditionElement
firCondition is FirOperatorCallImpl && firCondition.operation == FirOperation.OR -> {
firCondition.arguments += firConditionElement
}
else -> {
firCondition = FirOperatorCallImpl(this@RawFirBuilder.session, entry, FirOperation.OR).apply {
arguments += firCondition!!
arguments += firConditionElement
}
}
}
}
FirWhenBranchImpl(this@RawFirBuilder.session, entry, firCondition!!, branch)
val firCondition = entry.conditions.toFirWhenCondition(
this@RawFirBuilder.session,
entry,
{ toFirExpression(it) },
{ toFirOrErrorType() }
)
FirWhenBranchImpl(this@RawFirBuilder.session, entry, firCondition, branch)
} else {
val condition = entry.conditions.first() as? KtWhenConditionWithExpression
val firCondition = condition?.expression.toFirExpression("No expression in condition with expression")
@@ -1194,12 +1146,6 @@ class RawFirBuilder(val session: FirSession, val stubMode: Boolean) {
return FirContinueExpressionImpl(session, expression).bindLabel(expression)
}
private fun KtBinaryExpression.elvisToWhen(): FirWhenExpression {
val rightArgument = right.toFirExpression("No right operand")
val leftArgument = left.toFirExpression("No left operand")
return leftArgument.generateNotNullOrOther(session, rightArgument, "elvis", this)
}
private fun KtUnaryExpression.bangBangToWhen(): FirWhenExpression {
return baseExpression.toFirExpression("No operand").generateNotNullOrOther(
session,
@@ -1213,11 +1159,15 @@ class RawFirBuilder(val session: FirSession, val stubMode: Boolean) {
override fun visitBinaryExpression(expression: KtBinaryExpression, data: Unit): FirElement {
val operationToken = expression.operationToken
val leftArgument = expression.left.toFirExpression("No left operand")
val rightArgument = expression.right.toFirExpression("No right operand")
if (operationToken == ELVIS) {
return expression.elvisToWhen()
return leftArgument.generateNotNullOrOther(session, rightArgument, "elvis", expression)
}
val conventionCallName = operationToken.toBinaryName()
if (operationToken == ANDAND || operationToken == OROR) {
return leftArgument.generateLazyLogicalOperation(session, rightArgument, operationToken == ANDAND, expression)
}
return if (conventionCallName != null || operationToken == IDENTIFIER) {
FirFunctionCallImpl(
session, expression
@@ -1237,7 +1187,7 @@ class RawFirBuilder(val session: FirSession, val stubMode: Boolean) {
FirOperatorCallImpl(session, expression, firOperation)
}
}.apply {
arguments += expression.left.toFirExpression("No left operand")
arguments += leftArgument
arguments += rightArgument
}
}
@@ -37,7 +37,15 @@ FILE: branches.kt
}
public? final? fun grade(g: Int): String {
^grade when (g#) {
||(==($subj$, Int(6)), ==($subj$, Int(7))) -> {
when () {
==($subj$, Int(6)) -> {
Boolean(true)
}
else -> {
==($subj$, Int(7))
}
}
-> {
String(Outstanding)
}
==($subj$, Int(5)) -> {
@@ -293,11 +293,13 @@ open class FirBodyResolveTransformer(val session: FirSession, val implicitTypeOn
}
override fun transformWhenExpression(whenExpression: FirWhenExpression, data: Any?): CompositeTransformResult<FirStatement> {
val whenExpression = super.transformWhenExpression(whenExpression, data).single as FirWhenExpression
val type = commonSuperType(whenExpression.branches.mapNotNull {
it.result.resultType
})
if (type != null) whenExpression.resultType = type
whenExpression.transformChildren(this, data)
if (whenExpression.resultType !is FirResolvedTypeRef) {
val type = commonSuperType(whenExpression.branches.mapNotNull {
it.result.resultType
})
if (type != null) whenExpression.resultType = type
}
return whenExpression.compose()
}
@@ -16,8 +16,6 @@ enum class FirOperation(val operator: String = "???") {
GT(">"),
LT_EQ("<="),
GT_EQ(">="),
AND("&&"),
OR("||"),
IN("in"),
NOT_IN("!in"),
@@ -43,4 +43,9 @@ class FirImplicitEnumTypeRef(
class FirImplicitAnnotationTypeRef(
session: FirSession,
psi: PsiElement?
) : FirImplicitBuiltinTypeRef(session, psi, KotlinBuiltIns.FQ_NAMES.annotation.toUnsafe())
) : FirImplicitBuiltinTypeRef(session, psi, KotlinBuiltIns.FQ_NAMES.annotation.toUnsafe())
class FirImplicitBooleanTypeRef(
session: FirSession,
psi: PsiElement?
) : FirImplicitBuiltinTypeRef(session, psi, KotlinBuiltIns.FQ_NAMES._boolean)