Ginger Bill 8 lat temu
rodzic
commit
a75ccb6fbc
10 zmienionych plików z 338 dodań i 199 usunięć
  1. 1 1
      build.bat
  2. 17 4
      code/demo.odin
  3. 3 9
      core/fmt.odin
  4. 4 0
      core/math.odin
  5. 260 160
      src/check_expr.c
  6. 9 9
      src/check_stmt.c
  7. 35 11
      src/ir.c
  8. 2 2
      src/ir_print.c
  9. 1 1
      src/parser.c
  10. 6 2
      src/types.c

+ 1 - 1
build.bat

@@ -4,7 +4,7 @@
 set exe_name=odin.exe
 
 :: Debug = 0, Release = 1
-set release_mode=0
+set release_mode=1
 set compiler_flags= -nologo -Oi -TC -fp:fast -fp:except- -Gm- -MP -FC -GS- -EHsc- -GR-
 
 if %release_mode% EQU 0 ( rem Debug

+ 17 - 4
code/demo.odin

@@ -1,15 +1,18 @@
-#import "fmt.odin";
 #import "atomic.odin";
 #import "hash.odin";
-#import "math.odin";
 #import "mem.odin";
 #import "opengl.odin";
-#import "os.odin";
 #import "strconv.odin";
 #import "sync.odin";
 #import win32 "sys/windows.odin";
 
+#import "fmt.odin";
+#import "os.odin";
+#import "math.odin";
+
+
 main :: proc() {
+when true {
 /*
 	Added:
 		* Unexported entities and fields using an underscore prefix
@@ -59,13 +62,19 @@ main :: proc() {
 	{
 	#label thing
 		for i in 0..10 {
-			for j := i+1; j < 10; j++ {
+			for j in i+1..10 {
 				if j == 2 {
 					fmt.println(i, j);
+					continue thing;
+				}
+				if j == 3 {
 					break thing;
 				}
 			}
 		}
+
+		// Works with, `for`, `for in`, `match`, `match in`
+		// NOTE(bill): This solves most of the problems I need `goto` for
 	}
 
 	{
@@ -76,10 +85,13 @@ main :: proc() {
 			fmt.println("It's a number");
 		}
 
+
 		x: any = 123;
+	#label foo
 		match i in x {
 		case int, f32:
 			fmt.println("It's an int or f32");
+			break foo;
 		}
 	}
 
@@ -304,4 +316,5 @@ main :: proc() {
 		frog, _ = union_cast(Frog)entity; // ignore error and force cast
 	}
 }
+}
 

+ 3 - 9
core/fmt.odin

@@ -946,11 +946,9 @@ bprintf :: proc(b: ^[]byte, fmt: string, args: ..any) -> int {
 		// Process a "verb"
 		i++;
 
-
+		#label prefix_loop
 		for ; i < end; i++ {
-			skip_loop := false;
-			c := fmt[i];
-			match c {
+			match fmt[i] {
 			case '+':
 				fi.plus = true;
 			case '-':
@@ -963,11 +961,7 @@ bprintf :: proc(b: ^[]byte, fmt: string, args: ..any) -> int {
 			case '0':
 				fi.zero = !fi.minus;
 			default:
-				skip_loop = true;
-			}
-
-			if skip_loop {
-				break;
+				break prefix_loop;
 			}
 		}
 

+ 4 - 0
core/math.odin

@@ -36,6 +36,10 @@ cos  :: proc(x: f64) -> f64 #foreign __llvm_core "llvm.cos.f64";
 tan  :: proc(x: f32) -> f32 #inline { return sin(x)/cos(x); }
 tan  :: proc(x: f64) -> f64 #inline { return sin(x)/cos(x); }
 
+pow  :: proc(x, power: f32) -> f32 #foreign __llvm_core "llvm.pow.f32";
+pow  :: proc(x, power: f64) -> f64 #foreign __llvm_core "llvm.pow.f64";
+
+
 lerp :: proc(a, b, t: f32) -> f32 { return a*(1-t) + b*t; }
 lerp :: proc(a, b, t: f64) -> f64 { return a*(1-t) + b*t; }
 

+ 260 - 160
src/check_expr.c

@@ -1102,8 +1102,8 @@ Entity *check_ident(Checker *c, Operand *o, AstNode *n, Type *named_type, Type *
 
 
 	if (e->type == NULL) {
-		compiler_error("Compiler error: How did this happen? type: %s; identifier: %.*s\n", type_to_string(e->type), LIT(name));
-		return NULL;
+		compiler_error("How did this happen? type: %s; identifier: %.*s\n", type_to_string(e->type), LIT(name));
+		// return NULL;
 	}
 
 	e->flags |= EntityFlag_Used;
@@ -1339,14 +1339,11 @@ void check_map_type(Checker *c, Type *type, AstNode *node) {
 	// error_node(node, "`map` types are not yet implemented");
 }
 
-Type *check_type_extra(Checker *c, AstNode *e, Type *named_type) {
-	ExactValue null_value = {ExactValue_Invalid};
-	Type *type = NULL;
-	gbString err_str = NULL;
-
+bool check_type_extra_interal(Checker *c, AstNode *e, Type **type, Type *named_type) {
+	GB_ASSERT_NOT_NULL(type);
 	if (e == NULL) {
-		type = t_invalid;
-		goto end;
+		*type = t_invalid;
+		return true;
 	}
 
 	switch (e->kind) {
@@ -1358,17 +1355,19 @@ Type *check_type_extra(Checker *c, AstNode *e, Type *named_type) {
 		case Addressing_Invalid:
 			break;
 		case Addressing_Type: {
-			type = o.type;
-			goto end;
+			*type = o.type;
+			return true;
 		} break;
-		case Addressing_NoValue:
-			err_str = expr_to_string(e);
+		case Addressing_NoValue: {
+			gbString err_str = expr_to_string(e);
 			error_node(e, "`%s` used as a type", err_str);
-			break;
-		default:
-			err_str = expr_to_string(e);
+			gb_string_free(err_str);
+		} break;
+		default: {
+			gbString err_str = expr_to_string(e);
 			error_node(e, "`%s` used as a type when not a type", err_str);
-			break;
+			gb_string_free(err_str);
+		} break;
 		}
 	case_end;
 
@@ -1381,43 +1380,46 @@ Type *check_type_extra(Checker *c, AstNode *e, Type *named_type) {
 			break;
 		case Addressing_Type:
 			GB_ASSERT(o.type != NULL);
-			type = o.type;
-			goto end;
-		case Addressing_NoValue:
-			err_str = expr_to_string(e);
+			*type = o.type;
+			return true;
+		case Addressing_NoValue: {
+			gbString err_str = expr_to_string(e);
 			error_node(e, "`%s` used as a type", err_str);
-			break;
-		default:
-			err_str = expr_to_string(e);
+			gb_string_free(err_str);
+		} break;
+		default: {
+			gbString err_str = expr_to_string(e);
 			error_node(e, "`%s` is not a type", err_str);
-			break;
+			gb_string_free(err_str);
+		} break;
 		}
 	case_end;
 
 	case_ast_node(pe, ParenExpr, e);
-		type = check_type_extra(c, pe->expr, named_type);
-		goto end;
+		*type = check_type_extra(c, pe->expr, named_type);
+		return true;
 	case_end;
 
 	case_ast_node(ue, UnaryExpr, e);
 		if (ue->op.kind == Token_Pointer) {
-			type = make_type_pointer(c->allocator, check_type(c, ue->expr));
-			goto end;
+			*type = make_type_pointer(c->allocator, check_type(c, ue->expr));
+			return true;
 		} /* else if (ue->op.kind == Token_Maybe) {
-			type = make_type_maybe(c->allocator, check_type(c, ue->expr));
-			goto end;
+			*type = make_type_maybe(c->allocator, check_type(c, ue->expr));
+			return true;
 		} */
 	case_end;
 
 	case_ast_node(ht, HelperType, e);
-		type = check_type(c, ht->type);
-		goto end;
+		*type = check_type(c, ht->type);
+		return true;
 	case_end;
 
 	case_ast_node(pt, PointerType, e);
 		Type *elem = check_type(c, pt->type);
-		type = make_type_pointer(c->allocator, elem);
-		goto end;
+		i64 esz = type_size_of(c->allocator, elem);
+		*type = make_type_pointer(c->allocator, elem);
+		return true;
 	case_end;
 
 	case_ast_node(at, ArrayType, e);
@@ -1425,21 +1427,39 @@ Type *check_type_extra(Checker *c, AstNode *e, Type *named_type) {
 			Type *elem = check_type_extra(c, at->elem, NULL);
 			i64 count = check_array_or_map_count(c, at->count, false);
 			if (count < 0) {
-				error_node(at->count, "? can only be used in conjuction with compound literals");
+				error_node(at->count, ".. can only be used in conjuction with compound literals");
 				count = 0;
 			}
-			type = make_type_array(c->allocator, elem, count);
+			i64 esz = type_size_of(c->allocator, elem);
+			if (esz <= 0) {
+				gbString str = type_to_string(elem);
+				error_node(at->elem, "Zero sized element type `%s` is not allowed", str);
+				gb_string_free(str);
+			}
+			*type = make_type_array(c->allocator, elem, count);
 		} else {
 			Type *elem = check_type(c, at->elem);
-			type = make_type_slice(c->allocator, elem);
+			i64 esz = type_size_of(c->allocator, elem);
+			if (esz <= 0) {
+				gbString str = type_to_string(elem);
+				error_node(at->elem, "Zero sized element type `%s` is not allowed", str);
+				gb_string_free(str);
+			}
+			*type = make_type_slice(c->allocator, elem);
 		}
-		goto end;
+		return true;
 	case_end;
 
 	case_ast_node(dat, DynamicArrayType, e);
 		Type *elem = check_type_extra(c, dat->elem, NULL);
-		type = make_type_dynamic_array(c->allocator, elem);
-		goto end;
+		i64 esz = type_size_of(c->allocator, elem);
+		if (esz <= 0) {
+			gbString str = type_to_string(elem);
+			error_node(dat->elem, "Zero sized element type `%s` is not allowed", str);
+			gb_string_free(str);
+		}
+		*type = make_type_dynamic_array(c->allocator, elem);
+		return true;
 	case_end;
 
 
@@ -1449,84 +1469,96 @@ Type *check_type_extra(Checker *c, AstNode *e, Type *named_type) {
 		Type *be = base_type(elem);
 		i64 count = check_array_or_map_count(c, vt->count, false);
 		if (is_type_vector(be) || (!is_type_boolean(be) && !is_type_numeric(be))) {
-			err_str = type_to_string(elem);
+			gbString err_str = type_to_string(elem);
 			error_node(vt->elem, "Vector element type must be numerical or a boolean, got `%s`", err_str);
+			gb_string_free(err_str);
 		}
-		type = make_type_vector(c->allocator, elem, count);
-		goto end;
+		*type = make_type_vector(c->allocator, elem, count);
+		return true;
 	case_end;
 
 	case_ast_node(st, StructType, e);
-		type = make_type_struct(c->allocator);
-		set_base_type(named_type, type);
+		*type = make_type_struct(c->allocator);
+		set_base_type(named_type, *type);
 		check_open_scope(c, e);
-		check_struct_type(c, type, e);
+		check_struct_type(c, *type, e);
 		check_close_scope(c);
-		type->Record.node = e;
-		goto end;
+		(*type)->Record.node = e;
+		return true;
 	case_end;
 
 	case_ast_node(ut, UnionType, e);
-		type = make_type_union(c->allocator);
-		set_base_type(named_type, type);
+		*type = make_type_union(c->allocator);
+		set_base_type(named_type, *type);
 		check_open_scope(c, e);
-		check_union_type(c, type, e);
+		check_union_type(c, *type, e);
 		check_close_scope(c);
-		type->Record.node = e;
-		goto end;
+		(*type)->Record.node = e;
+		return true;
 	case_end;
 
 	case_ast_node(rut, RawUnionType, e);
-		type = make_type_raw_union(c->allocator);
-		set_base_type(named_type, type);
+		*type = make_type_raw_union(c->allocator);
+		set_base_type(named_type, *type);
 		check_open_scope(c, e);
-		check_raw_union_type(c, type, e);
+		check_raw_union_type(c, *type, e);
 		check_close_scope(c);
-		type->Record.node = e;
-		goto end;
+		(*type)->Record.node = e;
+		return true;
 	case_end;
 
 	case_ast_node(et, EnumType, e);
-		type = make_type_enum(c->allocator);
-		set_base_type(named_type, type);
+		*type = make_type_enum(c->allocator);
+		set_base_type(named_type, *type);
 		check_open_scope(c, e);
-		check_enum_type(c, type, named_type, e);
+		check_enum_type(c, *type, named_type, e);
 		check_close_scope(c);
-		type->Record.node = e;
-		goto end;
+		(*type)->Record.node = e;
+		return true;
 	case_end;
 
 	case_ast_node(pt, ProcType, e);
-		type = alloc_type(c->allocator, Type_Proc);
-		set_base_type(named_type, type);
+		*type = alloc_type(c->allocator, Type_Proc);
+		set_base_type(named_type, *type);
 		check_open_scope(c, e);
-		check_procedure_type(c, type, e);
+		check_procedure_type(c, *type, e);
 		check_close_scope(c);
-		goto end;
+		return true;
 	case_end;
 
 	case_ast_node(mt, MapType, e);
-		type = alloc_type(c->allocator, Type_Map);
-		set_base_type(named_type, type);
-		check_map_type(c, type, e);
-		goto end;
+		*type = alloc_type(c->allocator, Type_Map);
+		set_base_type(named_type, *type);
+		check_map_type(c, *type, e);
+		return true;
 	case_end;
 
 	case_ast_node(ce, CallExpr, e);
 		Operand o = {0};
 		check_expr_or_type(c, &o, e);
 		if (o.mode == Addressing_Type) {
-			type = o.type;
-			goto end;
+			*type = o.type;
+			return true;
 		}
 	case_end;
 	}
-	err_str = expr_to_string(e);
-	error_node(e, "`%s` is not a type", err_str);
 
-	type = t_invalid;
-end:
-	gb_string_free(err_str);
+	*type = t_invalid;
+	return false;
+}
+
+
+
+Type *check_type_extra(Checker *c, AstNode *e, Type *named_type) {
+	Type *type = NULL;
+	bool ok = check_type_extra_interal(c, e, &type, named_type);
+
+	if (!ok) {
+		gbString err_str = expr_to_string(e);
+		error_node(e, "`%s` is not a type", err_str);
+		gb_string_free(err_str);
+		type = t_invalid;
+	}
 
 	if (type == NULL) {
 		type = t_invalid;
@@ -1542,7 +1574,7 @@ end:
 	}
 
 	if (is_type_typed(type)) {
-		add_type_and_value(&c->info, e, Addressing_Type, type, null_value);
+		add_type_and_value(&c->info, e, Addressing_Type, type, (ExactValue){0});
 	} else {
 		gbString name = type_to_string(type);
 		error_node(e, "Invalid type definition of %s", name);
@@ -1551,8 +1583,6 @@ end:
 	}
 	set_base_type(named_type, type);
 
-
-
 	return type;
 }
 
@@ -2093,9 +2123,19 @@ Operand check_ptr_addition(Checker *c, TokenKind op, Operand *ptr, Operand *offs
 		return operand;
 	}
 
+	Type *base_ptr = base_type(ptr->type); GB_ASSERT(base_ptr->kind == Type_Pointer);
+	Type *elem = base_ptr->Pointer.elem;
+	i64 elem_size = type_size_of(c->allocator, elem);
+
+	if (elem_size <= 0) {
+		gbString str = type_to_string(elem);
+		error_node(node, "Size of pointer's element type `%s` is zero and cannot be used for pointer arithmetic", str);
+		gb_string_free(str);
+		operand.mode = Addressing_Invalid;
+		return operand;
+	}
 
 	if (ptr->mode == Addressing_Constant && offset->mode == Addressing_Constant) {
-		i64 elem_size = type_size_of(c->allocator, ptr->type);
 		i64 ptr_val = ptr->value.value_pointer;
 		i64 offset_val = exact_value_to_integer(offset->value).value_integer;
 		i64 new_ptr_val = ptr_val;
@@ -2523,7 +2563,9 @@ void convert_to_typed(Checker *c, Operand *operand, Type *target_type, i32 level
 				update_expr_type(c, operand->expr, target_type, false);
 			}
 		} else if (x_kind != y_kind) {
-			goto error;
+			operand->mode = Addressing_Invalid;
+			convert_untyped_error(c, operand, target_type);
+			return;
 		}
 		return;
 	}
@@ -2541,20 +2583,26 @@ void convert_to_typed(Checker *c, Operand *operand, Type *target_type, i32 level
 			switch (operand->type->Basic.kind) {
 			case Basic_UntypedBool:
 				if (!is_type_boolean(target_type)) {
-					goto error;
+					operand->mode = Addressing_Invalid;
+					convert_untyped_error(c, operand, target_type);
+					return;
 				}
 				break;
 			case Basic_UntypedInteger:
 			case Basic_UntypedFloat:
 			case Basic_UntypedRune:
 				if (!is_type_numeric(target_type)) {
-					goto error;
+					operand->mode = Addressing_Invalid;
+					convert_untyped_error(c, operand, target_type);
+					return;
 				}
 				break;
 
 			case Basic_UntypedNil:
 				if (!type_has_nil(target_type)) {
-					goto error;
+					operand->mode = Addressing_Invalid;
+					convert_untyped_error(c, operand, target_type);
+					return;
 				}
 				break;
 			}
@@ -2563,7 +2611,9 @@ void convert_to_typed(Checker *c, Operand *operand, Type *target_type, i32 level
 
 	default:
 		if (!is_type_untyped_nil(operand->type) || !type_has_nil(target_type)) {
-			goto error;
+			operand->mode = Addressing_Invalid;
+			convert_untyped_error(c, operand, target_type);
+			return;
 		}
 		target_type = t_untyped_nil;
 		break;
@@ -2571,11 +2621,6 @@ void convert_to_typed(Checker *c, Operand *operand, Type *target_type, i32 level
 
 	operand->type = target_type;
 	update_expr_type(c, operand->expr, target_type, true);
-	return;
-
-error:
-	operand->mode = Addressing_Invalid;
-	convert_untyped_error(c, operand, target_type);
 }
 
 bool check_index_value(Checker *c, AstNode *index_value, i64 max_count, i64 *value) {
@@ -2670,16 +2715,22 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h
 	Entity *entity = NULL;
 	Selection sel = {0}; // NOTE(bill): Not used if it's an import name
 
+	operand->expr = node;
+
 	AstNode *op_expr  = se->expr;
 	AstNode *selector = unparen_expr(se->selector);
 	if (selector == NULL) {
-		goto error;
+		operand->mode = Addressing_Invalid;
+		operand->expr = node;
+		return NULL;
 	}
 
 	// if (selector->kind != AstNode_Ident && selector->kind != AstNode_BasicLit) {
 	if (selector->kind != AstNode_Ident) {
 		error_node(selector, "Illegal selector kind: `%.*s`", LIT(ast_node_strings[selector->kind]));
-		goto error;
+		operand->mode = Addressing_Invalid;
+		operand->expr = node;
+		return NULL;
 	}
 
 	if (op_expr->kind == AstNode_Ident) {
@@ -2716,7 +2767,9 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h
 			}
 			if (!is_declared) {
 				error_node(op_expr, "`%.*s` is not declared by `%.*s`", LIT(entity_name), LIT(import_name));
-				goto error;
+				operand->mode = Addressing_Invalid;
+				operand->expr = node;
+				return NULL;
 			}
 			check_entity_decl(c, entity, NULL, NULL);
 			GB_ASSERT(entity->type != NULL);
@@ -2736,7 +2789,9 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h
 				gbString sel_str = expr_to_string(selector);
 				error_node(op_expr, "`%s` is not exported by `%.*s`", sel_str, LIT(import_name));
 				gb_string_free(sel_str);
-				goto error;
+				operand->mode = Addressing_Invalid;
+				operand->expr = node;
+				return NULL;
 			}
 
 			if (is_overloaded) {
@@ -2786,7 +2841,9 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h
 	if (check_op_expr) {
 		check_expr_base(c, operand, op_expr, NULL);
 		if (operand->mode == Addressing_Invalid) {
-			goto error;
+			operand->mode = Addressing_Invalid;
+			operand->expr = node;
+			return NULL;
 		}
 	}
 
@@ -2797,7 +2854,9 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h
 
 		if (operand->mode != Addressing_Type && !check_is_field_exported(c, sel.entity)) {
 			error_node(op_expr, "`%.*s` is an unexported field", LIT(field_name));
-			goto error;
+			operand->mode = Addressing_Invalid;
+			operand->expr = node;
+			return NULL;
 		}
 		entity = sel.entity;
 
@@ -2814,12 +2873,16 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h
 			if (o.mode != Addressing_Constant ||
 			    !is_type_integer(o.type)) {
 				error_node(op_expr, "Indexed based selectors must be a constant integer %s");
-				goto error;
+				operand->mode = Addressing_Invalid;
+				operand->expr = node;
+				return NULL;
 			}
 			i64 index = o.value.value_integer;
 			if (index < 0) {
 				error_node(o.expr, "Index %lld cannot be a negative value", index);
-				goto error;
+				operand->mode = Addressing_Invalid;
+				operand->expr = node;
+				return NULL;
 			}
 
 			i64 max_count = 0;
@@ -2830,7 +2893,9 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h
 
 			if (index >= max_count) {
 				error_node(o.expr, "Index %lld is out of bounds range 0..<%lld", index, max_count);
-				goto error;
+				operand->mode = Addressing_Invalid;
+				operand->expr = node;
+				return NULL;
 			}
 
 			sel = lookup_field_from_index(heap_allocator(), type, index);
@@ -2840,7 +2905,9 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h
 
 		} else {
 			error_node(op_expr, "Indexed based selectors may only be used on structs or tuples");
-			goto error;
+			operand->mode = Addressing_Invalid;
+			operand->expr = node;
+			return NULL;
 		}
 	}
 
@@ -2861,7 +2928,9 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h
 		gb_string_free(sel_str);
 		gb_string_free(type_str);
 		gb_string_free(op_str);
-		goto error;
+		operand->mode = Addressing_Invalid;
+		operand->expr = node;
+		return NULL;
 	}
 
 	if (expr_entity != NULL && expr_entity->kind == Entity_Constant && entity->kind != Entity_Constant) {
@@ -2872,7 +2941,9 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h
 		gb_string_free(sel_str);
 		gb_string_free(type_str);
 		gb_string_free(op_str);
-		goto error;
+		operand->mode = Addressing_Invalid;
+		operand->expr = node;
+		return NULL;
 	}
 
 
@@ -2915,11 +2986,6 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h
 	operand->expr = node;
 
 	return entity;
-
-error:
-	operand->mode = Addressing_Invalid;
-	operand->expr = node;
-	return NULL;
 }
 
 bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) {
@@ -4293,7 +4359,8 @@ bool check_set_index_data(Operand *o, Type *type, bool indirection, i64 *max_cou
 	return false;
 }
 
-ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint) {
+
+ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *type_hint) {
 	ExprKind kind = Expr_Stmt;
 
 	o->mode = Addressing_Invalid;
@@ -4301,16 +4368,15 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
 
 	switch (node->kind) {
 	default:
-		goto error;
-		break;
+		return kind;
 
 	case_ast_node(be, BadExpr, node)
-		goto error;
+		return kind;
 	case_end;
 
 	case_ast_node(i, IntervalExpr, node);
 		error_node(node, "Invalid use of an interval expression");
-		goto error;
+		return kind;
 	case_end;
 
 	case_ast_node(i, Implicit, node)
@@ -4318,7 +4384,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
 		case Token_context:
 			if (c->context.proc_name.len == 0) {
 				error_node(node, "`context` is only allowed within procedures");
-				goto error;
+				return kind;
 			}
 
 			o->mode = Addressing_Value;
@@ -4326,7 +4392,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
 			break;
 		default:
 			error_node(node, "Illegal implicit name `%.*s`", LIT(i->string));
-			goto error;
+			return kind;
 		}
 	case_end;
 
@@ -4378,7 +4444,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
 			error_node(node, "Invalid procedure literal `%s`", str);
 			gb_string_free(str);
 			check_close_scope(c);
-			goto error;
+			return kind;
 		}
 		if (pl->tags != 0) {
 			error_node(node, "A procedure literal cannot have tags");
@@ -4409,22 +4475,22 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
 			check_expr_with_type_hint(c, &y, te->y, type_hint);
 		} else {
 			error_node(node, "A ternary expression must have an else clause");
-			goto error;
+			return kind;
 		}
 
 		if (x.type == NULL || x.type == t_invalid ||
 		    y.type == NULL || y.type == t_invalid) {
-			goto error;
+			return kind;
 		}
 
 		convert_to_typed(c, &x, y.type, 0);
 		if (x.mode == Addressing_Invalid) {
-			goto error;
+			return kind;
 		}
 		convert_to_typed(c, &y, x.type, 0);
 		if (y.mode == Addressing_Invalid) {
 			x.mode = Addressing_Invalid;
-			goto error;
+			return kind;
 		}
 
 
