now correctly requires using & (address-of) when assigning the address of a label or subroutine, used to generate invalid code when it was omitted

This commit is contained in:
Irmen de Jong 2022-01-23 02:23:30 +01:00
parent 7bb41a30ed
commit 7afc96112b
5 changed files with 38 additions and 5 deletions

View File

@ -497,7 +497,7 @@ internal class AstChecker(private val program: Program,
val sourceDatatype = assignment.value.inferType(program)
if (sourceDatatype.isUnknown) {
if (assignment.value !is FunctionCallExpression)
errors.err("assignment value is invalid or has no proper datatype", assignment.value.position)
errors.err("assignment value is invalid or has no proper datatype, maybe forgot '&' (address-of)", assignment.value.position)
} else {
checkAssignmentCompatible(targetDatatype.getOr(DataType.BYTE),
sourceDatatype.getOr(DataType.BYTE), assignment.value)

View File

@ -5,6 +5,7 @@ import io.kotest.matchers.shouldBe
import io.kotest.matchers.string.shouldContain
import prog8.codegen.target.C64Target
import prog8tests.helpers.ErrorReporterForTests
import prog8tests.helpers.assertFailure
import prog8tests.helpers.assertSuccess
import prog8tests.helpers.compileText
@ -30,4 +31,29 @@ class TestAstChecks: FunSpec({
errors.warnings[0] shouldContain "converted to float"
errors.warnings[1] shouldContain "converted to float"
}
test("can't assign label or subroutine without using address-of") {
val text = """
main {
sub start() {
label:
uword @shared addr
addr = label
addr = thing
addr = &label
addr = &thing
}
sub thing() {
}
}
"""
val errors = ErrorReporterForTests()
compileText(C64Target, true, text, writeAssembly = true, errors=errors).assertFailure()
errors.errors.size shouldBe 2
errors.warnings.size shouldBe 0
errors.errors[0] shouldContain ":7:28) assignment value is invalid"
errors.errors[1] shouldContain ":8:28) assignment value is invalid"
}
})

View File

@ -896,7 +896,6 @@ data class IdentifierReference(val nameInSource: List<String>, override val posi
override fun inferType(program: Program): InferredTypes.InferredType {
return when (val targetStmt = targetStatement(program)) {
is VarDecl -> InferredTypes.knownFor(targetStmt.datatype)
is Label -> InferredTypes.InferredType.known(DataType.UWORD)
else -> InferredTypes.InferredType.unknown()
}
}

View File

@ -3,7 +3,6 @@ TODO
For next release
^^^^^^^^^^^^^^^^
- Fix: uword addr = label ; addr will be 0! required to use &label!
- Fix compiler stack overflow crash:
sub sprite_y_for_row(ubyte row) -> word {
return (8-row as byte)
@ -44,6 +43,7 @@ Blocked by an official Commander-x16 r39 release
Future Things and Ideas
^^^^^^^^^^^^^^^^^^^^^^^
- Fix: don't report as recursion if code assign address of its own subroutine to something, rather than calling it
- allow "xxx" * constexpr (where constexpr is not a number literal, now gives expression error not same type)
- can we promise a left-to-right function call argument evaluation? without sacrificing performance
- unify FunctioncallExpression + FunctioncallStatement and PipeExpression + Pipe statement, may require moving Expression/Statement into interfaces instead of abstract base classes

View File

@ -3,7 +3,15 @@
main {
sub start() {
uword @shared qq = $2ff33
cx16.r0 = $1fc0f
label:
uword @shared addr
addr = label
addr = thing
addr = &label
addr = &thing
}
sub thing() {
}
}