From 255d5c994292481cbb890e0065e99be028623e4a Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Tue, 15 Oct 2024 11:27:56 +0200 Subject: [PATCH 1/6] KE2: Extract binary operators on numeric types --- .../src/main/kotlin/KotlinFileExtractor.kt | 25 ------- .../src/main/kotlin/entities/Expression.kt | 75 ++++++++++++------- 2 files changed, 49 insertions(+), 51 deletions(-) diff --git a/java/kotlin-extractor2/src/main/kotlin/KotlinFileExtractor.kt b/java/kotlin-extractor2/src/main/kotlin/KotlinFileExtractor.kt index 74b49a4993bd..7a94685ba6ab 100644 --- a/java/kotlin-extractor2/src/main/kotlin/KotlinFileExtractor.kt +++ b/java/kotlin-extractor2/src/main/kotlin/KotlinFileExtractor.kt @@ -2981,11 +2981,6 @@ OLD: KE1 when { isNumericFunction( target, - "plus", - "minus", - "times", - "div", - "rem", "and", "or", "xor", @@ -2996,26 +2991,6 @@ OLD: KE1 val type = useType(c.type) val id: Label = when (val targetName = target.name.asString()) { - "minus" -> { - val id = tw.getFreshIdLabel() - tw.writeExprs_subexpr(id, type.javaResult.id, parent, idx) - id - } - "times" -> { - val id = tw.getFreshIdLabel() - tw.writeExprs_mulexpr(id, type.javaResult.id, parent, idx) - id - } - "div" -> { - val id = tw.getFreshIdLabel() - tw.writeExprs_divexpr(id, type.javaResult.id, parent, idx) - id - } - "rem" -> { - val id = tw.getFreshIdLabel() - tw.writeExprs_remexpr(id, type.javaResult.id, parent, idx) - id - } "and" -> { val id = tw.getFreshIdLabel() tw.writeExprs_andbitexpr(id, type.javaResult.id, parent, idx) diff --git a/java/kotlin-extractor2/src/main/kotlin/entities/Expression.kt b/java/kotlin-extractor2/src/main/kotlin/entities/Expression.kt index 15b8028a9f0a..3c50a3ac855d 100644 --- a/java/kotlin-extractor2/src/main/kotlin/entities/Expression.kt +++ b/java/kotlin-extractor2/src/main/kotlin/entities/Expression.kt @@ -297,37 +297,60 @@ 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() - 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) + if (target == null) { + TODO() + } - 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 !in listOf(KtTokens.PLUS, KtTokens.MINUS, KtTokens.MUL, KtTokens.DIV, KtTokens.PERC)) { + TODO("Unhandled binary op") } - else -> TODO() + TODO("Extract as method call") } +} +private fun KaFunctionSymbol.isBinaryPlus(): Boolean { + return this.isNumericWithName("plus") || + this.hasName("kotlin", "String", "plus") || + this.hasMatchingNames( + CallableId(FqName("kotlin"), null, Name.identifier("plus")), + ClassId(FqName("kotlin"), Name.identifier("String")), + nullability = KaTypeNullability.NULLABLE, + ) +} + +context(KaSession) +private fun KotlinFileExtractor.extractBinaryExpression( + expression: KtBinaryExpression, + callable: Label, + parent: StmtExprParent, + extractExpression: ( + id: Label, + typeid: Label, + parent: Label, + idx: Int + ) -> Unit +) { + val id = tw.getFreshIdLabel() + 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) From bc35c509f037e8ab8588098345732f6dca35f7cb Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Tue, 15 Oct 2024 14:41:49 +0200 Subject: [PATCH 2/6] Extract more numeric binary operators --- .../src/main/kotlin/KotlinFileExtractor.kt | 62 ------------------- .../src/main/kotlin/entities/Expression.kt | 16 +++-- 2 files changed, 12 insertions(+), 66 deletions(-) diff --git a/java/kotlin-extractor2/src/main/kotlin/KotlinFileExtractor.kt b/java/kotlin-extractor2/src/main/kotlin/KotlinFileExtractor.kt index 7a94685ba6ab..b9ac80027b42 100644 --- a/java/kotlin-extractor2/src/main/kotlin/KotlinFileExtractor.kt +++ b/java/kotlin-extractor2/src/main/kotlin/KotlinFileExtractor.kt @@ -2979,68 +2979,6 @@ OLD: KE1 val dr = c.dispatchReceiver when { - isNumericFunction( - target, - "and", - "or", - "xor", - "shl", - "shr", - "ushr" - ) -> { - val type = useType(c.type) - val id: Label = - when (val targetName = target.name.asString()) { - "and" -> { - val id = tw.getFreshIdLabel() - tw.writeExprs_andbitexpr(id, type.javaResult.id, parent, idx) - id - } - "or" -> { - val id = tw.getFreshIdLabel() - tw.writeExprs_orbitexpr(id, type.javaResult.id, parent, idx) - id - } - "xor" -> { - val id = tw.getFreshIdLabel() - tw.writeExprs_xorbitexpr(id, type.javaResult.id, parent, idx) - id - } - "shl" -> { - val id = tw.getFreshIdLabel() - tw.writeExprs_lshiftexpr(id, type.javaResult.id, parent, idx) - id - } - "shr" -> { - val id = tw.getFreshIdLabel() - tw.writeExprs_rshiftexpr(id, type.javaResult.id, parent, idx) - id - } - "ushr" -> { - val id = tw.getFreshIdLabel() - 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") && diff --git a/java/kotlin-extractor2/src/main/kotlin/entities/Expression.kt b/java/kotlin-extractor2/src/main/kotlin/entities/Expression.kt index 3c50a3ac855d..14a30938b80c 100644 --- a/java/kotlin-extractor2/src/main/kotlin/entities/Expression.kt +++ b/java/kotlin-extractor2/src/main/kotlin/entities/Expression.kt @@ -311,11 +311,19 @@ private fun KotlinFileExtractor.extractBinaryExpression( 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 !in listOf(KtTokens.PLUS, KtTokens.MINUS, KtTokens.MUL, KtTokens.DIV, KtTokens.PERC)) { - TODO("Unhandled binary op") - } - TODO("Extract as method call") } } From 227d30243c85d2c5bd9eaba2f3e110a23db5a60b Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Tue, 15 Oct 2024 15:07:29 +0200 Subject: [PATCH 3/6] Extract reference equals --- .../src/main/kotlin/KotlinFileExtractor.kt | 22 ---------- .../src/main/kotlin/entities/Expression.kt | 40 ++++++++++--------- 2 files changed, 21 insertions(+), 41 deletions(-) diff --git a/java/kotlin-extractor2/src/main/kotlin/KotlinFileExtractor.kt b/java/kotlin-extractor2/src/main/kotlin/KotlinFileExtractor.kt index b9ac80027b42..53b90b74c4c5 100644 --- a/java/kotlin-extractor2/src/main/kotlin/KotlinFileExtractor.kt +++ b/java/kotlin-extractor2/src/main/kotlin/KotlinFileExtractor.kt @@ -2992,18 +2992,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() - 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 && @@ -3113,16 +3101,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() - 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) diff --git a/java/kotlin-extractor2/src/main/kotlin/entities/Expression.kt b/java/kotlin-extractor2/src/main/kotlin/entities/Expression.kt index 14a30938b80c..312d34fabcf2 100644 --- a/java/kotlin-extractor2/src/main/kotlin/entities/Expression.kt +++ b/java/kotlin-extractor2/src/main/kotlin/entities/Expression.kt @@ -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) @@ -297,10 +298,6 @@ private fun KotlinFileExtractor.extractBinaryExpression( val op = expression.operationToken val target = expression.resolveCallTarget()?.symbol - if (target == null) { - TODO() - } - if (op == KtTokens.PLUS && target.isBinaryPlus()) { extractBinaryExpression(expression, callable, parent, tw::writeExprs_addexpr) } else if (op == KtTokens.MINUS && target.isNumericWithName("minus")) { @@ -323,19 +320,24 @@ private fun KotlinFileExtractor.extractBinaryExpression( 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 { TODO("Extract as method call") } } -private fun KaFunctionSymbol.isBinaryPlus(): Boolean { - return this.isNumericWithName("plus") || - this.hasName("kotlin", "String", "plus") || - this.hasMatchingNames( - CallableId(FqName("kotlin"), null, Name.identifier("plus")), - ClassId(FqName("kotlin"), Name.identifier("String")), - nullability = KaTypeNullability.NULLABLE, - ) +private fun KaFunctionSymbol?.isBinaryPlus(): Boolean { + return this != null && ( + this.isNumericWithName("plus") || + this.hasName("kotlin", "String", "plus") || + this.hasMatchingNames( + CallableId(FqName("kotlin"), null, Name.identifier("plus")), + ClassId(FqName("kotlin"), Name.identifier("String")), + nullability = KaTypeNullability.NULLABLE, + )) } context(KaSession) From a5fcfaf2896553056afee6672c6b3544ad0498cf Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Tue, 15 Oct 2024 15:18:13 +0200 Subject: [PATCH 4/6] Add todo comment with missing binary operators --- java/kotlin-extractor2/src/main/kotlin/entities/Expression.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/java/kotlin-extractor2/src/main/kotlin/entities/Expression.kt b/java/kotlin-extractor2/src/main/kotlin/entities/Expression.kt index 312d34fabcf2..700e28c995be 100644 --- a/java/kotlin-extractor2/src/main/kotlin/entities/Expression.kt +++ b/java/kotlin-extractor2/src/main/kotlin/entities/Expression.kt @@ -325,6 +325,7 @@ private fun KotlinFileExtractor.extractBinaryExpression( } else if (op == KtTokens.EXCLEQEQEQ && target == null) { extractBinaryExpression(expression, callable, parent, tw::writeExprs_neexpr) } else { + // todo: other operators, such as .., ..<, in, !in, +=, -=, *=, /=, %=, <, >, <=, >=, ==, !=, TODO("Extract as method call") } } From db13b322859f338d0e36d1ba946f9a53eb1ef20e Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Wed, 16 Oct 2024 14:32:29 +0200 Subject: [PATCH 5/6] Extract comparison operators --- .../src/main/kotlin/KotlinFileExtractor.kt | 40 ------------------- .../src/main/kotlin/entities/Expression.kt | 15 ++++++- 2 files changed, 14 insertions(+), 41 deletions(-) diff --git a/java/kotlin-extractor2/src/main/kotlin/KotlinFileExtractor.kt b/java/kotlin-extractor2/src/main/kotlin/KotlinFileExtractor.kt index 53b90b74c4c5..ff7cd7b86c76 100644 --- a/java/kotlin-extractor2/src/main/kotlin/KotlinFileExtractor.kt +++ b/java/kotlin-extractor2/src/main/kotlin/KotlinFileExtractor.kt @@ -3051,46 +3051,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() - 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() - 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() - 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() - 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) diff --git a/java/kotlin-extractor2/src/main/kotlin/entities/Expression.kt b/java/kotlin-extractor2/src/main/kotlin/entities/Expression.kt index 700e28c995be..2930a1dfe56f 100644 --- a/java/kotlin-extractor2/src/main/kotlin/entities/Expression.kt +++ b/java/kotlin-extractor2/src/main/kotlin/entities/Expression.kt @@ -324,8 +324,21 @@ private fun KotlinFileExtractor.extractBinaryExpression( 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: other operators, such as .., ..<, in, !in, +=, -=, *=, /=, %=, <, >, <=, >=, ==, !=, + // todo: other operators, such as .., ..<, in, !in, =, +=, -=, *=, /=, %=, ==, !=, TODO("Extract as method call") } } From 53460d7ca046976359eb2617498e2860210cb321 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Tue, 12 Nov 2024 09:19:04 +0100 Subject: [PATCH 6/6] Add comment --- java/kotlin-extractor2/src/main/kotlin/entities/Expression.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/java/kotlin-extractor2/src/main/kotlin/entities/Expression.kt b/java/kotlin-extractor2/src/main/kotlin/entities/Expression.kt index 2930a1dfe56f..dd62df86d98c 100644 --- a/java/kotlin-extractor2/src/main/kotlin/entities/Expression.kt +++ b/java/kotlin-extractor2/src/main/kotlin/entities/Expression.kt @@ -347,6 +347,7 @@ 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")),