@@ -4434,7 +4500,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
 			error_node(node, "Mismatched types in ternary expression, %s vs %s", its, ets);
 			gb_string_free(ets);
 			gb_string_free(its);
-			goto error;
+			return kind;
 		}
 
 		o->type = x.type;
@@ -4479,7 +4545,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
 
 		if (type == NULL) {
 			error_node(node, "Missing type in compound literal");
-			goto error;
+			return kind;
 		}
 
 		Type *t = base_type(type);
@@ -4773,7 +4839,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
 			gbString str = type_to_string(type);
 			error_node(node, "Invalid compound literal type `%s`", str);
 			gb_string_free(str);
-			goto error;
+			return kind;
 		} break;
 		}
 
@@ -4810,7 +4876,8 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
 		Type *t = check_type(c, ce->type);
 		check_expr(c, o, ce->expr);
 		if (o->mode == Addressing_Invalid) {
-			goto error;
+			o->expr = node;
+			return kind;
 		}
 		switch (ce->token.kind) {
 		case Token_cast:
@@ -4822,7 +4889,8 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
 				error_node(o->expr, "Cannot transmute constant expression: `%s`", expr_str);
 				gb_string_free(expr_str);
 				o->mode = Addressing_Invalid;
-				goto error;
+				o->expr = node;
+				return kind;
 			}
 
 			if (is_type_untyped(o->type)) {
@@ -4830,7 +4898,8 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
 				error_node(o->expr, "Cannot transmute untyped expression: `%s`", expr_str);
 				gb_string_free(expr_str);
 				o->mode = Addressing_Invalid;
-				goto error;
+				o->expr = node;
+				return kind;
 			}
 
 			i64 srcz = type_size_of(c->allocator, o->type);
