v
v copied to clipboard
Fixed error handling when appending empty array literal to 2D array
Resolves #23854
This PR improves error handling when appending an empty array literal [] to a 2D array such as [][]string.
Currently, doing this results in a cryptic C error because the compiler fails to infer the correct type of the empty literal. The operation is not marked invalid, but compilation fails downstream.
This fix adds a graceful error message during type checking, guiding the user to use an explicitly typed empty array like []string{}.
Example:
Before:
mut rows := [][]string{}
rows << [] // C error
After:
error: cannot infer type for empty array literal `[]`. Use `[]string{}` instead.
Test:
- Added append_empty_array_literal.v to vlib/v/tests/known_errors/testdata/, reproducing the issue and verifying the error message.
Connected to Huly®: V_0.6-22395
I do not get it - why would one want to append an empty array to another array? The result will be either a NOP (the original array stays as it is), or the compiler should warn/error that the operation will have no effect.
An empty array might be used as a placeholder or for dynamically constructing a 2D array (matrix). Currently, the compiler attempts to infer the type of an empty array when no type is specified and then attempts to append it to the matrix. This does not result in a no-op (NOP) but rather causes a 'C error' if type inference fails.
With this fix, the compiler now errors explicitly due to a typing issue and provides a clear, actionable error message rather than just a C error.
Alternatively, why doesn't the compiler infer correctly? When appending [] to an array, the compiler should "know" that it is the same type as the array. Nothing to infer - make it an inherent property... an extra if statement.
In the case of a 2D array, a << b, where a is [][]Element could mean that b is either of the same type as a i.e. [][]Element, (adding multiple elements), or b is of type []Element (adding a single element, which for 2D arrays, is a 1D array).
For adding empty [], that distinction is moot though, since in both cases, it should either not cgen error (since adding an empty array should be a NOP), or it should error at the checker stage (which this PR does).
i.e. I do not question the value of turning the cgen error into a more actionable checker error. I am just not convinced, that the compiler should not just ignore the statement a << [] (which was said to be useful only as a placeholder).
Placeholder as in adding an empty array to the array of arrays, which can be filled in later.
Using a variation of the original example, doing
mut rows := [][]string{}
println(rows)
rows << []
println(rows)
rows << []
println(rows)
rows[0] << 's'
println(rows)
would be expected to give the same results as
mut rows := [][]string{}
println(rows)
rows << []string{}
println(rows)
rows << []string{}
println(rows)
rows[0] << 's'
println(rows)
which is
[]
[[]]
[[], []]
[['s'], []]
I.e. modify cgen to consider a << [], as a new element []Type{}, of the [][]Type 2D array?
That can work too.
Ok, instead of doing an error message, I've made adjustments to the checker to infer the type of [] to be the same type as the left side's element type.
I've tested it against the original issue and the examples mentioned in this conversation. This approach seems to align better with the expected behavior of the operation.
(closing/opening again, to trigger the CI jobs)
Another close/open, to check with current CI.
The CI failure is due to this (reproduced locally):
#0 12:21:05 ^ fix-empty-array-infix ~/v>v run examples/gg/fire.v
examples/gg/fire.v:63:37: error: expected `[]int`, not `int literal`
61 | buf: [][]int{len: height - 1, init: []int{len: width}}
62 | }
63 | app.buf << []int{len: width, init: 36} // white fire base
| ~~
Using this instead: app.buf << [[]int{len: width, init: 36}] works.
Another open/close, due to check logs disappearing...
Since PR #25508 fixes the same bug this PR attempted to fix, I don't think it needs to be open anymore.
@TheAhmir Thanks for this PR 🙇🏻.