guzba / sunny

JSON in Nim with Go-like field tags.
MIT License
14 stars 0 forks source link

[Bug] Type mismatch with nested object variants #14

Open Luyten-Orion opened 3 months ago

Luyten-Orion commented 3 months ago

Hey there, with this code:

import sunny

type
  LlmEventResponseKind* = enum
    leUnknown = "unknown", leResponse = "response", leLookup = "lookup", leVariable = "variable"

  LlmLookupKind* = enum
    lkDnd = "d&d", lkWikipedia = "wikipedia", lkWikiVg = "wiki.vg", lkWeb = "web"

  LlmVariableKind* = enum
    lvSet = "set"

  LlmEventResponse* {.acyclic.} = object
    case kind* {.json: "event,required".}: LlmEventResponseKind
    of leUnknown:
      discard
    of leResponse:
      content* {.json: ",required".}: string
      id* {.json: ",required".}: string
    of leLookup:
      lookupKind* {.json: "type,required".}: LlmLookupKind
      query* {.json: ",required".}: string
    of leVariable:
      case variableKind* {.json: "type,required".}: LlmVariableKind
      of lvSet:
        key* {.json: "key,required".}: seq[string]
        value* {.json: ",required".}: string

echo LlmEventResponse.fromJson(default(LlmEventResponse).toJson())

I get a type mismatch, with the specific error below:

Hint: used config file '/home/chronos/.nim/config/nim.cfg' [Conf]
Hint: used config file '/home/chronos/.nim/config/config.nims' [Conf]
.........................................................................................................
/home/chronos/test/main.nim(29, 22) template/generic instantiation of `fromJson` from here
/home/chronos/.nimble/pkgs2/sunny-0.1.9-28b4b3459505b23011ff2e468755edc7b5536053/sunny.nim(1127, 9) template/generic instantiation of `fromJson` from here
/home/chronos/.nimble/pkgs2/sunny-0.1.9-28b4b3459505b23011ff2e468755edc7b5536053/sunny.nim(1104, 34) template/generic instantiation of `workAroundNimIssue19773` from here
/home/chronos/.nimble/pkgs2/sunny-0.1.9-28b4b3459505b23011ff2e468755edc7b5536053/sunny.nim(1090, 25) Error: type mismatch
Expression: fromJson(obj.variableKind, value.o[i`gensym88][1], input)
  [1] obj.variableKind: LlmVariableKind
  [2] value.o[i`gensym88][1]: JsonValue
  [3] input: string

Expected one of (first mismatch at [position]):
[1] proc fromJson(v: var RawJson; value: JsonValue; input: string)
[1] proc fromJson(v: var SomeFloat; value: JsonValue; input: string)
[1] proc fromJson(v: var SomeSignedInt; value: JsonValue; input: string)
[1] proc fromJson(v: var SomeUnsignedInt; value: JsonValue; input: string)
[1] proc fromJson(v: var bool; value: JsonValue; input: string)
[1] proc fromJson(v: var char; value: JsonValue; input: string)
[1] proc fromJson(v: var std.JsonNode; value: JsonValue; input: string)
[1] proc fromJson(v: var string; value: JsonValue; input: string)
[1] proc fromJson[T: array](v: var T; value: JsonValue; input: string)
[1] proc fromJson[T: distinct](v: var T; value: JsonValue; input: string)
[1] proc fromJson[T: enum](v: var T; value: JsonValue; input: string)
  expression 'obj.variableKind' is immutable, not 'var'
[1] proc fromJson[T: object](obj: var T; value: JsonValue; input: string)
[1] proc fromJson[T: ref](v: var T; value: JsonValue; input: string)
[1] proc fromJson[T: tuple](v: var T; value: JsonValue; input: string)
[1] proc fromJson[T](v: var (SomeSet[T] | set[T]); value: JsonValue; input: string)
[1] proc fromJson[T](v: var Option[T]; value: JsonValue; input: string)
[1] proc fromJson[T](v: var SomeTable[string, T]; value: JsonValue; input: string)
[1] proc fromJson[T](v: var seq[T]; value: JsonValue; input: string)
[1] proc fromJson[T](x: typedesc[T]; input: RawJson): T
[1] proc fromJson[T](x: typedesc[T]; input: string): T

It seems like it's an issue with nested object variants, as replacing the snippet

      case variableKind* {.json: "type,required".}: LlmVariableKind
      of lvSet:
        key* {.json: "key,required".}: seq[string]
        value* {.json: ",required".}: string

with

      variableKind* {.json: "type,required".}: LlmVariableKind
      key* {.json: "key,required".}: seq[string]
      value* {.json: ",required".}: string

Compiles just fine.

guzba commented 3 months ago

I don't think I support or have ever tested nested variant objects. This is more of a feature / improvement request. I've never found myself wanting nested variant so it is unlikely I'm going to add this in the near future.

Luyten-Orion commented 3 months ago

Fair enough, I can work around this anyway, but thought it was important to be put here, do you want me to change the name of the issue?

guzba commented 3 months ago

If you'd like to work on a PR for nested object variants (even just 1 extra level, not necessarily N-levels if that proves to be more annoying) I'd be happy to look at and merge a PR.

Even if not, keeping this issue open for tracking makes sense. It is a perfectly valid improvement to make.

Perhaps even a simpler PR detecting nested object variants and providing a better error message would be a big improvement.

I am not an expert on Nim macro stuff so this type of thing is much less pleasant for me vs "normal" programming.