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
|
@ -84,6 +84,7 @@ TypePtr TypeDataTuple::singleton;
|
|||
TypePtr TypeDataContinuation::singleton;
|
||||
TypePtr TypeDataNullLiteral::singleton;
|
||||
TypePtr TypeDataUnknown::singleton;
|
||||
TypePtr TypeDataNever::singleton;
|
||||
TypePtr TypeDataVoid::singleton;
|
||||
|
||||
void type_system_init() {
|
||||
|
@ -96,6 +97,7 @@ void type_system_init() {
|
|||
TypeDataContinuation::singleton = new TypeDataContinuation;
|
||||
TypeDataNullLiteral::singleton = new TypeDataNullLiteral;
|
||||
TypeDataUnknown::singleton = new TypeDataUnknown;
|
||||
TypeDataNever::singleton = new TypeDataNever;
|
||||
TypeDataVoid::singleton = new TypeDataVoid;
|
||||
}
|
||||
|
||||
|
@ -325,53 +327,56 @@ bool TypeDataInt::can_rhs_be_assigned(TypePtr rhs) const {
|
|||
if (rhs == this) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return rhs == TypeDataNever::create();
|
||||
}
|
||||
|
||||
bool TypeDataBool::can_rhs_be_assigned(TypePtr rhs) const {
|
||||
if (rhs == this) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return rhs == TypeDataNever::create();
|
||||
}
|
||||
|
||||
bool TypeDataCell::can_rhs_be_assigned(TypePtr rhs) const {
|
||||
if (rhs == this) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return rhs == TypeDataNever::create();
|
||||
}
|
||||
|
||||
bool TypeDataSlice::can_rhs_be_assigned(TypePtr rhs) const {
|
||||
if (rhs == this) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return rhs == TypeDataNever::create();
|
||||
}
|
||||
|
||||
bool TypeDataBuilder::can_rhs_be_assigned(TypePtr rhs) const {
|
||||
if (rhs == this) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return rhs == TypeDataNever::create();
|
||||
}
|
||||
|
||||
bool TypeDataTuple::can_rhs_be_assigned(TypePtr rhs) const {
|
||||
if (rhs == this) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return rhs == TypeDataNever::create();
|
||||
}
|
||||
|
||||
bool TypeDataContinuation::can_rhs_be_assigned(TypePtr rhs) const {
|
||||
if (rhs == this) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return rhs == TypeDataNever::create();
|
||||
}
|
||||
|
||||
bool TypeDataNullLiteral::can_rhs_be_assigned(TypePtr rhs) const {
|
||||
return rhs == this;
|
||||
if (rhs == this) {
|
||||
return true;
|
||||
}
|
||||
return rhs == TypeDataNever::create();
|
||||
}
|
||||
|
||||
bool TypeDataNullable::can_rhs_be_assigned(TypePtr rhs) const {
|
||||
|
@ -384,11 +389,17 @@ bool TypeDataNullable::can_rhs_be_assigned(TypePtr rhs) const {
|
|||
if (const TypeDataNullable* rhs_nullable = rhs->try_as<TypeDataNullable>()) {
|
||||
return inner->can_rhs_be_assigned(rhs_nullable->inner);
|
||||
}
|
||||
return inner->can_rhs_be_assigned(rhs);
|
||||
if (inner->can_rhs_be_assigned(rhs)) {
|
||||
return true;
|
||||
}
|
||||
return rhs == TypeDataNever::create();
|
||||
}
|
||||
|
||||
bool TypeDataFunCallable::can_rhs_be_assigned(TypePtr rhs) const {
|
||||
return rhs == this;
|
||||
if (rhs == this) {
|
||||
return true;
|
||||
}
|
||||
return rhs == TypeDataNever::create();
|
||||
}
|
||||
|
||||
bool TypeDataGenericT::can_rhs_be_assigned(TypePtr rhs) const {
|
||||
|
@ -405,7 +416,7 @@ bool TypeDataTensor::can_rhs_be_assigned(TypePtr rhs) const {
|
|||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return rhs == TypeDataNever::create();
|
||||
}
|
||||
|
||||
bool TypeDataTypedTuple::can_rhs_be_assigned(TypePtr rhs) const {
|
||||
|
@ -417,7 +428,7 @@ bool TypeDataTypedTuple::can_rhs_be_assigned(TypePtr rhs) const {
|
|||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return rhs == TypeDataNever::create();
|
||||
}
|
||||
|
||||
bool TypeDataUnknown::can_rhs_be_assigned(TypePtr rhs) const {
|
||||
|
@ -429,8 +440,15 @@ bool TypeDataUnresolved::can_rhs_be_assigned(TypePtr rhs) const {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool TypeDataNever::can_rhs_be_assigned(TypePtr rhs) const {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TypeDataVoid::can_rhs_be_assigned(TypePtr rhs) const {
|
||||
return rhs == this;
|
||||
if (rhs == this) {
|
||||
return true;
|
||||
}
|
||||
return rhs == TypeDataNever::create();
|
||||
}
|
||||
|
||||
|
||||
|
@ -551,6 +569,10 @@ bool TypeDataUnresolved::can_be_casted_with_as_operator(TypePtr cast_to) const {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool TypeDataNever::can_be_casted_with_as_operator(TypePtr cast_to) const {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TypeDataVoid::can_be_casted_with_as_operator(TypePtr cast_to) const {
|
||||
return cast_to == this;
|
||||
}
|
||||
|
@ -584,6 +606,10 @@ bool TypeDataTensor::can_hold_tvm_null_instead() const {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool TypeDataNever::can_hold_tvm_null_instead() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TypeDataVoid::can_hold_tvm_null_instead() const {
|
||||
return false;
|
||||
}
|
||||
|
@ -650,6 +676,7 @@ static TypePtr parse_simple_type(Lexer& lex) {
|
|||
case 5:
|
||||
if (str == "slice") return TypeDataSlice::create();
|
||||
if (str == "tuple") return TypeDataTuple::create();
|
||||
if (str == "never") return TypeDataNever::create();
|
||||
break;
|
||||
case 7:
|
||||
if (str == "builder") return TypeDataBuilder::create();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue