FIR: Support FirComparisonOperator in builders

^KT-31163 In Progress
This commit is contained in:
Denis Zharkov
2020-02-26 16:44:01 +03:00
parent 80b7fbd07a
commit c3aed433ae
5 changed files with 71 additions and 23 deletions
@@ -209,18 +209,23 @@ class ExpressionsConverter(
} }
val operationToken = operationTokenName.getOperationSymbol() val operationToken = operationTokenName.getOperationSymbol()
val leftArgAsFir = getAsFirExpression<FirExpression>(leftArgNode, "No left operand")
when (operationToken) { when (operationToken) {
ELVIS -> ELVIS ->
return getAsFirExpression<FirExpression>(leftArgNode, "No left operand").generateNotNullOrOther( return leftArgAsFir.generateNotNullOrOther(
baseSession, rightArgAsFir, "elvis", null baseSession, rightArgAsFir, "elvis", null
) )
ANDAND, OROR -> ANDAND, OROR ->
return getAsFirExpression<FirExpression>(leftArgNode, "No left operand").generateLazyLogicalOperation( return leftArgAsFir.generateLazyLogicalOperation(
rightArgAsFir, operationToken == ANDAND, null rightArgAsFir, operationToken == ANDAND, null
) )
in OperatorConventions.IN_OPERATIONS -> in OperatorConventions.IN_OPERATIONS ->
return rightArgAsFir.generateContainsOperation( return rightArgAsFir.generateContainsOperation(
getAsFirExpression(leftArgNode, "No left operand"), operationToken == NOT_IN, null, null leftArgAsFir, operationToken == NOT_IN, null, null
)
in OperatorConventions.COMPARISON_OPERATIONS ->
return leftArgAsFir.generateComparisonExpression(
rightArgAsFir, operationToken, null, null
) )
} }
val conventionCallName = operationToken.toBinaryName() val conventionCallName = operationToken.toBinaryName()
@@ -230,7 +235,7 @@ class ExpressionsConverter(
calleeReference = buildSimpleNamedReference { calleeReference = buildSimpleNamedReference {
name = conventionCallName ?: operationTokenName.nameAsSafeName() name = conventionCallName ?: operationTokenName.nameAsSafeName()
} }
explicitReceiver = getAsFirExpression(leftArgNode, "No left operand") explicitReceiver = leftArgAsFir
arguments += rightArgAsFir arguments += rightArgAsFir
} }
} else { } else {
@@ -241,7 +246,7 @@ class ExpressionsConverter(
buildOperatorCall { buildOperatorCall {
source = binaryExpression.toFirSourceElement() source = binaryExpression.toFirSourceElement()
operation = firOperation operation = firOperation
arguments += getAsFirExpression<FirExpression>(leftArgNode, "No left operand") arguments += leftArgAsFir
arguments += rightArgAsFir arguments += rightArgAsFir
} }
} }
@@ -257,17 +257,10 @@ fun FirExpression.generateContainsOperation(
operationReference: KtOperationReferenceExpression?, operationReference: KtOperationReferenceExpression?,
): FirFunctionCall { ): FirFunctionCall {
val baseSource = base?.toFirSourceElement() val baseSource = base?.toFirSourceElement()
val operationReferenceSource = operationReference?.toFirSourceElement() val containsCall = createConventionCall(operationReference, baseSource, argument, OperatorNameConventions.CONTAINS)
val containsCall = buildFunctionCall {
source = baseSource
calleeReference = buildSimpleNamedReference {
source = operationReferenceSource
name = OperatorNameConventions.CONTAINS
}
explicitReceiver = this@generateContainsOperation
arguments += argument
}
if (!inverted) return containsCall if (!inverted) return containsCall
val operationReferenceSource = operationReference?.toFirSourceElement()
return buildFunctionCall { return buildFunctionCall {
source = baseSource source = baseSource
calleeReference = buildSimpleNamedReference { calleeReference = buildSimpleNamedReference {
@@ -278,6 +271,52 @@ fun FirExpression.generateContainsOperation(
} }
} }
fun FirExpression.generateComparisonExpression(
argument: FirExpression,
operatorToken: IElementType,
base: KtExpression?,
operationReference: KtOperationReferenceExpression?,
): FirComparisonExpression {
require(operatorToken in OperatorConventions.COMPARISON_OPERATIONS) {
"$operatorToken is not in ${OperatorConventions.COMPARISON_OPERATIONS}"
}
val baseSource = base?.toFirSourceElement()
val compareToCall = createConventionCall(operationReference, baseSource, argument, OperatorNameConventions.COMPARE_TO)
val firOperation = when (operatorToken) {
KtTokens.LT -> FirOperation.LT
KtTokens.GT -> FirOperation.GT
KtTokens.LTEQ -> FirOperation.LT_EQ
KtTokens.GTEQ -> FirOperation.GT_EQ
else -> error("Unknown $operatorToken")
}
return buildComparisonExpression {
this.source = baseSource
this.operation = firOperation
this.compareToCall = compareToCall
}
}
private fun FirExpression.createConventionCall(
operationReference: KtOperationReferenceExpression?,
baseSource: FirPsiSourceElement?,
argument: FirExpression,
conventionName: Name
): FirFunctionCall {
val operationReferenceSource = operationReference?.toFirSourceElement()
return buildFunctionCall {
source = baseSource
calleeReference = buildSimpleNamedReference {
source = operationReferenceSource
name = conventionName
}
explicitReceiver = this@createConventionCall
arguments += argument
}
}
fun generateAccessExpression(source: FirSourceElement?, name: Name): FirQualifiedAccessExpression = fun generateAccessExpression(source: FirSourceElement?, name: Name): FirQualifiedAccessExpression =
buildQualifiedAccessExpression { buildQualifiedAccessExpression {
this.source = source this.source = source
@@ -1373,6 +1373,10 @@ class RawFirBuilder(
return rightArgument.generateContainsOperation( return rightArgument.generateContainsOperation(
leftArgument, operationToken == NOT_IN, expression, expression.operationReference, leftArgument, operationToken == NOT_IN, expression, expression.operationReference,
) )
in OperatorConventions.COMPARISON_OPERATIONS ->
return leftArgument.generateComparisonExpression(
rightArgument, operationToken, expression, expression.operationReference,
)
} }
val conventionCallName = operationToken.toBinaryName() val conventionCallName = operationToken.toBinaryName()
return if (conventionCallName != null || operationToken == IDENTIFIER) { return if (conventionCallName != null || operationToken == IDENTIFIER) {
@@ -1,7 +1,7 @@
FILE: branches.kt FILE: branches.kt
public? final? fun foo(a: Int, b: Int): <implicit> { public? final? fun foo(a: Int, b: Int): <implicit> {
^foo when () { ^foo when () {
>(a#, b#) -> { CMP(>, a#.compareTo#(b#)) -> {
a# a#
} }
else -> { else -> {
@@ -12,7 +12,7 @@ FILE: branches.kt
} }
public? final? fun bar(a: Double, b: Double): Double { public? final? fun bar(a: Double, b: Double): Double {
when () { when () {
>(a#, b#) -> { CMP(>, a#.compareTo#(b#)) -> {
println#(a#) println#(a#)
^bar a# ^bar a#
} }
@@ -25,7 +25,7 @@ FILE: branches.kt
} }
public? final? fun baz(a: Long, b: Long): Long { public? final? fun baz(a: Long, b: Long): Long {
when () { when () {
>(a#, b#) -> { CMP(>, a#.compareTo#(b#)) -> {
println#(a#) println#(a#)
^baz a# ^baz a#
} }
@@ -1,7 +1,7 @@
FILE: while.kt FILE: while.kt
public? final? fun foo(limit: Int): R|kotlin/Unit| { public? final? fun foo(limit: Int): R|kotlin/Unit| {
lvar k: <implicit> = IntegerLiteral(0) lvar k: <implicit> = IntegerLiteral(0)
some@while(<(k#, limit#)) { some@while(CMP(<, k#.compareTo#(limit#))) {
lval <unary>: <implicit> = k# lval <unary>: <implicit> = k#
k# = R|<local>/<unary>|.inc#() k# = R|<local>/<unary>|.inc#()
R|<local>/<unary>| R|<local>/<unary>|
@@ -11,13 +11,13 @@ FILE: while.kt
k# = R|<local>/<unary>|.inc#() k# = R|<local>/<unary>|.inc#()
R|<local>/<unary>| R|<local>/<unary>|
when () { when () {
<(k#, limit#) -> { CMP(<, k#.compareTo#(limit#)) -> {
break@@@[<(k#, limit#)] break@@@[CMP(<, k#.compareTo#(limit#))]
} }
} }
when () { when () {
>(k#, limit#) -> { CMP(>, k#.compareTo#(limit#)) -> {
continue@@@[==(k#, IntegerLiteral(13))] continue@@@[==(k#, IntegerLiteral(13))]
} }
} }
@@ -35,5 +35,5 @@ FILE: while.kt
R|<local>/<unary>| R|<local>/<unary>|
println#(k#) println#(k#)
} }
while(>=(k#, IntegerLiteral(0))) while(CMP(>=, k#.compareTo#(IntegerLiteral(0))))
} }