From 6b87cbb703de740ce41d845e1a473341c7785d5b Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Mon, 5 Feb 2024 00:53:18 +0100 Subject: [PATCH] optimizers --- .../src/prog8/optimizer/ConstExprEvaluator.kt | 23 +++---- .../optimizer/ConstantFoldingOptimizer.kt | 18 +++--- .../optimizer/ConstantIdentifierReplacer.kt | 26 ++++---- .../prog8/optimizer/ExpressionSimplifier.kt | 64 +++++++++++++------ .../src/prog8/optimizer/Extensions.kt | 5 +- .../src/prog8/optimizer/StatementOptimizer.kt | 34 +--------- compiler/src/prog8/compiler/Compiler.kt | 2 +- .../compiler/astprocessing/AstChecker.kt | 6 +- .../compiler/astprocessing/TypecastsAdder.kt | 18 +++--- .../compiler/astprocessing/VariousCleanups.kt | 4 +- 10 files changed, 96 insertions(+), 104 deletions(-) diff --git a/codeOptimizers/src/prog8/optimizer/ConstExprEvaluator.kt b/codeOptimizers/src/prog8/optimizer/ConstExprEvaluator.kt index b6cc67f18..6c1311cbe 100644 --- a/codeOptimizers/src/prog8/optimizer/ConstExprEvaluator.kt +++ b/codeOptimizers/src/prog8/optimizer/ConstExprEvaluator.kt @@ -7,6 +7,7 @@ import prog8.ast.expressions.FunctionCallExpression import prog8.ast.expressions.NumericLiteral import prog8.code.core.DataType import prog8.code.core.IntegerDatatypes +import prog8.code.core.IntegerDatatypesWithBoolean import prog8.code.core.Position import kotlin.math.* @@ -69,15 +70,15 @@ class ConstExprEvaluator { } private fun bitwiseXor(left: NumericLiteral, right: NumericLiteral): NumericLiteral { - if(left.type== DataType.UBYTE) { - if(right.type in IntegerDatatypes) { + if(left.type==DataType.UBYTE || left.type==DataType.BOOL) { + if(right.type in IntegerDatatypesWithBoolean) { return NumericLiteral(DataType.UBYTE, (left.number.toInt() xor (right.number.toInt() and 255)).toDouble(), left.position) } - } else if(left.type== DataType.UWORD) { + } else if(left.type==DataType.UWORD) { if(right.type in IntegerDatatypes) { return NumericLiteral(DataType.UWORD, (left.number.toInt() xor right.number.toInt() and 65535).toDouble(), left.position) } - } else if(left.type== DataType.LONG) { + } else if(left.type==DataType.LONG) { if(right.type in IntegerDatatypes) { return NumericLiteral.optimalNumeric((left.number.toInt() xor right.number.toInt()).toDouble(), left.position) } @@ -86,15 +87,15 @@ class ConstExprEvaluator { } private fun bitwiseOr(left: NumericLiteral, right: NumericLiteral): NumericLiteral { - if(left.type== DataType.UBYTE) { - if(right.type in IntegerDatatypes) { + if(left.type==DataType.UBYTE || left.type==DataType.BOOL) { + if(right.type in IntegerDatatypesWithBoolean) { return NumericLiteral(DataType.UBYTE, (left.number.toInt() or (right.number.toInt() and 255)).toDouble(), left.position) } - } else if(left.type== DataType.UWORD) { + } else if(left.type==DataType.UWORD) { if(right.type in IntegerDatatypes) { return NumericLiteral(DataType.UWORD, (left.number.toInt() or right.number.toInt() and 65535).toDouble(), left.position) } - } else if(left.type== DataType.LONG) { + } else if(left.type==DataType.LONG) { if(right.type in IntegerDatatypes) { return NumericLiteral.optimalNumeric((left.number.toInt() or right.number.toInt()).toDouble(), left.position) } @@ -103,11 +104,11 @@ class ConstExprEvaluator { } private fun bitwiseAnd(left: NumericLiteral, right: NumericLiteral): NumericLiteral { - if(left.type== DataType.UBYTE) { - if(right.type in IntegerDatatypes) { + if(left.type==DataType.UBYTE || left.type==DataType.BOOL) { + if(right.type in IntegerDatatypesWithBoolean) { return NumericLiteral(DataType.UBYTE, (left.number.toInt() and (right.number.toInt() and 255)).toDouble(), left.position) } - } else if(left.type== DataType.UWORD) { + } else if(left.type==DataType.UWORD) { if(right.type in IntegerDatatypes) { return NumericLiteral(DataType.UWORD, (left.number.toInt() and right.number.toInt() and 65535).toDouble(), left.position) } diff --git a/codeOptimizers/src/prog8/optimizer/ConstantFoldingOptimizer.kt b/codeOptimizers/src/prog8/optimizer/ConstantFoldingOptimizer.kt index 3721dd7dd..fa3311ec7 100644 --- a/codeOptimizers/src/prog8/optimizer/ConstantFoldingOptimizer.kt +++ b/codeOptimizers/src/prog8/optimizer/ConstantFoldingOptimizer.kt @@ -36,9 +36,9 @@ class ConstantFoldingOptimizer(private val program: Program, private val errors: if(parent is Assignment) { val iDt = parent.target.inferType(program) if(iDt.isKnown && !iDt.isBool && !iDt.istype(numLiteral.type)) { - val casted = numLiteral.cast(iDt.getOr(DataType.UNDEFINED)) + val casted = numLiteral.cast(iDt.getOr(DataType.UNDEFINED), true) if(casted.isValid) { - return listOf(IAstModification.ReplaceNode(numLiteral, casted.value!!, parent)) + return listOf(IAstModification.ReplaceNode(numLiteral, casted.valueOrZero(), parent)) } } } @@ -313,23 +313,23 @@ class ConstantFoldingOptimizer(private val program: Program, private val errors: override fun after(forLoop: ForLoop, parent: Node): Iterable { fun adjustRangeDt(rangeFrom: NumericLiteral, targetDt: DataType, rangeTo: NumericLiteral, stepLiteral: NumericLiteral?, range: RangeExpression): RangeExpression? { - val fromCast = rangeFrom.cast(targetDt) - val toCast = rangeTo.cast(targetDt) + val fromCast = rangeFrom.cast(targetDt, true) + val toCast = rangeTo.cast(targetDt, true) if(!fromCast.isValid || !toCast.isValid) return null val newStep = if(stepLiteral!=null) { - val stepCast = stepLiteral.cast(targetDt) + val stepCast = stepLiteral.cast(targetDt, true) if(stepCast.isValid) - stepCast.value!! + stepCast.valueOrZero() else range.step } else { range.step } - return RangeExpression(fromCast.value!!, toCast.value!!, newStep, range.position) + return RangeExpression(fromCast.valueOrZero(), toCast.valueOrZero(), newStep, range.position) } // adjust the datatype of a range expression in for loops to the loop variable. @@ -386,9 +386,9 @@ class ConstantFoldingOptimizer(private val program: Program, private val errors: val valueDt = numval.inferType(program) if(valueDt isnot decl.datatype) { if(decl.datatype!=DataType.BOOL || valueDt.isnot(DataType.UBYTE)) { - val cast = numval.cast(decl.datatype) + val cast = numval.cast(decl.datatype, true) if (cast.isValid) - return listOf(IAstModification.ReplaceNode(numval, cast.value!!, decl)) + return listOf(IAstModification.ReplaceNode(numval, cast.valueOrZero(), decl)) } } } diff --git a/codeOptimizers/src/prog8/optimizer/ConstantIdentifierReplacer.kt b/codeOptimizers/src/prog8/optimizer/ConstantIdentifierReplacer.kt index b13597521..49fc5b513 100644 --- a/codeOptimizers/src/prog8/optimizer/ConstantIdentifierReplacer.kt +++ b/codeOptimizers/src/prog8/optimizer/ConstantIdentifierReplacer.kt @@ -35,12 +35,12 @@ class VarConstantValueTypeAdjuster( // avoid silent float roundings if(decl.datatype in IntegerDatatypes && declConstValue.type == DataType.FLOAT) { errors.err("refused truncating of float to avoid loss of precision", decl.value!!.position) - } else { - // cast the numeric literal to the appropriate datatype of the variable + } else if(decl.datatype!=DataType.BOOL) { + // cast the numeric literal to the appropriate datatype of the variable if it's not boolean declConstValue.linkParents(decl) - val cast = declConstValue.cast(decl.datatype) + val cast = declConstValue.cast(decl.datatype, true) if (cast.isValid) - return listOf(IAstModification.ReplaceNode(decl.value!!, cast.value!!, decl)) + return listOf(IAstModification.ReplaceNode(decl.value!!, cast.valueOrZero(), decl)) } } } catch (x: UndefinedSymbolError) { @@ -292,7 +292,7 @@ internal class ConstantIdentifierReplacer(private val program: Program, private return noModifications val dt = identifier.inferType(program) - if(!dt.isKnown || !dt.isNumeric) + if(!dt.isKnown || !dt.isNumeric && !dt.isBool) return noModifications try { @@ -313,7 +313,7 @@ internal class ConstantIdentifierReplacer(private val program: Program, private } } when (cval.type) { - in NumericDatatypes -> { + in NumericDatatypesWithBoolean -> { if(parent is AddressOf) return noModifications // cannot replace the identifier INSIDE the addr-of here, let's do it later. return listOf( @@ -369,7 +369,7 @@ internal class ConstantIdentifierReplacer(private val program: Program, private DataType.FLOAT -> { // vardecl: for scalar float vars, promote constant integer initialization values to floats val litval = decl.value as? NumericLiteral - if (litval!=null && litval.type in IntegerDatatypes) { + if (litval!=null && litval.type in IntegerDatatypesWithBoolean) { val newValue = NumericLiteral(DataType.FLOAT, litval.number, litval.position) return listOf(IAstModification.ReplaceNode(decl.value!!, newValue, decl)) } @@ -470,12 +470,11 @@ internal class ConstantIdentifierReplacer(private val program: Program, private val numericLv = decl.value as? NumericLiteral val size = decl.arraysize?.constIndex() ?: return null if(rangeExpr==null && numericLv!=null) { - // arraysize initializer is a single int, and we know the size. + // arraysize initializer is a single int, and we know the array size. val fillvalue = numericLv.number if (fillvalue < compTarget.machine.FLOAT_MAX_NEGATIVE || fillvalue > compTarget.machine.FLOAT_MAX_POSITIVE) errors.err("float value overflow", numericLv.position) else { - // create the array itself, filled with the fillvalue. val array = Array(size) {fillvalue}.map { NumericLiteral(DataType.FLOAT, it, numericLv.position) }.toTypedArray() return ArrayLiteral(InferredTypes.InferredType.known(DataType.ARRAY_F), array, position = numericLv.position) } @@ -485,9 +484,12 @@ internal class ConstantIdentifierReplacer(private val program: Program, private val numericLv = decl.value as? NumericLiteral val size = decl.arraysize?.constIndex() ?: return null if(numericLv!=null) { - // arraysize initializer is a single int, and we know the size. - val fillvalue = if(numericLv.number==0.0) 0.0 else 1.0 - val array = Array(size) {fillvalue}.map { NumericLiteral(DataType.UBYTE, fillvalue, numericLv.position) }.toTypedArray() + // arraysize initializer is a single value, and we know the array size. + if(numericLv.type!=DataType.BOOL) { + errors.err("initializer value is not a boolean", numericLv.position) + return null + } + val array = Array(size) {numericLv.number}.map { NumericLiteral(DataType.BOOL, it, numericLv.position) }.toTypedArray() return ArrayLiteral(InferredTypes.InferredType.known(DataType.ARRAY_BOOL), array, position = numericLv.position) } } diff --git a/codeOptimizers/src/prog8/optimizer/ExpressionSimplifier.kt b/codeOptimizers/src/prog8/optimizer/ExpressionSimplifier.kt index 3244ffac5..14aee4d1c 100644 --- a/codeOptimizers/src/prog8/optimizer/ExpressionSimplifier.kt +++ b/codeOptimizers/src/prog8/optimizer/ExpressionSimplifier.kt @@ -19,9 +19,7 @@ import kotlin.math.pow // TODO add more peephole expression optimizations? Investigate what optimizations binaryen has? -class ExpressionSimplifier(private val program: Program, - private val errors: IErrorReporter, - private val compTarget: ICompilationTarget) : AstWalker() { +class ExpressionSimplifier(private val program: Program, private val errors: IErrorReporter) : AstWalker() { private val powersOfTwo = (1..16).map { (2.0).pow(it) }.toSet() private val negativePowersOfTwo = powersOfTwo.map { -it }.toSet() @@ -31,9 +29,9 @@ class ExpressionSimplifier(private val program: Program, // try to statically convert a literal value into one of the desired type val literal = typecast.expression as? NumericLiteral if (literal != null) { - val newLiteral = literal.cast(typecast.type) - if (newLiteral.isValid && newLiteral.value!! !== literal) { - mods += IAstModification.ReplaceNode(typecast, newLiteral.value!!, parent) + val newLiteral = literal.cast(typecast.type, typecast.implicit) + if (newLiteral.isValid && newLiteral.valueOrZero() !== literal) { + mods += IAstModification.ReplaceNode(typecast, newLiteral.valueOrZero(), parent) } } @@ -255,26 +253,51 @@ class ExpressionSimplifier(private val program: Program, } } - // boolvar & 1 --> boolvar - // boolvar & 2 --> false - if(expr.operator=="&" && rightDt in IntegerDatatypes && (leftDt == DataType.BOOL || (expr.left as? TypecastExpression)?.expression?.inferType(program)?.istype(DataType.BOOL)==true)) { - if(rightVal?.number==1.0) { - return listOf(IAstModification.ReplaceNode(expr, expr.left, parent)) - } else if(rightVal?.number!=null && (rightVal.number.toInt() and 1)==0) { - return listOf(IAstModification.ReplaceNode(expr, NumericLiteral.fromBoolean(false, expr.position), parent)) - } - } - if(leftDt==DataType.BOOL) { // optimize boolean constant comparisons -// if(expr.operator=="==" && rightVal?.number==0.0) -// return listOf(IAstModification.ReplaceNode(expr, PrefixExpression("not", expr.left, expr.position), parent)) -// if(expr.operator=="!=" && rightVal?.number==1.0) -// return listOf(IAstModification.ReplaceNode(expr, PrefixExpression("not", expr.left, expr.position), parent)) if(expr.operator=="==" && rightVal?.number==1.0) return listOf(IAstModification.ReplaceNode(expr, expr.left, parent)) if(expr.operator=="!=" && rightVal?.number==0.0) return listOf(IAstModification.ReplaceNode(expr, expr.left, parent)) + + if(rightDt==DataType.BOOL && expr.operator in arrayOf("and", "or", "xor")) { + if(leftVal!=null) { + val result = if(leftVal.asBooleanValue) { + when(expr.operator) { + "and" -> expr.right + "or" -> NumericLiteral.fromBoolean(true, expr.position) + "xor" -> PrefixExpression("not", expr.right, expr.position) + else -> throw FatalAstException("weird op") + } + } else { + when(expr.operator) { + "and" -> NumericLiteral.fromBoolean(false, expr.position) + "or" -> expr.right + "xor" -> expr.right + else -> throw FatalAstException("weird op") + } + } + return listOf(IAstModification.ReplaceNode(expr, result, parent)) + } + else if(rightVal!=null) { + val result = if(rightVal.asBooleanValue) { + when(expr.operator) { + "and" -> expr.left + "or" -> NumericLiteral.fromBoolean(true, expr.position) + "xor" -> PrefixExpression("not", expr.left, expr.position) + else -> throw FatalAstException("weird op") + } + } else { + when(expr.operator) { + "and" -> NumericLiteral.fromBoolean(false, expr.position) + "or" -> expr.left + "xor" -> expr.left + else -> throw FatalAstException("weird op") + } + } + return listOf(IAstModification.ReplaceNode(expr, result, parent)) + } + } } // simplify when a term is constant and directly determines the outcome @@ -387,7 +410,6 @@ class ExpressionSimplifier(private val program: Program, return noModifications } - private fun applyAbsorptionLaws(expr: BinaryExpression): Expression? { val rightB = expr.right as? BinaryExpression if(rightB!=null) { diff --git a/codeOptimizers/src/prog8/optimizer/Extensions.kt b/codeOptimizers/src/prog8/optimizer/Extensions.kt index 5c5bb80b3..00c48b021 100644 --- a/codeOptimizers/src/prog8/optimizer/Extensions.kt +++ b/codeOptimizers/src/prog8/optimizer/Extensions.kt @@ -3,7 +3,6 @@ package prog8.optimizer import prog8.ast.IBuiltinFunctions import prog8.ast.Program import prog8.code.core.CompilationOptions -import prog8.code.core.ICompilationTarget import prog8.code.core.IErrorReporter @@ -60,8 +59,8 @@ fun Program.inlineSubroutines(options: CompilationOptions): Int { return inliner.applyModifications() } -fun Program.simplifyExpressions(errors: IErrorReporter, target: ICompilationTarget) : Int { - val opti = ExpressionSimplifier(this, errors, target) +fun Program.simplifyExpressions(errors: IErrorReporter) : Int { + val opti = ExpressionSimplifier(this, errors) opti.visit(this) return opti.applyModifications() } diff --git a/codeOptimizers/src/prog8/optimizer/StatementOptimizer.kt b/codeOptimizers/src/prog8/optimizer/StatementOptimizer.kt index 921700f39..955c44005 100644 --- a/codeOptimizers/src/prog8/optimizer/StatementOptimizer.kt +++ b/codeOptimizers/src/prog8/optimizer/StatementOptimizer.kt @@ -83,7 +83,7 @@ class StatementOptimizer(private val program: Program, // empty true part? switch with the else part if(ifElse.truepart.isEmpty() && ifElse.elsepart.isNotEmpty()) { - val invertedCondition = BinaryExpression(ifElse.condition, "==", NumericLiteral(DataType.UBYTE, 0.0, ifElse.condition.position), ifElse.condition.position) + val invertedCondition = invertCondition(ifElse.condition, program) val emptyscope = AnonymousScope(mutableListOf(), ifElse.elsepart.position) val truepart = AnonymousScope(ifElse.elsepart.statements, ifElse.truepart.position) return listOf( @@ -445,38 +445,6 @@ class StatementOptimizer(private val program: Program, return listOf(IAstModification.ReplaceNode(whenStmt, ifStmt, parent)) } - if(whenStmt.condition.inferType(program).isBool) { - if(whenStmt.choices.all { it.values?.size==1 }) { - if (whenStmt.choices.all { it.values!!.single().constValue(program)!!.number in arrayOf(0.0, 1.0) }) { - // it's a when statement on booleans that can just be replaced by an if or if-else. - if (whenStmt.choices.size == 1) { - return if(whenStmt.choices[0].values!![0].constValue(program)!!.number==1.0) { - replaceWithIf(whenStmt.condition, whenStmt.choices[0].statements, null) - } else { - val notCondition = BinaryExpression(whenStmt.condition, "==", NumericLiteral(DataType.UBYTE, 0.0, whenStmt.condition.position), whenStmt.condition.position) - replaceWithIf(notCondition, whenStmt.choices[0].statements, null) - } - } else if (whenStmt.choices.size == 2) { - var trueBlock: AnonymousScope? = null - var elseBlock: AnonymousScope? = null - if(whenStmt.choices[0].values!![0].constValue(program)!!.number==1.0) { - trueBlock = whenStmt.choices[0].statements - } else { - elseBlock = whenStmt.choices[0].statements - } - if(whenStmt.choices[1].values!![0].constValue(program)!!.number==1.0) { - trueBlock = whenStmt.choices[1].statements - } else { - elseBlock = whenStmt.choices[1].statements - } - if(trueBlock!=null && elseBlock!=null) { - return replaceWithIf(whenStmt.condition, trueBlock, elseBlock) - } - } - } - } - } - val constantValue = whenStmt.condition.constValue(program)?.number if(constantValue!=null) { // when condition is a constant diff --git a/compiler/src/prog8/compiler/Compiler.kt b/compiler/src/prog8/compiler/Compiler.kt index 17a4fbd51..f07e1d555 100644 --- a/compiler/src/prog8/compiler/Compiler.kt +++ b/compiler/src/prog8/compiler/Compiler.kt @@ -430,7 +430,7 @@ private fun optimizeAst(program: Program, compilerOptions: CompilationOptions, e removeUnusedCode(program, errors,compilerOptions) while (true) { // keep optimizing expressions and statements until no more steps remain - val optsDone1 = program.simplifyExpressions(errors, compilerOptions.compTarget) + val optsDone1 = program.simplifyExpressions(errors) val optsDone2 = program.optimizeStatements(errors, functions, compilerOptions) val optsDone3 = program.inlineSubroutines(compilerOptions) program.constantFold(errors, compilerOptions) // because simplified statements and expressions can result in more constants that can be folded away diff --git a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt index 2e4b68765..94d82674a 100644 --- a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt +++ b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt @@ -1100,7 +1100,7 @@ internal class AstChecker(private val program: Program, errors.err("this expression doesn't return a value", typecast.expression.position) if(typecast.expression is NumericLiteral) { - val castResult = (typecast.expression as NumericLiteral).cast(typecast.type) + val castResult = (typecast.expression as NumericLiteral).cast(typecast.type, typecast.implicit) if(castResult.isValid) throw FatalAstException("cast should have been performed in const eval already") errors.err(castResult.whyFailed!!, typecast.expression.position) @@ -1673,11 +1673,11 @@ internal class AstChecker(private val program: Program, is IdentifierReference -> it.nameInSource.hashCode() and 0xffff is TypecastExpression -> { val constVal = it.expression.constValue(program) - val cast = constVal?.cast(it.type) + val cast = constVal?.cast(it.type, true) if(cast==null || !cast.isValid) -9999999 else - cast.value!!.number.toInt() + cast.valueOrZero().number.toInt() } else -> -9999999 } diff --git a/compiler/src/prog8/compiler/astprocessing/TypecastsAdder.kt b/compiler/src/prog8/compiler/astprocessing/TypecastsAdder.kt index a16f7e47c..3df2b1718 100644 --- a/compiler/src/prog8/compiler/astprocessing/TypecastsAdder.kt +++ b/compiler/src/prog8/compiler/astprocessing/TypecastsAdder.kt @@ -205,9 +205,9 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val return modifications } else { fun castLiteral(cvalue2: NumericLiteral): List { - val cast = cvalue2.cast(targettype) + val cast = cvalue2.cast(targettype, true) return if(cast.isValid) - listOf(IAstModification.ReplaceNode(assignment.value, cast.value!!, assignment)) + listOf(IAstModification.ReplaceNode(assignment.value, cast.valueOrZero(), assignment)) else emptyList() } @@ -314,7 +314,7 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val val modifications = mutableListOf() val dt = memread.addressExpression.inferType(program) if(dt.isKnown && dt.getOr(DataType.UWORD)!=DataType.UWORD) { - val castedValue = (memread.addressExpression as? NumericLiteral)?.cast(DataType.UWORD)?.value + val castedValue = (memread.addressExpression as? NumericLiteral)?.cast(DataType.UWORD, true)?.valueOrZero() if(castedValue!=null) modifications += IAstModification.ReplaceNode(memread.addressExpression, castedValue, memread) else @@ -328,7 +328,7 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val val modifications = mutableListOf() val dt = memwrite.addressExpression.inferType(program) if(dt.isKnown && dt.getOr(DataType.UWORD)!=DataType.UWORD) { - val castedValue = (memwrite.addressExpression as? NumericLiteral)?.cast(DataType.UWORD)?.value + val castedValue = (memwrite.addressExpression as? NumericLiteral)?.cast(DataType.UWORD, true)?.valueOrZero() if(castedValue!=null) modifications += IAstModification.ReplaceNode(memwrite.addressExpression, castedValue, memwrite) else @@ -349,9 +349,9 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val if (returnDt istype subReturnType or returnDt.isNotAssignableTo(subReturnType)) return noModifications if (returnValue is NumericLiteral) { - val cast = returnValue.cast(subReturnType) + val cast = returnValue.cast(subReturnType, true) if(cast.isValid) - returnStmt.value = cast.value + returnStmt.value = cast.valueOrZero() } else { val modifications = mutableListOf() addTypecastOrCastedValueModification(modifications, returnValue, subReturnType, returnStmt) @@ -399,12 +399,12 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val if(sourceDt == requiredType) return if(expressionToCast is NumericLiteral && expressionToCast.type!=DataType.FLOAT) { // refuse to automatically truncate floats - val castedValue = expressionToCast.cast(requiredType) + val castedValue = expressionToCast.cast(requiredType, true) if (castedValue.isValid) { val signOriginal = sign(expressionToCast.number) - val signCasted = sign(castedValue.value!!.number) + val signCasted = sign(castedValue.valueOrZero().number) if(signOriginal==signCasted) { - modifications += IAstModification.ReplaceNode(expressionToCast, castedValue.value!!, parent) + modifications += IAstModification.ReplaceNode(expressionToCast, castedValue.valueOrZero(), parent) } return } diff --git a/compiler/src/prog8/compiler/astprocessing/VariousCleanups.kt b/compiler/src/prog8/compiler/astprocessing/VariousCleanups.kt index b749ae19a..fc996cf5d 100644 --- a/compiler/src/prog8/compiler/astprocessing/VariousCleanups.kt +++ b/compiler/src/prog8/compiler/astprocessing/VariousCleanups.kt @@ -48,9 +48,9 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter, return listOf(IAstModification.ReplaceNode(typecast, constValue, parent)) if(typecast.expression is NumericLiteral) { - val value = (typecast.expression as NumericLiteral).cast(typecast.type) // TODO: add param typecast.implicit + val value = (typecast.expression as NumericLiteral).cast(typecast.type, typecast.implicit) if(value.isValid) - return listOf(IAstModification.ReplaceNode(typecast, value.value!!, parent)) // TODO: value.valueOrZero() + return listOf(IAstModification.ReplaceNode(typecast, value.valueOrZero(), parent)) } val sourceDt = typecast.expression.inferType(program)