@@ -4842,7 +4911,8 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
 				gb_string_free(type_str);
 				gb_string_free(expr_str);
 				o->mode = Addressing_Invalid;
-				goto error;
+				o->expr = node;
+				return kind;
 			}
 
 			o->type = t;
@@ -4854,7 +4924,8 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
 				error_node(o->expr, "Cannot `union_cast` a constant expression: `%s`", expr_str);
 				gb_string_free(expr_str);
 				o->mode = Addressing_Invalid;
-				goto error;
+				o->expr = node;
+				return kind;
 			}
 
 			if (is_type_untyped(o->type)) {
@@ -4862,7 +4933,8 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
 				error_node(o->expr, "Cannot `union_cast` an untyped expression: `%s`", expr_str);
 				gb_string_free(expr_str);
 				o->mode = Addressing_Invalid;
-				goto error;
+				o->expr = node;
+				return kind;
 			}
 
 			bool src_is_ptr = is_type_pointer(o->type);
@@ -4879,13 +4951,15 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
 				gb_string_free(dst_type_str);
 				gb_string_free(src_type_str);
 				o->mode = Addressing_Invalid;
-				goto error;
+				o->expr = node;
+				return kind;
 			}
 
 			if (!is_type_union(src)) {
 				error_node(o->expr, "`union_cast` can only operate on unions");
 				o->mode = Addressing_Invalid;
-				goto error;
+				o->expr = node;
+				return kind;
 			}
 
 			bool ok = false;
