diff --git a/CHANGELOG.md b/CHANGELOG.md index b0e661284..efe8944f2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,6 +37,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Message opcodes are now checked if they fit into 32 bits: PR [#771](https://github.com/tact-lang/tact/pull/771) - Disallow zero binary message opcodes as those are reserved for text messages: PR [#786](https://github.com/tact-lang/tact/pull/786) - Return-statements in `init()` function do not cause FunC compilation error anymore: PR [#794](https://github.com/tact-lang/tact/pull/794) +- `emptyMap()` in equality comparison expressions does not cause code generation failures: PR [#814](https://github.com/tact-lang/tact/pull/814) ## [1.4.4] - 2024-08-18 diff --git a/src/generator/writers/writeExpression.ts b/src/generator/writers/writeExpression.ts index 937d3144c..2ee49d62d 100644 --- a/src/generator/writers/writeExpression.ts +++ b/src/generator/writers/writeExpression.ts @@ -44,8 +44,8 @@ import { writeCastedExpression } from "./writeFunction"; import { evalConstantExpression } from "../../constEval"; import { isLvalue } from "../../types/resolveStatements"; -function isNull(f: AstExpression): boolean { - return f.kind === "null"; +function isNull(wCtx: WriterContext, expr: AstExpression): boolean { + return getExpType(wCtx.ctx, expr).kind === "null"; } function writeStructConstructor( @@ -213,23 +213,23 @@ export function writeExpression(f: AstExpression, wCtx: WriterContext): string { return funcIdOf(f.text); } - // NOTE: We always wrap in parentheses to avoid operator precedence issues + // NOTE: We always wrap expressions in parentheses to avoid operator precedence issues if (f.kind === "op_binary") { // Special case for non-integer types and nullable if (f.op === "==" || f.op === "!=") { - if (isNull(f.left) && isNull(f.right)) { + if (isNull(wCtx, f.left) && isNull(wCtx, f.right)) { if (f.op === "==") { return "true"; } else { return "false"; } - } else if (isNull(f.left) && !isNull(f.right)) { + } else if (isNull(wCtx, f.left) && !isNull(wCtx, f.right)) { if (f.op === "==") { return `null?(${writeExpression(f.right, wCtx)})`; } else { return `(~ null?(${writeExpression(f.right, wCtx)}))`; } - } else if (!isNull(f.left) && isNull(f.right)) { + } else if (!isNull(wCtx, f.left) && isNull(wCtx, f.right)) { if (f.op === "==") { return `null?(${writeExpression(f.left, wCtx)})`; } else { @@ -384,7 +384,7 @@ export function writeExpression(f: AstExpression, wCtx: WriterContext): string { // // Unary operations: !, -, +, !! - // NOTE: We always wrap in parenthesis to avoid operator precedence issues + // NOTE: We always wrap expressions in parentheses to avoid operator precedence issues // if (f.kind === "op_unary") { diff --git a/src/test/codegen/all-contracts.tact b/src/test/codegen/all-contracts.tact index 6f69532ed..5aeaaca06 100644 --- a/src/test/codegen/all-contracts.tact +++ b/src/test/codegen/all-contracts.tact @@ -6,4 +6,5 @@ import "./message-opcode-parsing.tact"; import "./struct-with-default-and-optional-fields"; import "./mutating-method-on-non-lvalues"; import "./var-scope-global-fun-shadowing-allowed"; -import "./map-uint-bool-get"; \ No newline at end of file +import "./map-uint-bool-get"; +import "./emptyMap-in-equality"; diff --git a/src/test/codegen/emptyMap-in-equality.tact b/src/test/codegen/emptyMap-in-equality.tact new file mode 100644 index 000000000..7c0c1204a --- /dev/null +++ b/src/test/codegen/emptyMap-in-equality.tact @@ -0,0 +1,8 @@ +contract TestContract { + get fun testEq(s: map): Bool { + return s == emptyMap(); + } + get fun testNeq(s: map): Bool { + return s != emptyMap(); + } +}