icerpc / icerpc-csharp

A C# RPC framework built for QUIC, with bidirectional streaming, first-class async/await, and Protobuf support.
https://docs.icerpc.dev
Apache License 2.0
101 stars 13 forks source link

Incorrect Generated Code for Tagged Custom Types in Slice1 #3918

Closed InsertCreativityHere closed 6 months ago

InsertCreativityHere commented 7 months ago

We allow custom types in Slice1 with the caveat that (per the docs):

If you use this custom type as an optional (with a ? suffix) outside of a tag context, you also need to supply methods to encode/decode a nullable value of this type. With our example:

But the generated code doesn't honor this. It will always use the nullable function, even in tagged contexts.

Example:

mode = Slice1
module Hello

[cs::type("DateTime")]
custom MyThing

class MyClass {
    tag(1) test: MyThing?
}

This generates:

    protected override void EncodeCore(ref SliceEncoder encoder)
    {
        encoder.StartSlice(SliceTypeId);
        if (this.Test is DateTime test_)
        {
            encoder.EncodeTagged(... => MyThingSliceEncoderExtensions.EncodeNullableMyThing(ref encoder, value));
        }
        encoder.EndSlice(true);
    }

    protected override void DecodeCore(ref SliceDecoder decoder)
    {
        decoder.StartSlice();
        this.Test = decoder.DecodeTagged(... => (DateTime?)MyThingSliceDecoderExtensions.DecodeNullableMyThing(ref decoder), useTagEndMarker: true);
        decoder.EndSlice();
    }

Note that we call 'EncodeNullable' and 'DecodeNullable' when we should be using the non-nullable versions.