@@ -4904,7 +4978,8 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
 				gb_string_free(dst_type_str);
 				gb_string_free(expr_str);
 				o->mode = Addressing_Invalid;
-				goto error;
+				o->expr = node;
+				return kind;
 			}
 
 			add_type_info_type(c, o->type);
@@ -4919,7 +4994,8 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
 				error_node(o->expr, "Cannot `down_cast` a constant expression: `%s`", expr_str);
 				gb_string_free(expr_str);
 				o->mode = Addressing_Invalid;
-				goto error;
+				o->expr = node;
+				return kind;
 			}
 
 			if (is_type_untyped(o->type)) {
@@ -4927,7 +5003,8 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
 				error_node(o->expr, "Cannot `down_cast` an untyped expression: `%s`", expr_str);
 				gb_string_free(expr_str);
 				o->mode = Addressing_Invalid;
-				goto error;
+				o->expr = node;
+				return kind;
 			}
 
 			if (!(is_type_pointer(o->type) && is_type_pointer(t))) {
@@ -4935,7 +5012,8 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
 				error_node(o->expr, "Can only `down_cast` pointers: `%s`", expr_str);
 				gb_string_free(expr_str);
 				o->mode = Addressing_Invalid;
-				goto error;
+				o->expr = node;
+				return kind;
 			}
 
 			Type *src = type_deref(o->type);
