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: allow optional types for self argument in extends mutates functions #854

Merged
merged 8 commits into from
Oct 1, 2024
Merged
Show file tree
Hide file tree
Changes from 5 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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Changed

- Optional types for `self` argument in `extends mutates` functions are now allowed: PR [#854](https://github.com/tact-lang/tact/pull/854)

### Fixed

- Collisions in getter method ids are now handled and reported properly: PR [#875](https://github.com/tact-lang/tact/pull/875)
Expand Down
1 change: 1 addition & 0 deletions cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
"decompiling",
"dentry",
"Descr",
"DICTUSET",
anton-trunov marked this conversation as resolved.
Show resolved Hide resolved
"disasm",
"divmod",
"dnsresolve",
Expand Down
7 changes: 0 additions & 7 deletions src/generator/writers/writeExpression.ts
Original file line number Diff line number Diff line change
Expand Up @@ -558,13 +558,6 @@ export function writeExpression(f: AstExpression, wCtx: WriterContext): string {

// Reference type
if (selfTyRef.kind === "ref") {
if (selfTyRef.optional) {
throwCompilationError(
`Cannot call function of non - direct type: "${printTypeRef(selfTyRef)}"`,
f.loc,
);
}

// Render function call
const selfTy = getType(wCtx.ctx, selfTyRef.name);

Expand Down
4 changes: 2 additions & 2 deletions src/generator/writers/writeFunction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -503,7 +503,7 @@ function writeCondition(

export function writeFunction(f: FunctionDescription, ctx: WriterContext) {
// Resolve self
const self = f.self ? getType(ctx.ctx, f.self) : null;
const self = f.self?.kind === "ref" ? getType(ctx.ctx, f.self.name) : null;

// Write function header
let returns: string = resolveFuncType(f.returns, ctx);
Expand Down Expand Up @@ -683,7 +683,7 @@ function writeNonMutatingFunction(

export function writeGetter(f: FunctionDescription, ctx: WriterContext) {
// Render tensors
const self = f.self !== null ? getType(ctx.ctx, f.self) : null;
const self = f.self?.kind === "ref" ? getType(ctx.ctx, f.self.name) : null;
if (!self) {
throw new Error(`No self type for getter ${idTextErr(f.name)}`); // Impossible
}
Expand Down
6 changes: 5 additions & 1 deletion src/storage/__snapshots__/resolveAllocation.spec.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -2293,7 +2293,11 @@ exports[`resolveAllocation should write program 1`] = `
"returns": {
"kind": "void",
},
"self": "Sample",
"self": {
"kind": "ref",
"name": "Sample",
"optional": false,
},
},
},
"header": null,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
asm(value key self keySize) extends mutates fun nativeUdictStoreUint(self: Cell?, keySize: Int, key: Int, value: Slice) { DICTUSET }

extends mutates fun multiply(self: Int, x: Int): Int {
self *= x;
return self;
}

extends fun multiplyExtends(self: Int?, x: Int): Int? {
if (self == null) {
return null;
}
return self!! * x;
}

struct Foo {
s: Slice;
}
Expand Down Expand Up @@ -64,4 +73,15 @@ contract Tester {
self.s.loadUint(1);
return self.s.loadUint(3);
}

get fun test10(dict: Cell?): Cell? {
dict.nativeUdictStoreUint(8, 123, rawSlice("456"));
anton-trunov marked this conversation as resolved.
Show resolved Hide resolved
return dict;
}

get fun test11(x: Int?): Int? {
x.multiplyExtends(2);
x.multiplyExtends(2).multiplyExtends(3);
return x.multiplyExtends(2).multiplyExtends(3);
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { toNano } from "@ton/core";
import { beginCell, BitString, Dictionary, toNano } from "@ton/core";
import { Blockchain, SandboxContract, TreasuryContract } from "@ton/sandbox";
import { Tester } from "./contracts/output/mutating-method-chaining_Tester";
import { Tester } from "./contracts/output/mutating-methods_Tester";
import "@ton/test-utils";

describe("bugs", () => {
Expand Down Expand Up @@ -52,5 +52,41 @@ describe("bugs", () => {
expect(await contract.getTest7()).toBe(42n);
expect(await contract.getTest8()).toBe(5n);
expect(await contract.getTest9()).toBe(5n);

// Test `extends mutates` function with optional self param
{
// Non-empty dictionary
const d = Dictionary.empty(
Dictionary.Keys.Uint(8),
Dictionary.Values.BitString(12),
);
d.set(1, new BitString(Buffer.from("1234", "hex"), 0, 12));
const c = beginCell().storeDictDirect(d).endCell();
const c2 = await contract.getTest10(c);
const d2 = c2
?.beginParse()
.loadDictDirect(
Dictionary.Keys.Uint(8),
Dictionary.Values.BitString(12),
);
expect(d2?.size).toBe(2);
expect(d2?.get(1)?.toString()).toBe("123");
expect(d2?.get(123)?.toString()).toBe("456");
}
{
// Empty dictionary
const c = await contract.getTest10(null);
const d = c
?.beginParse()
.loadDictDirect(
Dictionary.Keys.Uint(8),
Dictionary.Values.BitString(12),
);
expect(d?.size).toBe(1);
expect(d?.get(123)?.toString()).toBe("456");
}

expect(await contract.getTest11(1n)).toBe(6n);
expect(await contract.getTest11(2n)).toBe(12n);
});
});
Loading
Loading