@@ -1206,24 +1206,24 @@ open class KotlinFileExtractor(
12061206 isFunction(target, " kotlin" , " Double" , fName)
12071207 }
12081208
1209+ fun isArrayType (typeName : String ) =
1210+ when (typeName) {
1211+ " Array" -> true
1212+ " IntArray" -> true
1213+ " ByteArray" -> true
1214+ " ShortArray" -> true
1215+ " LongArray" -> true
1216+ " FloatArray" -> true
1217+ " DoubleArray" -> true
1218+ " CharArray" -> true
1219+ " BooleanArray" -> true
1220+ else -> false
1221+ }
1222+
12091223 fun extractCall (c : IrCall , callable : Label <out DbCallable >, parent : Label <out DbExprparent >, idx : Int , enclosingStmt : Label <out DbStmt >) {
12101224 with (" call" , c) {
12111225 val target = c.symbol.owner
12121226
1213- fun isArrayType (typeName : String ) =
1214- when (typeName) {
1215- " Array" -> true
1216- " IntArray" -> true
1217- " ByteArray" -> true
1218- " ShortArray" -> true
1219- " LongArray" -> true
1220- " FloatArray" -> true
1221- " DoubleArray" -> true
1222- " CharArray" -> true
1223- " BooleanArray" -> true
1224- else -> false
1225- }
1226-
12271227 fun extractMethodAccess (syntacticCallTarget : IrFunction , extractMethodTypeArguments : Boolean = true, extractClassTypeArguments : Boolean = false) {
12281228 val typeArgs =
12291229 if (extractMethodTypeArguments)
@@ -1782,6 +1782,113 @@ open class KotlinFileExtractor(
17821782 }
17831783 }
17841784
1785+ fun getStatementOriginOperator (origin : IrStatementOrigin ? ) = when (origin) {
1786+ IrStatementOrigin .PLUSEQ -> " plus"
1787+ IrStatementOrigin .MINUSEQ -> " minus"
1788+ IrStatementOrigin .MULTEQ -> " times"
1789+ IrStatementOrigin .DIVEQ -> " div"
1790+ IrStatementOrigin .PERCEQ -> " rem"
1791+ else -> null
1792+ }
1793+
1794+ fun getUpdateInPlaceRHS (origin : IrStatementOrigin ? , isExpectedLhs : (IrExpression ? ) -> Boolean , updateRhs : IrExpression ): IrExpression ? {
1795+ // Check for a desugared in-place update operator, such as "v += e":
1796+ return getStatementOriginOperator(origin)?.let {
1797+ if (updateRhs is IrCall &&
1798+ isNumericFunction(updateRhs.symbol.owner, it)
1799+ ) {
1800+ // Check for an expression like x = get(x).op(e):
1801+ val opReceiver = updateRhs.dispatchReceiver
1802+ if (isExpectedLhs(opReceiver)) {
1803+ updateRhs.getValueArgument(0 )
1804+ } else null
1805+ } else null
1806+ } ? : null
1807+ }
1808+
1809+ fun writeUpdateInPlaceExpr (origin : IrStatementOrigin , tw : TrapWriter , id : Label <DbAssignexpr >, type : TypeResults , exprParent : ExprParent ): Boolean {
1810+ when (origin) {
1811+ IrStatementOrigin .PLUSEQ -> tw.writeExprs_assignaddexpr(id as Label <DbAssignaddexpr >, type.javaResult.id, exprParent.parent, exprParent.idx)
1812+ IrStatementOrigin .MINUSEQ -> tw.writeExprs_assignsubexpr(id as Label <DbAssignsubexpr >, type.javaResult.id, exprParent.parent, exprParent.idx)
1813+ IrStatementOrigin .MULTEQ -> tw.writeExprs_assignmulexpr(id as Label <DbAssignmulexpr >, type.javaResult.id, exprParent.parent, exprParent.idx)
1814+ IrStatementOrigin .DIVEQ -> tw.writeExprs_assigndivexpr(id as Label <DbAssigndivexpr >, type.javaResult.id, exprParent.parent, exprParent.idx)
1815+ IrStatementOrigin .PERCEQ -> tw.writeExprs_assignremexpr(id as Label <DbAssignremexpr >, type.javaResult.id, exprParent.parent, exprParent.idx)
1816+ else -> return false
1817+ }
1818+ return true
1819+ }
1820+
1821+ fun tryExtractArrayUpdate (e : IrContainerExpression , callable : Label <out DbCallable >, parent : StmtExprParent ): Boolean {
1822+ /*
1823+ * We're expecting the pattern
1824+ * {
1825+ * val array = e1
1826+ * val idx = e2
1827+ * array.set(idx, array.get(idx).op(e3))
1828+ * }
1829+ *
1830+ * If we find it, we'll extract e1[e2] op= e3 (op is +, -, ...)
1831+ */
1832+ if (e.statements.size != 3 )
1833+ return false
1834+ (e.statements[0 ] as ? IrVariable )?.let { arrayVarDecl ->
1835+ arrayVarDecl.initializer?.let { arrayVarInitializer ->
1836+ (e.statements[1 ] as ? IrVariable )?.let { indexVarDecl ->
1837+ indexVarDecl.initializer?.let { indexVarInitializer ->
1838+ (e.statements[2 ] as ? IrCall )?.let { arraySetCall ->
1839+ if (isFunction(arraySetCall.symbol.owner, " kotlin" , " (some array type)" , { isArrayType(it) }, " set" )) {
1840+ getUpdateInPlaceRHS(
1841+ e.origin, // Using e.origin not arraySetCall.origin here distinguishes a compiler-generated block from a user manually code that looks the same.
1842+ { oldValue ->
1843+ oldValue is IrCall &&
1844+ isFunction(oldValue.symbol.owner, " kotlin" , " (some array type)" , { typeName -> isArrayType(typeName) }, " get" ) &&
1845+ (oldValue.dispatchReceiver as ? IrGetValue )?.let {
1846+ receiverVal -> receiverVal.symbol.owner == arrayVarDecl.symbol.owner
1847+ } ? : false
1848+ },
1849+ arraySetCall.getValueArgument(1 )!!
1850+ )?.let { updateRhs ->
1851+ // Create an assignment skeleton _ op= _
1852+ val exprParent = parent.expr(e, callable)
1853+ val assignId = tw.getFreshIdLabel<DbAssignexpr >()
1854+ val type = useType(arrayVarInitializer.type)
1855+ val locId = tw.getLocation(e)
1856+ tw.writeExprsKotlinType(assignId, type.kotlinResult.id)
1857+ tw.writeHasLocation(assignId, locId)
1858+ tw.writeCallableEnclosingExpr(assignId, callable)
1859+ tw.writeStatementEnclosingExpr(assignId, exprParent.enclosingStmt)
1860+
1861+ if (! writeUpdateInPlaceExpr(e.origin!! , tw, assignId, type, exprParent)) {
1862+ logger.errorElement(" Unexpected origin" , e)
1863+ return false
1864+ }
1865+
1866+ // Extract e1[e2]
1867+ val lhsId = tw.getFreshIdLabel<DbArrayaccess >()
1868+ val elementType = useType(updateRhs.type)
1869+ tw.writeExprs_arrayaccess(lhsId, elementType.javaResult.id, assignId, 0 )
1870+ tw.writeExprsKotlinType(lhsId, elementType.kotlinResult.id)
1871+ tw.writeHasLocation(lhsId, locId)
1872+ tw.writeCallableEnclosingExpr(lhsId, callable)
1873+ tw.writeStatementEnclosingExpr(lhsId, exprParent.enclosingStmt)
1874+ extractExpressionExpr(arrayVarInitializer, callable, lhsId, 0 , exprParent.enclosingStmt)
1875+ extractExpressionExpr(indexVarInitializer, callable, lhsId, 1 , exprParent.enclosingStmt)
1876+
1877+ // Extract e3
1878+ extractExpressionExpr(updateRhs, callable, assignId, 1 , exprParent.enclosingStmt)
1879+
1880+ return true
1881+ }
1882+ }
1883+ }
1884+ }
1885+ }
1886+ }
1887+ }
1888+
1889+ return false
1890+ }
1891+
17851892 fun extractExpressionStmt (e : IrExpression , callable : Label <out DbCallable >, parent : Label <out DbStmtparent >, idx : Int ) {
17861893 extractExpression(e, callable, StmtParent (parent, idx))
17871894 }
@@ -1879,13 +1986,15 @@ open class KotlinFileExtractor(
18791986 }
18801987 }
18811988 is IrContainerExpression -> {
1882- val stmtParent = parent.stmt(e, callable)
1883- val id = tw.getFreshIdLabel<DbBlock >()
1884- val locId = tw.getLocation(e)
1885- tw.writeStmts_block(id, stmtParent.parent, stmtParent.idx, callable)
1886- tw.writeHasLocation(id, locId)
1887- e.statements.forEachIndexed { i, s ->
1888- extractStatement(s, callable, id, i)
1989+ if (! tryExtractArrayUpdate(e, callable, parent)) {
1990+ val stmtParent = parent.stmt(e, callable)
1991+ val id = tw.getFreshIdLabel<DbBlock >()
1992+ val locId = tw.getLocation(e)
1993+ tw.writeStmts_block(id, stmtParent.parent, stmtParent.idx, callable)
1994+ tw.writeHasLocation(id, locId)
1995+ e.statements.forEachIndexed { i, s ->
1996+ extractStatement(s, callable, id, i)
1997+ }
18891998 }
18901999 }
18912000 is IrWhileLoop -> {
@@ -2170,34 +2279,14 @@ open class KotlinFileExtractor(
21702279 val rhsValue = e.value
21712280
21722281 // Check for a desugared in-place update operator, such as "v += e":
2173- val expectedOperator = when (e.origin) {
2174- IrStatementOrigin .PLUSEQ -> " plus"
2175- IrStatementOrigin .MINUSEQ -> " minus"
2176- IrStatementOrigin .MULTEQ -> " times"
2177- IrStatementOrigin .DIVEQ -> " div"
2178- IrStatementOrigin .PERCEQ -> " rem"
2179- else -> null
2180- }
2181- val inPlaceUpdateRhs = expectedOperator?.let {
2182- if (rhsValue is IrCall &&
2183- isNumericFunction(rhsValue.symbol.owner, expectedOperator)
2184- ) {
2185- // Check for an expression like x = get(x).op(e):
2186- val opReceiver = rhsValue.dispatchReceiver
2187- if (opReceiver is IrGetValue && opReceiver.symbol.owner == e.symbol.owner) {
2188- rhsValue.getValueArgument(0 )
2189- } else null
2190- } else null
2191- }
2192-
2193- val extractOrigin = if (inPlaceUpdateRhs == null ) null else e.origin
2194- when (extractOrigin) {
2195- IrStatementOrigin .PLUSEQ -> tw.writeExprs_assignaddexpr(id as Label <DbAssignaddexpr >, type.javaResult.id, exprParent.parent, exprParent.idx)
2196- IrStatementOrigin .MINUSEQ -> tw.writeExprs_assignsubexpr(id as Label <DbAssignsubexpr >, type.javaResult.id, exprParent.parent, exprParent.idx)
2197- IrStatementOrigin .MULTEQ -> tw.writeExprs_assignmulexpr(id as Label <DbAssignmulexpr >, type.javaResult.id, exprParent.parent, exprParent.idx)
2198- IrStatementOrigin .DIVEQ -> tw.writeExprs_assigndivexpr(id as Label <DbAssigndivexpr >, type.javaResult.id, exprParent.parent, exprParent.idx)
2199- IrStatementOrigin .PERCEQ -> tw.writeExprs_assignremexpr(id as Label <DbAssignremexpr >, type.javaResult.id, exprParent.parent, exprParent.idx)
2200- else -> tw.writeExprs_assignexpr(id, type.javaResult.id, exprParent.parent, exprParent.idx)
2282+ val inPlaceUpdateRhs = getUpdateInPlaceRHS(e.origin, { it is IrGetValue && it.symbol.owner == e.symbol.owner }, rhsValue)
2283+ if (inPlaceUpdateRhs != null ) {
2284+ if (! writeUpdateInPlaceExpr(e.origin!! , tw, id, type, exprParent)) {
2285+ logger.errorElement(" Unexpected origin" , e)
2286+ return
2287+ }
2288+ } else {
2289+ tw.writeExprs_assignexpr(id, type.javaResult.id, exprParent.parent, exprParent.idx)
22012290 }
22022291
22032292 val lhsType = useType(e.symbol.owner.type)
0 commit comments