@@ -4948,7 +5026,8 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
 				error_node(o->expr, "Can only `down_cast` pointer from structs or unions: `%s`", expr_str);
 				gb_string_free(expr_str);
 				o->mode = Addressing_Invalid;
-				goto error;
+				o->expr = node;
+				return kind;
 			}
 
 			if (!(is_type_struct(bdst) || is_type_raw_union(bdst))) {
@@ -4956,7 +5035,8 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
 				error_node(o->expr, "Can only `down_cast` pointer to structs or unions: `%s`", expr_str);
 				gb_string_free(expr_str);
 				o->mode = Addressing_Invalid;
-				goto error;
+				o->expr = node;
+				return kind;
 			}
 
 			String param_name = check_down_cast_name(dst, src);
@@ -4965,7 +5045,8 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
 				error_node(o->expr, "Illegal `down_cast`: `%s`", expr_str);
 				gb_string_free(expr_str);
 				o->mode = Addressing_Invalid;
-				goto error;
+				o->expr = node;
+				return kind;
 			}
 
 			o->mode = Addressing_Value;
@@ -4982,11 +5063,13 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
 	case_ast_node(ue, UnaryExpr, node);
 		check_expr_base(c, o, ue->expr, type_hint);
 		if (o->mode == Addressing_Invalid) {
-			goto error;
+			o->expr = node;
+			return kind;
 		}
 		check_unary_expr(c, o, ue->op, node);
 		if (o->mode == Addressing_Invalid) {
-			goto error;
+			o->expr = node;
+			return kind;
 		}
 	case_end;
 
