Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(types): improve "The "remainder" field can only be the last field" inspection #1300

Merged
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Remove `org.ton.chain.any.v0` interface: PR [#1207](https://github.com/tact-lang/tact/pull/1207)
- To reduce fees, Tact no longer stores the parent contract code in the system cell that holds all the child contract codes used in `initOf`. Instead, the `MYCODE` instruction is used: PR [#1213](https://github.com/tact-lang/tact/pull/1213)
- Generated TS wrappers now use `const` where possible for variable declarations: PR [#1292](https://github.com/tact-lang/tact/pull/1292)
- 'The "remainder" field can only be the last field:' inspection now shows location: PR [#1300](https://github.com/tact-lang/tact/pull/1300)
anton-trunov marked this conversation as resolved.
Show resolved Hide resolved

### Fixed

Expand Down
347 changes: 346 additions & 1 deletion src/types/__snapshots__/resolveDescriptors.spec.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,16 @@ Line 8, col 1:
"
`;

exports[`resolveDescriptors should fail descriptors for message-decl-remainder-in-the-middle 1`] = `
"<unknown>:8:5: The "remainder" field can only be the last field of the message
Line 8, col 5:
7 | a: Int;
> 8 | s: Cell as remaining;
^~~~~~~~~~~~~~~~~~~~
9 | b: Int;
"
`;

exports[`resolveDescriptors should fail descriptors for message-negative-opcode-1 1`] = `
"<unknown>:1:9: Opcode of message "Foo" is negative ('-1') which is not allowed
Line 1, col 9:
Expand Down Expand Up @@ -590,7 +600,15 @@ Line 4, col 8:
"
`;

exports[`resolveDescriptors should fail descriptors for struct-decl-remainder-in-the-middle 1`] = `"The "remainder" field can only be the last field of the struct"`;
exports[`resolveDescriptors should fail descriptors for struct-decl-remainder-in-the-middle 1`] = `
"<unknown>:8:5: The "remainder" field can only be the last field of the struct
Line 8, col 5:
7 | a: Int;
> 8 | s: Cell as remaining;
^~~~~~~~~~~~~~~~~~~~
9 | b: Int;
"
`;

exports[`resolveDescriptors should fail descriptors for struct-decl-self-reference 1`] = `
"<unknown>:4:8: Self-referencing types are not supported: type "A" refers to itself in its definition
Expand Down Expand Up @@ -11937,6 +11955,333 @@ exports[`resolveDescriptors should resolve descriptors for map-value-as-varuint

exports[`resolveDescriptors should resolve descriptors for map-value-as-varuint 2`] = `[]`;

exports[`resolveDescriptors should resolve descriptors for message-decl-remainder 1`] = `
[
{
"ast": {
"attributes": [],
"declarations": [],
"id": 2,
"kind": "trait",
"loc": trait BaseTrait { },
"name": {
"id": 1,
"kind": "id",
"loc": BaseTrait,
"text": "BaseTrait",
},
"traits": [],
},
"constants": [],
"dependsOn": [],
"fields": [],
"functions": Map {},
"header": null,
"init": null,
"interfaces": [],
"kind": "trait",
"name": "BaseTrait",
"origin": "user",
"partialFieldCount": 0,
"receivers": [],
"signature": null,
"tlb": null,
"traits": [],
"uid": 1020,
},
{
"ast": {
"id": 4,
"kind": "primitive_type_decl",
"loc": primitive Int;,
"name": {
"id": 3,
"kind": "id",
"loc": Int,
"text": "Int",
},
},
"constants": [],
"dependsOn": [],
"fields": [],
"functions": Map {},
"header": null,
"init": null,
"interfaces": [],
"kind": "primitive_type_decl",
"name": "Int",
"origin": "user",
"partialFieldCount": 0,
"receivers": [],
"signature": null,
"tlb": null,
"traits": [],
"uid": 38154,
},
{
"ast": {
"id": 6,
"kind": "primitive_type_decl",
"loc": primitive Cell;,
"name": {
"id": 5,
"kind": "id",
"loc": Cell,
"text": "Cell",
},
},
"constants": [],
"dependsOn": [],
"fields": [],
"functions": Map {},
"header": null,
"init": null,
"interfaces": [],
"kind": "primitive_type_decl",
"name": "Cell",
"origin": "user",
"partialFieldCount": 0,
"receivers": [],
"signature": null,
"tlb": null,
"traits": [],
"uid": 26294,
},
{
"ast": {
"fields": [
{
"as": null,
"id": 10,
"initializer": null,
"kind": "field_decl",
"loc": a: Int,
"name": {
"id": 8,
"kind": "id",
"loc": a,
"text": "a",
},
"type": {
"id": 9,
"kind": "type_id",
"loc": Int,
"text": "Int",
},
},
{
"as": null,
"id": 13,
"initializer": null,
"kind": "field_decl",
"loc": b: Int,
"name": {
"id": 11,
"kind": "id",
"loc": b,
"text": "b",
},
"type": {
"id": 12,
"kind": "type_id",
"loc": Int,
"text": "Int",
},
},
{
"as": {
"id": 16,
"kind": "id",
"loc": remaining,
"text": "remaining",
},
"id": 17,
"initializer": null,
"kind": "field_decl",
"loc": s: Cell as remaining,
"name": {
"id": 14,
"kind": "id",
"loc": s,
"text": "s",
},
"type": {
"id": 15,
"kind": "type_id",
"loc": Cell,
"text": "Cell",
},
},
],
"id": 18,
"kind": "message_decl",
"loc": message Test {
a: Int;
b: Int;
s: Cell as remaining;
},
"name": {
"id": 7,
"kind": "id",
"loc": Test,
"text": "Test",
},
"opcode": null,
},
"constants": [],
"dependsOn": [],
"fields": [
{
"abi": {
"name": "a",
"type": {
"format": 257,
"kind": "simple",
"optional": false,
"type": "int",
},
},
"as": null,
"ast": {
"as": null,
"id": 10,
"initializer": null,
"kind": "field_decl",
"loc": a: Int,
"name": {
"id": 8,
"kind": "id",
"loc": a,
"text": "a",
},
"type": {
"id": 9,
"kind": "type_id",
"loc": Int,
"text": "Int",
},
},
"default": undefined,
"index": 0,
"loc": a: Int,
"name": "a",
"type": {
"kind": "ref",
"name": "Int",
"optional": false,
},
},
{
"abi": {
"name": "b",
"type": {
"format": 257,
"kind": "simple",
"optional": false,
"type": "int",
},
},
"as": null,
"ast": {
"as": null,
"id": 13,
"initializer": null,
"kind": "field_decl",
"loc": b: Int,
"name": {
"id": 11,
"kind": "id",
"loc": b,
"text": "b",
},
"type": {
"id": 12,
"kind": "type_id",
"loc": Int,
"text": "Int",
},
},
"default": undefined,
"index": 1,
"loc": b: Int,
"name": "b",
"type": {
"kind": "ref",
"name": "Int",
"optional": false,
},
},
{
"abi": {
"name": "s",
"type": {
"format": "remainder",
"kind": "simple",
"optional": false,
"type": "cell",
},
},
"as": "remaining",
"ast": {
"as": {
"id": 16,
"kind": "id",
"loc": remaining,
"text": "remaining",
},
"id": 17,
"initializer": null,
"kind": "field_decl",
"loc": s: Cell as remaining,
"name": {
"id": 14,
"kind": "id",
"loc": s,
"text": "s",
},
"type": {
"id": 15,
"kind": "type_id",
"loc": Cell,
"text": "Cell",
},
},
"default": undefined,
"index": 2,
"loc": s: Cell as remaining,
"name": "s",
"type": {
"kind": "ref",
"name": "Cell",
"optional": false,
},
},
],
"functions": Map {},
"header": {
"base": 10,
"id": 0,
"kind": "number",
"loc": ,
"value": 3344478825n,
},
"init": null,
"interfaces": [],
"kind": "struct",
"name": "Test",
"origin": "user",
"partialFieldCount": 0,
"receivers": [],
"signature": "Test{a:int257,b:int257,s:remainder<cell>}",
"tlb": "test#c758b269 a:int257 b:int257 s:remainder<cell> = Test",
"traits": [],
"uid": 44104,
},
]
`;

exports[`resolveDescriptors should resolve descriptors for message-decl-remainder 2`] = `[]`;

exports[`resolveDescriptors should resolve descriptors for message-opcode-expr 1`] = `
[
{
Expand Down
5 changes: 4 additions & 1 deletion src/types/resolveSignatures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -187,8 +187,11 @@ export function resolveSignatures(ctx: CompilerContext, Ast: FactoryAst) {
// Check for no "remainder" in the middle of the struct
for (const field of t.fields.slice(0, -1)) {
if (field.as === "remaining") {
const kind =
t.ast.kind === "message_decl" ? "message" : "struct";
throwCompilationError(
`The "remainder" field can only be the last field of the struct`,
`The "remainder" field can only be the last field of the ${kind}`,
field.loc,
);
}
}
Expand Down
10 changes: 10 additions & 0 deletions src/types/test-failed/message-decl-remainder-in-the-middle.tact
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
trait BaseTrait { }

primitive Int;
primitive Cell;

message Test {
a: Int;
s: Cell as remaining;
b: Int;
}
Loading
Loading