diff options
Diffstat (limited to 'src/checker/expr.cpp')
| -rw-r--r-- | src/checker/expr.cpp | 215 |
1 files changed, 135 insertions, 80 deletions
diff --git a/src/checker/expr.cpp b/src/checker/expr.cpp index bf17cf2e3..3b1881ea0 100644 --- a/src/checker/expr.cpp +++ b/src/checker/expr.cpp @@ -68,13 +68,16 @@ b32 check_is_assignable_to(Checker *c, Operand *operand, Type *type, b32 is_argu if (is_type_untyped(src)) { switch (dst->kind) { case Type_Basic: - if (operand->mode == Addressing_Constant) + if (operand->mode == Addressing_Constant) { return check_value_is_expressible(c, operand->value, dst, NULL); - if (src->kind == Type_Basic) - return src->Basic.kind == Basic_UntypedBool && is_type_boolean(dst); + } + if (src->kind == Type_Basic && src->Basic.kind == Basic_UntypedBool) { + return is_type_boolean(dst); + } break; - case Type_Pointer: - return src->Basic.kind == Basic_UntypedPointer; + } + if (type_has_nil(dst)) { + return is_operand_nil(operand); } } @@ -85,6 +88,10 @@ b32 check_is_assignable_to(Checker *c, Operand *operand, Type *type, b32 is_argu return true; } + if (is_type_untyped_nil(src)) { + return type_has_nil(dst); + } + // ^T <- rawptr // TODO(bill): Should C-style (not C++) pointer cast be allowed? // if (is_type_pointer(dst) && is_type_rawptr(src)) { @@ -146,7 +153,13 @@ void check_assignment(Checker *c, Operand *operand, Type *type, String context_n if (is_type_untyped(operand->type)) { Type *target_type = type; - if (type == NULL || is_type_any(type)) { + if (type == NULL || is_type_any(type) || is_type_untyped_nil(type)) { + if (type == NULL && base_type(operand->type) == t_untyped_nil) { + error(ast_node_token(operand->expr), "Use of untyped nil in %.*s", LIT(context_name)); + operand->mode = Addressing_Invalid; + return; + } + add_type_info_type(c, type); target_type = default_type(operand->type); } @@ -229,14 +242,15 @@ void check_fields(Checker *c, AstNode *node, AstNodeArray decls, isize other_field_index = 0; Entity *using_index_expr = NULL; + + gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena); + defer (gb_temp_arena_memory_end(tmp)); struct Delay { Entity *e; AstNode *t; }; - gbArray(Delay) delayed_const; gb_array_init(delayed_const, gb_heap_allocator()); - gbArray(Delay) delayed_type; gb_array_init(delayed_type, gb_heap_allocator()); - defer (gb_array_free(delayed_const)); - defer (gb_array_free(delayed_type)); + gbArray(Delay) delayed_const; gb_array_init_reserve(delayed_const, c->tmp_allocator, other_field_count); + gbArray(Delay) delayed_type; gb_array_init_reserve(delayed_type, c->tmp_allocator, other_field_count); gb_for_array(decl_index, decls) { AstNode *decl = decls[decl_index]; @@ -729,8 +743,8 @@ void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *nod make_token_ident(make_string("max_value")), constant_type, make_exact_value_integer(max_value)); } -Type *check_get_params(Checker *c, Scope *scope, AstNodeArray fields, b32 *is_variadic_) { - if (fields == NULL || gb_array_count(fields) == 0) +Type *check_get_params(Checker *c, Scope *scope, AstNodeArray params, b32 *is_variadic_) { + if (params == NULL || gb_array_count(params) == 0) return NULL; b32 is_variadic = false; @@ -738,33 +752,32 @@ Type *check_get_params(Checker *c, Scope *scope, AstNodeArray fields, b32 *is_va Type *tuple = make_type_tuple(c->allocator); isize variable_count = 0; - gb_for_array(i, fields) { - AstNode *field = fields[i]; - ast_node(f, Field, field); - variable_count += gb_array_count(f->names); + gb_for_array(i, params) { + AstNode *field = params[i]; + ast_node(p, Parameter, field); + variable_count += gb_array_count(p->names); } Entity **variables = gb_alloc_array(c->allocator, Entity *, variable_count); isize variable_index = 0; - gb_for_array(i, fields) { - AstNode *field = fields[i]; - ast_node(f, Field, field); - AstNode *type_expr = f->type; + gb_for_array(i, params) { + ast_node(p, Parameter, params[i]); + AstNode *type_expr = p->type; if (type_expr) { if (type_expr->kind == AstNode_Ellipsis) { type_expr = type_expr->Ellipsis.expr; - if (i+1 == gb_array_count(fields)) { + if (i+1 == gb_array_count(params)) { is_variadic = true; } else { - error(ast_node_token(field), "Invalid AST: Invalid variadic parameter"); + error(ast_node_token(params[i]), "Invalid AST: Invalid variadic parameter"); } } Type *type = check_type(c, type_expr); - gb_for_array(j, f->names) { - AstNode *name = f->names[j]; + gb_for_array(j, p->names) { + AstNode *name = p->names[j]; if (name->kind == AstNode_Ident) { - Entity *param = make_entity_param(c->allocator, scope, name->Ident, type, f->is_using); + Entity *param = make_entity_param(c->allocator, scope, name->Ident, type, p->is_using); add_entity(c, scope, name, param); variables[variable_index++] = param; } else { @@ -774,10 +787,10 @@ Type *check_get_params(Checker *c, Scope *scope, AstNodeArray fields, b32 *is_va } } - if (is_variadic && gb_array_count(fields) > 0) { + if (is_variadic && gb_array_count(params) > 0) { // NOTE(bill): Change last variadic parameter to be a slice // Custom Calling convention for variadic parameters - Entity *end = variables[gb_array_count(fields)-1]; + Entity *end = variables[gb_array_count(params)-1]; end->type = make_type_slice(c->allocator, end->type); } @@ -927,6 +940,10 @@ void check_identifier(Checker *c, Operand *o, AstNode *n, Type *named_type, Cycl error(ast_node_token(n), "Use of import `%.*s` not in selector", LIT(e->ImportName.name)); return; + case Entity_Nil: + o->mode = Addressing_Value; + break; + default: compiler_error("Compiler error: Unknown EntityKind"); break; @@ -1184,15 +1201,20 @@ b32 check_binary_op(Checker *c, Operand *o, Token op) { } break; - case Token_Mod: case Token_And: case Token_Or: + case Token_AndEq: + case Token_OrEq: + if (!is_type_integer(type) && !is_type_boolean(type)) { + error(op, "Operator `%.*s` is only allowed with integers or booleans", LIT(op.string)); + return false; + } + break; + + case Token_Mod: case Token_Xor: case Token_AndNot: - case Token_ModEq: - case Token_AndEq: - case Token_OrEq: case Token_XorEq: case Token_AndNotEq: if (!is_type_integer(type)) { @@ -1350,7 +1372,17 @@ void check_unary_expr(Checker *c, Operand *o, Token op, AstNode *node) { if (o->mode == Addressing_Constant) { Type *type = base_type(o->type); - GB_ASSERT(type->kind == Type_Basic); + if (type->kind != Type_Basic) { + gbString xt = type_to_string(o->type); + gbString err_str = expr_to_string(node); + defer (gb_string_free(xt)); + defer (gb_string_free(err_str)); + error(op, "Invalid type, `%s`, for constant unary expression `%s`", xt, err_str); + o->mode = Addressing_Invalid; + return; + } + + i32 precision = 0; if (is_type_unsigned(type)) precision = cast(i32)(8 * type_size_of(c->sizes, c->allocator, type)); @@ -1368,6 +1400,9 @@ void check_unary_expr(Checker *c, Operand *o, Token op, AstNode *node) { } void check_comparison(Checker *c, Operand *x, Operand *y, Token op) { + gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena); + defer (gb_temp_arena_memory_end(tmp)); + gbString err_str = NULL; defer ({ if (err_str != NULL) @@ -1392,16 +1427,16 @@ void check_comparison(Checker *c, Operand *x, Operand *y, Token op) { if (!defined) { gbString type_string = type_to_string(x->type); - err_str = gb_string_make(gb_heap_allocator(), + defer (gb_string_free(type_string)); + err_str = gb_string_make(c->tmp_allocator, gb_bprintf("operator `%.*s` not defined for type `%s`", LIT(op.string), type_string)); - gb_string_free(type_string); } } else { gbString xt = type_to_string(x->type); gbString yt = type_to_string(y->type); defer(gb_string_free(xt)); defer(gb_string_free(yt)); - err_str = gb_string_make(gb_heap_allocator(), + err_str = gb_string_make(c->tmp_allocator, gb_bprintf("mismatched types `%s` and `%s`", xt, yt)); } @@ -1853,7 +1888,15 @@ void check_binary_expr(Checker *c, Operand *x, AstNode *node) { ExactValue b = y->value; Type *type = base_type(x->type); - GB_ASSERT(type->kind == Type_Basic); + if (type->kind != Type_Basic) { + gbString xt = type_to_string(x->type); + defer (gb_string_free(xt)); + err_str = expr_to_string(node); + error(op, "Invalid type, `%s`, for constant binary expression `%s`", xt, err_str); + x->mode = Addressing_Invalid; + return; + } + if (op.kind == Token_Quo && is_type_integer(type)) { op.kind = Token_QuoEq; // NOTE(bill): Hack to get division of integers } @@ -1932,8 +1975,10 @@ void convert_untyped_error(Checker *c, Operand *operand, Type *target_type) { if (operand->mode == Addressing_Constant) { if (operand->value.value_integer == 0) { - // NOTE(bill): Doesn't matter what the type is as it's still zero in the union - extra_text = " - Did you want `null`?"; + if (make_string(expr_str) != "nil") { // HACK NOTE(bill): Just in case + // NOTE(bill): Doesn't matter what the type is as it's still zero in the union + extra_text = " - Did you want `nil`?"; + } } } error(ast_node_token(operand->expr), "Cannot convert `%s` to `%s`%s", expr_str, type_str, extra_text); @@ -1989,36 +2034,27 @@ void convert_to_typed(Checker *c, Operand *operand, Type *target_type) { return; } break; + + case Basic_UntypedNil: + if (!type_has_nil(target_type)) { + convert_untyped_error(c, operand, target_type); + return; + } + break; } } break; - case Type_Pointer: - switch (operand->type->Basic.kind) { - case Basic_UntypedPointer: - target_type = t_untyped_pointer; - break; - default: - convert_untyped_error(c, operand, target_type); - return; - } - break; - case Type_Proc: - switch (operand->type->Basic.kind) { - case Basic_UntypedPointer: - break; - default: + default: + if (!type_has_nil(target_type)) { convert_untyped_error(c, operand, target_type); return; } break; - - default: - convert_untyped_error(c, operand, target_type); - return; } operand->type = target_type; + update_expr_type(c, operand->expr, target_type, true); } b32 check_index_value(Checker *c, AstNode *index_value, i64 max_count, i64 *value) { @@ -2415,6 +2451,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) error(ast_node_token(expr), "Invalid argument to `type_info`"); return false; } + add_type_info_type(c, type); operand->mode = Addressing_Value; @@ -2993,10 +3030,12 @@ void check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNode return; } + gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena); + defer (gb_temp_arena_memory_end(tmp)); + isize operand_count = 0; gbArray(Operand) operands; - gb_array_init_reserve(operands, gb_heap_allocator(), 2*param_count); - defer (gb_array_free(operands)); + gb_array_init_reserve(operands, c->tmp_allocator, 2*param_count); gb_for_array(i, ce->args) { Operand o = {}; @@ -3374,12 +3413,12 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint error(ast_node_token(e), "Index %lld is out of bounds (>= %lld) for vector literal", index, t->Vector.count); } - Operand o = {}; - check_expr_with_type_hint(c, &o, e, elem_type); - check_assignment(c, &o, elem_type, context_name); + Operand operand = {}; + check_expr_with_type_hint(c, &operand, e, elem_type); + check_assignment(c, &operand, elem_type, context_name); if (is_constant) { - is_constant = o.mode == Addressing_Constant; + is_constant = operand.mode == Addressing_Constant; } } if (max < index) @@ -3730,10 +3769,9 @@ void check_expr_or_type(Checker *c, Operand *o, AstNode *e) { check_expr_base(c, o, e); check_not_tuple(c, o); if (o->mode == Addressing_NoValue) { - AstNode *e = o->expr; - gbString str = expr_to_string(e); + gbString str = expr_to_string(o->expr); defer (gb_string_free(str)); - error(ast_node_token(e), + error(ast_node_token(o->expr), "`%s` used as value or type", str); o->mode = Addressing_Invalid; } @@ -3742,15 +3780,14 @@ void check_expr_or_type(Checker *c, Operand *o, AstNode *e) { gbString write_expr_to_string(gbString str, AstNode *node); -gbString write_fields_to_string(gbString str, AstNodeArray fields, char *sep) { - gb_for_array(i, fields) { - AstNode *field = fields[i]; - ast_node(f, Field, field); +gbString write_params_to_string(gbString str, AstNodeArray params, char *sep) { + gb_for_array(i, params) { + ast_node(p, Parameter, params[i]); if (i > 0) { str = gb_string_appendc(str, sep); } - str = write_expr_to_string(str, field); + str = write_expr_to_string(str, params[i]); } return str; } @@ -3885,19 +3922,19 @@ gbString write_expr_to_string(gbString str, AstNode *node) { str = write_expr_to_string(str, vt->elem); case_end; - case_ast_node(f, Field, node); - if (f->is_using) { + case_ast_node(p, Parameter, node); + if (p->is_using) { str = gb_string_appendc(str, "using "); } - gb_for_array(i, f->names) { - AstNode *name = f->names[i]; + gb_for_array(i, p->names) { + AstNode *name = p->names[i]; if (i > 0) str = gb_string_appendc(str, ", "); str = write_expr_to_string(str, name); } str = gb_string_appendc(str, ": "); - str = write_expr_to_string(str, f->type); + str = write_expr_to_string(str, p->type); case_end; case_ast_node(ce, CallExpr, node); @@ -3916,7 +3953,7 @@ gbString write_expr_to_string(gbString str, AstNode *node) { case_ast_node(pt, ProcType, node); str = gb_string_appendc(str, "proc("); - str = write_fields_to_string(str, pt->params, ", "); + str = write_params_to_string(str, pt->params, ", "); str = gb_string_appendc(str, ")"); case_end; @@ -3924,19 +3961,37 @@ gbString write_expr_to_string(gbString str, AstNode *node) { str = gb_string_appendc(str, "struct "); if (st->is_packed) str = gb_string_appendc(str, "#packed "); if (st->is_ordered) str = gb_string_appendc(str, "#ordered "); - // str = write_fields_to_string(str, st->decl_list, ", "); + gb_for_array(i, st->decls) { + if (i > 0) { + str = gb_string_appendc(str, "; "); + } + str = write_expr_to_string(str, st->decls[i]); + } + // str = write_params_to_string(str, st->decl_list, ", "); str = gb_string_appendc(str, "}"); case_end; case_ast_node(st, RawUnionType, node); str = gb_string_appendc(str, "raw_union {"); - // str = write_fields_to_string(str, st->decl_list, ", "); + gb_for_array(i, st->decls) { + if (i > 0) { + str = gb_string_appendc(str, "; "); + } + str = write_expr_to_string(str, st->decls[i]); + } + // str = write_params_to_string(str, st->decl_list, ", "); str = gb_string_appendc(str, "}"); case_end; case_ast_node(st, UnionType, node); str = gb_string_appendc(str, "union {"); - // str = write_fields_to_string(str, st->decl_list, ", "); + gb_for_array(i, st->decls) { + if (i > 0) { + str = gb_string_appendc(str, "; "); + } + str = write_expr_to_string(str, st->decls[i]); + } + // str = write_params_to_string(str, st->decl_list, ", "); str = gb_string_appendc(str, "}"); case_end; |