mirror of
https://github.com/ton-blockchain/ton
synced 2025-03-09 15:40:10 +00:00
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.
28 lines
571 B
Text
28 lines
571 B
Text
fun takeInt(a: int) {}
|
|
|
|
@method_id(101)
|
|
fun test1(x: int?) {
|
|
if (x == null && x != null) {
|
|
var y = x;
|
|
__expect_type(y, "never");
|
|
__expect_type(y!, "never");
|
|
// `never` type is assignable to anything, flow won't reach this point
|
|
var t: (int, int) = x;
|
|
t = y;
|
|
takeInt(x);
|
|
var cb: (int) -> int = x;
|
|
x as int?;
|
|
x as (int, int)?;
|
|
x as never;
|
|
return x;
|
|
}
|
|
return 123;
|
|
}
|
|
|
|
fun main() {
|
|
__expect_type(test1, "(int?) -> int");
|
|
}
|
|
|
|
/**
|
|
@testcase | 101 | null | 123
|
|
*/
|