Bläddra i källkod

Mock out for in multiple-return values

gingerBill 1 år sedan
förälder
incheckning
c55b3d49b5
3 ändrade filer med 270 tillägg och 133 borttagningar
  1. 7 1
      src/tilde_const.cpp
  2. 185 129
      src/tilde_expr.cpp
  3. 78 3
      src/tilde_stmt.cpp

+ 7 - 1
src/tilde_const.cpp

@@ -81,7 +81,6 @@ gb_internal void cg_global_source_code_location_const(cgModule *m, String const
 	}
 }
 
-
 gb_internal cgValue cg_emit_source_code_location_as_global(cgProcedure *p, String const &proc_name, TokenPos pos) {
 	cgModule *m = p->module;
 	char name[32] = {};
@@ -1047,3 +1046,10 @@ gb_internal cgValue cg_const_union_tag(cgProcedure *p, Type *u, Type *v) {
 	return cg_const_value(p, union_tag_type(u), exact_value_i64(union_variant_index(u, v)));
 }
 
+
+
+gb_internal cgValue cg_find_or_add_entity_string(cgProcedure *p, String const &s) {
+	// TODO(bill): make this better
+	return cg_const_string(p, t_string, s);
+}
+

+ 185 - 129
src/tilde_expr.cpp

@@ -945,6 +945,13 @@ gb_internal void cg_emit_store_union_variant(cgProcedure *p, cgValue parent, cgV
 	}
 }
 
