mirror of
https://github.com/ton-blockchain/ton
synced 2025-03-09 15:40:10 +00:00
[Tolk] Nullable types T?
and null safety
This commit introduces nullable types `T?` that are distinct from non-nullable `T`. Example: `int?` (int or null) and `int` are different now. Previously, `null` could be assigned to any primitive type. Now, it can be assigned only to `T?`. A non-null assertion operator `!` was also introduced, similar to `!` in TypeScript and `!!` in Kotlin. If `int?` still occupies 1 stack slot, `(int,int)?` and other nullable tensors occupy N+1 slots, the last for "null precedence". `v == null` actually compares that slot. Assigning `(int,int)` to `(int,int)?` implicitly creates a null presence slot. Assigning `null` to `(int,int)?` widens this null value to 3 slots. This is called "type transitioning". All stdlib functions prototypes have been updated to reflect whether they return/accept a nullable or a strict value. This commit also contains refactoring from `const FunctionData*` to `FunctionPtr` and similar.
This commit is contained in:
parent
1389ff6789
commit
f3e620f48c
62 changed files with 2031 additions and 702 deletions
|
@ -111,23 +111,16 @@ static void diagnose_addition_in_bitshift(SrcLocation loc, std::string_view bits
|
|||
}
|
||||
}
|
||||
|
||||
// replace (a == null) and similar to isNull(a) (call of a built-in function)
|
||||
static AnyExprV maybe_replace_eq_null_with_isNull_call(V<ast_binary_operator> v) {
|
||||
// replace (a == null) and similar to ast_is_null_check(a) (special AST vertex)
|
||||
static AnyExprV maybe_replace_eq_null_with_isNull_check(V<ast_binary_operator> v) {
|
||||
bool has_null = v->get_lhs()->type == ast_null_keyword || v->get_rhs()->type == ast_null_keyword;
|
||||
bool replace = has_null && (v->tok == tok_eq || v->tok == tok_neq);
|
||||
if (!replace) {
|
||||
return v;
|
||||
}
|
||||
|
||||
auto v_ident = createV<ast_identifier>(v->loc, "__isNull"); // built-in function
|
||||
auto v_ref = createV<ast_reference>(v->loc, v_ident, nullptr);
|
||||
AnyExprV v_null = v->get_lhs()->type == ast_null_keyword ? v->get_rhs() : v->get_lhs();
|
||||
AnyExprV v_arg = createV<ast_argument>(v->loc, v_null, false);
|
||||
AnyExprV v_isNull = createV<ast_function_call>(v->loc, v_ref, createV<ast_argument_list>(v->loc, {v_arg}));
|
||||
if (v->tok == tok_neq) {
|
||||
v_isNull = createV<ast_unary_operator>(v->loc, "!", tok_logical_not, v_isNull);
|
||||
}
|
||||
return v_isNull;
|
||||
AnyExprV v_nullable = v->get_lhs()->type == ast_null_keyword ? v->get_rhs() : v->get_lhs();
|
||||
return createV<ast_is_null_check>(v->loc, v_nullable, v->tok == tok_neq);
|
||||
}
|
||||
|
||||
|
||||
|
@ -372,16 +365,31 @@ static AnyExprV parse_expr100(Lexer& lex) {
|
|||
}
|
||||
}
|
||||
|
||||
// parse E(...) (left-to-right)
|
||||
// parse E(...) and E! having parsed E already (left-to-right)
|
||||
static AnyExprV parse_fun_call_postfix(Lexer& lex, AnyExprV lhs) {
|
||||
while (true) {
|
||||
if (lex.tok() == tok_oppar) {
|
||||
lhs = createV<ast_function_call>(lhs->loc, lhs, parse_argument_list(lex));
|
||||
} else if (lex.tok() == tok_logical_not) {
|
||||
lex.next();
|
||||
lhs = createV<ast_not_null_operator>(lhs->loc, lhs);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return lhs;
|
||||
}
|
||||
|
||||
// parse E(...) and E! (left-to-right)
|
||||
static AnyExprV parse_expr90(Lexer& lex) {
|
||||
AnyExprV res = parse_expr100(lex);
|
||||
while (lex.tok() == tok_oppar) {
|
||||
res = createV<ast_function_call>(res->loc, res, parse_argument_list(lex));
|
||||
if (lex.tok() == tok_oppar || lex.tok() == tok_logical_not) {
|
||||
res = parse_fun_call_postfix(lex, res);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
// parse E.field and E.method(...) (left-to-right)
|
||||
// parse E.field and E.method(...) and E.field! (left-to-right)
|
||||
static AnyExprV parse_expr80(Lexer& lex) {
|
||||
AnyExprV lhs = parse_expr90(lex);
|
||||
while (lex.tok() == tok_dot) {
|
||||
|
@ -402,8 +410,8 @@ static AnyExprV parse_expr80(Lexer& lex) {
|
|||
lex.unexpected("method name");
|
||||
}
|
||||
lhs = createV<ast_dot_access>(loc, lhs, v_ident, v_instantiationTs);
|
||||
while (lex.tok() == tok_oppar) {
|
||||
lhs = createV<ast_function_call>(lex.cur_location(), lhs, parse_argument_list(lex));
|
||||
if (lex.tok() == tok_oppar || lex.tok() == tok_logical_not) {
|
||||
lhs = parse_fun_call_postfix(lex, lhs);
|
||||
}
|
||||
}
|
||||
return lhs;
|
||||
|
@ -491,7 +499,7 @@ static AnyExprV parse_expr15(Lexer& lex) {
|
|||
AnyExprV rhs = parse_expr17(lex);
|
||||
lhs = createV<ast_binary_operator>(loc, operator_name, t, lhs, rhs);
|
||||
if (t == tok_eq || t == tok_neq) {
|
||||
lhs = maybe_replace_eq_null_with_isNull_call(lhs->as<ast_binary_operator>());
|
||||
lhs = maybe_replace_eq_null_with_isNull_check(lhs->as<ast_binary_operator>());
|
||||
}
|
||||
}
|
||||
return lhs;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue