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

Implement local type inference for let statements #198

Merged
merged 12 commits into from
Jun 14, 2024
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- Trailing semicolons in struct and message declarations are optional now: PR [#395](https://github.com/tact-lang/tact/pull/395)
- Tests are refactored and renamed to convey the sense of what is being tested and to reduce the amount of merge conflicts during development: PR [#402](https://github.com/tact-lang/tact/pull/402)
- `let` statements can now be used without an explicit type declaration and determine the type automatically if it was not specified: PR [#198](https://github.com/tact-lang/tact/pull/198)
- The outdated TextMate-style grammar files for text editors have been removed (the most recent grammar files can be found in the [tact-sublime](https://github.com/tact-lang/tact-sublime) repo): PR [#404](https://github.com/tact-lang/tact/pull/404)
- The JSON schema for `tact.config.json` has been moved to the `json-schemas` project folder: PR [#404](https://github.com/tact-lang/tact/pull/404)

Expand Down
6 changes: 5 additions & 1 deletion src/generator/writers/writeFunction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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") {
Expand Down
3 changes: 1 addition & 2 deletions src/grammar/ast.ts
Original file line number Diff line number Diff line change
Expand Up @@ -418,7 +418,7 @@ export type ASTStatementLet = {
kind: "statement_let";
id: number;
name: string;
type: ASTTypeRef;
type: ASTTypeRef | null;
expression: ASTExpression;
ref: ASTRef;
};
Expand Down Expand Up @@ -729,7 +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_return") {
Expand Down
5 changes: 4 additions & 1 deletion src/grammar/clone.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export function cloneNode<T extends ASTNode>(src: T): T {
} else if (src.kind === "statement_let") {
return cloneASTNode({
...src,
type: cloneASTNode(src.type),
anton-trunov marked this conversation as resolved.
Show resolved Hide resolved
type: src.type ? cloneASTNode(src.type) : null,
expression: cloneNode(src.expression),
});
} else if (src.kind === "statement_condition") {
Expand Down Expand Up @@ -132,12 +132,14 @@ export function cloneNode<T extends ASTNode>(src: T): T {
} else if (src.kind === "def_function") {
return cloneASTNode({
...src,
return: src.return ? cloneASTNode(src.return) : null,
statements: src.statements ? src.statements.map(cloneNode) : null,
args: src.args.map(cloneNode),
});
} else if (src.kind === "def_native_function") {
return cloneASTNode({
...src,
return: src.return ? cloneASTNode(src.return) : null,
args: src.args.map(cloneNode),
});
} else if (src.kind === "def_receive") {
Expand All @@ -158,6 +160,7 @@ export function cloneNode<T extends ASTNode>(src: T): T {
} else if (src.kind === "def_constant") {
return cloneASTNode({
...src,
type: cloneASTNode(src.type),
value: src.value ? cloneNode(src.value) : src.value,
});
}
Expand Down
2 changes: 1 addition & 1 deletion src/grammar/grammar.ohm
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ Tact {

StatementBlock = "{" Statement* "}"

StatementLet = let id ":" Type "=" Expression ";"
StatementLet = let id (":" Type)? "=" Expression ";"

StatementReturn = return Expression? ";"

Expand Down
12 changes: 10 additions & 2 deletions src/grammar/grammar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -571,13 +571,21 @@ semantics.addOperation<ASTNode>("astOfDeclaration", {
semantics.addOperation<ASTNode>("astOfStatement", {
// TODO: process StatementBlock

StatementLet(_letKwd, id, _colon, type, _equals, expression, _semicolon) {
StatementLet(
_letKwd,
id,
_optColon,
optType,
_equals,
expression,
_semicolon,
) {
checkVariableName(id.sourceString, createRef(id));

return createNode({
kind: "statement_let",
name: id.sourceString,
type: type.astOfType(),
type: unwrapOptNode(optType, (t) => t.astOfType()),
expression: expression.astOfExpression(),
ref: createRef(this),
});
Expand Down
Loading
Loading