@@ -4994,7 +5077,8 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
 	case_ast_node(be, BinaryExpr, node);
 		check_binary_expr(c, o, node);
 		if (o->mode == Addressing_Invalid) {
-			goto error;
+			o->expr = node;
+			return kind;
 		}
 	case_end;
 
@@ -5008,7 +5092,8 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
 	case_ast_node(ie, IndexExpr, node);
 		check_expr(c, o, ie->expr);
 		if (o->mode == Addressing_Invalid) {
-			goto error;
+			o->expr = node;
+			return kind;
 		}
 
 		Type *t = base_type(type_deref(o->type));
@@ -5020,7 +5105,9 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
 			check_expr(c, &key, ie->index);
 			check_assignment(c, &key, t->Map.key, str_lit("map index"));
 			if (key.mode == Addressing_Invalid) {
-				goto error;
+				o->mode = Addressing_Invalid;
+				o->expr = node;
+				return kind;
 			}
 			o->mode = Addressing_MapIndex;
 			o->type = t->Map.value;
@@ -5050,14 +5137,18 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
 				error_node(o->expr, "Cannot index `%s`", str);
 			}
 			gb_string_free(str);
-			goto error;
+			o->mode = Addressing_Invalid;
+			o->expr = node;
+			return kind;
 		}
 
 		if (ie->index == NULL) {
 			gbString str = expr_to_string(o->expr);
 			error_node(o->expr, "Missing index for `%s`", str);
 			gb_string_free(str);
-			goto error;
+			o->mode = Addressing_Invalid;
+			o->expr = node;
+			return kind;
 		}
 
 		i64 index = 0;
