From 713da44c019c021065a2e71c9fe0dcdf5ad6046f Mon Sep 17 00:00:00 2001 From: Gusarich Date: Tue, 11 Jun 2024 20:31:47 +0300 Subject: [PATCH] remove separation between statement_let and statement_let_no_type --- src/generator/writers/writeFunction.ts | 30 +++-------------- src/grammar/ast.ts | 16 +-------- src/grammar/clone.ts | 6 ---- src/grammar/grammar.ohm | 3 +- src/grammar/grammar.ts | 22 ++----------- src/test/feature-local-type-inference.spec.ts | 33 +++++++++++-------- src/types/resolveStatements.ts | 32 +++++++----------- 7 files changed, 41 insertions(+), 101 deletions(-) diff --git a/src/generator/writers/writeFunction.ts b/src/generator/writers/writeFunction.ts index 261cf89fa..eda59a495 100644 --- a/src/generator/writers/writeFunction.ts +++ b/src/generator/writers/writeFunction.ts @@ -91,7 +91,11 @@ export function writeStatement( return; } else if (f.kind === "statement_let") { // Contract/struct case - const t = resolveTypeRef(ctx.ctx, f.type); + const t = + f.type === null + ? getExpType(ctx.ctx, f.expression) + : resolveTypeRef(ctx.ctx, f.type); + if (t.kind === "ref") { const tt = getType(ctx.ctx, t.name); if (tt.kind === "contract" || tt.kind === "struct") { @@ -112,30 +116,6 @@ export function writeStatement( `${resolveFuncType(t, ctx)} ${id(f.name)} = ${writeCastedExpression(f.expression, t, ctx)};`, ); return; - } else if (f.kind === "statement_let_no_type") { - const varType = getExpType(ctx.ctx, f.expression); - - // Contract/struct case - if (varType.kind === "ref") { - const tt = getType(ctx.ctx, varType.name); - if (tt.kind === "contract" || tt.kind === "struct") { - if (varType.optional) { - ctx.append( - `tuple ${id(f.name)} = ${writeCastedExpression(f.expression, varType, ctx)};`, - ); - } else { - ctx.append( - `var ${resolveFuncTypeUnpack(varType, id(f.name), ctx)} = ${writeCastedExpression(f.expression, varType, ctx)};`, - ); - } - return; - } - } - - ctx.append( - `${resolveFuncType(varType, ctx)} ${id(f.name)} = ${writeCastedExpression(f.expression, varType, ctx)};`, - ); - return; } else if (f.kind === "statement_assign") { // Prepare lvalue const path = f.path diff --git a/src/grammar/ast.ts b/src/grammar/ast.ts index 7b7d16d62..8cbef0f38 100644 --- a/src/grammar/ast.ts +++ b/src/grammar/ast.ts @@ -418,15 +418,7 @@ export type ASTStatementLet = { kind: "statement_let"; id: number; name: string; - type: ASTTypeRef; - expression: ASTExpression; - ref: ASTRef; -}; - -export type ASTStatementLetNoType = { - kind: "statement_let_no_type"; - id: number; - name: string; + type: ASTTypeRef | null; expression: ASTExpression; ref: ASTRef; }; @@ -538,7 +530,6 @@ export type ASTStatementForEach = { export type ASTStatement = | ASTStatementLet - | ASTStatementLetNoType | ASTStatementReturn | ASTStatementExpression | ASTStatementAssign @@ -559,7 +550,6 @@ export type ASTNode = | ASTFunction | ASTOpCall | ASTStatementLet - | ASTStatementLetNoType | ASTStatementReturn | ASTProgram | ASTPrimitive @@ -739,10 +729,6 @@ export function traverse(node: ASTNode, callback: (node: ASTNode) => void) { // if (node.kind === "statement_let") { - traverse(node.type, callback); - traverse(node.expression, callback); - } - if (node.kind === "statement_let_no_type") { traverse(node.expression, callback); } if (node.kind === "statement_return") { diff --git a/src/grammar/clone.ts b/src/grammar/clone.ts index 3fb669f7e..2a2a6cf79 100644 --- a/src/grammar/clone.ts +++ b/src/grammar/clone.ts @@ -26,12 +26,6 @@ export function cloneNode(src: T): T { expression: cloneNode(src.expression), }); } else if (src.kind === "statement_let") { - return cloneASTNode({ - ...src, - type: cloneASTNode(src.type), - expression: cloneNode(src.expression), - }); - } else if (src.kind === "statement_let_no_type") { return cloneASTNode({ ...src, expression: cloneNode(src.expression), diff --git a/src/grammar/grammar.ohm b/src/grammar/grammar.ohm index a93383469..913812563 100644 --- a/src/grammar/grammar.ohm +++ b/src/grammar/grammar.ohm @@ -100,8 +100,7 @@ Tact { StatementBlock = "{" Statement* "}" - StatementLet = let id ":" Type "=" Expression ";" --withType - | let id "=" Expression ";" --withoutType + StatementLet = let id (":" Type)? "=" Expression ";" StatementReturn = return Expression? ";" diff --git a/src/grammar/grammar.ts b/src/grammar/grammar.ts index 4e5eab083..e2e97f7aa 100644 --- a/src/grammar/grammar.ts +++ b/src/grammar/grammar.ts @@ -571,35 +571,17 @@ semantics.addOperation("astOfDeclaration", { semantics.addOperation("astOfStatement", { // TODO: process StatementBlock - StatementLet_withType( - _letKwd, - id, - _colon, - type, - _equals, - expression, - _semicolon, - ) { + StatementLet(_letKwd, id, _colon, type, _equals, expression, _semicolon) { checkVariableName(id.sourceString, createRef(id)); return createNode({ kind: "statement_let", name: id.sourceString, - type: type.astOfType(), + type: unwrapOptNode(type, (t) => t.astOfType()), expression: expression.astOfExpression(), ref: createRef(this), }); }, - StatementLet_withoutType(_arg0, arg1, _arg2, arg3, _arg4) { - checkVariableName(arg1.sourceString, createRef(arg1)); - - return createNode({ - kind: "statement_let_no_type", - name: arg1.sourceString, - expression: arg3.astOfExpression(), - ref: createRef(this), - }); - }, StatementReturn(_returnKwd, optExpression, _semicolon) { return createNode({ kind: "statement_return", diff --git a/src/test/feature-local-type-inference.spec.ts b/src/test/feature-local-type-inference.spec.ts index 4eb90af16..b5007e7df 100644 --- a/src/test/feature-local-type-inference.spec.ts +++ b/src/test/feature-local-type-inference.spec.ts @@ -1,26 +1,33 @@ -import { toNano } from '@ton/core'; -import { ContractSystem } from '@tact-lang/emulator'; -import { __DANGER_resetNodeId } from '../grammar/ast'; -import { LocalTypeInferenceTester } from './features/output/local-type-inference_LocalTypeInferenceTester'; +import { toNano } from "@ton/core"; +import { ContractSystem } from "@tact-lang/emulator"; +import { __DANGER_resetNodeId } from "../grammar/ast"; +import { LocalTypeInferenceTester } from "./features/output/local-type-inference_LocalTypeInferenceTester"; -describe('feature-local-type-inference', () => { +describe("feature-local-type-inference", () => { beforeEach(() => { __DANGER_resetNodeId(); }); - it('should automatically set types for let statements', async () => { - + it("should automatically set types for let statements", async () => { // Init const system = await ContractSystem.create(); - const treasure = system.treasure('treasure'); + const treasure = system.treasure("treasure"); const contract = system.open(await LocalTypeInferenceTester.fromInit()); - await contract.send(treasure, { value: toNano('10') }, { $$type: 'Deploy', queryId: 0n }); + await contract.send( + treasure, + { value: toNano("10") }, + { $$type: "Deploy", queryId: 0n }, + ); await system.run(); - + expect(contract.abi).toMatchSnapshot(); expect(await contract.getTest1()).toStrictEqual(1n); expect(await contract.getTest2()).toStrictEqual(2n); - expect((await contract.getTest3()).toRawString()).toBe(contract.address.toRawString()); - expect((await contract.getTest4()).toRawString()).toBe(contract.address.toRawString()); + expect((await contract.getTest3()).toRawString()).toBe( + contract.address.toRawString(), + ); + expect((await contract.getTest4()).toRawString()).toBe( + contract.address.toRawString(), + ); expect(await contract.getTest5()).toStrictEqual(true); }); -}); \ No newline at end of file +}); diff --git a/src/types/resolveStatements.ts b/src/types/resolveStatements.ts index e82813a1b..ffebbd3fe 100644 --- a/src/types/resolveStatements.ts +++ b/src/types/resolveStatements.ts @@ -170,33 +170,25 @@ function processStatements( // Process expression ctx = resolveExpression(s.expression, sctx, ctx); - // Check type - const expressionType = getExpType(ctx, s.expression); - const variableType = resolveTypeRef(ctx, s.type); - if (!isAssignable(expressionType, variableType)) { - throwError( - `Type mismatch: "${printTypeRef(expressionType)}" is not assignable to "${printTypeRef(variableType)}"`, - s.ref, - ); - } - - // Add variable to statement context + // Check variable name if (sctx.vars.has(s.name)) { throwError(`Variable "${s.name}" already exists`, s.ref); } - sctx = addVariable(s.name, variableType, sctx); - } else if (s.kind === "statement_let_no_type") { - // Process expression - ctx = resolveExpression(s.expression, sctx, ctx); // Check type const expressionType = getExpType(ctx, s.expression); - - // Add variable to statement context - if (sctx.vars.has(s.name)) { - throwError(`Variable already exists: ${s.name}`, s.ref); + if (s.type !== null) { + const variableType = resolveTypeRef(ctx, s.type); + if (!isAssignable(expressionType, variableType)) { + throwError( + `Type mismatch: "${printTypeRef(expressionType)}" is not assignable to "${printTypeRef(variableType)}"`, + s.ref, + ); + } + sctx = addVariable(s.name, variableType, sctx); + } else { + sctx = addVariable(s.name, expressionType, sctx); } - sctx = addVariable(s.name, expressionType, sctx); } else if (s.kind === "statement_assign") { // Process lvalue ctx = resolveLValueRef(s.path, sctx, ctx);