diff --git a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt index a869dc656..fcef294c2 100644 --- a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt +++ b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt @@ -2362,6 +2362,12 @@ internal class AstChecker(private val program: Program, errors.err("on..goto index must be an unsigned byte", onGoto.index.position) } } + + override fun visit(idxderef: PtrIndexedDereference) { + val dt = idxderef.indexed.arrayvar.inferType(program) + if(!dt.isUnsignedWord && !dt.isPointer) + errors.err("cannot array index on this field type", idxderef.indexed.position) + } } internal fun checkUnusedReturnValues(call: FunctionCallStatement, target: Statement, errors: IErrorReporter) { diff --git a/compiler/src/prog8/compiler/astprocessing/SimplifiedAstMaker.kt b/compiler/src/prog8/compiler/astprocessing/SimplifiedAstMaker.kt index 5ab49fb3d..9a87cf0bb 100644 --- a/compiler/src/prog8/compiler/astprocessing/SimplifiedAstMaker.kt +++ b/compiler/src/prog8/compiler/astprocessing/SimplifiedAstMaker.kt @@ -108,14 +108,18 @@ class SimplifiedAstMaker(private val program: Program, private val errors: IErro val type = idxderef.inferType(program).getOrElse { throw FatalAstException("unknown dt") } - require(type.isPointer && type.sub!=null) - val deref = PtPointerIndexedDeref(DataType.forDt(type.sub!!), idxderef.position) - val indexer = PtArrayIndexer(DataType.forDt(type.sub!!), idxderef.position) - val identifier = PtIdentifier(idxderef.indexed.arrayvar.nameInSource.joinToString("."), type, idxderef.indexed.arrayvar.position) - indexer.add(identifier) - indexer.add(transformExpression(idxderef.indexed.indexer.indexExpr)) - deref.add(indexer) - return deref + require(type.isPointer || type.isUnsignedWord) + if(type.isUnsignedWord) { + TODO("indexing uword field $idxderef") // TODO hmm, wasn't there code elsewhere for this already? + } else { + val deref = PtPointerIndexedDeref(DataType.forDt(type.sub!!), idxderef.position) + val indexer = PtArrayIndexer(DataType.forDt(type.sub!!), idxderef.position) + val identifier = PtIdentifier(idxderef.indexed.arrayvar.nameInSource.joinToString("."), type, idxderef.indexed.arrayvar.position) + indexer.add(identifier) + indexer.add(transformExpression(idxderef.indexed.indexer.indexExpr)) + deref.add(indexer) + return deref + } } private fun transform(deref: PtrDereference): PtPointerDeref { diff --git a/compiler/test/TestPointers.kt b/compiler/test/TestPointers.kt index 3f6ce3a58..c4043deab 100644 --- a/compiler/test/TestPointers.kt +++ b/compiler/test/TestPointers.kt @@ -314,4 +314,28 @@ main { a2.target.array shouldNotBe null } + test("array indexing on non pointer fields give correct error messages") { + val src=""" +main { + struct List { + bool s + ubyte n + uword ptr + } + sub start() { + ^^List @shared l1 = List() + l1.s[1] = 4444 + l1.n[1] = true + l1.ptr[1] = 4444 + } +}""" + + val errors = ErrorReporterForTests() + compileText(VMTarget(), false, src, outputDir, errors=errors) shouldBe null + errors.errors.size shouldBe 4 + errors.errors[0] shouldContain "cannot array index" + errors.errors[1] shouldContain "cannot array index" + errors.errors[2] shouldContain "out of range" + } + }) \ No newline at end of file diff --git a/compilerAst/src/prog8/ast/expressions/AstExpressions.kt b/compilerAst/src/prog8/ast/expressions/AstExpressions.kt index fa989bc04..2274153d6 100644 --- a/compilerAst/src/prog8/ast/expressions/AstExpressions.kt +++ b/compilerAst/src/prog8/ast/expressions/AstExpressions.kt @@ -1624,12 +1624,17 @@ class PtrIndexedDereference(val indexed: ArrayIndexedExpression, override val po TODO("cannot determine type of dereferenced indexed pointer(?) that is not a pointer to a basic type") } - if(parent is AssignTarget) { + if(parent is AssignTarget || parent is Assignment) { val dt = indexed.arrayvar.traverseDerefChainForDt(null) - return if(dt.isUndefined) - InferredTypes.unknown() - else - InferredTypes.knownFor(dt) + return when { + dt.isUndefined -> InferredTypes.unknown() + dt.isUnsignedWord -> InferredTypes.knownFor(BaseDataType.UBYTE) + dt.isPointer -> { + return if(dt.sub!=null) InferredTypes.knownFor(dt.sub!!) + else InferredTypes.unknown() + } + else -> InferredTypes.unknown() + } } return InferredTypes.unknown() diff --git a/examples/test.p8 b/examples/test.p8 index 30fa1c83d..6b77bf3a9 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,55 +1,25 @@ main { struct List { - bool s + ^^uword s + ubyte n + } + sub start() { + ^^List l1 = List() ; TODO fix unused var removal + l1.s[2] = 1 + } +} + +/* +main { + struct List { + ^^uword s ubyte n } sub start() { ^^List @shared l1 = List() - l1.s[1] = 4444 ; TODO wrong error message, instead should give an error that you can't index a boolean (only uword or pointer) - l1.s[1] = true ; TODO should give an error that you can't index a boolean (only uword or pointer) - } -} - - -/* - -main { - struct List { - bool s - ubyte n - } - sub start() { - ^^List @shared l1 = List() ; TODO gets removed as 'unused var' when not @shared - l1.s[0] = true + cx16.r0= l1.s[2] + ;l1.s[l1.n] = 1 + ;l1.s[0] = 2 } } */ - - -/* -main { - struct List { - ^^uword s - ubyte n - } - sub start() { - ^^List l1 = List() - l1.s[l1.n] = 1 - } -} -*/ - -/* -main { - struct List { - ^^uword s - ubyte n - } - sub start() { - ^^List l1 = List() - l1.s[l1.n] = 1 - l1.s[0] = 2 - } -} -*/ -