+gb_internal cgValue cg_emit_union_tag_value(cgProcedure *p, cgValue u) {
+	cgValue ptr = cg_address_from_load_or_generate_local(p, u);
+	cgValue tag_ptr = cg_emit_union_tag_ptr(p, ptr);
+	return cg_emit_load(p, tag_ptr);
+}
+
+
 gb_internal cgValue cg_emit_conv(cgProcedure *p, cgValue value, Type *t) {
 	t = reduce_tuple_to_single_type(t);
 
@@ -3154,6 +3161,7 @@ cgAddr cg_build_addr_compound_lit(cgProcedure *p, Ast *expr) {
 	}
 
 	case Type_SimdVector: {
+		GB_PANIC("TODO(bill): #simd compound literals");
 		// auto temp_data = array_make<cgCompoundLitElemTempData>(temporary_allocator(), 0, cl->elems.count);
 
 		// populate(p, cl->elems, &temp_data, type);
@@ -3241,151 +3249,150 @@ gb_internal cgValue cg_build_unary_and(cgProcedure *p, Ast *expr) {
 		cgAddr addr = cg_build_addr_compound_lit(p, expr);
 		return addr.addr;
 	} else if (ue_expr->kind == Ast_TypeAssertion) {
-		GB_PANIC("TODO(bill): &v.(T)");
-		// if (is_type_tuple(tv.type)) {
-		// 	Type *tuple = tv.type;
-		// 	Type *ptr_type = tuple->Tuple.variables[0]->type;
-		// 	Type *ok_type = tuple->Tuple.variables[1]->type;
-
-		// 	ast_node(ta, TypeAssertion, ue_expr);
-		// 	TokenPos pos = ast_token(expr).pos;
-		// 	Type *type = type_of_expr(ue_expr);
-		// 	GB_ASSERT(!is_type_tuple(type));
-
-		// 	lbValue e = lb_build_expr(p, ta->expr);
-		// 	Type *t = type_deref(e.type);
-		// 	if (is_type_union(t)) {
-		// 		lbValue v = e;
-		// 		if (!is_type_pointer(v.type)) {
-		// 			v = lb_address_from_load_or_generate_local(p, v);
-		// 		}
-		// 		Type *src_type = type_deref(v.type);
-		// 		Type *dst_type = type;
-
-		// 		lbValue src_tag = {};
-		// 		lbValue dst_tag = {};
-		// 		if (is_type_union_maybe_pointer(src_type)) {
-		// 			src_tag = lb_emit_comp_against_nil(p, Token_NotEq, v);
-		// 			dst_tag = lb_const_bool(p->module, t_bool, true);
-		// 		} else {
-		// 			src_tag = lb_emit_load(p, lb_emit_union_tag_ptr(p, v));
-		// 			dst_tag = lb_const_union_tag(p->module, src_type, dst_type);
-		// 		}
+		if (is_type_tuple(tv.type)) {
+			Type *tuple = tv.type;
+			Type *ptr_type = tuple->Tuple.variables[0]->type;
+			Type *ok_type = tuple->Tuple.variables[1]->type;
+
+			ast_node(ta, TypeAssertion, ue_expr);
+			TokenPos pos = ast_token(expr).pos;
+			Type *type = type_of_expr(ue_expr);
+			GB_ASSERT(!is_type_tuple(type));
+
+			cgValue e = cg_build_expr(p, ta->expr);
+			Type *t = type_deref(e.type);
+			if (is_type_union(t)) {
+				cgValue v = e;
+				if (!is_type_pointer(v.type)) {
+					v = cg_address_from_load_or_generate_local(p, v);
+				}
+				Type *src_type = type_deref(v.type);
+				Type *dst_type = type;
+
+				cgValue src_tag = {};
+				cgValue dst_tag = {};
+				if (is_type_union_maybe_pointer(src_type)) {
+					src_tag = cg_emit_comp_against_nil(p, Token_NotEq, v);
+					dst_tag = cg_const_bool(p, t_bool, true);
+				} else {
+					src_tag = cg_emit_load(p, cg_emit_union_tag_ptr(p, v));
+					dst_tag = cg_const_union_tag(p, src_type, dst_type);
+				}
 
-		// 		lbValue ok = lb_emit_comp(p, Token_CmpEq, src_tag, dst_tag);
-
-		// 		lbValue data_ptr = lb_emit_conv(p, v, ptr_type);
-		// 		lbAddr res = lb_add_local_generated(p, tuple, true);
-		// 		lbValue gep0 = lb_emit_struct_ep(p, res.addr, 0);
-		// 		lbValue gep1 = lb_emit_struct_ep(p, res.addr, 1);
-		// 		lb_emit_store(p, gep0, lb_emit_select(p, ok, data_ptr, lb_const_nil(p->module, ptr_type)));
-		// 		lb_emit_store(p, gep1, lb_emit_conv(p, ok, ok_type));
-		// 		return lb_addr_load(p, res);
-		// 	} else if (is_type_any(t)) {
-		// 		lbValue v = e;
-		// 		if (is_type_pointer(v.type)) {
-		// 			v = lb_emit_load(p, v);
-		// 		}
+				cgValue ok = cg_emit_comp(p, Token_CmpEq, src_tag, dst_tag);
+
+				cgValue data_ptr = cg_emit_conv(p, v, ptr_type);
+				cgAddr res = cg_add_local(p, tuple, nullptr, true);
+				cgValue gep0 = cg_emit_struct_ep(p, res.addr, 0);
+				cgValue gep1 = cg_emit_struct_ep(p, res.addr, 1);
+				cg_emit_store(p, gep0, cg_emit_select(p, ok, data_ptr, cg_const_nil(p, ptr_type)));
+				cg_emit_store(p, gep1, cg_emit_conv(p, ok, ok_type));
+				return cg_addr_load(p, res);
+			} else if (is_type_any(t)) {
+				cgValue v = e;
+				if (is_type_pointer(v.type)) {
+					v = cg_emit_load(p, v);
+				}
 
-		// 		lbValue data_ptr = lb_emit_conv(p, lb_emit_struct_ev(p, v, 0), ptr_type);
-		// 		lbValue any_id = lb_emit_struct_ev(p, v, 1);
-		// 		lbValue id = lb_typeid(p->module, type);
+				cgValue data_ptr = cg_emit_conv(p, cg_emit_struct_ev(p, v, 0), ptr_type);
+				cgValue any_id = cg_emit_struct_ev(p, v, 1);
+				cgValue id = cg_typeid(p, type);
 
-		// 		lbValue ok = lb_emit_comp(p, Token_CmpEq, any_id, id);
+				cgValue ok = cg_emit_comp(p, Token_CmpEq, any_id, id);
 
-		// 		lbAddr res = lb_add_local_generated(p, tuple, false);
-		// 		lbValue gep0 = lb_emit_struct_ep(p, res.addr, 0);
-		// 		lbValue gep1 = lb_emit_struct_ep(p, res.addr, 1);
-		// 		lb_emit_store(p, gep0, lb_emit_select(p, ok, data_ptr, lb_const_nil(p->module, ptr_type)));
-		// 		lb_emit_store(p, gep1, lb_emit_conv(p, ok, ok_type));
-		// 		return lb_addr_load(p, res);
-		// 	} else {
-		// 		GB_PANIC("TODO(bill): type assertion %s", type_to_string(type));
-		// 	}
+				cgAddr res = cg_add_local(p, tuple, nullptr, false);
+				cgValue gep0 = cg_emit_struct_ep(p, res.addr, 0);
+				cgValue gep1 = cg_emit_struct_ep(p, res.addr, 1);
+				cg_emit_store(p, gep0, cg_emit_select(p, ok, data_ptr, cg_const_nil(p, ptr_type)));
+				cg_emit_store(p, gep1, cg_emit_conv(p, ok, ok_type));
+				return cg_addr_load(p, res);
+			} else {
+				GB_PANIC("TODO(bill): type assertion %s", type_to_string(type));
+			}
 
-		// } else {
-		// 	GB_ASSERT(is_type_pointer(tv.type));
-
-		// 	ast_node(ta, TypeAssertion, ue_expr);
-		// 	TokenPos pos = ast_token(expr).pos;
-		// 	Type *type = type_of_expr(ue_expr);
-		// 	GB_ASSERT(!is_type_tuple(type));
-
-		// 	lbValue e = lb_build_expr(p, ta->expr);
-		// 	Type *t = type_deref(e.type);
-		// 	if (is_type_union(t)) {
-		// 		lbValue v = e;
-		// 		if (!is_type_pointer(v.type)) {
-		// 			v = lb_address_from_load_or_generate_local(p, v);
-		// 		}
-		// 		Type *src_type = type_deref(v.type);
-		// 		Type *dst_type = type;
-
-
-		// 		if ((p->state_flags & StateFlag_no_type_assert) == 0) {
-		// 			lbValue src_tag = {};
-		// 			lbValue dst_tag = {};
-		// 			if (is_type_union_maybe_pointer(src_type)) {
-		// 				src_tag = lb_emit_comp_against_nil(p, Token_NotEq, v);
-		// 				dst_tag = lb_const_bool(p->module, t_bool, true);
-		// 			} else {
-		// 				src_tag = lb_emit_load(p, lb_emit_union_tag_ptr(p, v));
-		// 				dst_tag = lb_const_union_tag(p->module, src_type, dst_type);
-		// 			}
+		} else {
+			GB_ASSERT(is_type_pointer(tv.type));
+
+			ast_node(ta, TypeAssertion, ue_expr);
+			TokenPos pos = ast_token(expr).pos;
+			Type *type = type_of_expr(ue_expr);
+			GB_ASSERT(!is_type_tuple(type));
+
+			cgValue e = cg_build_expr(p, ta->expr);
+			Type *t = type_deref(e.type);
+			if (is_type_union(t)) {
+				cgValue v = e;
+				if (!is_type_pointer(v.type)) {
+					v = cg_address_from_load_or_generate_local(p, v);
+				}
+				Type *src_type = type_deref(v.type);
+				Type *dst_type = type;
 
 
-		// 			isize arg_count = 6;
-		// 			if (build_context.no_rtti) {
-		// 				arg_count = 4;
-		// 			}
+				if (!build_context.no_type_assert && (p->state_flags & StateFlag_no_type_assert) == 0) {
+					cgValue src_tag = {};
+					cgValue dst_tag = {};
+					if (is_type_union_maybe_pointer(src_type)) {
+						src_tag = cg_emit_comp_against_nil(p, Token_NotEq, v);
+						dst_tag = cg_const_bool(p, t_bool, true);
+					} else {
+						src_tag = cg_emit_load(p, cg_emit_union_tag_ptr(p, v));
+						dst_tag = cg_const_union_tag(p, src_type, dst_type);
+					}
 
-		// 			lbValue ok = lb_emit_comp(p, Token_CmpEq, src_tag, dst_tag);
-		// 			auto args = array_make<lbValue>(permanent_allocator(), arg_count);
-		// 			args[0] = ok;
 
-		// 			args[1] = lb_find_or_add_entity_string(p->module, get_file_path_string(pos.file_id));
-		// 			args[2] = lb_const_int(p->module, t_i32, pos.line);
-		// 			args[3] = lb_const_int(p->module, t_i32, pos.column);
+					isize arg_count = 6;
+					if (build_context.no_rtti) {
+						arg_count = 4;
+					}
 
-		// 			if (!build_context.no_rtti) {
-		// 				args[4] = lb_typeid(p->module, src_type);
-		// 				args[5] = lb_typeid(p->module, dst_type);
-		// 			}
-		// 			lb_emit_runtime_call(p, "type_assertion_check", args);
-		// 		}
+					cgValue ok = cg_emit_comp(p, Token_CmpEq, src_tag, dst_tag);
+					auto args = slice_make<cgValue>(permanent_allocator(), arg_count);
+					args[0] = ok;
 
-		// 		lbValue data_ptr = v;
-		// 		return lb_emit_conv(p, data_ptr, tv.type);
-		// 	} else if (is_type_any(t)) {
-		// 		lbValue v = e;
-		// 		if (is_type_pointer(v.type)) {
-		// 			v = lb_emit_load(p, v);
-		// 		}
-		// 		lbValue data_ptr = lb_emit_struct_ev(p, v, 0);
-		// 		if ((p->state_flags & StateFlag_no_type_assert) == 0) {
-		// 			GB_ASSERT(!build_context.no_rtti);
+					args[1] = cg_find_or_add_entity_string(p, get_file_path_string(pos.file_id));
+					args[2] = cg_const_int(p, t_i32, pos.line);
+					args[3] = cg_const_int(p, t_i32, pos.column);
 
-		// 			lbValue any_id = lb_emit_struct_ev(p, v, 1);
+					if (!build_context.no_rtti) {
+						args[4] = cg_typeid(p, src_type);
+						args[5] = cg_typeid(p, dst_type);
+					}
+					cg_emit_runtime_call(p, "type_assertion_check", args);
+				}
 
-		// 			lbValue id = lb_typeid(p->module, type);
-		// 			lbValue ok = lb_emit_comp(p, Token_CmpEq, any_id, id);
-		// 			auto args = array_make<lbValue>(permanent_allocator(), 6);
-		// 			args[0] = ok;
+				cgValue data_ptr = v;
+				return cg_emit_conv(p, data_ptr, tv.type);
+			} else if (is_type_any(t)) {
+				cgValue v = e;
+				if (is_type_pointer(v.type)) {
+					v = cg_emit_load(p, v);
+				}
+				cgValue data_ptr = cg_emit_struct_ev(p, v, 0);
+				if (!build_context.no_type_assert && (p->state_flags & StateFlag_no_type_assert) == 0) {
+					GB_ASSERT(!build_context.no_rtti);
 
-		// 			args[1] = lb_find_or_add_entity_string(p->module, get_file_path_string(pos.file_id));
-		// 			args[2] = lb_const_int(p->module, t_i32, pos.line);
-		// 			args[3] = lb_const_int(p->module, t_i32, pos.column);
+					cgValue any_id = cg_emit_struct_ev(p, v, 1);
 
-		// 			args[4] = any_id;
-		// 			args[5] = id;
-		// 			lb_emit_runtime_call(p, "type_assertion_check", args);
-		// 		}
+					cgValue id = cg_typeid(p, type);
+					cgValue ok = cg_emit_comp(p, Token_CmpEq, any_id, id);
+					auto args = slice_make<cgValue>(permanent_allocator(), 6);
+					args[0] = ok;
 
-		// 		return lb_emit_conv(p, data_ptr, tv.type);
-		// 	} else {
-		// 		GB_PANIC("TODO(bill): type assertion %s", type_to_string(type));
-		// 	}
-		// }
+					args[1] = cg_find_or_add_entity_string(p, get_file_path_string(pos.file_id));
+					args[2] = cg_const_int(p, t_i32, pos.line);
+					args[3] = cg_const_int(p, t_i32, pos.column);
+
+					args[4] = any_id;
+					args[5] = id;
+					cg_emit_runtime_call(p, "type_assertion_check", args);
+				}
+
+				return cg_emit_conv(p, data_ptr, tv.type);
+			} else {
+				GB_PANIC("TODO(bill): type assertion %s", type_to_string(type));
+			}
+		}
 	}
 
 	return cg_build_addr_ptr(p, ue->expr);
@@ -3558,6 +3565,52 @@ gb_internal cgValue cg_emit_cast_any(cgProcedure *p, cgValue value, Type *type,
 	return cg_value_multi2(cg_emit_load(p, gep0), cg_emit_load(p, gep1), tuple);
 }
 
+gb_internal cgValue cg_emit_cast_union_ok_only(cgProcedure *p, cgValue value, Type *type, TokenPos pos) {
+	GB_ASSERT(is_type_tuple(type));
+
+	Type *src_type = value.type;
+	bool is_ptr = is_type_pointer(src_type);
+
+
+	// IMPORTANT NOTE(bill): This assumes that the value is completely ignored
+	// so when it does an assignment, it complete ignores the value.
+	// Just make it two booleans and ignore the first one
+	//
+	// _, ok := x.(T);
+	//
+	Type *ok_type = type->Tuple.variables[1]->type;
+	Type *gen_tuple_types[2] = {};
+	gen_tuple_types[0] = ok_type;
+	gen_tuple_types[1] = ok_type;
+
+	Type *gen_tuple = alloc_type_tuple_from_field_types(gen_tuple_types, gb_count_of(gen_tuple_types), false, true);
+
+	cgAddr v = cg_add_local(p, gen_tuple, nullptr, false);
+
+	if (is_ptr) {
+		value = cg_emit_load(p, value);
+	}
+	Type *src = base_type(type_deref(src_type));
+	GB_ASSERT_MSG(is_type_union(src), "%s", type_to_string(src_type));
+	Type *dst = type->Tuple.variables[0]->type;
+
+	cgValue cond = {};
+
+	if (is_type_union_maybe_pointer(src)) {
+		cgValue data = cg_emit_transmute(p, value, dst);
+		cond = cg_emit_comp_against_nil(p, Token_NotEq, data);
+	} else {
+		cgValue tag = cg_emit_union_tag_value(p, value);
+		cgValue dst_tag = cg_const_union_tag(p, src, dst);
+		cond = cg_emit_comp(p, Token_CmpEq, tag, dst_tag);
+	}
+
+	cgValue gep1 = cg_emit_struct_ep(p, v.addr, 1);
+	cg_emit_store(p, gep1, cond);
+
+	return cg_addr_load(p, v);
+}
+
 
 gb_internal cgValue cg_build_type_assertion(cgProcedure *p, Ast *expr, Type *type) {
 	ast_node(ta, TypeAssertion, expr);
@@ -3567,6 +3620,9 @@ gb_internal cgValue cg_build_type_assertion(cgProcedure *p, Ast *expr, Type *typ
 	Type *t = type_deref(e.type);
 
 	if (is_type_union(t)) {
+		if (ta->ignores[0]) {
+			return cg_emit_cast_union_ok_only(p, e, type, pos);
+		}
 		return cg_emit_cast_union(p, e, type, pos);
 	} else if (is_type_any(t)) {
 		return cg_emit_cast_any(p, e, type, pos);

+ 78 - 3
src/tilde_stmt.cpp

@@ -771,6 +771,16 @@ gb_internal cgValue cg_emit_struct_ev(cgProcedure *p, cgValue s, i64 index) {
 	return cg_flatten_value(p, cg_emit_load(p, ptr));
 }
 
+gb_internal cgValue cg_emit_tuple_ev(cgProcedure *p, cgValue value, i64 index) {
+	GB_ASSERT(value.kind == cgValue_Multi);
+	GB_ASSERT(value.multi != nullptr);
+	GB_ASSERT(value.type->kind == Type_Tuple);
+	GB_ASSERT(0 <= index && index < value.type->Tuple.variables.count);
+	return value.multi->values[index];
+}
+
+
+
 
 gb_internal cgValue cg_emit_deep_field_gep(cgProcedure *p, cgValue e, Selection const &sel) {
 	GB_ASSERT(sel.index.count > 0);
@@ -1950,6 +1960,58 @@ gb_internal void cg_build_range_stmt_struct_soa(cgProcedure *p, AstRangeStmt *rs
 
 }
 
+gb_internal void cg_build_range_tuple(cgProcedure *p, AstRangeStmt *rs, Scope *scope) {
+	Ast *expr = unparen_expr(rs->expr);
+
+	Type *expr_type = type_of_expr(expr);
+	Type *et = base_type(type_deref(expr_type));
+	GB_ASSERT(et->kind == Type_Tuple);
+
+	i32 value_count = cast(i32)et->Tuple.variables.count;
+
+	cgValue *values = gb_alloc_array(permanent_allocator(), cgValue, value_count);
+
+	cg_scope_open(p, scope);
+
+	TB_Node *loop = cg_control_region(p, "for.tuple.loop");
+	cg_emit_goto(p, loop);
+	tb_inst_set_control(p->func, loop);
+
+	TB_Node *body = cg_control_region(p, "for.tuple.body");
+	TB_Node *done = cg_control_region(p, "for.tuple.done");
+
+	cgValue tuple_value = cg_build_expr(p, expr);
+	Type *tuple = tuple_value.type;
+	GB_ASSERT(tuple->kind == Type_Tuple);
+	i32 tuple_count = cast(i32)tuple->Tuple.variables.count;
+	i32 cond_index = tuple_count-1;
+
+	cgValue cond = cg_emit_struct_ev(p, tuple_value, cond_index);
+	cg_emit_if(p, cond, body, done);
+	tb_inst_set_control(p->func, body);
+
+	for (i32 i = 0; i < value_count; i++) {
+		values[i] = cg_emit_tuple_ev(p, tuple_value, i);
+	}
+
+	GB_ASSERT(rs->vals.count <= value_count);
+	for (isize i = 0; i < rs->vals.count; i++) {
+		Ast *val = rs->vals[i];
+		if (val != nullptr) {
+			cg_range_stmt_store_val(p, val, values[i]);
+		}
+	}
+
+	cg_push_target_list(p, rs->label, done, loop, nullptr);
+
+	cg_build_stmt(p, rs->body);
+
+	cg_scope_close(p, cgDeferExit_Default, nullptr);
+	cg_pop_target_list(p);
+	cg_emit_goto(p, loop);
+	tb_inst_set_control(p->func, done);
+}
+
 
 gb_internal void cg_build_range_stmt(cgProcedure *p, Ast *node) {
 	ast_node(rs, RangeStmt, node);
@@ -1970,6 +2032,17 @@ gb_internal void cg_build_range_stmt(cgProcedure *p, Ast *node) {
 		}
 	}
 
+	TypeAndValue tav = type_and_value_of_expr(expr);
+	if (tav.mode != Addressing_Type) {
+		Type *expr_type = type_of_expr(expr);
+		Type *et = base_type(type_deref(expr_type));
+		if (et->kind == Type_Tuple) {
+			cg_build_range_tuple(p, rs, rs->scope);
+			return;
+		}
+	}
+
+
 	cg_scope_open(p, rs->scope);
 
 
@@ -1989,7 +2062,6 @@ gb_internal void cg_build_range_stmt(cgProcedure *p, Ast *node) {
 	TB_Node *loop = nullptr;
 	TB_Node *done = nullptr;
 	bool is_map = false;
-	TypeAndValue tav = type_and_value_of_expr(expr);
 
 	if (tav.mode == Addressing_Type) {
 		cg_build_range_stmt_enum(p, type_deref(tav.type), val0_type, &val, &key, &loop, &done);
@@ -2067,8 +2139,11 @@ gb_internal void cg_build_range_stmt(cgProcedure *p, Ast *node) {
 			break;
 		}
 		case Type_Tuple:
-			GB_PANIC("TODO(bill): cg_build_range_tuple");
-			// cg_build_range_tuple(p, expr, val0_type, val1_type, &val, &key, &loop, &done);
+			GB_PANIC("Should be handled already");
+			break;
+
+		case Type_BitSet:
+			GB_PANIC("TODO(bill): for in bit_set");
 			break;
 		default:
 			GB_PANIC("Cannot range over %s", type_to_string(expr_type));