diff --git a/CHANGELOG.md b/CHANGELOG.md index 64c75a964..ba52d4359 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - The implicit empty `init` function is now present by default in the contract if not declared: PR [#167](https://github.com/tact-lang/tact/pull/167) - `@stdlib/stoppable` now imports `@stdlib/ownable` so the programmer does not have to do it separately: PR [#193](https://github.com/tact-lang/tact/pull/193) - Support escape sequences for strings (`\\`, `\"`, `\n`, `\r`, `\t`, `\v`, `\b`, `\f`, `\u{0}` through `\u{FFFFFF}`, `\u0000` through `\uFFFF`, `\x00` through `\xFF`): PR [#192](https://github.com/tact-lang/tact/pull/192) +- `newAddress` function now evaluates to a constant value if possible: PR [#237](https://github.com/tact-lang/tact/pull/237) ### Fixed diff --git a/src/test/feature-constants.spec.ts b/src/test/feature-constants.spec.ts new file mode 100644 index 000000000..b1f36a084 --- /dev/null +++ b/src/test/feature-constants.spec.ts @@ -0,0 +1,35 @@ +import { toNano } from "@ton/core"; +import { ContractSystem } from "@tact-lang/emulator"; +import { __DANGER_resetNodeId } from "../grammar/ast"; +import { ConstantTester } from "./features/output/constants_ConstantTester"; + +describe("feature-constants", () => { + beforeEach(() => { + __DANGER_resetNodeId(); + }); + it("should implement constants correctly", async () => { + // Init + const system = await ContractSystem.create(); + const treasure = system.treasure("treasure"); + const contract = system.open(await ConstantTester.fromInit()); + await contract.send(treasure, { value: toNano("10") }, null); + await system.run(); + + // Check methods + expect(await contract.getSomething1()).toEqual(11n); + expect(await contract.getSomething2()).toBeNull(); + expect(await contract.getSomething3()).toEqual(toNano("123")); + expect(await contract.getSomething4()).toEqual(toNano("456")); + expect(await contract.getSomething5()).toEqual("Hello world!"); + expect(await contract.getSomething6()).toEqual(10n); + expect(await contract.getSomething7()).toEqual(5n); + expect(await contract.getSomething8()).toEqual(4n); + expect((await contract.getSomething9()).toRawString()).toEqual( + "0:4a81708d2cf7b15a1b362fbf64880451d698461f52f05f145b36c08517d76873", + ); + expect((await contract.getSomething10()).toRawString()).toEqual( + "0:4a81708d2cf7b15a1b362fbf64880451d698461f52f05f145b36c08517d76873", + ); + expect(await contract.getGlobalConst()).toEqual(100n); + }); +}); diff --git a/src/test/features/constants.tact b/src/test/features/constants.tact index 7d7f0c89a..7042cdba1 100644 --- a/src/test/features/constants.tact +++ b/src/test/features/constants.tact @@ -9,11 +9,17 @@ contract ConstantTester { const something6: Int = 10 * 1; const something7: Int = 10 >> 1; const something8: Int = (2 + 4) & 4; + const something9: Address = address("UQBKgXCNLPexWhs2L79kiARR1phGH1LwXxRbNsCFF9doczSI"); + const something10: Address = newAddress(0, 0x4a81708d2cf7b15a1b362fbf64880451d698461f52f05f145b36c08517d76873); init() { } + receive() { + + } + get fun something1(): Int { return self.something1; } @@ -46,6 +52,14 @@ contract ConstantTester { return self.something8; } + get fun something9(): Address { + return self.something9; + } + + get fun something10(): Address { + return self.something10; + } + get fun globalConst(): Int { return someGlobalConst; } diff --git a/src/types/resolveConstantValue.ts b/src/types/resolveConstantValue.ts index 6a4d3f118..7dc4df07b 100644 --- a/src/types/resolveConstantValue.ts +++ b/src/types/resolveConstantValue.ts @@ -121,6 +121,29 @@ function reduceAddress(ast: ASTExpression, ctx: CompilerContext): Address { } return address; } + } else if (ast.name === "newAddress") { + if (ast.args.length === 2) { + const wc = reduceInt(ast.args[0]); + const addr = Buffer.from( + reduceInt(ast.args[1]).toString(16), + "hex", + ); + if (wc !== 0n && wc !== -1n) { + throwError( + `Expected workchain to equal 0 or -1, received: ${wc}`, + ast.ref, + ); + } + if (!enabledMasterchain(ctx)) { + if (wc !== 0n) { + throwError( + `Address ${wc}:${addr} from masterchain are not enabled for this contract`, + ast.ref, + ); + } + } + return new Address(parseInt(wc.toString()), addr); + } } } throwError("Cannot reduce expression to a constant Address", ast.ref);