diff --git a/core/_preload.odin b/core/_preload.odin index 4a95b2ed7..4a324f90c 100644 --- a/core/_preload.odin +++ b/core/_preload.odin @@ -290,32 +290,32 @@ __check_context :: proc() { } */ -alloc :: inline proc(size: int, alignment: int = DEFAULT_ALIGNMENT) -> rawptr { +alloc :: inline proc(size: int, alignment: int = DEFAULT_ALIGNMENT, location := #caller_location) -> rawptr { a := context.allocator; - return a.procedure(a.data, Allocator_Mode.Alloc, size, alignment, nil, 0, 0); + return a.procedure(a.data, Allocator_Mode.Alloc, size, alignment, nil, 0, 0, location); } -free_ptr_with_allocator :: inline proc(a: Allocator, ptr: rawptr) { +free_ptr_with_allocator :: inline proc(a: Allocator, ptr: rawptr, location := #caller_location) { if ptr == nil do return; if a.procedure == nil do return; - a.procedure(a.data, Allocator_Mode.Free, 0, 0, ptr, 0, 0); + a.procedure(a.data, Allocator_Mode.Free, 0, 0, ptr, 0, 0, location); } -free_ptr :: inline proc(ptr: rawptr) do free_ptr_with_allocator(context.allocator, ptr); +free_ptr :: inline proc(ptr: rawptr, location := #caller_location) do free_ptr_with_allocator(context.allocator, ptr); -free_all :: inline proc() { +free_all :: inline proc(location := #caller_location) { a := context.allocator; - a.procedure(a.data, Allocator_Mode.FreeAll, 0, 0, nil, 0, 0); + a.procedure(a.data, Allocator_Mode.FreeAll, 0, 0, nil, 0, 0, location); } -resize :: inline proc(ptr: rawptr, old_size, new_size: int, alignment: int = DEFAULT_ALIGNMENT) -> rawptr { +resize :: inline proc(ptr: rawptr, old_size, new_size: int, alignment: int = DEFAULT_ALIGNMENT, location := #caller_location) -> rawptr { a := context.allocator; - return a.procedure(a.data, Allocator_Mode.Resize, new_size, alignment, ptr, old_size, 0); + return a.procedure(a.data, Allocator_Mode.Resize, new_size, alignment, ptr, old_size, 0, location); } -copy :: proc(dst, src: $T/[]$E) -> int { +copy :: proc "contextless" (dst, src: $T/[]$E) -> int { n := max(0, min(len(dst), len(src))); if n > 0 do __mem_copy(&dst[0], &src[0], n*size_of(E)); return n; @@ -406,7 +406,7 @@ clear :: inline proc "contextless" (m: ^$T/map[$K]$V) { entries.len = 0; } -reserve :: proc(array: ^$T/[dynamic]$E, capacity: int) -> bool { +reserve :: proc(array: ^$T/[dynamic]$E, capacity: int, location := #caller_location) -> bool { if array == nil do return false; a := cast(^raw.Dynamic_Array)array; @@ -421,7 +421,10 @@ reserve :: proc(array: ^$T/[dynamic]$E, capacity: int) -> bool { new_size := capacity * size_of(E); allocator := a.allocator; - new_data := allocator.procedure(allocator.data, Allocator_Mode.Resize, new_size, align_of(E), a.data, old_size, 0); + new_data := allocator.procedure( + allocator.data, Allocator_Mode.Resize, new_size, align_of(E), + a.data, old_size, 0, location, + ); if new_data == nil do return false; a.data = new_data; @@ -490,25 +493,33 @@ delete :: proc(m: ^$T/map[$K]$V, key: K) { -new :: inline proc(T: type) -> ^T { - ptr := cast(^T)alloc(size_of(T), align_of(T)); +new :: inline proc(T: type, location := #caller_location) -> ^T { + ptr := cast(^T)alloc(size_of(T), align_of(T), location); ptr^ = T{}; return ptr; } -new_clone :: inline proc(data: $T) -> ^T { - ptr := cast(^T)alloc(size_of(T), align_of(T)); +new_clone :: inline proc(data: $T, location := #caller_location) -> ^T { + ptr := cast(^T)alloc(size_of(T), align_of(T), location); ptr^ = data; return ptr; } -free :: proc(ptr: rawptr) do free_ptr(ptr); -free :: proc(str: $T/string) do free_ptr((^raw.String )(&str).data); -free :: proc(array: $T/[dynamic]$E) do free_ptr((^raw.Dynamic_Array)(&array).data); -free :: proc(slice: $T/[]$E) do free_ptr((^raw.Slice )(&slice).data); -free :: proc(m: $T/map[$K]$V) { +free :: proc(ptr: rawptr, location := #caller_location) { + free_ptr(ptr, location); +} +free :: proc(str: $T/string, location := #caller_location) { + free_ptr((^raw.String)(&str).data, location); +} +free :: proc(array: $T/[dynamic]$E, location := #caller_location) { + free_ptr((^raw.Dynamic_Array)(&array).data, location); +} +free :: proc(slice: $T/[]$E, location := #caller_location) { + free_ptr((^raw.Slice)(&slice).data, location); +} +free :: proc(m: $T/map[$K]$V, location := #caller_location) { raw := cast(^raw.Map)&m; - free(raw.hashes); - free(raw.entries.data); + free(raw.hashes, location); + free(raw.entries.data, location); } // NOTE(bill): This code works but I will prefer having `make` a built-in procedure @@ -557,21 +568,21 @@ make :: proc(T: type/map[$K]$V, cap: int = 16, using location := #caller_locatio -default_resize_align :: proc(old_memory: rawptr, old_size, new_size, alignment: int) -> rawptr { - if old_memory == nil do return alloc(new_size, alignment); +default_resize_align :: proc(old_memory: rawptr, old_size, new_size, alignment: int, location := #caller_location) -> rawptr { + if old_memory == nil do return alloc(new_size, alignment, location); if new_size == 0 { - free(old_memory); + free(old_memory, location); return nil; } if new_size == old_size do return old_memory; - new_memory := alloc(new_size, alignment); + new_memory := alloc(new_size, alignment, location); if new_memory == nil do return nil; __mem_copy(new_memory, old_memory, min(old_size, new_size));; - free(old_memory); + free(old_memory, location); return new_memory; } diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 46e3f7b84..cd61d9fd0 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -4082,13 +4082,17 @@ void check_unpack_arguments(Checker *c, Entity **lhs, isize lhs_count, Arrayinfo, lhs[tuple_index]); + Entity *e = lhs[tuple_index]; + DeclInfo *decl = decl_info_of_entity(&c->info, e); if (decl) c->context.decl = decl; + type_hint = e->type; } - check_expr_base(c, &o, rhs[i], nullptr); + check_expr_base(c, &o, rhs[i], type_hint); if (o.mode == Addressing_NoValue) { error_operand_no_value(&o); o.mode = Addressing_Invalid; @@ -5508,7 +5512,7 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t } fields_visited[sel.index[0]] = true; - check_expr(c, o, fv->value); + check_expr_with_type_hint(c, o, fv->value, field->type); if (is_type_any(field->type) || is_type_union(field->type) || is_type_raw_union(field->type)) { is_constant = false; @@ -5530,7 +5534,13 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t } } + isize field_index = 0; for_array(index, cl->elems) { + Entity *field = t->Struct.fields_in_src_order[field_index++]; + if (!all_fields_are_blank && is_blank_ident(field->token)) { + // NOTE(bill): Ignore blank identifiers + continue; + } AstNode *elem = cl->elems[index]; if (elem->kind == AstNode_FieldValue) { error(elem, "Mixture of `field = value` and value elements in a literal is not allowed"); @@ -5541,12 +5551,7 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t break; } - Entity *field = t->Struct.fields_in_src_order[index]; - if (!all_fields_are_blank && is_blank_ident(field->token)) { - // NOTE(bill): Ignore blank identifiers - continue; - } - check_expr(c, o, elem); + check_expr_with_type_hint(c, o, elem, field->type); if (!check_is_field_exported(c, field)) { gbString t = type_to_string(type); diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index ce406f9d5..9f6609f0f 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -181,13 +181,13 @@ bool check_is_terminating(AstNode *node) { return false; } -Type *check_assignment_variable(Checker *c, Operand *rhs, AstNode *lhs_node) { +Type *check_assignment_variable(Checker *c, Operand *lhs, Operand *rhs) { if (rhs->mode == Addressing_Invalid || (rhs->type == t_invalid && rhs->mode != Addressing_Overload)) { return nullptr; } - AstNode *node = unparen_expr(lhs_node); + AstNode *node = unparen_expr(lhs->expr); // NOTE(bill): Ignore assignments to `_` if (is_blank_ident(node)) { @@ -201,12 +201,9 @@ Type *check_assignment_variable(Checker *c, Operand *rhs, AstNode *lhs_node) { Entity *e = nullptr; bool used = false; - Operand lhs = {Addressing_Invalid}; - - check_expr(c, &lhs, lhs_node); - if (lhs.mode == Addressing_Invalid || - (lhs.type == t_invalid && lhs.mode != Addressing_Overload)) { + if (lhs->mode == Addressing_Invalid || + (lhs->type == t_invalid && lhs->mode != Addressing_Overload)) { return nullptr; } @@ -224,7 +221,7 @@ Type *check_assignment_variable(Checker *c, Operand *rhs, AstNode *lhs_node) { Operand x = {}; x.mode = Addressing_Value; x.type = t; - if (check_is_assignable_to(c, &x, lhs.type)) { + if (check_is_assignable_to(c, &x, lhs->type)) { e = procs[i]; add_entity_use(c, rhs->expr, e); break; @@ -253,14 +250,14 @@ Type *check_assignment_variable(Checker *c, Operand *rhs, AstNode *lhs_node) { e->flags |= EntityFlag_Used; } - Type *assignment_type = lhs.type; - switch (lhs.mode) { + Type *assignment_type = lhs->type; + switch (lhs->mode) { case Addressing_Invalid: return nullptr; case Addressing_Variable: { - if (is_type_bit_field_value(lhs.type)) { - Type *lt = base_type(lhs.type); + if (is_type_bit_field_value(lhs->type)) { + Type *lt = base_type(lhs->type); i64 lhs_bits = lt->BitFieldValue.bits; if (rhs->mode == Addressing_Constant) { ExactValue v = exact_value_to_integer(rhs->value); @@ -284,7 +281,7 @@ Type *check_assignment_variable(Checker *c, Operand *rhs, AstNode *lhs_node) { // TODO(bill): Any other checks? return rhs->type; } - gbString lhs_expr = expr_to_string(lhs.expr); + gbString lhs_expr = expr_to_string(lhs->expr); gbString rhs_expr = expr_to_string(rhs->expr); error(rhs->expr, "Cannot assign `%s` to bit field `%s`", rhs_expr, lhs_expr); gb_string_free(rhs_expr); @@ -295,15 +292,15 @@ Type *check_assignment_variable(Checker *c, Operand *rhs, AstNode *lhs_node) { } case Addressing_MapIndex: { - AstNode *ln = unparen_expr(lhs_node); + AstNode *ln = unparen_expr(lhs->expr); if (ln->kind == AstNode_IndexExpr) { AstNode *x = ln->IndexExpr.expr; TypeAndValue tav = type_and_value_of_expr(&c->info, x); GB_ASSERT(tav.mode != Addressing_Invalid); if (tav.mode != Addressing_Variable) { if (!is_type_pointer(tav.type)) { - gbString str = expr_to_string(lhs.expr); - error(lhs.expr, "Cannot assign to the value of a map `%s`", str); + gbString str = expr_to_string(lhs->expr); + error(lhs->expr, "Cannot assign to the value of a map `%s`", str); gb_string_free(str); return nullptr; } @@ -314,24 +311,24 @@ Type *check_assignment_variable(Checker *c, Operand *rhs, AstNode *lhs_node) { } default: { - if (lhs.expr->kind == AstNode_SelectorExpr) { + if (lhs->expr->kind == AstNode_SelectorExpr) { // NOTE(bill): Extra error checks Operand op_c = {Addressing_Invalid}; - ast_node(se, SelectorExpr, lhs.expr); + ast_node(se, SelectorExpr, lhs->expr); check_expr(c, &op_c, se->expr); if (op_c.mode == Addressing_MapIndex) { - gbString str = expr_to_string(lhs.expr); - error(lhs.expr, "Cannot assign to struct field `%s` in map", str); + gbString str = expr_to_string(lhs->expr); + error(lhs->expr, "Cannot assign to struct field `%s` in map", str); gb_string_free(str); return nullptr; } } - gbString str = expr_to_string(lhs.expr); - if (lhs.mode == Addressing_Immutable) { - error(lhs.expr, "Cannot assign to an immutable: `%s`", str); + gbString str = expr_to_string(lhs->expr); + if (lhs->mode == Addressing_Immutable) { + error(lhs->expr, "Cannot assign to an immutable: `%s`", str); } else { - error(lhs.expr, "Cannot assign to `%s`", str); + error(lhs->expr, "Cannot assign to `%s`", str); } gb_string_free(str); @@ -694,26 +691,31 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { // NOTE(bill): If there is a bad syntax error, rhs > lhs which would mean there would need to be // an extra allocation - Array operands = {}; - array_init(&operands, c->tmp_allocator, 2 * lhs_count); - check_unpack_arguments(c, nullptr, lhs_count, &operands, as->rhs, true); + Array lhs_operands = {}; + Array rhs_operands = {}; + array_init_count(&lhs_operands, c->tmp_allocator, lhs_count); + array_init(&rhs_operands, c->tmp_allocator, 2 * lhs_count); - isize rhs_count = operands.count; - for_array(i, operands) { - if (operands[i].mode == Addressing_Invalid) { + for_array(i, as->lhs) { + check_expr(c, &lhs_operands[i], as->lhs[i]); + } + + check_unpack_arguments(c, nullptr, lhs_operands.count, &rhs_operands, as->rhs, true); + + isize rhs_count = rhs_operands.count; + for_array(i, rhs_operands) { + if (rhs_operands[i].mode == Addressing_Invalid) { rhs_count--; } } isize max = gb_min(lhs_count, rhs_count); for (isize i = 0; i < max; i++) { - check_assignment_variable(c, &operands[i], as->lhs[i]); + check_assignment_variable(c, &lhs_operands[i], &rhs_operands[i]); } if (lhs_count != rhs_count) { error(as->lhs[0], "Assignment count mismatch `%td` = `%td`", lhs_count, rhs_count); } - - break; } @@ -728,7 +730,8 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { error(op, "Unknown Assignment operation `%.*s`", LIT(op.string)); return; } - Operand operand = {Addressing_Invalid}; + Operand lhs = {Addressing_Invalid}; + Operand rhs = {Addressing_Invalid}; AstNode binary_expr = {AstNode_BinaryExpr}; ast_node(be, BinaryExpr, &binary_expr); be->op = op; @@ -737,12 +740,13 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { be->left = as->lhs[0]; be->right = as->rhs[0]; - check_binary_expr(c, &operand, &binary_expr); - if (operand.mode == Addressing_Invalid) { + check_expr(c, &lhs, as->lhs[0]); + check_binary_expr(c, &rhs, &binary_expr); + if (rhs.mode == Addressing_Invalid) { return; } // NOTE(bill): Only use the first one will be used - check_assignment_variable(c, &operand, as->lhs[0]); + check_assignment_variable(c, &lhs, &rhs); break; } diff --git a/src/parser.cpp b/src/parser.cpp index 4ba465e64..abc556d5c 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -2223,6 +2223,9 @@ AstNode *parse_operand(AstFile *f, bool lhs) { return ast_basic_lit(f, token); } + case Token_OpenBrace: + if (!lhs) return parse_literal_value(f, nullptr); + break; case Token_OpenParen: { Token open, close;