v icon indicating copy to clipboard operation
v copied to clipboard

accessing multiple structs at comptime generics results in wrong values

Open ttytm opened this issue 2 years ago • 0 comments

Describe the bug

Working with generics and structs at comptime I'm running into the issue that it only works correctly for one struct, or if the other structs have fields with the same names.

Expected Behavior

Fields and values are correctly recognized.

Current Behavior

Decoding a single struct by itself makes no issues. With multiple structs values are only correct for the the last struct or if both nested structs have the same values.

Struct by itself:

S1{
    str: 'John'
    s1_child: S1Child{
        key: 'abc'
    }
}

2 Structs with differing fields:

S1{
    str: 'John'
    s1_child: S1Child{
        key: 'toml.Any(toml.Null{})' // <-- wrong value
    }
}
S2{
    str: 'John'
    s2_child: S2Child{
        other_key: 'def'
    }
}

2 Structs with same fields:

S1{
    str: 'John'
    s1_child: S1Child{
        key: 'abc'
    }
}
S2{
    str: 'John'
    s2_child: S2Child{
        key: 'def'
    }
}

Reproduction Steps

module main

import toml

struct S1 {
	str      string
	s1_child S1Child
}

struct S1Child {
	key string
}

struct S2 {
	str      string
	s2_child S2Child
}

struct S2Child {
	other_key string // using same field name `key`, gives the correct values.
}

fn main() {
	s := 'str = "John"
s1_child = { key = "abc" }'
	println(decode[S1](s)!)

	s2 := 'str = "John"
s2_child = { other_key = "def" }' // other_key / key
	// or commenting out the second decode makes decode no.1 work
	println(decode[S2](s2)!)
}

fn decode[T](toml_txt string) !T {
	doc := toml.parse_text(toml_txt)!

	mut typ := T{}
	decode_struct(doc.to_any(), mut typ)

	return typ
}

fn decode_struct[T](doc toml.Any, mut typ T) {
	$for field in T.fields {
		value := doc.value(field.name)
		$if field.typ is string {
			typ.$(field.name) = value.string()
		} $else $if field.typ is int {
			typ.$(field.name) = value.int()
		} $else $if field.is_struct {
			mut s := typ.$(field.name)
			decode_struct(value, mut s)
			typ.$(field.name) = s
		}
	}
}

Possible Solution

No response

Additional Information/Context

If it's of help providing other scenarios as full examples please let me know.

Things like: trying a different approach without passing a mutable struct but returning the decodes result gives a cgen error.

/tmp/v_1000/ct_struct.16472575457635537429.tmp.c:27441: error: '{' expected (got ";"
)
...

Or depending on the struct contents we might run into the error that - despite generics - Struct1 can't be used as Struct2.

V version

0.3.4

Environment details (OS name and version, etc.)

linux, arch

ttytm avatar May 04 '23 14:05 ttytm