@@ -5070,7 +5161,9 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
 	case_ast_node(se, SliceExpr, node);
 		check_expr(c, o, se->expr);
 		if (o->mode == Addressing_Invalid) {
-			goto error;
+			o->mode = Addressing_Invalid;
+			o->expr = node;
+			return kind;
 		}
 
 		bool valid = false;
@@ -5081,7 +5174,9 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
 			if (is_type_string(t)) {
 				if (se->index3) {
 					error_node(node, "3-index slice on a string in not needed");
-					goto error;
+					o->mode = Addressing_Invalid;
+					o->expr = node;
+					return kind;
 				}
 				valid = true;
 				if (o->mode == Addressing_Constant) {
@@ -5098,7 +5193,9 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
 				gbString str = expr_to_string(node);
 				error_node(node, "Cannot slice array `%s`, value is not addressable", str);
 				gb_string_free(str);
-				goto error;
+				o->mode = Addressing_Invalid;
+				o->expr = node;
+				return kind;
 			}
 			o->type = make_type_slice(c->allocator, t->Array.elem);
 			break;
@@ -5116,7 +5213,9 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
 			gbString str = expr_to_string(o->expr);
 			error_node(o->expr, "Cannot slice `%s`", str);
 			gb_string_free(str);
-			goto error;
+			o->mode = Addressing_Invalid;
+			o->expr = node;
+			return kind;
 		}
 
 		if (o->mode != Addressing_Immutable) {
@@ -5125,7 +5224,9 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
 
 		if (se->index3 && (se->high == NULL || se->max == NULL)) {
 			error(se->close, "2nd and 3rd indices are required in a 3-index slice");
-			goto error;
+			o->mode = Addressing_Invalid;
+			o->expr = node;
+			return kind;
 		}
 
 		i64 indices[2] = {0};
@@ -5171,7 +5272,9 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
 	case_ast_node(de, DerefExpr, node);
 		check_expr_or_type(c, o, de->expr);
 		if (o->mode == Addressing_Invalid) {
-			goto error;
+			o->mode = Addressing_Invalid;
+			o->expr = node;
+			return kind;
 		} else {
 			Type *t = base_type(o->type);
 			if (t->kind == Type_Pointer) {
@@ -5183,7 +5286,9 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
  				gbString str = expr_to_string(o->expr);
  				error_node(o->expr, "Cannot dereference `%s`", str);
  				gb_string_free(str);
- 				goto error;
+ 				o->mode = Addressing_Invalid;
+ 				o->expr = node;
+ 				return kind;
  			}
 		}
 	case_end;
@@ -5207,15 +5312,10 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
 	kind = Expr_Expr;
 	o->expr = node;
 	return kind;
-
-error:
-	o->mode = Addressing_Invalid;
-	o->expr = node;
-	return kind;
 }
 
 ExprKind check_expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint) {
-	ExprKind kind = check__expr_base(c, o, node, type_hint);
+	ExprKind kind = check_expr_base_internal(c, o, node, type_hint);
 	Type *type = NULL;
 	ExactValue value = {ExactValue_Invalid};
 	switch (o->mode) {

+ 9 - 9
src/check_stmt.c

@@ -689,8 +689,8 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
 
 	case_ast_node(rs, RangeStmt, node);
 		u32 new_flags = mod_flags | Stmt_BreakAllowed | Stmt_ContinueAllowed;
-		check_open_scope(c, node);
 
+		check_open_scope(c, node);
 		check_label(c, rs->label);
 
 		Type *val = NULL;
@@ -885,6 +885,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
 
 		mod_flags |= Stmt_BreakAllowed;
 		check_open_scope(c, node);
+		check_label(c, ms->label); // TODO(bill): What should the label's "scope" be?
 
 		if (ms->init != NULL) {
 			check_stmt(c, ms->init, 0);
@@ -897,8 +898,8 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
 			x.type  = t_bool;
 			x.value = exact_value_bool(true);
 
-			Token token = {0};
-			token.pos = ast_node_token(ms->body).pos;
+			Token token  = {0};
+			token.pos    = ast_node_token(ms->body).pos;
 			token.string = str_lit("true");
 			x.expr       = ast_ident(c->curr_ast_file, token);
 		}
@@ -1025,6 +1026,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
 
 		mod_flags |= Stmt_BreakAllowed;
 		check_open_scope(c, node);
+		check_label(c, ms->label); // TODO(bill): What should the label's "scope" be?
 
 		MatchTypeKind match_type_kind = MatchType_Invalid;
 
@@ -1051,8 +1053,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
 		match_type_kind = check_valid_type_match_type(x.type);
 		if (check_valid_type_match_type(x.type) == MatchType_Invalid) {
 			gbString str = type_to_string(x.type);
-			error_node(x.expr,
-			           "Invalid type for this type match expression, got `%s`", str);
+			error_node(x.expr, "Invalid type for this type match expression, got `%s`", str);
 			gb_string_free(str);
 			break;
 		}
@@ -1387,7 +1388,9 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
 
 	case_ast_node(vd, ValueDecl, node);
 		GB_ASSERT(!c->context.scope->is_file);
-		if (vd->is_var) {
+		if (!vd->is_var) {
+			// NOTE(bill): Handled elsewhere
+		} else {
 			Entity **entities = gb_alloc_array(c->allocator, Entity *, vd->names.count);
 			isize entity_count = 0;
 
@@ -1497,9 +1500,6 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
 					}
 				}
 			}
-
-		} else {
-			// NOTE(bill): Handled elsewhere
 		}
 	case_end;
 	}

