From 9f1a72d06c42ea8020be872399a4098318503be8 Mon Sep 17 00:00:00 2001 From: Gusarich Date: Wed, 19 Jun 2024 13:43:41 +0300 Subject: [PATCH] implement for structs and fields --- .../const-string-receiver.spec.ts.snap | 140 +++- .../const-string-receiver.spec.ts | 2 + .../contracts/const-string-receiver.tact | 24 + .../resolveDescriptors.spec.ts.snap | 712 +++++++++++++++++- src/types/resolveDescriptors.ts | 77 +- ...tract-const-string-receiver-not-found.tact | 24 + ...ract-const-string-receiver-not-found2.tact | 24 + ...ract-const-string-receiver-not-found3.tact | 28 + ...ract-duplicate-const-string-receiver5.tact | 10 +- .../test/contract-const-string-receiver.tact | 20 + .../test/contract-const-string-receiver2.tact | 18 + 11 files changed, 1022 insertions(+), 57 deletions(-) create mode 100644 src/types/test-failed/contract-const-string-receiver-not-found.tact create mode 100644 src/types/test-failed/contract-const-string-receiver-not-found2.tact create mode 100644 src/types/test-failed/contract-const-string-receiver-not-found3.tact create mode 100644 src/types/test/contract-const-string-receiver.tact create mode 100644 src/types/test/contract-const-string-receiver2.tact diff --git a/src/test/e2e-emulated/__snapshots__/const-string-receiver.spec.ts.snap b/src/test/e2e-emulated/__snapshots__/const-string-receiver.spec.ts.snap index 4c3de2697..ae2fb0596 100644 --- a/src/test/e2e-emulated/__snapshots__/const-string-receiver.spec.ts.snap +++ b/src/test/e2e-emulated/__snapshots__/const-string-receiver.spec.ts.snap @@ -112,6 +112,20 @@ exports[`constant string receiver should implement const string receiver correct }, "receiver": "internal", }, + { + "message": { + "kind": "text", + "text": "string 5", + }, + "receiver": "internal", + }, + { + "message": { + "kind": "text", + "text": "string 6", + }, + "receiver": "internal", + }, ], "types": [ { @@ -239,6 +253,34 @@ exports[`constant string receiver should implement const string receiver correct "header": null, "name": "SendParameters", }, + { + "fields": [ + { + "name": "s", + "type": { + "kind": "simple", + "optional": false, + "type": "string", + }, + }, + ], + "header": null, + "name": "MyStruct", + }, + { + "fields": [ + { + "name": "struct", + "type": { + "kind": "simple", + "optional": false, + "type": "MyStruct", + }, + }, + ], + "header": null, + "name": "MyNestedStruct", + }, ], } `; @@ -257,7 +299,7 @@ exports[`constant string receiver should implement const string receiver correct }, "bounce": true, "from": "@treasure(treasure)", - "to": "kQCjCGWLilNv7PPffKoWdQHPZ-88MekCb9F_U5ddfPTsuH3_", + "to": "kQBO2__AL4wOwtXplvVV7psQ7PAJKpbbqzS36LyZWcW01Pl7", "type": "internal", "value": "10", }, @@ -275,7 +317,7 @@ exports[`constant string receiver should implement const string receiver correct "type": "text", }, "bounce": true, - "from": "kQCjCGWLilNv7PPffKoWdQHPZ-88MekCb9F_U5ddfPTsuH3_", + "from": "kQBO2__AL4wOwtXplvVV7psQ7PAJKpbbqzS36LyZWcW01Pl7", "to": "@treasure(treasure)", "type": "internal", "value": "9.991947", @@ -296,7 +338,7 @@ exports[`constant string receiver should implement const string receiver correct }, "bounce": true, "from": "@treasure(treasure)", - "to": "kQCjCGWLilNv7PPffKoWdQHPZ-88MekCb9F_U5ddfPTsuH3_", + "to": "kQBO2__AL4wOwtXplvVV7psQ7PAJKpbbqzS36LyZWcW01Pl7", "type": "internal", "value": "10", }, @@ -314,7 +356,7 @@ exports[`constant string receiver should implement const string receiver correct "type": "text", }, "bounce": true, - "from": "kQCjCGWLilNv7PPffKoWdQHPZ-88MekCb9F_U5ddfPTsuH3_", + "from": "kQBO2__AL4wOwtXplvVV7psQ7PAJKpbbqzS36LyZWcW01Pl7", "to": "@treasure(treasure)", "type": "internal", "value": "9.989336", @@ -335,7 +377,7 @@ exports[`constant string receiver should implement const string receiver correct }, "bounce": true, "from": "@treasure(treasure)", - "to": "kQCjCGWLilNv7PPffKoWdQHPZ-88MekCb9F_U5ddfPTsuH3_", + "to": "kQBO2__AL4wOwtXplvVV7psQ7PAJKpbbqzS36LyZWcW01Pl7", "type": "internal", "value": "10", }, @@ -353,7 +395,7 @@ exports[`constant string receiver should implement const string receiver correct "type": "text", }, "bounce": true, - "from": "kQCjCGWLilNv7PPffKoWdQHPZ-88MekCb9F_U5ddfPTsuH3_", + "from": "kQBO2__AL4wOwtXplvVV7psQ7PAJKpbbqzS36LyZWcW01Pl7", "to": "@treasure(treasure)", "type": "internal", "value": "9.989223", @@ -374,14 +416,14 @@ exports[`constant string receiver should implement const string receiver correct }, "bounce": true, "from": "@treasure(treasure)", - "to": "kQCjCGWLilNv7PPffKoWdQHPZ-88MekCb9F_U5ddfPTsuH3_", + "to": "kQBO2__AL4wOwtXplvVV7psQ7PAJKpbbqzS36LyZWcW01Pl7", "type": "internal", "value": "10", }, }, { "$type": "processed", - "gasUsed": 9730n, + "gasUsed": 9766n, }, { "$type": "sent", @@ -392,10 +434,88 @@ exports[`constant string receiver should implement const string receiver correct "type": "text", }, "bounce": true, - "from": "kQCjCGWLilNv7PPffKoWdQHPZ-88MekCb9F_U5ddfPTsuH3_", + "from": "kQBO2__AL4wOwtXplvVV7psQ7PAJKpbbqzS36LyZWcW01Pl7", + "to": "@treasure(treasure)", + "type": "internal", + "value": "9.989038", + }, + ], + }, + ], + }, + { + "$seq": 5, + "events": [ + { + "$type": "received", + "message": { + "body": { + "text": "string 5", + "type": "text", + }, + "bounce": true, + "from": "@treasure(treasure)", + "to": "kQBO2__AL4wOwtXplvVV7psQ7PAJKpbbqzS36LyZWcW01Pl7", + "type": "internal", + "value": "10", + }, + }, + { + "$type": "processed", + "gasUsed": 7453n, + }, + { + "$type": "sent", + "messages": [ + { + "body": { + "text": "string 5", + "type": "text", + }, + "bounce": true, + "from": "kQBO2__AL4wOwtXplvVV7psQ7PAJKpbbqzS36LyZWcW01Pl7", + "to": "@treasure(treasure)", + "type": "internal", + "value": "9.991351", + }, + ], + }, + ], + }, + { + "$seq": 6, + "events": [ + { + "$type": "received", + "message": { + "body": { + "text": "string 6", + "type": "text", + }, + "bounce": true, + "from": "@treasure(treasure)", + "to": "kQBO2__AL4wOwtXplvVV7psQ7PAJKpbbqzS36LyZWcW01Pl7", + "type": "internal", + "value": "10", + }, + }, + { + "$type": "processed", + "gasUsed": 7602n, + }, + { + "$type": "sent", + "messages": [ + { + "body": { + "text": "string 6", + "type": "text", + }, + "bounce": true, + "from": "kQBO2__AL4wOwtXplvVV7psQ7PAJKpbbqzS36LyZWcW01Pl7", "to": "@treasure(treasure)", "type": "internal", - "value": "9.989074", + "value": "9.991202", }, ], }, diff --git a/src/test/e2e-emulated/const-string-receiver.spec.ts b/src/test/e2e-emulated/const-string-receiver.spec.ts index 88f5fe823..f119bb0a3 100644 --- a/src/test/e2e-emulated/const-string-receiver.spec.ts +++ b/src/test/e2e-emulated/const-string-receiver.spec.ts @@ -27,6 +27,8 @@ describe("constant string receiver", () => { await contract.send(treasure, { value: toNano("10") }, "string 2"); await contract.send(treasure, { value: toNano("10") }, "string 3"); await contract.send(treasure, { value: toNano("10") }, "string 4"); + await contract.send(treasure, { value: toNano("10") }, "string 5"); + await contract.send(treasure, { value: toNano("10") }, "string 6"); await system.run(); expect(tracker.collect()).toMatchSnapshot(); diff --git a/src/test/e2e-emulated/contracts/const-string-receiver.tact b/src/test/e2e-emulated/contracts/const-string-receiver.tact index b0f37186b..b514a5c27 100644 --- a/src/test/e2e-emulated/contracts/const-string-receiver.tact +++ b/src/test/e2e-emulated/contracts/const-string-receiver.tact @@ -2,8 +2,24 @@ const string1: String = "string 1"; const string2: String = "string 2"; const string3: String = "string 3"; +struct MyStruct { + s: String; +} + +struct MyNestedStruct { + struct: MyStruct; +} + contract ConstStringReceiverTester { const string4: String = "string 4"; + const struct: MyStruct = MyStruct { + s: "string 5" + }; + const nestedStruct: MyNestedStruct = MyNestedStruct { + struct: MyStruct { + s: "string 6" + } + }; receive() { } @@ -22,4 +38,12 @@ contract ConstStringReceiverTester { receive(self.string4) { self.reply(self.string4.asComment()); } + + receive(self.struct.s) { + self.reply("string 5".asComment()); // until const struct fields are fixed + } + + receive(self.nestedStruct.struct.s) { + self.reply("string 6".asComment()); // until const struct fields are fixed + } } \ No newline at end of file diff --git a/src/types/__snapshots__/resolveDescriptors.spec.ts.snap b/src/types/__snapshots__/resolveDescriptors.spec.ts.snap index 74f26fdca..4e42d50f4 100644 --- a/src/types/__snapshots__/resolveDescriptors.spec.ts.snap +++ b/src/types/__snapshots__/resolveDescriptors.spec.ts.snap @@ -30,6 +30,36 @@ Line 15, col 3: " `; +exports[`resolveDescriptors should fail descriptors for contract-const-string-receiver-not-found 1`] = ` +":21:5: Constant "self.struct.s2" not found +Line 21, col 5: + 20 | +> 21 | receive(self.struct.s2) { + ^~~~~~~~~~~~~~~~~~~~~~~~~ + 22 | +" +`; + +exports[`resolveDescriptors should fail descriptors for contract-const-string-receiver-not-found2 1`] = ` +":21:5: Constant "self.struct2.s" not found +Line 21, col 5: + 20 | +> 21 | receive(self.struct2.s) { + ^~~~~~~~~~~~~~~~~~~~~~~~~ + 22 | +" +`; + +exports[`resolveDescriptors should fail descriptors for contract-const-string-receiver-not-found3 1`] = ` +":25:5: Constant "self.struct.s" not found +Line 25, col 5: + 24 | +> 25 | receive(self.struct.s) { + ^~~~~~~~~~~~~~~~~~~~~~~~ + 26 | +" +`; + exports[`resolveDescriptors should fail descriptors for contract-duplicate-bounced-fallback-receiver 1`] = ` ":24:3: Fallback bounce receive function already exists Line 24, col 3: @@ -91,12 +121,12 @@ Line 15, col 5: `; exports[`resolveDescriptors should fail descriptors for contract-duplicate-const-string-receiver5 1`] = ` -":25:5: Invalid comment receiver selector -Line 25, col 5: - 24 | -> 25 | receive(self.struct.s) { +":21:5: Receive function for string "string 1" already exists +Line 21, col 5: + 20 | +> 21 | receive(self.struct.s) { ^~~~~~~~~~~~~~~~~~~~~~~~ - 26 | + 22 | " `; @@ -1220,6 +1250,678 @@ exports[`resolveDescriptors should resolve descriptors for contract-bounced-too- exports[`resolveDescriptors should resolve descriptors for contract-bounced-too-small-not-detected 2`] = `{}`; +exports[`resolveDescriptors should resolve descriptors for contract-const-string-receiver 1`] = ` +{ + "BaseTrait": { + "ast": { + "attributes": [], + "declarations": [], + "id": 3, + "kind": "def_trait", + "name": "BaseTrait", + "origin": "user", + "ref": trait 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, + }, + "Int": { + "ast": { + "id": 1, + "kind": "primitive", + "name": "Int", + "origin": "user", + "ref": primitive Int;, + }, + "constants": [], + "dependsOn": [], + "fields": [], + "functions": Map {}, + "header": null, + "init": null, + "interfaces": [], + "kind": "primitive", + "name": "Int", + "origin": "user", + "partialFieldCount": 0, + "receivers": [], + "signature": null, + "tlb": null, + "traits": [], + "uid": 38154, + }, + "Main": { + "ast": { + "attributes": [], + "declarations": [ + { + "attributes": [], + "id": 11, + "kind": "def_constant", + "name": "struct", + "ref": const struct: MyStruct = MyStruct { + s: "string 1" + };, + "type": { + "id": 7, + "kind": "type_ref_simple", + "name": "MyStruct", + "optional": false, + "ref": MyStruct, + }, + "value": { + "args": [ + { + "exp": { + "id": 8, + "kind": "string", + "ref": "string 1", + "value": "string 1", + }, + "id": 9, + "kind": "new_parameter", + "name": "s", + "ref": s: "string 1", + }, + ], + "id": 10, + "kind": "op_new", + "ref": MyStruct { + s: "string 1" + }, + "type": "MyStruct", + }, + }, + { + "id": 15, + "kind": "def_receive", + "ref": receive(self.struct.s) { + + }, + "selector": { + "comment": [ + { + "id": 12, + "kind": "lvalue_ref", + "name": "self", + "ref": self., + }, + { + "id": 13, + "kind": "lvalue_ref", + "name": "struct", + "ref": struct., + }, + { + "id": 14, + "kind": "lvalue_ref", + "name": "s", + "ref": s, + }, + ], + "kind": "internal-const-comment", + }, + "statements": [], + }, + ], + "id": 16, + "kind": "def_contract", + "name": "Main", + "origin": "user", + "ref": contract Main { + const struct: MyStruct = MyStruct { + s: "string 1" + }; + + receive(self.struct.s) { + + } +}, + "traits": [], + }, + "constants": [ + { + "ast": { + "attributes": [], + "id": 11, + "kind": "def_constant", + "name": "struct", + "ref": const struct: MyStruct = MyStruct { + s: "string 1" + };, + "type": { + "id": 7, + "kind": "type_ref_simple", + "name": "MyStruct", + "optional": false, + "ref": MyStruct, + }, + "value": { + "args": [ + { + "exp": { + "id": 8, + "kind": "string", + "ref": "string 1", + "value": "string 1", + }, + "id": 9, + "kind": "new_parameter", + "name": "s", + "ref": s: "string 1", + }, + ], + "id": 10, + "kind": "op_new", + "ref": MyStruct { + s: "string 1" + }, + "type": "MyStruct", + }, + }, + "name": "struct", + "ref": const struct: MyStruct = MyStruct { + s: "string 1" + };, + "type": { + "kind": "ref", + "name": "MyStruct", + "optional": false, + }, + "value": { + "$tactStruct": "MyStruct", + "s": "string 1", + }, + }, + ], + "dependsOn": [], + "fields": [], + "functions": Map {}, + "header": null, + "init": { + "args": [], + "ast": { + "args": [], + "id": 18, + "kind": "def_init_function", + "ref": contract Main { + const struct: MyStruct = MyStruct { + s: "string 1" + }; + + receive(self.struct.s) { + + } +}, + "statements": [], + }, + }, + "interfaces": [], + "kind": "contract", + "name": "Main", + "origin": "user", + "partialFieldCount": 0, + "receivers": [ + { + "ast": { + "id": 15, + "kind": "def_receive", + "ref": receive(self.struct.s) { + + }, + "selector": { + "comment": [ + { + "id": 12, + "kind": "lvalue_ref", + "name": "self", + "ref": self., + }, + { + "id": 13, + "kind": "lvalue_ref", + "name": "struct", + "ref": struct., + }, + { + "id": 14, + "kind": "lvalue_ref", + "name": "s", + "ref": s, + }, + ], + "kind": "internal-const-comment", + }, + "statements": [], + }, + "selector": { + "comment": "string 1", + "kind": "internal-comment", + }, + }, + ], + "signature": null, + "tlb": null, + "traits": [ + { + "ast": { + "attributes": [], + "declarations": [], + "id": 3, + "kind": "def_trait", + "name": "BaseTrait", + "origin": "user", + "ref": trait 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, + }, + ], + "uid": 51099, + }, + "MyStruct": { + "ast": { + "fields": [ + { + "as": null, + "id": 5, + "init": null, + "kind": "def_field", + "name": "s", + "ref": s: String, + "type": { + "id": 4, + "kind": "type_ref_simple", + "name": "String", + "optional": false, + "ref": String, + }, + }, + ], + "id": 6, + "kind": "def_struct", + "message": false, + "name": "MyStruct", + "origin": "user", + "prefix": null, + "ref": struct MyStruct { + s: String; +}, + }, + "constants": [], + "dependsOn": [], + "fields": [ + { + "abi": { + "name": "s", + "type": { + "kind": "simple", + "optional": false, + "type": "string", + }, + }, + "as": null, + "ast": { + "as": null, + "id": 5, + "init": null, + "kind": "def_field", + "name": "s", + "ref": s: String, + "type": { + "id": 4, + "kind": "type_ref_simple", + "name": "String", + "optional": false, + "ref": String, + }, + }, + "default": undefined, + "index": 0, + "name": "s", + "ref": s: String, + "type": { + "kind": "ref", + "name": "String", + "optional": false, + }, + }, + ], + "functions": Map {}, + "header": null, + "init": null, + "interfaces": [], + "kind": "struct", + "name": "MyStruct", + "origin": "user", + "partialFieldCount": 0, + "receivers": [], + "signature": "MyStruct{s:^string}", + "tlb": "_ s:^string = MyStruct", + "traits": [], + "uid": 55650, + }, + "String": { + "ast": { + "id": 2, + "kind": "primitive", + "name": "String", + "origin": "user", + "ref": primitive String;, + }, + "constants": [], + "dependsOn": [], + "fields": [], + "functions": Map {}, + "header": null, + "init": null, + "interfaces": [], + "kind": "primitive", + "name": "String", + "origin": "user", + "partialFieldCount": 0, + "receivers": [], + "signature": null, + "tlb": null, + "traits": [], + "uid": 46199, + }, +} +`; + +exports[`resolveDescriptors should resolve descriptors for contract-const-string-receiver 2`] = `{}`; + +exports[`resolveDescriptors should resolve descriptors for contract-const-string-receiver2 1`] = ` +{ + "BaseTrait": { + "ast": { + "attributes": [], + "declarations": [], + "id": 6, + "kind": "def_trait", + "name": "BaseTrait", + "origin": "user", + "ref": trait 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, + }, + "Int": { + "ast": { + "id": 1, + "kind": "primitive", + "name": "Int", + "origin": "user", + "ref": primitive Int;, + }, + "constants": [], + "dependsOn": [], + "fields": [], + "functions": Map {}, + "header": null, + "init": null, + "interfaces": [], + "kind": "primitive", + "name": "Int", + "origin": "user", + "partialFieldCount": 0, + "receivers": [], + "signature": null, + "tlb": null, + "traits": [], + "uid": 38154, + }, + "Main": { + "ast": { + "attributes": [], + "declarations": [ + { + "id": 8, + "kind": "def_receive", + "ref": receive("string 1") { + + }, + "selector": { + "comment": { + "id": 7, + "kind": "string", + "ref": "string 1", + "value": "string 1", + }, + "kind": "internal-comment", + }, + "statements": [], + }, + { + "id": 10, + "kind": "def_receive", + "ref": receive(string2) { + + }, + "selector": { + "comment": [ + { + "id": 9, + "kind": "lvalue_ref", + "name": "string2", + "ref": string2, + }, + ], + "kind": "internal-const-comment", + }, + "statements": [], + }, + ], + "id": 11, + "kind": "def_contract", + "name": "Main", + "origin": "user", + "ref": contract Main { + receive("string 1") { + + } + + receive(string2) { + + } +}, + "traits": [], + }, + "constants": [], + "dependsOn": [], + "fields": [], + "functions": Map {}, + "header": null, + "init": { + "args": [], + "ast": { + "args": [], + "id": 13, + "kind": "def_init_function", + "ref": contract Main { + receive("string 1") { + + } + + receive(string2) { + + } +}, + "statements": [], + }, + }, + "interfaces": [], + "kind": "contract", + "name": "Main", + "origin": "user", + "partialFieldCount": 0, + "receivers": [ + { + "ast": { + "id": 8, + "kind": "def_receive", + "ref": receive("string 1") { + + }, + "selector": { + "comment": { + "id": 7, + "kind": "string", + "ref": "string 1", + "value": "string 1", + }, + "kind": "internal-comment", + }, + "statements": [], + }, + "selector": { + "comment": "string 1", + "kind": "internal-comment", + }, + }, + { + "ast": { + "id": 10, + "kind": "def_receive", + "ref": receive(string2) { + + }, + "selector": { + "comment": [ + { + "id": 9, + "kind": "lvalue_ref", + "name": "string2", + "ref": string2, + }, + ], + "kind": "internal-const-comment", + }, + "statements": [], + }, + "selector": { + "comment": "string 2", + "kind": "internal-comment", + }, + }, + ], + "signature": null, + "tlb": null, + "traits": [ + { + "ast": { + "attributes": [], + "declarations": [], + "id": 6, + "kind": "def_trait", + "name": "BaseTrait", + "origin": "user", + "ref": trait 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, + }, + ], + "uid": 51099, + }, + "String": { + "ast": { + "id": 2, + "kind": "primitive", + "name": "String", + "origin": "user", + "ref": primitive String;, + }, + "constants": [], + "dependsOn": [], + "fields": [], + "functions": Map {}, + "header": null, + "init": null, + "interfaces": [], + "kind": "primitive", + "name": "String", + "origin": "user", + "partialFieldCount": 0, + "receivers": [], + "signature": null, + "tlb": null, + "traits": [], + "uid": 46199, + }, +} +`; + +exports[`resolveDescriptors should resolve descriptors for contract-const-string-receiver2 2`] = `{}`; + exports[`resolveDescriptors should resolve descriptors for contract-external-fallback-receiver 1`] = ` { "A": { diff --git a/src/types/resolveDescriptors.ts b/src/types/resolveDescriptors.ts index 1af3b084f..ee1294474 100644 --- a/src/types/resolveDescriptors.ts +++ b/src/types/resolveDescriptors.ts @@ -3,6 +3,7 @@ import { ASTField, ASTFunction, ASTInitFunction, + ASTLvalueRef, ASTNativeFunction, ASTNode, ASTRef, @@ -25,6 +26,7 @@ import { TypeOrigin, TypeRef, typeRefEquals, + Value, } from "./types"; import { getRawAST } from "../grammar/store"; import { cloneNode } from "../grammar/clone"; @@ -34,6 +36,7 @@ import { resolveABIType } from "./resolveABITypeRef"; import { enabledExternals } from "../config/features"; import { isRuntimeType } from "./isRuntimeType"; import { GlobalFunctions } from "../abi/global"; +import { Issue74 } from "../test/codegen/output/codegen_Issue74"; const store = createContextStore(); const staticFunctionsStore = createContextStore(); @@ -1033,54 +1036,58 @@ export function resolveDescriptors(ctx: CompilerContext) { const internal = d.selector.kind === "internal-const-comment"; - if ( - d.selector.comment.length > 2 || - (d.selector.comment.length == 2 && - d.selector.comment[0].name !== "self") - ) { - // TEMPORARY - // to be reworked after #284 and #400 are resolved - throwSyntaxError( - "Invalid comment receiver selector", - d.ref, - ); - } + let path = d.selector.comment; - const isSelf = - d.selector.comment.length === 2 && - d.selector.comment[0].name === "self"; + const pathString = path.map((v) => v.name).join("."); - const commentId = - d.selector.comment[d.selector.comment.length - 1] - .name; - const commentConstant = isSelf - ? s.constants.find((v) => v.name === commentId) - : staticConstants.get(commentId); + const isSelf = + path.length >= 2 && path[0].name === "self"; - if (!commentConstant) { - throwSyntaxError( - `Constant "${commentId}" not found`, - d.ref, + let commentConstant: ConstantDescription | undefined = + undefined; + if (isSelf) { + commentConstant = s.constants.find( + (v) => v.name === path[1].name, ); + path = path.slice(2); + } else { + commentConstant = staticConstants.get(path[0].name); + path = path.slice(1); } - if (commentConstant.type.kind !== "ref") { + let commentValue: Value | undefined = + commentConstant?.value; + + while (commentValue && path.length > 0) { + if ( + commentValue == null || + typeof commentValue !== "object" || + !("$tactStruct" in commentValue) + ) { + throwSyntaxError( + `Cannot find constant "${path[0].name}" in ${pathString}`, + d.ref, + ); + } + commentValue = commentValue[path[0].name]; + path = path.slice(1); + } + + if (!commentValue) { throwSyntaxError( - `Constant "${commentId}" must be a reference type`, + `Constant "${pathString}" not found`, d.ref, ); } - if (commentConstant.type.name !== "String") { + if (typeof commentValue !== "string") { throwSyntaxError( - `Constant "${commentId}" must be of type String`, + `Constant "${pathString}" must be of type String`, d.ref, ); } - const c = commentConstant.value as string; - - if (c === "") { + if (commentValue === "") { throwSyntaxError( "To use empty comment receiver, just remove argument instead of passing empty string", d.ref, @@ -1094,11 +1101,11 @@ export function resolveDescriptors(ctx: CompilerContext) { (internal ? "internal-comment" : "external-comment") && - v.selector.comment === c, + v.selector.comment === commentValue, ) ) { throwSyntaxError( - `Receive function for string "${c}" already exists`, + `Receive function for string "${commentValue}" already exists`, d.ref, ); } @@ -1107,7 +1114,7 @@ export function resolveDescriptors(ctx: CompilerContext) { kind: internal ? "internal-comment" : "external-comment", - comment: c, + comment: commentValue, }, ast: d, }); diff --git a/src/types/test-failed/contract-const-string-receiver-not-found.tact b/src/types/test-failed/contract-const-string-receiver-not-found.tact new file mode 100644 index 000000000..1eb75e2aa --- /dev/null +++ b/src/types/test-failed/contract-const-string-receiver-not-found.tact @@ -0,0 +1,24 @@ +primitive Int; +primitive String; + +trait BaseTrait { + +} + +struct MyStruct { + s: String; +} + +contract Main { + const struct: MyStruct = MyStruct { + s: "string 1" + }; + + receive("string 1") { + + } + + receive(self.struct.s2) { + + } +} \ No newline at end of file diff --git a/src/types/test-failed/contract-const-string-receiver-not-found2.tact b/src/types/test-failed/contract-const-string-receiver-not-found2.tact new file mode 100644 index 000000000..8daa49efd --- /dev/null +++ b/src/types/test-failed/contract-const-string-receiver-not-found2.tact @@ -0,0 +1,24 @@ +primitive Int; +primitive String; + +trait BaseTrait { + +} + +struct MyStruct { + s: String; +} + +contract Main { + const struct: MyStruct = MyStruct { + s: "string 1" + }; + + receive("string 1") { + + } + + receive(self.struct2.s) { + + } +} \ No newline at end of file diff --git a/src/types/test-failed/contract-const-string-receiver-not-found3.tact b/src/types/test-failed/contract-const-string-receiver-not-found3.tact new file mode 100644 index 000000000..dd4ead50c --- /dev/null +++ b/src/types/test-failed/contract-const-string-receiver-not-found3.tact @@ -0,0 +1,28 @@ +primitive Int; +primitive String; + +trait BaseTrait { + +} + +struct MyStruct { + s: String; +} + +contract Main { + struct: MyStruct; + + init () { + self.struct = MyStruct { + s: "string 1" + }; + } + + receive("string 1") { + + } + + receive(self.struct.s) { + + } +} \ No newline at end of file diff --git a/src/types/test-failed/contract-duplicate-const-string-receiver5.tact b/src/types/test-failed/contract-duplicate-const-string-receiver5.tact index dd4ead50c..315f1618a 100644 --- a/src/types/test-failed/contract-duplicate-const-string-receiver5.tact +++ b/src/types/test-failed/contract-duplicate-const-string-receiver5.tact @@ -10,13 +10,9 @@ struct MyStruct { } contract Main { - struct: MyStruct; - - init () { - self.struct = MyStruct { - s: "string 1" - }; - } + const struct: MyStruct = MyStruct { + s: "string 1" + }; receive("string 1") { diff --git a/src/types/test/contract-const-string-receiver.tact b/src/types/test/contract-const-string-receiver.tact new file mode 100644 index 000000000..cd0404fc3 --- /dev/null +++ b/src/types/test/contract-const-string-receiver.tact @@ -0,0 +1,20 @@ +primitive Int; +primitive String; + +trait BaseTrait { + +} + +struct MyStruct { + s: String; +} + +contract Main { + const struct: MyStruct = MyStruct { + s: "string 1" + }; + + receive(self.struct.s) { + + } +} \ No newline at end of file diff --git a/src/types/test/contract-const-string-receiver2.tact b/src/types/test/contract-const-string-receiver2.tact new file mode 100644 index 000000000..01729115e --- /dev/null +++ b/src/types/test/contract-const-string-receiver2.tact @@ -0,0 +1,18 @@ +primitive Int; +primitive String; + +const string2: String = "string 2"; + +trait BaseTrait { + +} + +contract Main { + receive("string 1") { + + } + + receive(string2) { + + } +} \ No newline at end of file