Skip to content

$zero(field.typ.payload_type) inside $for field in T.fields uses the same payload type for every option field #26996

@enghitalo

Description

@enghitalo

Describe the bug

Inside $for field in T.fields, when a struct has multiple ?T fields with different non-pointer payload types, $zero(field.typ.payload_type) resolves to the same payload type for every iteration (the last one) instead of the current field's payload type. This causes a C compilation error.

Introduced by 8b5f74e.

Related: #26995 — same family of bug for T.pointee_type.

Reproduction Steps

module main

struct Foo {
mut:
    a ?int
    b ?string
}

fn fill[T](mut x T) {
    $for field in T.fields {
        $if field.typ is $option {
            mut v := $zero(field.typ.payload_type)
            x.$(field.name) = v
        }
    }
}

fn main() {
    mut f := Foo{}
    fill(mut f)
    dump(f)
}

Expected Behavior

Compile cleanly. f.a becomes Some(0) and f.b becomes Some('').

Current Behavior

================== C compilation error (from tcc): ==============
cc: /tmp/v_1000/<...>.tmp.c:8530: error: cannot convert 'struct string' to 'int'
=================================================================

With gcc:

error: incompatible types when initializing type 'int' using type 'string'
 8530 |    builtin___option_ok(&(int[]) { v }, (_option*)(&_t2), sizeof(int));

Generated C for the a: ?int iteration declares v as string (the payload type of b: ?string, the last option field) and then tries to wrap it in _option_int, hence the type mismatch.

Possible Solution

Resolve field.typ.payload_type per-iteration of $for field in T.fields instead of using a single resolved type for the whole expansion.

V version

V 0.5.1 6dd9033.eb1d47b

Environment details

linux, Ubuntu 24.04 LTS, gcc 14.2.0, tcc 0.9.28rc

Note

You can use the 👍 reaction to increase the issue's priority for developers.

Please note that only the 👍 reaction to the issue itself counts as a vote.
Other reactions and those to comments will not be taken into account.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions