SOA arrays are not supported for struct with `using` statement on a struct member
Context
The compilation process is failing when using a SOA array of structs where one of the members is a nested struct with a using statement.
- Operating System & Odin Version:
Odin: dev-2023-10:12c316cd OS: Windows 11 Professional (version: 22H2), build 22621.2428 CPU: AMD Ryzen 7 3700X 8-Core Processor RAM: 32679 MiB
Expected Behavior
The compiler creates arrays for each member of Outer and each member of Inner in the SOA array. As pointed out in the discussion, it's a good question what should happen in this case. Maybe a tag can be added to guide the compiler whether to "flatten" (create the arrays) the members of the nested struct?
Current Behavior
The program doesn't compile
Failure Information (for bugs)
The compilation error is
Assertion Failure: cast(usize)index < cast(usize)count Index 1 is out of bounds ranges 0..<1
Steps to Reproduce
package main
import "core:log"
Inner :: struct {
foo: int,
}
Outer :: struct {
using inner: Inner,
bar: int,
}
main :: proc() {
my_array: #soa[]Outer = make_soa(#soa[]Outer, 10)
my_ptr := &my_array[0]
my_ptr.foo = 2
log.info(my_ptr)
}
This code works though
package main
import "core:log"
Inner :: struct {
foo: int,
}
Outer :: struct {
inner: Inner,
bar: int,
}
main :: proc() {
my_array: #soa[]Outer = make_soa(#soa[]Outer, 10)
my_ptr := &my_array[0]
my_ptr.inner.foo = 2
log.info(my_ptr)
}
This is a very curious bug, seems like that violates some assumptions about soa-able types.
Can I ask you to clarify on the expected behaviour? The program compiles, sure, but how exactly should it behave? Under the hood, should it create a separate array for each Inner struct, or should it create an array for each field of the Inner struct.
Actually you don't have to clarify what is your expected behaviour, but it's an interesting food for thought for other contributors, i guess.
In my case I'd expect it to create an array for each of the members of the Inner struct too. But you actually have a point, I didn't think about it like this
My assumption is that it shouldn't create an array for each member of the Inner struct. That's because using is currently just a syntactic sugar, plus I often want to use member structs to separate fields into "groups" depending on their usage and memory access patterns. Here is an example:
Foo :: struct {
using common: struct {
pos: Vec3,
health: f32,
rot: Quat,
},
using graphics: struct {
mesh: Mesh,
material: Material,
...
},
using physics: struct {
collider: Collider,
...
},
}
However having a way to tell the compiler what's the intended memory layout could be very useful. Maybe something like this..?
Inner :: struct {
x: int,
y: int,
}
Outer :: struct {
#soa_using using inner: Inner,
bar: int,
}
This might be somewhat related to #2041