avoid silent type casts that remove precision (such as float -> word)

This commit is contained in:
Irmen de Jong 2020-08-20 12:49:48 +02:00
parent 65ba91411d
commit 774897260e
7 changed files with 27 additions and 23 deletions

View File

@ -277,7 +277,7 @@ class TypecastExpression(var expression: Expression, var type: DataType, val imp
override fun inferType(program: Program): InferredTypes.InferredType = InferredTypes.knownFor(type) override fun inferType(program: Program): InferredTypes.InferredType = InferredTypes.knownFor(type)
override fun constValue(program: Program): NumericLiteralValue? { override fun constValue(program: Program): NumericLiteralValue? {
val cv = expression.constValue(program) ?: return null val cv = expression.constValue(program) ?: return null
return cv.cast(type) return cv.castNoCheck(type)
// val value = RuntimeValue(cv.type, cv.asNumericValue!!).cast(type) // val value = RuntimeValue(cv.type, cv.asNumericValue!!).cast(type)
// return LiteralValue.fromNumber(value.numericValue(), value.type, position).cast(type) // return LiteralValue.fromNumber(value.numericValue(), value.type, position).cast(type)
} }
@ -398,7 +398,7 @@ class NumericLiteralValue(val type: DataType, // only numerical types allowed
operator fun compareTo(other: NumericLiteralValue): Int = number.toDouble().compareTo(other.number.toDouble()) operator fun compareTo(other: NumericLiteralValue): Int = number.toDouble().compareTo(other.number.toDouble())
fun cast(targettype: DataType): NumericLiteralValue { fun castNoCheck(targettype: DataType): NumericLiteralValue {
if(type==targettype) if(type==targettype)
return this return this
val numval = number.toDouble() val numval = number.toDouble()
@ -567,7 +567,7 @@ class ArrayLiteralValue(val type: InferredTypes.InferredType, // inferred be
it it
} else { } else {
try { try {
num.cast(elementType) num.castNoCheck(elementType)
} catch(x: ExpressionError) { } catch(x: ExpressionError) {
return null return null
} }

View File

@ -1225,7 +1225,7 @@ internal class AstChecker(private val program: Program,
is AddressOf -> it.identifier.heapId(program.namespace) is AddressOf -> it.identifier.heapId(program.namespace)
is TypecastExpression -> { is TypecastExpression -> {
val constVal = it.expression.constValue(program) val constVal = it.expression.constValue(program)
constVal?.cast(it.type)?.number?.toInt() ?: -9999999 constVal?.castNoCheck(it.type)?.number?.toInt() ?: -9999999
} }
else -> -9999999 else -> -9999999
} }

View File

@ -52,7 +52,7 @@ class TypecastsAdder(val program: Program, val errors: ErrorReporter) : AstWalke
assignment)) assignment))
} else { } else {
fun castLiteral(cvalue: NumericLiteralValue): List<IAstModification.ReplaceNode> = fun castLiteral(cvalue: NumericLiteralValue): List<IAstModification.ReplaceNode> =
listOf(IAstModification.ReplaceNode(cvalue, cvalue.cast(targettype), cvalue.parent)) listOf(IAstModification.ReplaceNode(cvalue, cvalue.castNoCheck(targettype), cvalue.parent))
val cvalue = assignment.value.constValue(program) val cvalue = assignment.value.constValue(program)
if(cvalue!=null) { if(cvalue!=null) {
val number = cvalue.number.toDouble() val number = cvalue.number.toDouble()
@ -109,14 +109,16 @@ class TypecastsAdder(val program: Program, val errors: ErrorReporter) : AstWalke
AddressOf(arg.second.value as IdentifierReference, arg.second.value.position), AddressOf(arg.second.value as IdentifierReference, arg.second.value.position),
call as Node) call as Node)
} else if(arg.second.value is NumericLiteralValue) { } else if(arg.second.value is NumericLiteralValue) {
if(argtype.isAssignableTo(requiredType)) {
try { try {
val castedValue = (arg.second.value as NumericLiteralValue).cast(requiredType) val castedValue = (arg.second.value as NumericLiteralValue).castNoCheck(requiredType)
modifications += IAstModification.ReplaceNode( modifications += IAstModification.ReplaceNode(
call.args[arg.second.index], call.args[arg.second.index],
castedValue, castedValue,
call as Node) call as Node)
} catch (x: ExpressionError) { } catch (x: ExpressionError) {
// no cast possible // cast failed
}
} }
} }
} }
@ -161,7 +163,7 @@ class TypecastsAdder(val program: Program, val errors: ErrorReporter) : AstWalke
// make sure the memory address is an uword // make sure the memory address is an uword
val dt = memread.addressExpression.inferType(program) val dt = memread.addressExpression.inferType(program)
if(dt.isKnown && dt.typeOrElse(DataType.UWORD)!=DataType.UWORD) { if(dt.isKnown && dt.typeOrElse(DataType.UWORD)!=DataType.UWORD) {
val typecast = (memread.addressExpression as? NumericLiteralValue)?.cast(DataType.UWORD) val typecast = (memread.addressExpression as? NumericLiteralValue)?.castNoCheck(DataType.UWORD)
?: TypecastExpression(memread.addressExpression, DataType.UWORD, true, memread.addressExpression.position) ?: TypecastExpression(memread.addressExpression, DataType.UWORD, true, memread.addressExpression.position)
return listOf(IAstModification.ReplaceNode(memread.addressExpression, typecast, memread)) return listOf(IAstModification.ReplaceNode(memread.addressExpression, typecast, memread))
} }
@ -172,7 +174,7 @@ class TypecastsAdder(val program: Program, val errors: ErrorReporter) : AstWalke
// make sure the memory address is an uword // make sure the memory address is an uword
val dt = memwrite.addressExpression.inferType(program) val dt = memwrite.addressExpression.inferType(program)
if(dt.isKnown && dt.typeOrElse(DataType.UWORD)!=DataType.UWORD) { if(dt.isKnown && dt.typeOrElse(DataType.UWORD)!=DataType.UWORD) {
val typecast = (memwrite.addressExpression as? NumericLiteralValue)?.cast(DataType.UWORD) val typecast = (memwrite.addressExpression as? NumericLiteralValue)?.castNoCheck(DataType.UWORD)
?: TypecastExpression(memwrite.addressExpression, DataType.UWORD, true, memwrite.addressExpression.position) ?: TypecastExpression(memwrite.addressExpression, DataType.UWORD, true, memwrite.addressExpression.position)
return listOf(IAstModification.ReplaceNode(memwrite.addressExpression, typecast, memwrite)) return listOf(IAstModification.ReplaceNode(memwrite.addressExpression, typecast, memwrite))
} }
@ -189,7 +191,7 @@ class TypecastsAdder(val program: Program, val errors: ErrorReporter) : AstWalke
if (returnValue.inferType(program).istype(subReturnType)) if (returnValue.inferType(program).istype(subReturnType))
return noModifications return noModifications
if (returnValue is NumericLiteralValue) { if (returnValue is NumericLiteralValue) {
returnStmt.value = returnValue.cast(subroutine.returntypes.single()) returnStmt.value = returnValue.castNoCheck(subroutine.returntypes.single())
} else { } else {
return listOf(IAstModification.ReplaceNode( return listOf(IAstModification.ReplaceNode(
returnValue, returnValue,

View File

@ -34,7 +34,7 @@ internal class VariousCleanups: AstWalker() {
override fun before(typecast: TypecastExpression, parent: Node): Iterable<IAstModification> { override fun before(typecast: TypecastExpression, parent: Node): Iterable<IAstModification> {
if(typecast.expression is NumericLiteralValue) { if(typecast.expression is NumericLiteralValue) {
val value = (typecast.expression as NumericLiteralValue).cast(typecast.type) val value = (typecast.expression as NumericLiteralValue).castNoCheck(typecast.type)
return listOf(IAstModification.ReplaceNode(typecast, value, parent)) return listOf(IAstModification.ReplaceNode(typecast, value, parent))
} }

View File

@ -171,7 +171,7 @@ internal class ConstantIdentifierReplacer(private val program: Program, private
if(declValue!=null && decl.type==VarDeclType.VAR if(declValue!=null && decl.type==VarDeclType.VAR
&& declValue is NumericLiteralValue && !declValue.inferType(program).istype(decl.datatype)) { && declValue is NumericLiteralValue && !declValue.inferType(program).istype(decl.datatype)) {
// cast the numeric literal to the appropriate datatype of the variable // cast the numeric literal to the appropriate datatype of the variable
return listOf(IAstModification.ReplaceNode(decl.value!!, declValue.cast(decl.datatype), decl)) return listOf(IAstModification.ReplaceNode(decl.value!!, declValue.castNoCheck(decl.datatype), decl))
} }
return noModifications return noModifications
@ -323,13 +323,13 @@ internal class ConstantFoldingOptimizer(private val program: Program) : AstWalke
val newFrom: NumericLiteralValue val newFrom: NumericLiteralValue
val newTo: NumericLiteralValue val newTo: NumericLiteralValue
try { try {
newFrom = rangeFrom.cast(targetDt) newFrom = rangeFrom.castNoCheck(targetDt)
newTo = rangeTo.cast(targetDt) newTo = rangeTo.castNoCheck(targetDt)
} catch (x: ExpressionError) { } catch (x: ExpressionError) {
return range return range
} }
val newStep: Expression = try { val newStep: Expression = try {
stepLiteral?.cast(targetDt)?: range.step stepLiteral?.castNoCheck(targetDt)?: range.step
} catch(ee: ExpressionError) { } catch(ee: ExpressionError) {
range.step range.step
} }

View File

@ -29,7 +29,7 @@ internal class ExpressionSimplifier(private val program: Program) : AstWalker()
// try to statically convert a literal value into one of the desired type // try to statically convert a literal value into one of the desired type
val literal = typecast.expression as? NumericLiteralValue val literal = typecast.expression as? NumericLiteralValue
if (literal != null) { if (literal != null) {
val newLiteral = literal.cast(typecast.type) val newLiteral = literal.castNoCheck(typecast.type)
if (newLiteral !== literal) if (newLiteral !== literal)
mods += IAstModification.ReplaceNode(typecast.expression, newLiteral, typecast) mods += IAstModification.ReplaceNode(typecast.expression, newLiteral, typecast)
} }

View File

@ -24,8 +24,10 @@ main {
uword xx = 4.5678 uword xx = 4.5678
ubyte bb = 33 ubyte bb = 33
float ff = 1.234
foo2(-33) foo(1.234, 4.456) ; TODO truncation warning
foo2(2.3456) ; TODO truncation warning
foo2(bb) foo2(bb)
foo2(4.55) ; TODO truncation warning foo2(4.55) ; TODO truncation warning