mirror of
https://github.com/ton-blockchain/ton
synced 2025-03-09 15:40:10 +00:00
[Tolk] Smart casts and control flow graph
With the introduction of nullable types, we want the compiler to be smart in cases like > if (x == null) return; > // x is int now or > if (x == null) x = 0; > // x is int now These are called smart casts: when the type of variable at particular usage might differ from its declaration. Implementing smart casts is very challenging. They are based on building control-flow graph and handling every AST vertex with care. Actually, I represent cfg not a as a "graph with edges". Instead, it's a "structured DFS" for the AST: 1) at every point of inferring, we have "current flow facts" 2) when we see an `if (...)`, we create two derived contexts 3) after `if`, finalize them at the end and unify 4) if we detect unreachable code, we mark that context In other words, we get the effect of a CFG but in a more direct approach. That's enough for AST-level data-flow. Smart casts work for local variables and tensor/tuple indices. Compilation errors have been reworked and now are more friendly. There are also compilation warnings for always true/false conditions inside if, assert, etc.
This commit is contained in:
parent
f3e620f48c
commit
7bcb8b895f
47 changed files with 3057 additions and 833 deletions
|
@ -26,7 +26,9 @@ fun test2(x: int?) {
|
|||
if (null != x) {
|
||||
var y: int? = null;
|
||||
if (y != null) { return 10; }
|
||||
return y;
|
||||
if (10 < 20) { // always true at runtime (not at compile-time)
|
||||
return y;
|
||||
}
|
||||
}
|
||||
try {
|
||||
return x! + 10; // will throw, since not a number
|
||||
|
@ -45,14 +47,6 @@ fun test3(x: int) {
|
|||
return myIsNull(x > 10 ? null : x);
|
||||
}
|
||||
|
||||
fun getUntypedNull() {
|
||||
var untyped: null = null;
|
||||
if (true) {
|
||||
return untyped;
|
||||
}
|
||||
return untyped;
|
||||
}
|
||||
|
||||
@method_id(104)
|
||||
fun test4(): null {
|
||||
var (_, (_, untyped: null)) = (3, (createEmptyTuple, null));
|
||||
|
@ -62,12 +56,6 @@ fun test4(): null {
|
|||
return untyped;
|
||||
}
|
||||
|
||||
@method_id(105)
|
||||
fun test5() {
|
||||
var n: slice? = getUntypedNull();
|
||||
return !(null == n) ? n!.loadInt(32) : 100;
|
||||
}
|
||||
|
||||
@method_id(107)
|
||||
fun test7() {
|
||||
var b = beginCell().storeMaybeRef(null) as builder?;
|
||||
|
@ -85,6 +73,7 @@ fun test8() {
|
|||
}
|
||||
|
||||
fun main() {
|
||||
// the compiler optimizes this at compile-time
|
||||
var i: int? = null;
|
||||
if (i == null) {
|
||||
return 1;
|
||||
|
@ -99,7 +88,6 @@ fun main() {
|
|||
@testcase | 103 | 5 | 5
|
||||
@testcase | 103 | 15 | -1
|
||||
@testcase | 104 | | (null)
|
||||
@testcase | 105 | | 100
|
||||
@testcase | 107 | | -11
|
||||
@fif_codegen
|
||||
"""
|
||||
|
@ -127,12 +115,7 @@ fun main() {
|
|||
"""
|
||||
main PROC:<{
|
||||
//
|
||||
PUSHNULL // i
|
||||
ISNULL // '2
|
||||
IFJMP:<{ //
|
||||
1 PUSHINT // '3=1
|
||||
}> //
|
||||
10 PUSHINT // '4=10
|
||||
1 PUSHINT // '3=1
|
||||
}>
|
||||
"""
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue