mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-06 15:48:51 +00:00
Optional ok for union_cast (similar to map indices)
This commit is contained in:
+7
-1
@@ -2,6 +2,12 @@
|
|||||||
|
|
||||||
|
|
||||||
main :: proc() {
|
main :: proc() {
|
||||||
|
x := type_info(int);
|
||||||
|
t1, ok := union_cast(^Type_Info.Integer)x;
|
||||||
|
_, ok = union_cast(^Type_Info.Integer)x;
|
||||||
|
t2 := union_cast(^Type_Info.Integer)x;
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
/*
|
/*
|
||||||
Version 0.1.1
|
Version 0.1.1
|
||||||
@@ -17,7 +23,7 @@ main :: proc() {
|
|||||||
* Entities prefixes with an underscore do not get exported on imports
|
* Entities prefixes with an underscore do not get exported on imports
|
||||||
* Overloaded `free` for pointers, slices, strings, dynamic arrays, and dynamic maps
|
* Overloaded `free` for pointers, slices, strings, dynamic arrays, and dynamic maps
|
||||||
* enum types have an implict `names` field, a []string of all the names in that enum
|
* enum types have an implict `names` field, a []string of all the names in that enum
|
||||||
* immutable variables are "completely immutable"
|
* immutable variables are "completely immutable" - rules need a full explanation
|
||||||
* `slice_to_bytes` - convert any slice to a slice of bytes
|
* `slice_to_bytes` - convert any slice to a slice of bytes
|
||||||
|
|
||||||
Removed:
|
Removed:
|
||||||
|
|||||||
+14
-11
@@ -315,7 +315,11 @@ __assert :: proc(file: string, line, column: int, msg: string) #inline {
|
|||||||
file, line, column, msg);
|
file, line, column, msg);
|
||||||
__debug_trap();
|
__debug_trap();
|
||||||
}
|
}
|
||||||
|
__panic :: proc(file: string, line, column: int, msg: string) #inline {
|
||||||
|
fmt.fprintf(os.stderr, "%s(%d:%d) Panic: %s\n",
|
||||||
|
file, line, column, msg);
|
||||||
|
__debug_trap();
|
||||||
|
}
|
||||||
__bounds_check_error :: proc(file: string, line, column: int, index, count: int) {
|
__bounds_check_error :: proc(file: string, line, column: int, index, count: int) {
|
||||||
if 0 <= index && index < count {
|
if 0 <= index && index < count {
|
||||||
return;
|
return;
|
||||||
@@ -341,6 +345,13 @@ __substring_expr_error :: proc(file: string, line, column: int, low, high: int)
|
|||||||
file, line, column, low, high);
|
file, line, column, low, high);
|
||||||
__debug_trap();
|
__debug_trap();
|
||||||
}
|
}
|
||||||
|
__union_cast_check :: proc(ok: bool, file: string, line, column: int, from, to: ^Type_Info) {
|
||||||
|
if !ok {
|
||||||
|
fmt.fprintf(os.stderr, "%s(%d:%d) Invalid `union_cast` from %T to %T\n",
|
||||||
|
file, line, column, from, to);
|
||||||
|
__debug_trap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
__string_decode_rune :: proc(s: string) -> (rune, int) #inline {
|
__string_decode_rune :: proc(s: string) -> (rune, int) #inline {
|
||||||
return utf8.decode_rune(s);
|
return utf8.decode_rune(s);
|
||||||
@@ -449,6 +460,8 @@ __dynamic_array_append_nothing :: proc(array_: rawptr, elem_size, elem_align: in
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Map stuff
|
||||||
|
|
||||||
__default_hash :: proc(data: []byte) -> u64 {
|
__default_hash :: proc(data: []byte) -> u64 {
|
||||||
return hash.fnv64a(data);
|
return hash.fnv64a(data);
|
||||||
}
|
}
|
||||||
@@ -650,13 +663,3 @@ __dynamic_map_erase :: proc(using h: __Map_Header, fr: __Map_Find_Result) {
|
|||||||
m.hashes[last.hash_index] = fr.entry_index;
|
m.hashes[last.hash_index] = fr.entry_index;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
__print_ti_ptr :: proc(ti: ^Type_Info) {
|
|
||||||
fmt.println(ti);
|
|
||||||
match e in ti {
|
|
||||||
case Type_Info.Enum:
|
|
||||||
fmt.println(e.names);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -790,10 +790,10 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
|
|||||||
buffer_write_string(fi.buf, "map[");
|
buffer_write_string(fi.buf, "map[");
|
||||||
defer buffer_write_byte(fi.buf, ']');
|
defer buffer_write_byte(fi.buf, ']');
|
||||||
entries := ^(cast(^Raw_Dynamic_Map)v.data).entries;
|
entries := ^(cast(^Raw_Dynamic_Map)v.data).entries;
|
||||||
gs, gs_ok := union_cast(^Struct)type_info_base(info.generated_struct); assert(gs_ok);
|
gs := union_cast(^Struct)type_info_base(info.generated_struct);
|
||||||
ed, ed_ok := union_cast(^Dynamic_Array)type_info_base(gs.types[1]); assert(ed_ok);
|
ed := union_cast(^Dynamic_Array)type_info_base(gs.types[1]);
|
||||||
|
|
||||||
entry_type, et_ok := union_cast(^Struct)ed.elem; assert(et_ok);
|
entry_type := union_cast(^Struct)ed.elem;
|
||||||
entry_size := ed.elem_size;
|
entry_size := ed.elem_size;
|
||||||
for i in 0..<entries.count {
|
for i in 0..<entries.count {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
|
|||||||
@@ -72,25 +72,14 @@ void check_init_variables(Checker *c, Entity **lhs, isize lhs_count, AstNodeArra
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
isize max = gb_min(lhs_count, rhs_count);
|
isize max = gb_min(lhs_count, rhs_count);
|
||||||
for (isize i = 0; i < max; i++) {
|
for (isize i = 0; i < max; i++) {
|
||||||
check_init_variable(c, lhs[i], &operands.e[i], context_name);
|
check_init_variable(c, lhs[i], &operands.e[i], context_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rhs_count > 0 && lhs_count != rhs_count) {
|
if (rhs_count > 0 && lhs_count != rhs_count) {
|
||||||
error(lhs[0]->token, "Assignment count mismatch `%td` = `%td`", lhs_count, rhs_count);
|
error(lhs[0]->token, "Assignment count mismatch `%td` = `%td`", lhs_count, rhs_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
|
||||||
if (lhs[0]->kind == Entity_Variable &&
|
|
||||||
lhs[0]->Variable.is_let) {
|
|
||||||
if (lhs_count != rhs_count) {
|
|
||||||
error(lhs[0]->token, "`let` variables must be initialized, `%td` = `%td`", lhs_count, rhs_count);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
gb_temp_arena_memory_end(tmp);
|
gb_temp_arena_memory_end(tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+12
-21
@@ -265,8 +265,6 @@ void check_assignment(Checker *c, Operand *operand, Type *type, String context_n
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (type == NULL) {
|
if (type == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1115,7 +1113,7 @@ i64 check_array_or_map_count(Checker *c, AstNode *e, bool is_map) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Type *make_map_tuple_type(gbAllocator a, Type *value) {
|
Type *make_optional_ok_type(gbAllocator a, Type *value) {
|
||||||
Type *t = make_type_tuple(a);
|
Type *t = make_type_tuple(a);
|
||||||
t->Tuple.variables = gb_alloc_array(a, Entity *, 2);
|
t->Tuple.variables = gb_alloc_array(a, Entity *, 2);
|
||||||
t->Tuple.variable_count = 2;
|
t->Tuple.variable_count = 2;
|
||||||
@@ -1221,7 +1219,7 @@ void check_map_type(Checker *c, Type *type, AstNode *node) {
|
|||||||
type->Map.generated_struct_type = generated_struct_type;
|
type->Map.generated_struct_type = generated_struct_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
type->Map.lookup_result_type = make_map_tuple_type(a, value);
|
type->Map.lookup_result_type = make_optional_ok_type(a, value);
|
||||||
|
|
||||||
// error_node(node, "`map` types are not yet implemented");
|
// error_node(node, "`map` types are not yet implemented");
|
||||||
}
|
}
|
||||||
@@ -3821,17 +3819,15 @@ int valid_proc_and_score_cmp(void const *a, void const *b) {
|
|||||||
|
|
||||||
typedef Array(Operand) ArrayOperand;
|
typedef Array(Operand) ArrayOperand;
|
||||||
|
|
||||||
void check_unpack_arguments(Checker *c, isize lhs_count, ArrayOperand *operands, AstNodeArray args, bool allow_map_ok) {
|
void check_unpack_arguments(Checker *c, isize lhs_count, ArrayOperand *operands, AstNodeArray rhs, bool allow_ok) {
|
||||||
for_array(i, args) {
|
for_array(i, rhs) {
|
||||||
Operand o = {0};
|
Operand o = {0};
|
||||||
check_multi_expr(c, &o, args.e[i]);
|
check_multi_expr(c, &o, rhs.e[i]);
|
||||||
|
|
||||||
if (o.type == NULL || o.type->kind != Type_Tuple) {
|
if (o.type == NULL || o.type->kind != Type_Tuple) {
|
||||||
if (o.mode == Addressing_MapIndex &&
|
if (allow_ok && lhs_count == 2 && rhs.count == 1 &&
|
||||||
allow_map_ok &&
|
(o.mode == Addressing_MapIndex || o.mode == Addressing_OptionalOk)) {
|
||||||
lhs_count == 2 &&
|
Type *tuple = make_optional_ok_type(c->allocator, o.type);
|
||||||
args.count == 1) {
|
|
||||||
Type *tuple = make_map_tuple_type(c->allocator, o.type);
|
|
||||||
add_type_and_value(&c->info, o.expr, o.mode, tuple, o.value);
|
add_type_and_value(&c->info, o.expr, o.mode, tuple, o.value);
|
||||||
|
|
||||||
Operand val = o;
|
Operand val = o;
|
||||||
@@ -4922,16 +4918,11 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
Entity **variables = gb_alloc_array(c->allocator, Entity *, 2);
|
add_type_info_type(c, o->type);
|
||||||
variables[0] = make_entity_param(c->allocator, NULL, empty_token, t, false, true);
|
add_type_info_type(c, t);
|
||||||
variables[1] = make_entity_param(c->allocator, NULL, empty_token, t_bool, false, true);
|
|
||||||
|
|
||||||
Type *tuple = make_type_tuple(c->allocator);
|
o->type = t;
|
||||||
tuple->Tuple.variables = variables;
|
o->mode = Addressing_OptionalOk;
|
||||||
tuple->Tuple.variable_count = 2;
|
|
||||||
|
|
||||||
o->type = tuple;
|
|
||||||
o->mode = Addressing_Value;
|
|
||||||
} break;
|
} break;
|
||||||
case Token_down_cast: {
|
case Token_down_cast: {
|
||||||
if (o->mode == Addressing_Constant) {
|
if (o->mode == Addressing_Constant) {
|
||||||
|
|||||||
+18
-22
@@ -260,6 +260,7 @@ Type *check_assignment_variable(Checker *c, Operand *rhs, AstNode *lhs_node) {
|
|||||||
switch (lhs.mode) {
|
switch (lhs.mode) {
|
||||||
case Addressing_Invalid:
|
case Addressing_Invalid:
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
case Addressing_Variable:
|
case Addressing_Variable:
|
||||||
break;
|
break;
|
||||||
case Addressing_MapIndex: {
|
case Addressing_MapIndex: {
|
||||||
@@ -278,6 +279,7 @@ Type *check_assignment_variable(Checker *c, Operand *rhs, AstNode *lhs_node) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
if (lhs.expr->kind == AstNode_SelectorExpr) {
|
if (lhs.expr->kind == AstNode_SelectorExpr) {
|
||||||
// NOTE(bill): Extra error checks
|
// NOTE(bill): Extra error checks
|
||||||
@@ -434,40 +436,34 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
|||||||
switch (as->op.kind) {
|
switch (as->op.kind) {
|
||||||
case Token_Eq: {
|
case Token_Eq: {
|
||||||
// a, b, c = 1, 2, 3; // Multisided
|
// a, b, c = 1, 2, 3; // Multisided
|
||||||
if (as->lhs.count == 0) {
|
|
||||||
|
isize lhs_count = as->lhs.count;
|
||||||
|
if (lhs_count == 0) {
|
||||||
error(as->op, "Missing lhs in assignment statement");
|
error(as->op, "Missing lhs in assignment statement");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO(bill): This is a very similar to check_init_variables, should I merge the two some how or just
|
||||||
|
// leave it?
|
||||||
|
|
||||||
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena);
|
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena);
|
||||||
|
|
||||||
// NOTE(bill): If there is a bad syntax error, rhs > lhs which would mean there would need to be
|
// NOTE(bill): If there is a bad syntax error, rhs > lhs which would mean there would need to be
|
||||||
// an extra allocation
|
// an extra allocation
|
||||||
Array(Operand) operands;
|
ArrayOperand operands = {0};
|
||||||
array_init_reserve(&operands, c->tmp_allocator, 2 * as->lhs.count);
|
array_init_reserve(&operands, c->tmp_allocator, 2 * lhs_count);
|
||||||
|
check_unpack_arguments(c, lhs_count, &operands, as->rhs, true);
|
||||||
|
|
||||||
for_array(i, as->rhs) {
|
isize rhs_count = operands.count;
|
||||||
AstNode *rhs = as->rhs.e[i];
|
for_array(i, operands) {
|
||||||
Operand o = {0};
|
if (operands.e[i].mode == Addressing_Invalid) {
|
||||||
check_multi_expr(c, &o, rhs);
|
rhs_count--;
|
||||||
if (o.type->kind != Type_Tuple) {
|
|
||||||
array_add(&operands, o);
|
|
||||||
} else {
|
|
||||||
TypeTuple *tuple = &o.type->Tuple;
|
|
||||||
for (isize j = 0; j < tuple->variable_count; j++) {
|
|
||||||
o.type = tuple->variables[j]->type;
|
|
||||||
array_add(&operands, o);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
isize lhs_count = as->lhs.count;
|
isize max = gb_min(lhs_count, rhs_count);
|
||||||
isize rhs_count = operands.count;
|
for (isize i = 0; i < max; i++) {
|
||||||
|
check_assignment_variable(c, &operands.e[i], as->lhs.e[i]);
|
||||||
isize operand_count = gb_min(as->lhs.count, operands.count);
|
|
||||||
for (isize i = 0; i < operand_count; i++) {
|
|
||||||
AstNode *lhs = as->lhs.e[i];
|
|
||||||
check_assignment_variable(c, &operands.e[i], lhs);
|
|
||||||
}
|
}
|
||||||
if (lhs_count != rhs_count) {
|
if (lhs_count != rhs_count) {
|
||||||
error_node(as->lhs.e[0], "Assignment count mismatch `%td` = `%td`", lhs_count, rhs_count);
|
error_node(as->lhs.e[0], "Assignment count mismatch `%td` = `%td`", lhs_count, rhs_count);
|
||||||
|
|||||||
+13
-12
@@ -109,18 +109,19 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_Count] = {
|
|||||||
#include "types.c"
|
#include "types.c"
|
||||||
|
|
||||||
typedef enum AddressingMode {
|
typedef enum AddressingMode {
|
||||||
Addressing_Invalid, // invalid addressing mode
|
Addressing_Invalid, // invalid addressing mode
|
||||||
Addressing_NoValue, // no value (void in C)
|
Addressing_NoValue, // no value (void in C)
|
||||||
Addressing_Value, // computed value (rvalue)
|
Addressing_Value, // computed value (rvalue)
|
||||||
Addressing_Immutable, // immutable computed value (const rvalue)
|
Addressing_Immutable, // immutable computed value (const rvalue)
|
||||||
Addressing_Variable, // addressable variable (lvalue)
|
Addressing_Variable, // addressable variable (lvalue)
|
||||||
Addressing_Constant, // constant & type will be a of Type_Basic (stripping Type_Named)
|
Addressing_Constant, // constant & type will be a of Type_Basic (stripping Type_Named)
|
||||||
Addressing_Type, // type
|
Addressing_Type, // type
|
||||||
Addressing_Builtin, // built in procedure
|
Addressing_Builtin, // built in procedure
|
||||||
Addressing_Overload, // overloaded procedure
|
Addressing_Overload, // overloaded procedure
|
||||||
Addressing_MapIndex, // map index expression
|
Addressing_MapIndex, // map index expression -
|
||||||
// lhs: acts like a Variable
|
// lhs: acts like a Variable
|
||||||
// ths: acts like a value with an optional boolean part (for existence check)
|
// rhs: acts like OptionalOk
|
||||||
|
Addressing_OptionalOk, // rhs: acts like a value with an optional boolean part (for existence check)
|
||||||
} AddressingMode;
|
} AddressingMode;
|
||||||
|
|
||||||
// Operand is used as an intermediate value whilst checking
|
// Operand is used as an intermediate value whilst checking
|
||||||
|
|||||||
@@ -2462,13 +2462,19 @@ irValue *ir_emit_down_cast(irProcedure *proc, irValue *value, Type *t) {
|
|||||||
return ir_emit_conv(proc, head, t);
|
return ir_emit_conv(proc, head, t);
|
||||||
}
|
}
|
||||||
|
|
||||||
irValue *ir_emit_union_cast(irProcedure *proc, irValue *value, Type *tuple) {
|
irValue *ir_emit_union_cast(irProcedure *proc, irValue *value, Type *type, TokenPos pos) {
|
||||||
GB_ASSERT(tuple->kind == Type_Tuple);
|
|
||||||
gbAllocator a = proc->module->allocator;
|
gbAllocator a = proc->module->allocator;
|
||||||
|
|
||||||
Type *src_type = ir_type(value);
|
Type *src_type = ir_type(value);
|
||||||
bool is_ptr = is_type_pointer(src_type);
|
bool is_ptr = is_type_pointer(src_type);
|
||||||
|
|
||||||
|
bool is_tuple = true;
|
||||||
|
Type *tuple = type;
|
||||||
|
if (type->kind != Type_Tuple) {
|
||||||
|
is_tuple = false;
|
||||||
|
tuple = make_optional_ok_type(a, type);
|
||||||
|
}
|
||||||
|
|
||||||
irValue *v = ir_add_local_generated(proc, tuple);
|
irValue *v = ir_add_local_generated(proc, tuple);
|
||||||
|
|
||||||
if (is_ptr) {
|
if (is_ptr) {
|
||||||
@@ -2541,6 +2547,25 @@ irValue *ir_emit_union_cast(irProcedure *proc, irValue *value, Type *tuple) {
|
|||||||
ir_start_block(proc, end_block);
|
ir_start_block(proc, end_block);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!is_tuple) {
|
||||||
|
// NOTE(bill): Panic on invalid conversion
|
||||||
|
Type *dst_type = tuple->Tuple.variables[0]->type;
|
||||||
|
|
||||||
|
irValue *ok = ir_emit_load(proc, ir_emit_struct_ep(proc, v, 1));
|
||||||
|
irValue **args = gb_alloc_array(a, irValue *, 6);
|
||||||
|
args[0] = ok;
|
||||||
|
|
||||||
|
args[1] = ir_make_const_string(a, pos.file);
|
||||||
|
args[2] = ir_make_const_int(a, pos.line);
|
||||||
|
args[3] = ir_make_const_int(a, pos.column);
|
||||||
|
|
||||||
|
args[4] = ir_type_info(proc, src_type);
|
||||||
|
args[5] = ir_type_info(proc, dst_type);
|
||||||
|
ir_emit_global_call(proc, "__union_cast_check", args, 6);
|
||||||
|
|
||||||
|
return ir_emit_load(proc, ir_emit_struct_ep(proc, v, 0));
|
||||||
|
}
|
||||||
return ir_emit_load(proc, v);
|
return ir_emit_load(proc, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2930,23 +2955,23 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv
|
|||||||
|
|
||||||
case_ast_node(ce, CastExpr, expr);
|
case_ast_node(ce, CastExpr, expr);
|
||||||
Type *type = tv->type;
|
Type *type = tv->type;
|
||||||
irValue *expr = ir_build_expr(proc, ce->expr);
|
irValue *e = ir_build_expr(proc, ce->expr);
|
||||||
switch (ce->token.kind) {
|
switch (ce->token.kind) {
|
||||||
case Token_cast:
|
case Token_cast:
|
||||||
ir_emit_comment(proc, str_lit("cast - cast"));
|
ir_emit_comment(proc, str_lit("cast - cast"));
|
||||||
return ir_emit_conv(proc, expr, type);
|
return ir_emit_conv(proc, e, type);
|
||||||
|
|
||||||
case Token_transmute:
|
case Token_transmute:
|
||||||
ir_emit_comment(proc, str_lit("cast - transmute"));
|
ir_emit_comment(proc, str_lit("cast - transmute"));
|
||||||
return ir_emit_transmute(proc, expr, type);
|
return ir_emit_transmute(proc, e, type);
|
||||||
|
|
||||||
case Token_down_cast:
|
case Token_down_cast:
|
||||||
ir_emit_comment(proc, str_lit("cast - down_cast"));
|
ir_emit_comment(proc, str_lit("cast - down_cast"));
|
||||||
return ir_emit_down_cast(proc, expr, type);
|
return ir_emit_down_cast(proc, e, type);
|
||||||
|
|
||||||
case Token_union_cast:
|
case Token_union_cast:
|
||||||
ir_emit_comment(proc, str_lit("cast - union_cast"));
|
ir_emit_comment(proc, str_lit("cast - union_cast"));
|
||||||
return ir_emit_union_cast(proc, expr, type);
|
return ir_emit_union_cast(proc, e, type, ast_node_token(expr).pos);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
GB_PANIC("Unknown cast expression");
|
GB_PANIC("Unknown cast expression");
|
||||||
@@ -3384,7 +3409,7 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv
|
|||||||
args[1] = ir_make_const_int(proc->module->allocator, pos.line);
|
args[1] = ir_make_const_int(proc->module->allocator, pos.line);
|
||||||
args[2] = ir_make_const_int(proc->module->allocator, pos.column);
|
args[2] = ir_make_const_int(proc->module->allocator, pos.column);
|
||||||
args[3] = msg;
|
args[3] = msg;
|
||||||
ir_emit_global_call(proc, "__assert", args, 4);
|
ir_emit_global_call(proc, "__panic", args, 4);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
} break;
|
} break;
|
||||||
|
|||||||
Reference in New Issue
Block a user