+ 35 - 11
src/ir.c

@@ -1659,6 +1659,39 @@ irValue *ir_emit_ptr_offset(irProcedure *proc, irValue *ptr, irValue *offset) {
 	return ir_emit(proc, ir_instr_ptr_offset(proc, ptr, offset));
 }
 
+irValue *ir_emit_unary_arith(irProcedure *proc, TokenKind op, irValue *x, Type *type) {
+	switch (op) {
+	case Token_Add:
+		return x;
+	case Token_Not: // Boolean not
+	case Token_Xor: // Bitwise not
+	case Token_Sub: // Bitwise Not
+		break;
+	case Token_Pointer:
+		GB_PANIC("This should be handled elsewhere");
+		break;
+	}
+	if (is_type_vector(ir_type(x))) {
+		ir_emit_comment(proc, str_lit("vector.arith.begin"));
+		// IMPORTANT TODO(bill): This is very wasteful with regards to stack memory
+		Type *tl = base_type(ir_type(x));
+		irValue *val = ir_address_from_load_or_generate_local(proc, x);
+		GB_ASSERT(is_type_vector(type));
+		Type *elem_type = base_type(type)->Vector.elem;
+
+		irValue *res = ir_add_local_generated(proc, type);
+		for (i32 i = 0; i < tl->Vector.count; i++) {
+			irValue *e = ir_emit_load(proc, ir_emit_array_epi(proc, val, i));
+			irValue *z = ir_emit_unary_arith(proc, op, e, elem_type);
+			ir_emit_store(proc, ir_emit_array_epi(proc, res, i), z);
+		}
+		ir_emit_comment(proc, str_lit("vector.arith.end"));
+		return ir_emit_load(proc, res);
+
+	}
+	return ir_emit(proc, ir_instr_unary_op(proc, op, x, type));
+}
+
 irValue *ir_emit_arith(irProcedure *proc, TokenKind op, irValue *left, irValue *right, Type *type) {
 	Type *t_left = ir_type(left);
 	Type *t_right = ir_type(right);
@@ -3143,17 +3176,8 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) {
 		switch (ue->op.kind) {
 		case Token_Pointer:
 			return ir_emit_ptr_offset(proc, ir_build_addr(proc, ue->expr).addr, v_zero); // Make a copy of the pointer
-
-		// case Token_Maybe:
-			// return ir_emit_conv(proc, ir_build_expr(proc, ue->expr), type_of_expr(proc->module->info, expr));
-
-		case Token_Add:
-			return ir_build_expr(proc, ue->expr);
-
-		case Token_Not: // Boolean not
-		case Token_Xor: // Bitwise not
-		case Token_Sub: // Bitwise not
-			return ir_emit(proc, ir_instr_unary_op(proc, ue->op.kind, ir_build_expr(proc, ue->expr), tv->type));
+		default:
+			return ir_emit_unary_arith(proc, ue->op.kind, ir_build_expr(proc, ue->expr), tv->type);
 		}
 	case_end;
 

+ 2 - 2
src/ir_print.c

@@ -364,7 +364,7 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
 		}
 	} break;
 	case ExactValue_Float: {
-		GB_ASSERT(is_type_float(type));
+		GB_ASSERT_MSG(is_type_float(type), "%s", type_to_string(type));
 		type = base_type(type);
 		u64 u = *cast(u64*)&value.value_float;
 		switch (type->Basic.kind) {
@@ -942,7 +942,7 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
 		switch (uo->op) {
 		case Token_Sub:
 			if (is_type_float(elem_type)) {
-				ir_print_exact_value(f, m, exact_value_float(0), type);
+				ir_print_exact_value(f, m, exact_value_float(0), elem_type);
 			} else {
 				ir_fprintf(f, "0");
 			}

+ 1 - 1
src/parser.c

@@ -3366,7 +3366,7 @@ AstNode *parse_stmt(AstFile *f) {
 			_SET_LABEL(MatchStmt, label);
 			_SET_LABEL(TypeMatchStmt, label);
 			default:
-				syntax_error(token, "#label may only be applied to a loop");
+				syntax_error(token, "#label cannot only be applied to a loop or match statement");
 				break;
 			}
 		#undef _SET_LABEL

+ 6 - 2
src/types.c

@@ -1037,8 +1037,12 @@ typedef enum ProcTypeOverloadKind {
 
 
 ProcTypeOverloadKind are_proc_types_overload_safe(Type *x, Type *y) {
- 	if (!is_type_proc(x)) return ProcOverload_NotProcedure;
- 	if (!is_type_proc(y)) return ProcOverload_NotProcedure;
+	if (x == NULL && y == NULL) return ProcOverload_NotProcedure;
+	if (x == NULL && y != NULL) return ProcOverload_NotProcedure;
+	if (x != NULL && y == NULL) return ProcOverload_NotProcedure;
+ 	if (!is_type_proc(x))       return ProcOverload_NotProcedure;
+ 	if (!is_type_proc(y))       return ProcOverload_NotProcedure;
+
 	TypeProc px = base_type(x)->Proc;
 	TypeProc py = base_type(y)->Proc;