Quellcode durchsuchen

Optional ok for `union_cast` (similar to map indices)

Ginger Bill vor 8 Jahren
Ursprung
Commit
8b5e3428a1
8 geänderte Dateien mit 100 neuen und 89 gelöschten Zeilen
  1. 7 1
      code/demo.odin
  2. 14 11
      core/_preload.odin
  3. 3 3
      core/fmt.odin
  4. 0 11
      src/check_decl.c
  5. 12 21
      src/check_expr.c
  6. 18 22
      src/check_stmt.c
  7. 13 12
      src/checker.c
  8. 33 8
      src/ir.c

+ 7 - 1
code/demo.odin

@@ -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
core/_preload.odin

@@ -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
core/fmt.odin

@@ -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 {

+ 0 - 11
src/check_decl.c

@@ -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
src/check_expr.c

@@ -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);
-
-			Type *tuple = make_type_tuple(c->allocator);
-			tuple->Tuple.variables = variables;
-			tuple->Tuple.variable_count = 2;
+			add_type_info_type(c, o->type);
+			add_type_info_type(c, t);
 
-			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
src/check_stmt.c

@@ -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
src/checker.c

@@ -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
src/ir.c

@@ -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;