mirror of
https://github.com/irmen/prog8.git
synced 2025-02-16 22:30:46 +00:00
avoid silent type casts that remove precision (such as float -> word)
This commit is contained in:
parent
65ba91411d
commit
774897260e
@ -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 constValue(program: Program): NumericLiteralValue? {
|
||||
val cv = expression.constValue(program) ?: return null
|
||||
return cv.cast(type)
|
||||
return cv.castNoCheck(type)
|
||||
// val value = RuntimeValue(cv.type, cv.asNumericValue!!).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())
|
||||
|
||||
fun cast(targettype: DataType): NumericLiteralValue {
|
||||
fun castNoCheck(targettype: DataType): NumericLiteralValue {
|
||||
if(type==targettype)
|
||||
return this
|
||||
val numval = number.toDouble()
|
||||
@ -567,7 +567,7 @@ class ArrayLiteralValue(val type: InferredTypes.InferredType, // inferred be
|
||||
it
|
||||
} else {
|
||||
try {
|
||||
num.cast(elementType)
|
||||
num.castNoCheck(elementType)
|
||||
} catch(x: ExpressionError) {
|
||||
return null
|
||||
}
|
||||
|
@ -1225,7 +1225,7 @@ internal class AstChecker(private val program: Program,
|
||||
is AddressOf -> it.identifier.heapId(program.namespace)
|
||||
is TypecastExpression -> {
|
||||
val constVal = it.expression.constValue(program)
|
||||
constVal?.cast(it.type)?.number?.toInt() ?: -9999999
|
||||
constVal?.castNoCheck(it.type)?.number?.toInt() ?: -9999999
|
||||
}
|
||||
else -> -9999999
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ class TypecastsAdder(val program: Program, val errors: ErrorReporter) : AstWalke
|
||||
assignment))
|
||||
} else {
|
||||
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)
|
||||
if(cvalue!=null) {
|
||||
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),
|
||||
call as Node)
|
||||
} else if(arg.second.value is NumericLiteralValue) {
|
||||
try {
|
||||
val castedValue = (arg.second.value as NumericLiteralValue).cast(requiredType)
|
||||
modifications += IAstModification.ReplaceNode(
|
||||
call.args[arg.second.index],
|
||||
castedValue,
|
||||
call as Node)
|
||||
} catch (x: ExpressionError) {
|
||||
// no cast possible
|
||||
if(argtype.isAssignableTo(requiredType)) {
|
||||
try {
|
||||
val castedValue = (arg.second.value as NumericLiteralValue).castNoCheck(requiredType)
|
||||
modifications += IAstModification.ReplaceNode(
|
||||
call.args[arg.second.index],
|
||||
castedValue,
|
||||
call as Node)
|
||||
} catch (x: ExpressionError) {
|
||||
// cast failed
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -161,7 +163,7 @@ class TypecastsAdder(val program: Program, val errors: ErrorReporter) : AstWalke
|
||||
// make sure the memory address is an uword
|
||||
val dt = memread.addressExpression.inferType(program)
|
||||
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)
|
||||
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
|
||||
val dt = memwrite.addressExpression.inferType(program)
|
||||
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)
|
||||
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))
|
||||
return noModifications
|
||||
if (returnValue is NumericLiteralValue) {
|
||||
returnStmt.value = returnValue.cast(subroutine.returntypes.single())
|
||||
returnStmt.value = returnValue.castNoCheck(subroutine.returntypes.single())
|
||||
} else {
|
||||
return listOf(IAstModification.ReplaceNode(
|
||||
returnValue,
|
||||
|
@ -34,7 +34,7 @@ internal class VariousCleanups: AstWalker() {
|
||||
|
||||
override fun before(typecast: TypecastExpression, parent: Node): Iterable<IAstModification> {
|
||||
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))
|
||||
}
|
||||
|
||||
|
@ -171,7 +171,7 @@ internal class ConstantIdentifierReplacer(private val program: Program, private
|
||||
if(declValue!=null && decl.type==VarDeclType.VAR
|
||||
&& declValue is NumericLiteralValue && !declValue.inferType(program).istype(decl.datatype)) {
|
||||
// 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
|
||||
@ -323,13 +323,13 @@ internal class ConstantFoldingOptimizer(private val program: Program) : AstWalke
|
||||
val newFrom: NumericLiteralValue
|
||||
val newTo: NumericLiteralValue
|
||||
try {
|
||||
newFrom = rangeFrom.cast(targetDt)
|
||||
newTo = rangeTo.cast(targetDt)
|
||||
newFrom = rangeFrom.castNoCheck(targetDt)
|
||||
newTo = rangeTo.castNoCheck(targetDt)
|
||||
} catch (x: ExpressionError) {
|
||||
return range
|
||||
}
|
||||
val newStep: Expression = try {
|
||||
stepLiteral?.cast(targetDt)?: range.step
|
||||
stepLiteral?.castNoCheck(targetDt)?: range.step
|
||||
} catch(ee: ExpressionError) {
|
||||
range.step
|
||||
}
|
||||
|
@ -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
|
||||
val literal = typecast.expression as? NumericLiteralValue
|
||||
if (literal != null) {
|
||||
val newLiteral = literal.cast(typecast.type)
|
||||
val newLiteral = literal.castNoCheck(typecast.type)
|
||||
if (newLiteral !== literal)
|
||||
mods += IAstModification.ReplaceNode(typecast.expression, newLiteral, typecast)
|
||||
}
|
||||
|
@ -24,8 +24,10 @@ main {
|
||||
|
||||
uword xx = 4.5678
|
||||
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(4.55) ; TODO truncation warning
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user