Skip to content

Commit

Permalink
feat: optional types for self argument in extends mutates functio…
Browse files Browse the repository at this point in the history
…ns (#854)
  • Loading branch information
Gusarich authored Oct 1, 2024
1 parent 7e6d4cc commit 2fea700
Show file tree
Hide file tree
Showing 15 changed files with 1,384 additions and 206 deletions.
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
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"));
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

0 comments on commit 2fea700

Please sign in to comment.