aboutsummaryrefslogtreecommitdiff
path: root/src/checker/expr.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/checker/expr.cpp')
-rw-r--r--src/checker/expr.cpp149
1 files changed, 93 insertions, 56 deletions
diff --git a/src/checker/expr.cpp b/src/checker/expr.cpp
index 4129e6e73..fc5020f9b 100644
--- a/src/checker/expr.cpp
+++ b/src/checker/expr.cpp
@@ -105,11 +105,6 @@ Type *check_get_results(Checker *c, Scope *scope, AstNode *list, isize list_coun
Entity *param = make_entity_param(c->allocator, scope, token, type);
// NOTE(bill): No need to record
variables[variable_index++] = param;
-
- if (get_base_type(type)->kind == Type_Array) {
- // TODO(bill): Should I allow array's to returned?
- error(&c->error_collector, token, "You cannot return an array from a procedure");
- }
}
tuple->tuple.variables = variables;
tuple->tuple.variable_count = list_count;
@@ -129,11 +124,11 @@ void check_procedure_type(Checker *c, Type *type, AstNode *proc_type_node) {
Type *params = check_get_params(c, c->context.scope, pt->param_list, param_count);
Type *results = check_get_results(c, c->context.scope, pt->result_list, result_count);
- type->procedure.scope = c->context.scope;
- type->procedure.params = params;
- type->procedure.param_count = pt->param_count;
- type->procedure.results = results;
- type->procedure.result_count = pt->result_count;
+ type->proc.scope = c->context.scope;
+ type->proc.params = params;
+ type->proc.param_count = pt->param_count;
+ type->proc.results = results;
+ type->proc.result_count = pt->result_count;
}
@@ -292,7 +287,7 @@ Type *check_type_expr_extra(Checker *c, AstNode *e, Type *named_type) {
case_end;
case_ast_node(pt, ProcType, e);
- Type *t = alloc_type(c->allocator, Type_Procedure);
+ Type *t = alloc_type(c->allocator, Type_Proc);
set_base_type(named_type, t);
check_open_scope(c, e);
check_procedure_type(c, t, e);
@@ -384,7 +379,7 @@ Type *check_type(Checker *c, AstNode *e, Type *named_type) {
case_end;
case_ast_node(pt, ProcType, e);
- type = alloc_type(c->allocator, Type_Procedure);
+ type = alloc_type(c->allocator, Type_Proc);
set_base_type(named_type, type);
check_procedure_type(c, type, e);
goto end;
@@ -958,7 +953,7 @@ Entity *lookup_field(Type *type, AstNode *field_node, isize *index = NULL) {
GB_ASSERT(field_node->kind == AstNode_Ident);
type = get_base_type(type);
if (type->kind == Type_Pointer)
- type = get_base_type(type->pointer.element);
+ type = get_base_type(type->pointer.elem);
ast_node(i, Ident, field_node);
String field_str = i->token.string;
@@ -1016,7 +1011,7 @@ void check_selector(Checker *c, Operand *operand, AstNode *node) {
b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) {
GB_ASSERT(call->kind == AstNode_CallExpr);
ast_node(ce, CallExpr, call);
- BuiltinProcedure *bp = &builtin_procedures[id];
+ BuiltinProc *bp = &builtin_procs[id];
{
char *err = NULL;
if (ce->arg_list_count < bp->arg_count)
@@ -1033,9 +1028,9 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
}
switch (id) {
- case BuiltinProcedure_size_of:
- case BuiltinProcedure_align_of:
- case BuiltinProcedure_offset_of:
+ case BuiltinProc_size_of:
+ case BuiltinProc_align_of:
+ case BuiltinProc_offset_of:
// NOTE(bill): The first arg is a Type, this will be checked case by case
break;
default:
@@ -1043,7 +1038,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
}
switch (id) {
- case BuiltinProcedure_size_of: {
+ case BuiltinProc_size_of: {
// size_of :: proc(Type)
Type *type = check_type(c, ce->arg_list);
if (!type) {
@@ -1057,7 +1052,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
} break;
- case BuiltinProcedure_size_of_val:
+ case BuiltinProc_size_of_val:
// size_of_val :: proc(val)
check_assignment(c, operand, NULL, make_string("argument of `size_of`"));
if (operand->mode == Addressing_Invalid)
@@ -1068,7 +1063,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
operand->type = t_int;
break;
- case BuiltinProcedure_align_of: {
+ case BuiltinProc_align_of: {
// align_of :: proc(Type)
Type *type = check_type(c, ce->arg_list);
if (!type) {
@@ -1080,7 +1075,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
operand->type = t_int;
} break;
- case BuiltinProcedure_align_of_val:
+ case BuiltinProc_align_of_val:
// align_of_val :: proc(val)
check_assignment(c, operand, NULL, make_string("argument of `align_of`"));
if (operand->mode == Addressing_Invalid)
@@ -1091,7 +1086,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
operand->type = t_int;
break;
- case BuiltinProcedure_offset_of: {
+ case BuiltinProc_offset_of: {
// offset_val :: proc(Type, field)
Type *type = get_base_type(check_type(c, ce->arg_list));
AstNode *field_arg = unparen_expr(ce->arg_list->next);
@@ -1122,7 +1117,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
operand->type = t_int;
} break;
- case BuiltinProcedure_offset_of_val: {
+ case BuiltinProc_offset_of_val: {
// offset_val :: proc(val)
AstNode *arg = unparen_expr(ce->arg_list);
if (arg->kind != AstNode_SelectorExpr) {
@@ -1140,7 +1135,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
if (get_base_type(type)->kind == Type_Pointer) {
Type *p = get_base_type(type);
if (get_base_type(p)->kind == Type_Structure)
- type = p->pointer.element;
+ type = p->pointer.elem;
}
isize index = 0;
@@ -1158,7 +1153,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
operand->type = t_int;
} break;
- case BuiltinProcedure_static_assert:
+ case BuiltinProc_static_assert:
// static_assert :: proc(cond: bool)
// TODO(bill): Should `static_assert` and `assert` be unified?
@@ -1180,8 +1175,8 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
break;
// TODO(bill): Should these be procedures and are their names appropriate?
- case BuiltinProcedure_len:
- case BuiltinProcedure_cap: {
+ case BuiltinProc_len:
+ case BuiltinProc_cap: {
Type *t = get_base_type(operand->type);
AddressingMode mode = Addressing_Invalid;
@@ -1189,7 +1184,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
switch (t->kind) {
case Type_Basic:
- if (id == BuiltinProcedure_len) {
+ if (id == BuiltinProc_len) {
if (is_type_string(t)) {
if (operand->mode == Addressing_Constant) {
mode = Addressing_Constant;
@@ -1226,14 +1221,13 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
} break;
- // TODO(bill): copy() pointer version?
- case BuiltinProcedure_copy: {
+ case BuiltinProc_copy: {
// copy :: proc(x, y: []Type) -> int
Type *dest_type = NULL, *src_type = NULL;
Type *d = get_base_type(operand->type);
if (d->kind == Type_Slice)
- dest_type = d->slice.element;
+ dest_type = d->slice.elem;
Operand op = {};
check_expr(c, &op, ce->arg_list->next);
@@ -1241,7 +1235,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
return false;
Type *s = get_base_type(op.type);
if (s->kind == Type_Slice)
- src_type = s->slice.element;
+ src_type = s->slice.elem;
if (dest_type == NULL || src_type == NULL) {
error(&c->error_collector, ast_node_token(call), "`copy` only expects slices as arguments");
@@ -1258,20 +1252,56 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
defer (gb_string_free(d_str));
defer (gb_string_free(s_str));
error(&c->error_collector, ast_node_token(call),
- "Arguments to `copy`, %s, %s, have different element types: %s vs %s",
+ "Arguments to `copy`, %s, %s, have different elem types: %s vs %s",
+ d_arg, s_arg, d_str, s_str);
+ return false;
+ }
+
+ operand->type = t_int; // Returns number of elems copied
+ operand->mode = Addressing_Value;
+ } break;
+
+ case BuiltinProc_append: {
+ // append :: proc(x : ^[]Type, y : Type) -> bool
+ Type *x_type = NULL, *y_type = NULL;
+ x_type = get_base_type(operand->type);
+
+ Operand op = {};
+ check_expr(c, &op, ce->arg_list->next);
+ if (op.mode == Addressing_Invalid)
+ return false;
+ y_type = get_base_type(op.type);
+
+ if (!(is_type_pointer(x_type) && is_type_slice(x_type->pointer.elem))) {
+ error(&c->error_collector, ast_node_token(call), "First argument to `append` must be a pointer to a slice");
+ return false;
+ }
+
+ Type *elem_type = x_type->pointer.elem->slice.elem;
+ if (!check_is_assignable_to(c, &op, elem_type)) {
+ gbString d_arg = expr_to_string(ce->arg_list);
+ gbString s_arg = expr_to_string(ce->arg_list->next);
+ gbString d_str = type_to_string(elem_type);
+ gbString s_str = type_to_string(y_type);
+ defer (gb_string_free(d_arg));
+ defer (gb_string_free(s_arg));
+ defer (gb_string_free(d_str));
+ defer (gb_string_free(s_str));
+ error(&c->error_collector, ast_node_token(call),
+ "Arguments to `append`, %s, %s, have different element types: %s vs %s",
d_arg, s_arg, d_str, s_str);
return false;
}
- operand->type = t_int; // Returns number of elements copied
+ operand->type = t_bool; // Returns if it was successful
operand->mode = Addressing_Value;
} break;
- case BuiltinProcedure_print:
- case BuiltinProcedure_println: {
+ case BuiltinProc_print:
+ case BuiltinProc_println: {
for (AstNode *arg = ce->arg_list; arg != NULL; arg = arg->next) {
// TOOD(bill): `check_assignment` doesn't allow tuples at the moment, should it?
- // Or should we destruct the tuple and use each element?
+ // Or should we destruct the tuple and use each elem?
check_assignment(c, operand, NULL, make_string("argument"));
if (operand->mode == Addressing_Invalid)
return false;
@@ -1285,14 +1315,14 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
void check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNode *call) {
GB_ASSERT(call->kind == AstNode_CallExpr);
- GB_ASSERT(proc_type->kind == Type_Procedure);
+ GB_ASSERT(proc_type->kind == Type_Proc);
ast_node(ce, CallExpr, call);
isize error_code = 0;
isize param_index = 0;
isize param_count = 0;
- if (proc_type->procedure.params)
- param_count = proc_type->procedure.params->tuple.variable_count;
+ if (proc_type->proc.params)
+ param_count = proc_type->proc.params->tuple.variable_count;
if (ce->arg_list_count == 0 && param_count == 0)
return;
@@ -1300,7 +1330,7 @@ void check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNode
if (ce->arg_list_count > param_count) {
error_code = +1;
} else {
- Entity **sig_params = proc_type->procedure.params->tuple.variables;
+ Entity **sig_params = proc_type->proc.params->tuple.variables;
AstNode *call_arg = ce->arg_list;
for (; call_arg != NULL; call_arg = call_arg->next) {
check_multi_expr(c, operand, call_arg);
@@ -1376,11 +1406,11 @@ ExpressionKind check_call_expr(Checker *c, Operand *operand, AstNode *call) {
if (!check_builtin_procedure(c, operand, call, id))
operand->mode = Addressing_Invalid;
operand->expr = call;
- return builtin_procedures[id].kind;
+ return builtin_procs[id].kind;
}
Type *proc_type = get_base_type(operand->type);
- if (proc_type == NULL || proc_type->kind != Type_Procedure) {
+ if (proc_type == NULL || proc_type->kind != Type_Proc) {
AstNode *e = operand->expr;
gbString str = expr_to_string(e);
defer (gb_string_free(str));
@@ -1395,7 +1425,7 @@ ExpressionKind check_call_expr(Checker *c, Operand *operand, AstNode *call) {
check_call_arguments(c, operand, proc_type, call);
- auto *proc = &proc_type->procedure;
+ auto *proc = &proc_type->proc;
if (proc->result_count == 0) {
operand->mode = Addressing_NoValue;
} else if (proc->result_count == 1) {
@@ -1448,6 +1478,14 @@ b32 check_castable_to(Checker *c, Operand *operand, Type *y) {
return true;
}
+ // []byte/[]u8 <-> string
+ if (is_type_byte_slice(xb) && is_type_string(yb)) {
+ return true;
+ }
+ if (is_type_string(xb) && is_type_byte_slice(yb)) {
+ return true;
+ }
+
return false;
}
@@ -1590,13 +1628,13 @@ ExpressionKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *typ
case Type_Slice:
case Type_Array:
{
- Type *element_type = NULL;
+ Type *elem_type = NULL;
String context_name = {};
if (t->kind == Type_Slice) {
- element_type = t->slice.element;
+ elem_type = t->slice.elem;
context_name = make_string("slice literal");
} else {
- element_type = t->array.element;
+ elem_type = t->array.elem;
context_name = make_string("array literal");
}
@@ -1612,8 +1650,8 @@ ExpressionKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *typ
}
Operand o = {};
- check_expr_with_type_hint(c, &o, e, element_type);
- check_assignment(c, &o, element_type, context_name);
+ check_expr_with_type_hint(c, &o, e, elem_type);
+ check_assignment(c, &o, elem_type, context_name);
}
if (max < index)
max = index;
@@ -1693,19 +1731,19 @@ ExpressionKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *typ
max_count = t->array.count;
if (o->mode != Addressing_Variable)
o->mode = Addressing_Value;
- o->type = t->array.element;
+ o->type = t->array.elem;
break;
case Type_Slice:
valid = true;
- o->type = t->slice.element;
+ o->type = t->slice.elem;
o->mode = Addressing_Variable;
break;
case Type_Pointer:
valid = true;
o->mode = Addressing_Variable;
- o->type = get_base_type(t->pointer.element);
+ o->type = get_base_type(t->pointer.elem);
break;
}
@@ -1757,7 +1795,7 @@ ExpressionKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *typ
gb_string_free(str);
goto error;
}
- o->type = make_type_slice(c->allocator, t->array.element);
+ o->type = make_type_slice(c->allocator, t->array.elem);
o->mode = Addressing_Value;
break;
@@ -1768,7 +1806,7 @@ ExpressionKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *typ
case Type_Pointer:
valid = true;
- o->type = make_type_slice(c->allocator, get_base_type(t->pointer.element));
+ o->type = make_type_slice(c->allocator, get_base_type(t->pointer.elem));
o->mode = Addressing_Value;
break;
}
@@ -1832,7 +1870,7 @@ ExpressionKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *typ
Type *t = get_base_type(o->type);
if (t->kind == Type_Pointer) {
o->mode = Addressing_Variable;
- o->type = t->pointer.element;
+ o->type = t->pointer.elem;
} else {
gbString str = expr_to_string(o->expr);
error(&c->error_collector, ast_node_token(o->expr), "Cannot dereference `%s`", str);
@@ -1911,7 +1949,6 @@ void check_multi_expr(Checker *c, Operand *o, AstNode *e) {
o->mode = Addressing_Invalid;
}
-// TODO(bill): Should I remove this entirely?
void check_not_tuple(Checker *c, Operand *o) {
if (o->mode == Addressing_Value) {
// NOTE(bill): Tuples are not first class thus never named