Skip to content

Commit

Permalink
fix(codegen): emptyMap() in equality comparisons (tact-lang#814)
Browse files Browse the repository at this point in the history
  • Loading branch information
anton-trunov authored Sep 12, 2024
1 parent 4a0f8fd commit a2863d4
Show file tree
Hide file tree
Showing 4 changed files with 18 additions and 8 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
14 changes: 7 additions & 7 deletions src/generator/writers/writeExpression.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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") {
Expand Down
3 changes: 2 additions & 1 deletion src/test/codegen/all-contracts.tact
Original file line number Diff line number Diff line change
Expand Up @@ -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";
import "./map-uint-bool-get";
import "./emptyMap-in-equality";
8 changes: 8 additions & 0 deletions src/test/codegen/emptyMap-in-equality.tact
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
contract TestContract {
get fun testEq(s: map<Int,Int>): Bool {
return s == emptyMap();
}
get fun testNeq(s: map<Int,Int>): Bool {
return s != emptyMap();
}
}

0 comments on commit a2863d4

Please sign in to comment.