odin-lang / Odin

Odin Programming Language
https://odin-lang.org
BSD 3-Clause "New" or "Revised" License
6.17k stars 550 forks source link

encoding/json: unmarshal uses the first struct in a union of structs #3474

Open Feoramund opened 2 months ago

Feoramund commented 2 months ago

Context

json.unmarshal seems to be ignoring alternative structs in a union, because if it doesn't find the fields it's looking for on the first struct variant it tries, it parses it as any value, skipping the other possibilities.

https://github.com/odin-lang/Odin/blob/5b6c96cd18af9818c37ecdef5130d79ca7149b87/core/encoding/json/unmarshal.odin#L461-L474

Odin:    dev-2024-04:2416380f3
OS:      Arch Linux, Linux 6.8.7-arch1-1
CPU:     12th Gen Intel(R) Core(TM) i7-12700K
RAM:     31916 MiB
Backend: LLVM 14.0.6

Expected Behavior

JSON unmarshalling to B instead of A, or some sort of error/advisory/workaround.

Current Behavior

Invalid type assertion from U to B, actual type: A

Failure Information (for bugs)

Steps to Reproduce

package main

import "core:encoding/json"

A :: struct {
    a: int,
}

B :: struct {
    b: string,
}

U :: union {
    rawptr,
    A,
    B,
}

main :: proc() {
    u: U

    error := json.unmarshal_string(`{"b": "Hellope"}`, &u)
    assert(error == nil)
    assert(u.(B).b == "Hellope")
}
gingerBill commented 2 months ago

So this is actually tricky to handle correctly because it has to do a best fit search, and currently it does the "first fit" search. In the case other structs, a missing field might not be an error, so it just gets ignored.