fixed function argument type cast bug

This commit is contained in:
Irmen de Jong 2020-07-03 17:24:43 +02:00
parent c07907e7bd
commit a6d789cfbc
4 changed files with 70 additions and 17 deletions

View File

@ -38,6 +38,12 @@ internal fun Program.addTypecasts(errors: ErrorReporter) {
caster.applyModifications()
}
internal fun Program.simplifyNumericCasts() {
val fixer = TypecastsSimplifier(this)
fixer.visit(this)
fixer.applyModifications()
}
internal fun Program.transformAssignments(errors: ErrorReporter) {
val transform = AssignmentTransformer(this, errors)
transform.visit(this)

View File

@ -7,6 +7,7 @@ import prog8.ast.Program
import prog8.ast.base.*
import prog8.ast.expressions.*
import prog8.ast.statements.*
import prog8.compiler.CompilerException
import prog8.functions.BuiltinFunctions
@ -125,21 +126,18 @@ class TypecastsAdder(val program: Program, val errors: ErrorReporter) : AstWalke
}
is BuiltinFunctionStatementPlaceholder -> {
val func = BuiltinFunctions.getValue(sub.name)
if(func.pure) {
// non-pure functions don't get automatic typecasts because sometimes they act directly on their parameters
for (arg in func.parameters.zip(call.args.withIndex())) {
val argItype = arg.second.value.inferType(program)
if (argItype.isKnown) {
val argtype = argItype.typeOrElse(DataType.STRUCT)
if (arg.first.possibleDatatypes.any { argtype == it })
continue
for (possibleType in arg.first.possibleDatatypes) {
if (argtype isAssignableTo possibleType) {
modifications += IAstModification.ReplaceNode(
call.args[arg.second.index],
TypecastExpression(arg.second.value, possibleType, true, arg.second.value.position),
call as Node)
}
for (arg in func.parameters.zip(call.args.withIndex())) {
val argItype = arg.second.value.inferType(program)
if (argItype.isKnown) {
val argtype = argItype.typeOrElse(DataType.STRUCT)
if (arg.first.possibleDatatypes.any { argtype == it })
continue
for (possibleType in arg.first.possibleDatatypes) {
if (argtype isAssignableTo possibleType) {
modifications += IAstModification.ReplaceNode(
call.args[arg.second.index],
TypecastExpression(arg.second.value, possibleType, true, arg.second.value.position),
call as Node)
}
}
}
@ -249,3 +247,52 @@ class TypecastsAdder(val program: Program, val errors: ErrorReporter) : AstWalke
return noModifications
}
}
class TypecastsSimplifier(val program: Program) : AstWalker() {
/*
* Typecasts of a numeric literal value can be replaced by the numeric value of the type directly.
*/
private val noModifications = emptyList<IAstModification>()
override fun before(typecast: TypecastExpression, parent: Node): Iterable<IAstModification> {
if(typecast.expression is NumericLiteralValue) {
val value = (typecast.expression as NumericLiteralValue).cast(typecast.type)
return listOf(IAstModification.ReplaceNode(typecast, value, parent))
}
return noModifications
}
override fun after(functionCallStatement: FunctionCallStatement, parent: Node): Iterable<IAstModification>
= checkCallArgTypes(functionCallStatement as IFunctionCall, functionCallStatement.definingScope())
override fun after(functionCall: FunctionCall, parent: Node): Iterable<IAstModification>
= checkCallArgTypes(functionCall as IFunctionCall, functionCall.definingScope())
private fun checkCallArgTypes(call: IFunctionCall, scope: INameScope): Iterable<IAstModification> {
val argtypes = call.args.map { it.inferType(program).typeOrElse(DataType.STRUCT) }
val target = call.target.targetStatement(scope)
when(target) {
is Subroutine -> {
val paramtypes = target.parameters.map { it.type }
if(argtypes!=paramtypes)
throw CompilerException("parameter type mismatch $call")
}
is BuiltinFunctionStatementPlaceholder -> {
val func = BuiltinFunctions.getValue(target.name)
val paramtypes = func.parameters.map { it.possibleDatatypes }
for(x in argtypes.zip(paramtypes)) {
if(x.first !in x.second)
throw CompilerException("parameter type mismatch $call")
}
}
else -> {}
}
println("**** $target")
return noModifications
}
}

View File

@ -180,6 +180,7 @@ private fun postprocessAst(programAst: Program, errors: ErrorReporter, compilerO
errors.handle()
programAst.addTypecasts(errors)
errors.handle()
programAst.simplifyNumericCasts()
programAst.removeNopsFlattenAnonScopes()
programAst.checkValid(compilerOptions, errors) // check if final tree is still valid
errors.handle()

View File

@ -9,8 +9,7 @@
; TODO fix crash when piece reaches bottom. (codegen issue).
; TODO fix wrong behavior when compiled without optimizations (codegen issue).
; TODO fix wrong block behavior at bottom when compiled without optimizations (codegen issue).
main {