Odin icon indicating copy to clipboard operation
Odin copied to clipboard

SOA arrays are not supported for struct with `using` statement on a struct member

Open wookie41 opened this issue 2 years ago • 4 comments

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)
}

wookie41 avatar Oct 24 '23 08:10 wookie41

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.

flysand7 avatar Oct 24 '23 08:10 flysand7

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

wookie41 avatar Oct 24 '23 08:10 wookie41

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,
}

jakubtomsu avatar Nov 25 '23 12:11 jakubtomsu

This might be somewhat related to #2041

jakubtomsu avatar Nov 25 '23 13:11 jakubtomsu