Fixing type checking

This commit is contained in:
Krzosa Karol
2022-06-06 22:14:30 +02:00
parent d042251c21
commit 729e7aee86
6 changed files with 219 additions and 205 deletions

View File

@@ -130,19 +130,9 @@ gen_expr(Ast_Expr *ast){
}
CASE(UNARY, Unary){
switch(node->op){
case TK_Pointer: {
gen("(*");
gen_expr(node->expr);
gen(")");
} break;
case TK_Dereference: {
gen("(&");
gen_expr(node->expr);
gen(")");
} break;
invalid_default_case;
}
gen("(%s", name(node->op));
gen_expr(node->expr);
gen(")");
BREAK();
}

View File

@@ -10,7 +10,6 @@ const_function_alias :: test_function
// Booleans
//-----------------------------------------------------------------------------
Boolean: Bool = true
value_of_Bool: S64 = cast(Boolean: S64)
//-----------------------------------------------------------------------------
// Nulls

View File

@@ -68,10 +68,17 @@ cast(expr: type)
convert between typed to other typed
check if types compatible
Stmt:
Return - Expression should match lambda return type
Expr:
Lambda - Arguments, default values should match type
ArrayT - Should match type int and be constant or not at all
Call - Arguments should match type
@todo
[ ] - Fix casting
[ ] - Make sure pointer arithmetic works
[ ] - Passing down program to compile through command line
[ ] - More for loop variations
[ ] - Write up on order independent declarations
@@ -160,7 +167,7 @@ int main(){
String result = {};
#if 0
#if 1
result = compile_file("globals.kl"_s);
printf("%s", result.str);
result = compile_file("enums.kl"_s);

View File

@@ -564,6 +564,50 @@ ast_package(Token *pos, String name, Array<Ast_Named *> decls){
return result;
}
//-----------------------------------------------------------------------------
// Value
//-----------------------------------------------------------------------------
function Value
value_bool(B32 v){
Value value;
value.bool_val = v;
value.type = untyped_bool;
return value;
}
function Value
value_int(BigInt b){
Value value;
value.big_int_val = b;
value.type = untyped_int;
return value;
}
function Value
value_int(S64 s64){
Value value;
value.type = untyped_int;
bigint_init_signed(&value.big_int_val, s64);
return value;
}
function Value
value_float(F64 b){
Value value;
value.f64_val = b;
value.type = untyped_float;
return value;
}
function Value
value_float(BigInt a){
Value value;
value.f64_val = bigint_as_float(&a);
value.type = untyped_float;
return value;
}
//-----------------------------------------------------------------------------
// Utillities
//-----------------------------------------------------------------------------

View File

@@ -14,6 +14,11 @@ unary_test :: ()
neg32: S32 = ~int_val
big_neg32: U32 = ~cast(41512512: U32)
var1: S64
var2: S64 = 20
var_bool: Bool = !var1 == !var2
// uns: U64 = -int_val
// int_float: S64 = float_val
// string :: -"Thing"

View File

@@ -31,46 +31,6 @@ type_error(Token *token, Ast_Resolved_Type *expected, Ast_Resolved_Type *actual,
//-----------------------------------------------------------------------------
// Evaluating constant expressions
//-----------------------------------------------------------------------------
function Value
value_bool(B32 v){
Value value;
value.bool_val = v;
value.type = untyped_bool;
return value;
}
function Value
value_int(BigInt b){
Value value;
value.big_int_val = b;
value.type = untyped_int;
return value;
}
function Value
value_int(S64 s64){
Value value;
value.type = untyped_int;
bigint_init_signed(&value.big_int_val, s64);
return value;
}
function Value
value_float(F64 b){
Value value;
value.f64_val = b;
value.type = untyped_float;
return value;
}
function Value
value_float(BigInt a){
Value value;
value.f64_val = bigint_as_float(&a);
value.type = untyped_float;
return value;
}
function void
check_value_bounds(Token *pos, Value *a){
if(!is_int(a->type)) return;
@@ -83,7 +43,7 @@ check_value_bounds(Token *pos, Value *a){
}
function Value
convert_untyped(Token *pos, Value a, Ast_Resolved_Type *new_type){
convert_untyped_to_typed(Token *pos, Value a, Ast_Resolved_Type *new_type){
assert(new_type);
if(a.type == 0) return a;
if(is_typed(a.type)) return a;
@@ -106,19 +66,19 @@ convert_untyped(Token *pos, Value a, Ast_Resolved_Type *new_type){
}
function void
match_values(Token *pos, Value *a, Value *b){
make_sure_types_are_compatible(Token *pos, Value *a, Value *b){
if(is_typed(a->type) && is_typed(b->type)){
if(a->type != b->type){
parsing_error(pos, "Type mismatch in match_values - left: %s right: %s", docname(a->type), docname(b->type));
parsing_error(pos, "Type mismatch in make_sure_types_are_compatible - left: %s right: %s", docname(a->type), docname(b->type));
}
}
if(is_untyped(a->type) && is_typed(b->type)){
assert(is_typed(b->type));
*a = convert_untyped(pos, *a, b->type);
*a = convert_untyped_to_typed(pos, *a, b->type);
}
else if(is_typed(a->type) && is_untyped(b->type)){
assert(is_typed(a->type));
*b = convert_untyped(pos, *b, a->type);
*b = convert_untyped_to_typed(pos, *b, a->type);
}
else if(is_int(a->type) && is_float(b->type)){
@@ -130,175 +90,178 @@ match_values(Token *pos, Value *a, Value *b){
}
function Value
compare_values(Token *pos, Token_Kind op, Value a, Value b){
if(!(is_numeric(a.type) && is_numeric(b.type))) parsing_error(pos, "Constant application of binary %s on values of type %s and %s is not allowed", name(op), docname(a.type), docname(a.type));
match_values(pos, &a, &b);
compare_values(Token *pos, Token_Kind op, Value a, Value b, bool is_const){
if(!(is_numeric(a.type) && is_numeric(b.type)))
parsing_error(pos, "Constant application of binary %s on values of type %s and %s is not allowed", name(op), docname(a.type), docname(a.type));
make_sure_types_are_compatible(pos, &a, &b);
B32 result = 0;
switch(a.type->kind){
CASE_INT:{
CmpRes cmp = bigint_cmp(&a.big_int_val, &b.big_int_val);
switch(op){
case TK_LesserThenOrEqual: result = (cmp == CMP_LT) || (cmp == CMP_EQ); break;
case TK_GreaterThenOrEqual: result = (cmp == CMP_GT) || (cmp == CMP_EQ); break;
case TK_GreaterThen: result = cmp == CMP_GT; break;
case TK_LesserThen: result = cmp == CMP_LT; break;
case TK_Equals: result = cmp == CMP_EQ; break;
case TK_NotEquals: result = cmp != CMP_EQ; break;
invalid_default_case;
}
}break;
CASE_BOOL:{
switch(op){
case TK_Equals: result = a.bool_val == b.bool_val; break;
case TK_NotEquals: result = a.bool_val != b.bool_val; break;
invalid_default_case;
}
}break;
CASE_FLOAT:{
switch(op){
case TK_LesserThenOrEqual: result = a.f64_val <= b.f64_val; break;
case TK_GreaterThenOrEqual: result = a.f64_val >= b.f64_val; break;
case TK_GreaterThen: result = a.f64_val > b.f64_val; break;
case TK_LesserThen: result = a.f64_val < b.f64_val; break;
case TK_Equals: result = a.f64_val == b.f64_val; break;
case TK_NotEquals: result = a.f64_val != b.f64_val; break;
invalid_default_case;
}
}break;
CASE_STRING:{
invalid_codepath;
}break;
invalid_default_case;
if(is_const){
switch(a.type->kind){
CASE_INT:{
CmpRes cmp = bigint_cmp(&a.big_int_val, &b.big_int_val);
switch(op){
case TK_LesserThenOrEqual: result = (cmp == CMP_LT) || (cmp == CMP_EQ); break;
case TK_GreaterThenOrEqual: result = (cmp == CMP_GT) || (cmp == CMP_EQ); break;
case TK_GreaterThen: result = cmp == CMP_GT; break;
case TK_LesserThen: result = cmp == CMP_LT; break;
case TK_Equals: result = cmp == CMP_EQ; break;
case TK_NotEquals: result = cmp != CMP_EQ; break;
invalid_default_case;
}
}break;
CASE_BOOL:{
switch(op){
case TK_Equals: result = a.bool_val == b.bool_val; break;
case TK_NotEquals: result = a.bool_val != b.bool_val; break;
invalid_default_case;
}
}break;
CASE_FLOAT:{
switch(op){
case TK_LesserThenOrEqual: result = a.f64_val <= b.f64_val; break;
case TK_GreaterThenOrEqual: result = a.f64_val >= b.f64_val; break;
case TK_GreaterThen: result = a.f64_val > b.f64_val; break;
case TK_LesserThen: result = a.f64_val < b.f64_val; break;
case TK_Equals: result = a.f64_val == b.f64_val; break;
case TK_NotEquals: result = a.f64_val != b.f64_val; break;
invalid_default_case;
}
}break;
CASE_STRING:{
invalid_codepath;
}break;
invalid_default_case;
}
}
return value_bool(result);
}
function Value
eval_binary(Token *pos, Token_Kind op, Value a, Value b){
if(token_is_compare(op)){
return compare_values(pos, op, a, b);
}
eval_binary(Token *pos, Token_Kind op, Value a, Value b, bool is_const){
if(token_is_compare(op))
return compare_values(pos, op, a, b, is_const);
if(!(is_numeric(a.type) && is_numeric(b.type))) parsing_error(pos, "Constant application of binary %s on values of type %s and %s is not allowed", name(op), docname(a.type), docname(a.type));
match_values(pos, &a, &b);
if(!(is_numeric(a.type) && is_numeric(b.type)))
parsing_error(pos, "Constant application of binary %s on values of type %s and %s is not allowed", name(op), docname(a.type), docname(a.type));
make_sure_types_are_compatible(pos, &a, &b);
Value result = {};
result.type = a.type;
switch(a.type->kind){
CASE_INT:{
switch(op){
case TK_BitXor: bigint_xor(&result.big_int_val, &a.big_int_val, &b.big_int_val); break;
case TK_BitAnd: bigint_and(&result.big_int_val, &a.big_int_val, &b.big_int_val); break;
case TK_BitOr: bigint_or(&result.big_int_val, &a.big_int_val, &b.big_int_val); break;
case TK_Add: bigint_add(&result.big_int_val, &a.big_int_val, &b.big_int_val); break;
case TK_Sub: bigint_sub(&result.big_int_val, &a.big_int_val, &b.big_int_val); break;
case TK_Mul: bigint_mul(&result.big_int_val, &a.big_int_val, &b.big_int_val); break;
case TK_Div: bigint_div_trunc(&result.big_int_val, &a.big_int_val, &b.big_int_val); break;
case TK_Mod: bigint_mod(&result.big_int_val, &a.big_int_val, &b.big_int_val); break;
case TK_LeftShift: bigint_shl(&result.big_int_val, &a.big_int_val, &b.big_int_val); break;
case TK_RightShift: bigint_shr(&result.big_int_val, &a.big_int_val, &b.big_int_val); break;
invalid_default_case;
}
}break;
CASE_BOOL:{
switch(op){
case TK_And: result.bool_val = a.bool_val && b.bool_val; break;
case TK_Or: result.bool_val = a.bool_val || b.bool_val; break;
case TK_BitAnd: result.bool_val = a.bool_val & b.bool_val; break;
case TK_BitOr: result.bool_val = a.bool_val | b.bool_val; break;
case TK_BitXor: result.bool_val = a.bool_val ^ b.bool_val; break;
invalid_default_case;
}
}break;
CASE_FLOAT:{
switch(op){
case TK_Add: result.f64_val = a.f64_val + b.f64_val; break;
case TK_Sub: result.f64_val = a.f64_val - b.f64_val; break;
case TK_Mul: result.f64_val = a.f64_val * b.f64_val; break;
case TK_Div: result.f64_val = a.f64_val / b.f64_val; break;
invalid_default_case;
}
}break;
CASE_STRING:{
invalid_codepath;
}break;
invalid_default_case;
if(is_const){
switch(a.type->kind){
CASE_INT:{
switch(op){
case TK_BitXor: bigint_xor(&result.big_int_val, &a.big_int_val, &b.big_int_val); break;
case TK_BitAnd: bigint_and(&result.big_int_val, &a.big_int_val, &b.big_int_val); break;
case TK_BitOr: bigint_or(&result.big_int_val, &a.big_int_val, &b.big_int_val); break;
case TK_Add: bigint_add(&result.big_int_val, &a.big_int_val, &b.big_int_val); break;
case TK_Sub: bigint_sub(&result.big_int_val, &a.big_int_val, &b.big_int_val); break;
case TK_Mul: bigint_mul(&result.big_int_val, &a.big_int_val, &b.big_int_val); break;
case TK_Div: bigint_div_trunc(&result.big_int_val, &a.big_int_val, &b.big_int_val); break;
case TK_Mod: bigint_mod(&result.big_int_val, &a.big_int_val, &b.big_int_val); break;
case TK_LeftShift: bigint_shl(&result.big_int_val, &a.big_int_val, &b.big_int_val); break;
case TK_RightShift: bigint_shr(&result.big_int_val, &a.big_int_val, &b.big_int_val); break;
invalid_default_case;
}
}break;
CASE_BOOL:{
switch(op){
case TK_And: result.bool_val = a.bool_val && b.bool_val; break;
case TK_Or: result.bool_val = a.bool_val || b.bool_val; break;
case TK_BitAnd: result.bool_val = a.bool_val & b.bool_val; break;
case TK_BitOr: result.bool_val = a.bool_val | b.bool_val; break;
case TK_BitXor: result.bool_val = a.bool_val ^ b.bool_val; break;
invalid_default_case;
}
}break;
CASE_FLOAT:{
switch(op){
case TK_Add: result.f64_val = a.f64_val + b.f64_val; break;
case TK_Sub: result.f64_val = a.f64_val - b.f64_val; break;
case TK_Mul: result.f64_val = a.f64_val * b.f64_val; break;
case TK_Div: result.f64_val = a.f64_val / b.f64_val; break;
invalid_default_case;
}
}break;
CASE_STRING:{
invalid_codepath;
}break;
invalid_default_case;
}
}
return result;
}
function S64
digit_count(Value a){
S64 digit_count = a.big_int_val.digit_count*64;
if(is_typed(a.type)){
digit_count = a.type->size*8;
digit_count(const Value *a){
S64 digit_count = a->big_int_val.digit_count*64;
if(is_typed(a->type)){
digit_count = a->type->size*8;
}
return digit_count;
}
function Value
eval_unary(Token *pos, Token_Kind op, Value a){
function void
eval_unary(Token *pos, Token_Kind op, Value *a, bool is_const){
Ast_Resolved_Type *type = a->type;
if(!is_numeric(type))
parsing_error(pos, "Unary [%s] cant be applied to value of type %s", name(op), docname(type));
if(op == TK_Not)
a->type = untyped_bool;
if(!is_const)
return;
BigInt result = {};
switch(op){
case TK_Add:{
return a;
} break;
case TK_Add:{} break;
case TK_Sub:{
switch(a.type->kind){
switch(type->kind){
CASE_INT:{
bigint_negate(&result, &a.big_int_val);
return value_int(result);
bigint_negate(&result, &a->big_int_val);
a->big_int_val = result;
}break;
CASE_FLOAT:{
return value_float(-a.f64_val);
a->f64_val = -a->f64_val;
}break;
default:goto failure;
}
} break;
case TK_Neg:{
switch(a.type->kind){
CASE_SINT: case TYPE_UNTYPED_INT:{
bigint_not(&result, &a.big_int_val, digit_count(a), 1);
return value_int(result);
}break;
CASE_UINT:{
bigint_not(&result, &a.big_int_val, digit_count(a), 0);
return value_int(result);
}
switch(type->kind){
CASE_SINT: case TYPE_UNTYPED_INT:
bigint_not(&result, &a->big_int_val, digit_count(a), 1); break;
CASE_UINT:
bigint_not(&result, &a->big_int_val, digit_count(a), 0); break;
default:goto failure;
}
a->big_int_val = result;
} break;
case TK_Not:{
switch(a.type->kind){
switch(type->kind){
CASE_INT: {
if(CMP_EQ == bigint_cmp_zero(&a.big_int_val))
return value_bool(1);
return value_bool(0);
}break;
CASE_FLOAT:{
return value_bool(!a.f64_val);
}break;
CASE_BOOL:{
a.bool_val = !a.bool_val;
return a;
if(CMP_EQ == bigint_cmp_zero(&a->big_int_val))
a->bool_val = 1;
a->bool_val = 0;
}break;
CASE_FLOAT: a->bool_val = !a->f64_val; break;
CASE_BOOL: a->bool_val = !a->bool_val; break;
default:goto failure;
}
} break;
default:goto failure;
default: failure: parsing_error(pos, "Constant application of unary %s on values of type %s is not allowed", name(op), docname(a->type));
}
failure: parsing_error(pos, "Constant application of binary %s on values of type %s is not allowed", name(op), docname(a.type));
invalid_return;
}
function void
try_untyping(Operand *op){
convert_untyped_to_typed_default(Operand *op){
if(!op) return;
if(is_untyped(op->type)){
if(op->type->kind == TYPE_UNTYPED_INT) op->type = type_s64;
@@ -310,18 +273,18 @@ try_untyping(Operand *op){
}
function void
resolve_var(Token *pos, Operand *expr, Ast_Resolved_Type *type = 0){
if(type == expr->type) {
make_sure_types_are_compatible_for_assignment(Token *pos, Operand *expr, Ast_Resolved_Type *type = 0){
if(type == expr->type){
assert(expr->type);
return;
}
if(!type)
try_untyping(expr);
convert_untyped_to_typed_default(expr);
else if(!expr->type)
expr->type = type;
else if(is_untyped(expr->type))
expr->value = convert_untyped(pos, expr->value, type);
expr->value = convert_untyped_to_typed(pos, expr->value, type);
if(type && expr->type != type){
parsing_error(pos, "Assigning but incompatible types, expression: %s expected var type: %s", docname(expr->type), docname(type));
@@ -349,9 +312,12 @@ _rewrite_into_const(Ast *node, U64 ast_size, Sym *sym){
function Ast_Resolved_Type *
resolve_typespec(Ast_Expr *ast, B32 ast_can_be_null){
if(ast_can_be_null && ast == 0) return 0;
if(ast_can_be_null && ast == 0)
return 0;
Operand resolved = resolve_expr(ast);
if(resolved.type != type_type) parsing_error(ast->pos, "Expected [Type] got instead %s", type_names[resolved.type->kind]);
if(resolved.type != type_type)
parsing_error(ast->pos, "Expected [Type] got instead %s", type_names[resolved.type->kind]);
return resolved.type_val;
}
@@ -373,7 +339,7 @@ resolve_stmt(Ast *ast, Ast_Resolved_Type *ret){
CASE(RETURN, Return){ // @todo: need to check if all paths return a value
Operand op = resolve_expr(node->expr);
if(!op.type && ret != type_void) parsing_error(node->pos, "Function expects a void return value but the returned value is %s", docname(op.type));
op.value = convert_untyped(node->pos, op.value, ret);
op.value = convert_untyped_to_typed(node->pos, op.value, ret);
if(op.type && op.type != ret) parsing_error(node->pos, "Return statement has different type then returned value, expecting: %s got instead %s", docname(ret), docname(op.type));
BREAK();
}
@@ -415,6 +381,7 @@ resolve_stmt(Ast *ast, Ast_Resolved_Type *ret){
default:{
if(is_flag_set(ast->flags, AST_EXPR)){
assert(is_flag_set(ast->flags, AST_STMT));
resolve_expr((Ast_Expr *)ast);
}
else invalid_codepath;
@@ -440,9 +407,10 @@ resolve_lambda(Ast_Lambda *lambda, Sym *sym = 0){
Ast_Resolved_Type *ret_type = resolve_typespec(lambda->ret);
Array<Ast_Resolved_Type *> args = {scratch};
For(lambda->args){
Ast_Resolved_Type *type = resolve_typespec(it->typespec, AST_CANT_BE_NULL);
Ast_Resolved_Type *type =
resolve_typespec(it->typespec, AST_CANT_BE_NULL);
Operand default_value = resolve_expr(it->default_value, type);
resolve_var(it->pos, &default_value, type);
make_sure_types_are_compatible_for_assignment(it->pos, &default_value, type);
args.add(type);
}
@@ -569,7 +537,8 @@ resolve_expr(Ast_Expr *ast, Ast_Resolved_Type *expected_type, Sym *lambda_to_res
if(index > (type->arr.size - 1)) parsing_error(i->pos, "Invalid index in compound expression, larger then type can store");
}
Operand expr = resolve_expr(i->item, item_type);
expr.value = convert_untyped(i->pos, expr.value, item_type);
expr.value = convert_untyped_to_typed(i->pos, expr.value, item_type);
// @todo I don't think this detects when types are different
}
}
else if(type->kind == TYPE_STRUCT){
@@ -608,7 +577,7 @@ resolve_expr(Ast_Expr *ast, Ast_Resolved_Type *expected_type, Sym *lambda_to_res
Operand op = resolve_expr(expr->item, found_type->type);
op.value = convert_untyped(node->pos, op.value, found_type->type);
op.value = convert_untyped_to_typed(node->pos, op.value, found_type->type);
if(found_type->type != op.type) parsing_error(expr->pos, "Invalid type of compound constructor item, expected %s got instead %s", type_names[found_type->type->kind], type_names[op.type->kind]);
}
@@ -649,7 +618,7 @@ resolve_expr(Ast_Expr *ast, Ast_Resolved_Type *expected_type, Sym *lambda_to_res
if(item){
item->flags = set_flag(item->flags, AST_ITEM_INCLUDED);
Operand expr = resolve_expr(item->item);
expr.value = convert_untyped(node->pos, expr.value, resolved);
expr.value = convert_untyped_to_typed(node->pos, expr.value, resolved);
if(expr.type != resolved) type_error(item->pos, resolved, expr.type, "Type is not matching function definition");
items.add(item);
@@ -690,7 +659,7 @@ resolve_expr(Ast_Expr *ast, Ast_Resolved_Type *expected_type, Sym *lambda_to_res
else goto failure;
} break;
CASE_UNTYPED: {
expr.value = convert_untyped(node->pos, expr.value, type);
expr.value = convert_untyped_to_typed(node->pos, expr.value, type);
} break;
CASE_UINT:
CASE_SINT:{
@@ -734,11 +703,10 @@ resolve_expr(Ast_Expr *ast, Ast_Resolved_Type *expected_type, Sym *lambda_to_res
case TK_Dereference:{return operand_lvalue(type_pointer(value.type));}break;
case TK_Neg:case TK_Not:case TK_Add:case TK_Sub:{
Operand op = resolve_expr(node->expr);
if(!is_numeric(op.type)) parsing_error(node->pos, "Unary [%s] cant be applied to value of type %s", name(node->op), docname(op.type));
eval_unary(node->pos, node->op, &op.value, op.is_const);
if(op.is_const){
Value value = eval_unary(node->pos, node->op, op.value);
rewrite_into_const(node, Ast_Unary, value);
return operand_const_rvalue(value);
rewrite_into_const(node, Ast_Unary, op.value);
return operand_const_rvalue(op.value);
}
return operand_rvalue(op.value.type);
}break;
@@ -756,7 +724,7 @@ resolve_expr(Ast_Expr *ast, Ast_Resolved_Type *expected_type, Sym *lambda_to_res
assert(node->left->kind == AST_IDENT);
Operand right = resolve_expr(node->right);
resolve_var(node->pos, &right);
make_sure_types_are_compatible_for_assignment(node->pos, &right);
assert(right.type);
auto atom = (Ast_Atom *)node->left;
@@ -771,7 +739,7 @@ resolve_expr(Ast_Expr *ast, Ast_Resolved_Type *expected_type, Sym *lambda_to_res
if(!left.is_lvalue) parsing_error(node->pos, "Assigning to rvalue");
Operand right = resolve_expr(node->right);
right.value = convert_untyped(node->pos, right.value, left.type);
right.value = convert_untyped_to_typed(node->pos, right.value, left.type);
if(left.type != right.type) parsing_error(node->pos, "Can't assign value when left is %s and right is %s", docname(left.type), docname(right.type));
}
//-----------------------------------------------------------------------------
@@ -866,8 +834,9 @@ resolve_expr(Ast_Expr *ast, Ast_Resolved_Type *expected_type, Sym *lambda_to_res
else{
Operand left = resolve_expr(node->left);
Operand right = resolve_expr(node->right);
Value value = eval_binary(node->pos, node->op, left.value, right.value);
if(left.is_const && right.is_const){
B32 is_const = left.is_const && right.is_const;
Value value = eval_binary(node->pos, node->op, left.value, right.value, is_const);
if(is_const){
rewrite_into_const(node, Ast_Binary, value);
result = operand_const_rvalue(value);
}
@@ -934,7 +903,7 @@ resolve_binding(Ast *ast, Sym *sym){
Ast_Resolved_Type *type = resolve_typespec(node->typespec, AST_CAN_BE_NULL);
Operand expr = resolve_expr(node->expr, type);
assert(expr.type != 0 || type != 0);
resolve_var(node->pos, &expr, type);
make_sure_types_are_compatible_for_assignment(node->pos, &expr, type);
assert(expr.type);
return expr;
BREAK();