I have a testcase where the IR generated for indirect assignment without GC and no syntax generates a bad error message.
The root cause is that the left-hand-side used in indirect assignment must be able to accept more than one parameter, even if this is a semantic error for some variables. Indirect assignment must defer catching errors.
(= v (list 1 2 3))
(= (v 1 2) 7)
Using (v 1 2) here is a semantic error because it uses more than one index to access a list. It would be useful to generate a correct error message:
(error "parameter count mismatch in indirect set" (= (v 1 2) 7))
The reason not to generate this error message is that passing more than one parameter in indirect assignment can be valid for other expressions. In such cases the error message would be confusing instead of useful. Indirect assignment must allow at compile-time for an expression that looks similar but is semantically different:
(= somefn (fn (a b c) (list a b c)))
(= ((somefn 10 20 30) 1) 200)
Using (somefn 10 20 30) here isn't a semantic error. It's a valid function call that returns a list. The outermost object of the left-hand-side in indirect assignment can be expressed as a list instead of an atom — expressed as the outermost object (somefn 10 20 30) in the left-hand-side ((somefn 10 20 30) 1) instead of the atom v in (v 1 2) — and as a list it must be able to accept more than one parameter. Here it accepts three: 10 20 30. Whereas the atom v should accept only one parameter instead of two: only 1 instead of 1 2.
This example reduces to (= 20 200) which leads to a different type of run-time error. It would be useful to generate the correct error message for it at run-time: