Optional ok for union_cast (similar to map indices)

This commit is contained in:
Ginger Bill
2017-02-14 16:37:24 +00:00
parent d1f65097c4
commit 8b5e3428a1
8 changed files with 100 additions and 89 deletions
+7 -1
View File
@@ -2,6 +2,12 @@
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
@@ -17,7 +23,7 @@ main :: proc() {
* Entities prefixes with an underscore do not get exported on imports
* 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
* 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
Removed:
+14 -11
View File
@@ -315,7 +315,11 @@ __assert :: proc(file: string, line, column: int, msg: string) #inline {
file, line, column, msg);
__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) {
if 0 <= index && index < count {
return;
@@ -341,6 +345,13 @@ __substring_expr_error :: proc(file: string, line, column: int, low, high: int)
file, line, column, low, high);
__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 {
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 {
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;
}
}
__print_ti_ptr :: proc(ti: ^Type_Info) {
fmt.println(ti);
match e in ti {
case Type_Info.Enum:
fmt.println(e.names);
}
}
+3 -3
View File
@@ -790,10 +790,10 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
buffer_write_string(fi.buf, "map[");
defer buffer_write_byte(fi.buf, ']');
entries := ^(cast(^Raw_Dynamic_Map)v.data).entries;
gs, gs_ok := union_cast(^Struct)type_info_base(info.generated_struct); assert(gs_ok);
ed, ed_ok := union_cast(^Dynamic_Array)type_info_base(gs.types[1]); assert(ed_ok);
gs := union_cast(^Struct)type_info_base(info.generated_struct);
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;
for i in 0..<entries.count {
if i > 0 {
-11
View File
@@ -72,25 +72,14 @@ void check_init_variables(Checker *c, Entity **lhs, isize lhs_count, AstNodeArra
}
}
isize max = gb_min(lhs_count, rhs_count);
for (isize i = 0; i < max; i++) {
check_init_variable(c, lhs[i], &operands.e[i], context_name);
}
if (rhs_count > 0 && 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);
}
+12 -21
View File
@@ -265,8 +265,6 @@ void check_assignment(Checker *c, Operand *operand, Type *type, String context_n
}
if (type == NULL) {
return;
}
@@ -1115,7 +1113,7 @@ i64 check_array_or_map_count(Checker *c, AstNode *e, bool is_map) {
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);
t->Tuple.variables = gb_alloc_array(a, Entity *, 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.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");
}
@@ -3821,17 +3819,15 @@ int valid_proc_and_score_cmp(void const *a, void const *b) {
typedef Array(Operand) ArrayOperand;
void check_unpack_arguments(Checker *c, isize lhs_count, ArrayOperand *operands, AstNodeArray args, bool allow_map_ok) {
for_array(i, args) {
void check_unpack_arguments(Checker *c, isize lhs_count, ArrayOperand *operands, AstNodeArray rhs, bool allow_ok) {
for_array(i, rhs) {
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.mode == Addressing_MapIndex &&
allow_map_ok &&
lhs_count == 2 &&
args.count == 1) {
Type *tuple = make_map_tuple_type(c->allocator, o.type);
if (allow_ok && lhs_count == 2 && rhs.count == 1 &&
(o.mode == Addressing_MapIndex || o.mode == Addressing_OptionalOk)) {
Type *tuple = make_optional_ok_type(c->allocator, o.type);
add_type_and_value(&c->info, o.expr, o.mode, tuple, o.value);
Operand val = o;
@@ -4922,16 +4918,11 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
goto error;
}
Entity **variables = gb_alloc_array(c->allocator, Entity *, 2);
variables[0] = make_entity_param(c->allocator, NULL, empty_token, t, false, true);
variables[1] = make_entity_param(c->allocator, NULL, empty_token, t_bool, false, true);
add_type_info_type(c, o->type);
add_type_info_type(c, t);
Type *tuple = make_type_tuple(c->allocator);
tuple->Tuple.variables = variables;
tuple->Tuple.variable_count = 2;
o->type = tuple;
o->mode = Addressing_Value;
o->type = t;
o->mode = Addressing_OptionalOk;
} break;
case Token_down_cast: {
if (o->mode == Addressing_Constant) {
+18 -22
View File
@@ -260,6 +260,7 @@ Type *check_assignment_variable(Checker *c, Operand *rhs, AstNode *lhs_node) {
switch (lhs.mode) {
case Addressing_Invalid:
return NULL;
case Addressing_Variable:
break;
case Addressing_MapIndex: {
@@ -278,6 +279,7 @@ Type *check_assignment_variable(Checker *c, Operand *rhs, AstNode *lhs_node) {
}
}
} break;
default: {
if (lhs.expr->kind == AstNode_SelectorExpr) {
// NOTE(bill): Extra error checks
@@ -434,40 +436,34 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
switch (as->op.kind) {
case Token_Eq: {
// 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");
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);
// NOTE(bill): If there is a bad syntax error, rhs > lhs which would mean there would need to be
// an extra allocation
Array(Operand) operands;
array_init_reserve(&operands, c->tmp_allocator, 2 * as->lhs.count);
ArrayOperand operands = {0};
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) {
AstNode *rhs = as->rhs.e[i];
Operand o = {0};
check_multi_expr(c, &o, rhs);
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 rhs_count = operands.count;
for_array(i, operands) {
if (operands.e[i].mode == Addressing_Invalid) {
rhs_count--;
}
}
isize lhs_count = as->lhs.count;
isize rhs_count = operands.count;
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);
isize max = gb_min(lhs_count, rhs_count);
for (isize i = 0; i < max; i++) {
check_assignment_variable(c, &operands.e[i], as->lhs.e[i]);
}
if (lhs_count != rhs_count) {
error_node(as->lhs.e[0], "Assignment count mismatch `%td` = `%td`", lhs_count, rhs_count);
+13 -12
View File
@@ -109,18 +109,19 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_Count] = {
#include "types.c"
typedef enum AddressingMode {
Addressing_Invalid, // invalid addressing mode
Addressing_NoValue, // no value (void in C)
Addressing_Value, // computed value (rvalue)
Addressing_Immutable, // immutable computed value (const rvalue)
Addressing_Variable, // addressable variable (lvalue)
Addressing_Constant, // constant & type will be a of Type_Basic (stripping Type_Named)
Addressing_Type, // type
Addressing_Builtin, // built in procedure
Addressing_Overload, // overloaded procedure
Addressing_MapIndex, // map index expression
// lhs: acts like a Variable
// ths: acts like a value with an optional boolean part (for existence check)
Addressing_Invalid, // invalid addressing mode
Addressing_NoValue, // no value (void in C)
Addressing_Value, // computed value (rvalue)
Addressing_Immutable, // immutable computed value (const rvalue)
Addressing_Variable, // addressable variable (lvalue)
Addressing_Constant, // constant & type will be a of Type_Basic (stripping Type_Named)
Addressing_Type, // type
Addressing_Builtin, // built in procedure
Addressing_Overload, // overloaded procedure
Addressing_MapIndex, // map index expression -
// lhs: acts like a Variable
// rhs: acts like OptionalOk
Addressing_OptionalOk, // rhs: acts like a value with an optional boolean part (for existence check)
} AddressingMode;
// Operand is used as an intermediate value whilst checking
+33 -8
View File
@@ -2462,13 +2462,19 @@ irValue *ir_emit_down_cast(irProcedure *proc, irValue *value, Type *t) {
return ir_emit_conv(proc, head, t);
}
irValue *ir_emit_union_cast(irProcedure *proc, irValue *value, Type *tuple) {
GB_ASSERT(tuple->kind == Type_Tuple);
irValue *ir_emit_union_cast(irProcedure *proc, irValue *value, Type *type, TokenPos pos) {
gbAllocator a = proc->module->allocator;
Type *src_type = ir_type(value);
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);
if (is_ptr) {
@@ -2541,6 +2547,25 @@ irValue *ir_emit_union_cast(irProcedure *proc, irValue *value, Type *tuple) {
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);
}
@@ -2930,23 +2955,23 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv
case_ast_node(ce, CastExpr, expr);
Type *type = tv->type;
irValue *expr = ir_build_expr(proc, ce->expr);
irValue *e = ir_build_expr(proc, ce->expr);
switch (ce->token.kind) {
case Token_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:
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:
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:
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:
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[2] = ir_make_const_int(proc->module->allocator, pos.column);
args[3] = msg;
ir_emit_global_call(proc, "__assert", args, 4);
ir_emit_global_call(proc, "__panic", args, 4);
return NULL;
} break;