From 1e702439b7c8ea512718f9023a2c0278eebed9a2 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Thu, 24 Apr 2025 17:48:09 +0200 Subject: [PATCH] avoid JDK 21+/Kotlin method conflict of removeLast()/removeFirst() background: see https://www.reddit.com/r/androiddev/comments/1gspjrs/dont_use_kotlins_removefirst_and_removelast_when/ https://youtrack.jetbrains.com/issue/KT-71375/Prevent-Kotlins-removeFirst-and-removeLast-from-causing-crashes-on-Android-14-and-below-after-upgrading-to-Android-API-Level-35 it's about Android but the problem also occurs on desktop JDKs for example when running a Java21 compiled prog8 with Java17 --- codeOptimizers/src/prog8/optimizer/Inliner.kt | 2 +- compilerAst/src/prog8/compiler/CallGraph.kt | 2 +- intermediate/src/prog8/intermediate/IRInstructions.kt | 4 ++-- simpleAst/src/prog8/code/ast/AstStatements.kt | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/codeOptimizers/src/prog8/optimizer/Inliner.kt b/codeOptimizers/src/prog8/optimizer/Inliner.kt index 5781df4c2..71eb2bc66 100644 --- a/codeOptimizers/src/prog8/optimizer/Inliner.kt +++ b/codeOptimizers/src/prog8/optimizer/Inliner.kt @@ -105,7 +105,7 @@ class Inliner(private val program: Program, private val options: CompilationOpti if (subroutine.inline && subroutine.statements.size > 1) { require(subroutine.statements.size == 2 && isEmptyReturn(subroutine.statements[1])) - subroutine.statements.removeLast() // get rid of the Return, to be able to inline the (single) statement preceding it. + subroutine.statements.removeLastOrNull() // get rid of the Return, to be able to inline the (single) statement preceding it. } } } diff --git a/compilerAst/src/prog8/compiler/CallGraph.kt b/compilerAst/src/prog8/compiler/CallGraph.kt index 17eb4a883..021f9d69b 100644 --- a/compilerAst/src/prog8/compiler/CallGraph.kt +++ b/compilerAst/src/prog8/compiler/CallGraph.kt @@ -126,7 +126,7 @@ class CallGraph(private val program: Program) : IAstVisitor { // if it's a scoped identifier, the subroutines in the name are also referenced! val scope = identifier.definingScope - val name = identifier.nameInSource.toMutableList() + val name = ArrayDeque(identifier.nameInSource) while(name.size>1) { name.removeLast() val scopeTarget = scope.lookup(name) diff --git a/intermediate/src/prog8/intermediate/IRInstructions.kt b/intermediate/src/prog8/intermediate/IRInstructions.kt index 579c9be77..ea45333e4 100644 --- a/intermediate/src/prog8/intermediate/IRInstructions.kt +++ b/intermediate/src/prog8/intermediate/IRInstructions.kt @@ -1088,7 +1088,7 @@ data class IRInstruction( } } if(result.last().endsWith(',')) { - result.add(result.removeLast().trimEnd(',')) + result.add(result.removeLastOrNull()!!.trimEnd(',')) } result.add(")") val returns = fcallArgs.returns @@ -1158,7 +1158,7 @@ data class IRInstruction( } } if(result.last() == ",") - result.removeLast() + result.removeLastOrNull() return result.joinToString("").trimEnd() } } diff --git a/simpleAst/src/prog8/code/ast/AstStatements.kt b/simpleAst/src/prog8/code/ast/AstStatements.kt index c8e387b45..66e453b6b 100644 --- a/simpleAst/src/prog8/code/ast/AstStatements.kt +++ b/simpleAst/src/prog8/code/ast/AstStatements.kt @@ -39,8 +39,8 @@ sealed interface IPtSubroutine { val availableFloatRegisters = mutableListOf(RegisterOrPair.FAC1) // just one value is possible val others = returns.drop(1).map { type -> when { - type.isFloat -> RegisterOrStatusflag(availableFloatRegisters.removeLast(), null) to type - type.isIntegerOrBool -> RegisterOrStatusflag(availableIntegerRegisters.removeLast(), null) to type + type.isFloat -> RegisterOrStatusflag(availableFloatRegisters.removeLastOrNull()!!, null) to type + type.isIntegerOrBool -> RegisterOrStatusflag(availableIntegerRegisters.removeLastOrNull()!!, null) to type else -> throw AssemblyError("unsupported return type $type") } }