Skip to content

Commit

Permalink
Merge pull request #17761 from tamasvajk/ke2-binary-ops
Browse files Browse the repository at this point in the history
KE2: extract binary operators
  • Loading branch information
tamasvajk authored Nov 12, 2024
2 parents 83b3e8c + 53460d7 commit a9e45d8
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 182 deletions.
149 changes: 0 additions & 149 deletions java/kotlin-extractor2/src/main/kotlin/KotlinFileExtractor.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2977,93 +2977,6 @@ OLD: KE1
val dr = c.dispatchReceiver
when {
isNumericFunction(
target,
"plus",
"minus",
"times",
"div",
"rem",
"and",
"or",
"xor",
"shl",
"shr",
"ushr"
) -> {
val type = useType(c.type)
val id: Label<out DbExpr> =
when (val targetName = target.name.asString()) {
"minus" -> {
val id = tw.getFreshIdLabel<DbSubexpr>()
tw.writeExprs_subexpr(id, type.javaResult.id, parent, idx)
id
}
"times" -> {
val id = tw.getFreshIdLabel<DbMulexpr>()
tw.writeExprs_mulexpr(id, type.javaResult.id, parent, idx)
id
}
"div" -> {
val id = tw.getFreshIdLabel<DbDivexpr>()
tw.writeExprs_divexpr(id, type.javaResult.id, parent, idx)
id
}
"rem" -> {
val id = tw.getFreshIdLabel<DbRemexpr>()
tw.writeExprs_remexpr(id, type.javaResult.id, parent, idx)
id
}
"and" -> {
val id = tw.getFreshIdLabel<DbAndbitexpr>()
tw.writeExprs_andbitexpr(id, type.javaResult.id, parent, idx)
id
}
"or" -> {
val id = tw.getFreshIdLabel<DbOrbitexpr>()
tw.writeExprs_orbitexpr(id, type.javaResult.id, parent, idx)
id
}
"xor" -> {
val id = tw.getFreshIdLabel<DbXorbitexpr>()
tw.writeExprs_xorbitexpr(id, type.javaResult.id, parent, idx)
id
}
"shl" -> {
val id = tw.getFreshIdLabel<DbLshiftexpr>()
tw.writeExprs_lshiftexpr(id, type.javaResult.id, parent, idx)
id
}
"shr" -> {
val id = tw.getFreshIdLabel<DbRshiftexpr>()
tw.writeExprs_rshiftexpr(id, type.javaResult.id, parent, idx)
id
}
"ushr" -> {
val id = tw.getFreshIdLabel<DbUrshiftexpr>()
tw.writeExprs_urshiftexpr(id, type.javaResult.id, parent, idx)
id
}
else -> {
logger.errorElement("Unhandled binary target name: $targetName", c)
return
}
}
tw.writeExprsKotlinType(id, type.kotlinResult.id)
if (
isFunction(
target,
"kotlin",
"Byte or Short",
{ it == "Byte" || it == "Short" },
"and",
"or",
"xor"
)
)
binopExt(id)
else binopDisp(id)
}
// != gets desugared into not and ==. Here we resugar it.
c.origin == IrStatementOrigin.EXCLEQ &&
isFunction(target, "kotlin", "Boolean", "not") &&
Expand All @@ -3077,18 +2990,6 @@ OLD: KE1
tw.writeExprsKotlinType(id, type.kotlinResult.id)
binOp(id, dr, callable, enclosingStmt)
}
c.origin == IrStatementOrigin.EXCLEQEQ &&
isFunction(target, "kotlin", "Boolean", "not") &&
c.valueArgumentsCount == 0 &&
dr != null &&
dr is IrCall &&
isBuiltinCallInternal(dr, "EQEQEQ") -> {
val id = tw.getFreshIdLabel<DbNeexpr>()
val type = useType(c.type)
tw.writeExprs_neexpr(id, type.javaResult.id, parent, idx)
tw.writeExprsKotlinType(id, type.kotlinResult.id)
binOp(id, dr, callable, enclosingStmt)
}
c.origin == IrStatementOrigin.EXCLEQ &&
isFunction(target, "kotlin", "Boolean", "not") &&
c.valueArgumentsCount == 0 &&
Expand Down Expand Up @@ -3148,46 +3049,6 @@ OLD: KE1
// We need to handle all the builtin operators defines in BuiltInOperatorNames in
// compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/IrBuiltIns.kt
// as they can't be extracted as external dependencies.
isBuiltinCallInternal(c, "less") -> {
if (c.origin != IrStatementOrigin.LT) {
logger.warnElement("Unexpected origin for LT: ${c.origin}", c)
}
val id = tw.getFreshIdLabel<DbLtexpr>()
val type = useType(c.type)
tw.writeExprs_ltexpr(id, type.javaResult.id, parent, idx)
tw.writeExprsKotlinType(id, type.kotlinResult.id)
binOp(id, c, callable, enclosingStmt)
}
isBuiltinCallInternal(c, "lessOrEqual") -> {
if (c.origin != IrStatementOrigin.LTEQ) {
logger.warnElement("Unexpected origin for LTEQ: ${c.origin}", c)
}
val id = tw.getFreshIdLabel<DbLeexpr>()
val type = useType(c.type)
tw.writeExprs_leexpr(id, type.javaResult.id, parent, idx)
tw.writeExprsKotlinType(id, type.kotlinResult.id)
binOp(id, c, callable, enclosingStmt)
}
isBuiltinCallInternal(c, "greater") -> {
if (c.origin != IrStatementOrigin.GT) {
logger.warnElement("Unexpected origin for GT: ${c.origin}", c)
}
val id = tw.getFreshIdLabel<DbGtexpr>()
val type = useType(c.type)
tw.writeExprs_gtexpr(id, type.javaResult.id, parent, idx)
tw.writeExprsKotlinType(id, type.kotlinResult.id)
binOp(id, c, callable, enclosingStmt)
}
isBuiltinCallInternal(c, "greaterOrEqual") -> {
if (c.origin != IrStatementOrigin.GTEQ) {
logger.warnElement("Unexpected origin for GTEQ: ${c.origin}", c)
}
val id = tw.getFreshIdLabel<DbGeexpr>()
val type = useType(c.type)
tw.writeExprs_geexpr(id, type.javaResult.id, parent, idx)
tw.writeExprsKotlinType(id, type.kotlinResult.id)
binOp(id, c, callable, enclosingStmt)
}
isBuiltinCallInternal(c, "EQEQ") -> {
if (c.origin != IrStatementOrigin.EQEQ) {
logger.warnElement("Unexpected origin for EQEQ: ${c.origin}", c)
Expand All @@ -3198,16 +3059,6 @@ OLD: KE1
tw.writeExprsKotlinType(id, type.kotlinResult.id)
binOp(id, c, callable, enclosingStmt)
}
isBuiltinCallInternal(c, "EQEQEQ") -> {
if (c.origin != IrStatementOrigin.EQEQEQ) {
logger.warnElement("Unexpected origin for EQEQEQ: ${c.origin}", c)
}
val id = tw.getFreshIdLabel<DbEqexpr>()
val type = useType(c.type)
tw.writeExprs_eqexpr(id, type.javaResult.id, parent, idx)
tw.writeExprsKotlinType(id, type.kotlinResult.id)
binOp(id, c, callable, enclosingStmt)
}
isBuiltinCallInternal(c, "ieee754equals") -> {
if (c.origin != IrStatementOrigin.EQEQ) {
logger.warnElement("Unexpected origin for ieee754equals: ${c.origin}", c)
Expand Down
114 changes: 81 additions & 33 deletions java/kotlin-extractor2/src/main/kotlin/entities/Expression.kt
Original file line number Diff line number Diff line change
Expand Up @@ -256,13 +256,14 @@ private fun KaFunctionSymbol.hasName(
)
}

private fun KaFunctionSymbol.isNumericWithName(functionName: String): Boolean {
return this.hasName("kotlin", "Int", functionName) ||
this.hasName("kotlin", "Byte", functionName) ||
this.hasName("kotlin", "Short", functionName) ||
this.hasName("kotlin", "Long", functionName) ||
this.hasName("kotlin", "Float", functionName) ||
this.hasName("kotlin", "Double", functionName)
private fun KaFunctionSymbol?.isNumericWithName(functionName: String): Boolean {
return this != null &&
(this.hasName("kotlin", "Int", functionName) ||
this.hasName("kotlin", "Byte", functionName) ||
this.hasName("kotlin", "Short", functionName) ||
this.hasName("kotlin", "Long", functionName) ||
this.hasName("kotlin", "Float", functionName) ||
this.hasName("kotlin", "Double", functionName))
}

context(KaSession)
Expand Down Expand Up @@ -297,37 +298,84 @@ private fun KotlinFileExtractor.extractBinaryExpression(
val op = expression.operationToken
val target = expression.resolveCallTarget()?.symbol

when (op) {
KtTokens.PLUS -> {
if (target == null) {
TODO()
}

if (target.isNumericWithName("plus") ||
target.hasName("kotlin", "String", "plus") ||
target.hasMatchingNames(
CallableId(FqName("kotlin"), null, Name.identifier("plus")),
ClassId(FqName("kotlin"), Name.identifier("String")),
nullability = KaTypeNullability.NULLABLE,
)
) {
val id = tw.getFreshIdLabel<DbAddexpr>()
val type = useType(expression.expressionType)
val exprParent = parent.expr(expression, callable)
tw.writeExprs_addexpr(id, type.javaResult.id, exprParent.parent, exprParent.idx)
tw.writeExprsKotlinType(id, type.kotlinResult.id)

extractExprContext(id, tw.getLocation(expression), callable, exprParent.enclosingStmt)
extractExpressionExpr(expression.left!!, callable, id, 0, exprParent.enclosingStmt)
extractExpressionExpr(expression.right!!, callable, id, 1, exprParent.enclosingStmt)
} else {
TODO("Extract as method call")
if (op == KtTokens.PLUS && target.isBinaryPlus()) {
extractBinaryExpression(expression, callable, parent, tw::writeExprs_addexpr)
} else if (op == KtTokens.MINUS && target.isNumericWithName("minus")) {
extractBinaryExpression(expression, callable, parent, tw::writeExprs_subexpr)
} else if (op == KtTokens.MUL && target.isNumericWithName("times")) {
extractBinaryExpression(expression, callable, parent, tw::writeExprs_mulexpr)
} else if (op == KtTokens.DIV && target.isNumericWithName("div")) {
extractBinaryExpression(expression, callable, parent, tw::writeExprs_divexpr)
} else if (op == KtTokens.PERC && target.isNumericWithName("rem")) {
extractBinaryExpression(expression, callable, parent, tw::writeExprs_remexpr)
} else if (op == KtTokens.IDENTIFIER && target.isNumericWithName("and")) {
extractBinaryExpression(expression, callable, parent, tw::writeExprs_andbitexpr)
} else if (op == KtTokens.IDENTIFIER && target.isNumericWithName("or")) {
extractBinaryExpression(expression, callable, parent, tw::writeExprs_orbitexpr)
} else if (op == KtTokens.IDENTIFIER && target.isNumericWithName("xor")) {
extractBinaryExpression(expression, callable, parent, tw::writeExprs_xorbitexpr)
} else if (op == KtTokens.IDENTIFIER && target.isNumericWithName("shl")) {
extractBinaryExpression(expression, callable, parent, tw::writeExprs_lshiftexpr)
} else if (op == KtTokens.IDENTIFIER && target.isNumericWithName("shr")) {
extractBinaryExpression(expression, callable, parent, tw::writeExprs_rshiftexpr)
} else if (op == KtTokens.IDENTIFIER && target.isNumericWithName("ushr")) {
extractBinaryExpression(expression, callable, parent, tw::writeExprs_urshiftexpr)
} else if (op == KtTokens.EQEQEQ && target == null) {
extractBinaryExpression(expression, callable, parent, tw::writeExprs_eqexpr)
} else if (op == KtTokens.EXCLEQEQEQ && target == null) {
extractBinaryExpression(expression, callable, parent, tw::writeExprs_neexpr)
} else if (op in listOf(KtTokens.LT, KtTokens.GT, KtTokens.LTEQ, KtTokens.GTEQ)) {
if (target.isNumericWithName("compareTo")) {
when (op) {
KtTokens.LT -> extractBinaryExpression(expression, callable, parent, tw::writeExprs_ltexpr)
KtTokens.GT -> extractBinaryExpression(expression, callable, parent, tw::writeExprs_gtexpr)
KtTokens.LTEQ -> extractBinaryExpression(expression, callable, parent, tw::writeExprs_leexpr)
KtTokens.GTEQ -> extractBinaryExpression(expression, callable, parent, tw::writeExprs_geexpr)
else -> TODO("error")
}
} else {
TODO("Extract lowered equivalent call, such as `a.compareTo(b) < 0`")
}

else -> TODO()
} else {
// todo: other operators, such as .., ..<, in, !in, =, +=, -=, *=, /=, %=, ==, !=,
TODO("Extract as method call")
}
}

private fun KaFunctionSymbol?.isBinaryPlus(): Boolean {
return this != null && (
this.isNumericWithName("plus") ||
this.hasName("kotlin", "String", "plus") ||
/* The target for `(null as String?) + null` is `public operator fun String?.plus(other: Any?): String` */
this.hasMatchingNames(
CallableId(FqName("kotlin"), null, Name.identifier("plus")),
ClassId(FqName("kotlin"), Name.identifier("String")),
nullability = KaTypeNullability.NULLABLE,
))
}

context(KaSession)
private fun <T : DbBinaryexpr> KotlinFileExtractor.extractBinaryExpression(
expression: KtBinaryExpression,
callable: Label<out DbCallable>,
parent: StmtExprParent,
extractExpression: (
id: Label<out T>,
typeid: Label<out DbType>,
parent: Label<out DbExprparent>,
idx: Int
) -> Unit
) {
val id = tw.getFreshIdLabel<T>()
val type = useType(expression.expressionType)
val exprParent = parent.expr(expression, callable)
extractExpression(id, type.javaResult.id, exprParent.parent, exprParent.idx)
tw.writeExprsKotlinType(id, type.kotlinResult.id)

extractExprContext(id, tw.getLocation(expression), callable, exprParent.enclosingStmt)
extractExpressionExpr(expression.left!!, callable, id, 0, exprParent.enclosingStmt)
extractExpressionExpr(expression.right!!, callable, id, 1, exprParent.enclosingStmt)
}

context(KaSession)
Expand Down

0 comments on commit a9e45d8

Please sign in to comment.