tact-lang / tact

Tact compiler main repository
https://tact-lang.org
MIT License
275 stars 56 forks source link

Struct field punning doesn't work with nested struct fields #355

Closed novusnota closed 1 month ago

novusnota commented 1 month ago

Consider the following example:

import "@stdlib/deploy";

message Add {
    queryId: Int as uint64;
    amount: Int as uint32;
}

message AddOk {
    queryId: Int as uint64;
    amount: Int as uint32;
}

contract TactCounter with Deployable {
    // ... some logic there ...

    receive(msg: Add) {
        self.reply(AddOk{msg.queryId, msg.amount}.toCell()); // ← this causes a syntax error
    }
}

One would expect for fields of Add to be automatically coerced with fields of AddOk, as they're named the same, have identical types and are layed out in the same order.


We may also consider making values of such 1-to-1 mapped types to be directly assignable to each other (duck typing of sorts), like:

receive(msg: Add) {
    let newMsg: AddOk = msg; // implicit type conversion
    self.reply(newMsg.toCell());
}

Although I'm not sure about the use case and bug-freeness of such approach, so just making struct field punning one level deeper than it is now would be more than enough.

Gusarich commented 1 month ago

One would expect for fields of Add to be automatically coerced with fields of AddOk, as they're named the same, have identical types and are layed out in the same order.

I'm not sure if we need this. It doesn't even work this way in Typescript (the following snippet doesn't compile):

type Test = {
    x: number;
    y: number;
}

const a: Test = {
    x: 123,
    y: 234,
};

const b: Test = {
    a.x,
    a.y
}
}
anton-trunov commented 1 month ago

Let me close this for now. Punning is not supposed to work with expressions that are not identifiers.