Преглед изворни кода

Best viable overloading procedure algorithm; `no_alias`; call expr style casts

Ginger Bill пре 8 година
родитељ
комит
383f5b55ad
14 измењених фајлова са 366 додато и 222 уклоњено
  1. 21 4
      code/demo.odin
  2. 2 2
      core/_preload.odin
  3. 7 7
      core/fmt.odin
  4. 1 1
      core/math.odin
  5. 3 2
      src/check_decl.c
  6. 260 180
      src/check_expr.c
  7. 3 1
      src/check_stmt.c
  8. 10 6
      src/checker.c
  9. 1 0
      src/entity.c
  10. 9 0
      src/ir.c
  11. 6 0
      src/ir_print.c
  12. 40 18
      src/parser.c
  13. 1 0
      src/tokenizer.c
  14. 2 1
      src/types.c

+ 21 - 4
code/demo.odin

@@ -2,9 +2,23 @@
 #import "fmt.odin";
 #import "math.odin";
 #import "mem.odin";
-#import "opengl.odin";
 
 main :: proc() {
+	foo :: proc(x: ^int) {
+		fmt.println("^int");
+	}
+	foo :: proc(x: rawptr) {
+		fmt.println("rawptr");
+	}
+
+	a: ^int;
+	b: ^f32;
+	c: rawptr;
+	foo(a);
+	foo(b);
+	foo(c);
+	// foo(nil);
+
 	foo :: proc() {
 		fmt.printf("Zero args\n");
 	}
@@ -18,13 +32,16 @@ main :: proc() {
 	THINGI :: 14451;
 	THINGF :: 14451.1;
 
+
 	foo();
 	foo(THINGI as int);
+	foo(int(THINGI));
+	// foo(THINGI);
 	foo(THINGF);
 	fmt.println(THINGI);
 	fmt.println(THINGF);
 
-	x: proc();
-	x = foo;
-	x();
+	f: proc();
+	f = foo;
+	f();
 }

+ 2 - 2
core/_preload.odin

@@ -297,11 +297,11 @@ __string_eq :: proc(a, b: string) -> bool {
 	if a.data == b.data {
 		return true;
 	}
-	return mem.compare(a.data, b.data, a.count) == 0;
+	return mem.compare(a.data as rawptr, b.data as rawptr, a.count) == 0;
 }
 
 __string_cmp :: proc(a, b: string) -> int {
-	return mem.compare(a.data, b.data, min(a.count, b.count));
+	return mem.compare(a.data as rawptr, b.data as rawptr, min(a.count, b.count));
 }
 
 __string_ne :: proc(a, b: string) -> bool #inline { return !__string_eq(a, b); }

+ 7 - 7
core/fmt.odin

@@ -236,7 +236,7 @@ bprint :: proc(buf: ^Buffer, args: ...any) -> int {
 		if i > 0 && !is_string && !prev_string {
 			buffer_write_rune(buf, ' ');
 		}
-		fmt_value(^fi, arg, 'v');
+		fmt_value(^fi, args[i], 'v');
 		prev_string = is_string;
 	}
 	return buf.length;
@@ -250,7 +250,7 @@ bprintln :: proc(buf: ^Buffer, args: ...any) -> int {
 		if i > 0 {
 			buffer_write_rune(buf, ' ');
 		}
-		fmt_value(^fi, arg, 'v');
+		fmt_value(^fi, args[i], 'v');
 	}
 	buffer_write_rune(buf, '\n');
 	return buf.length;
@@ -967,16 +967,16 @@ fmt_enum :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
 			}
 
 			if is_type_integer(e.base) {
-				for val, idx : e.values {
-					if val.i == i {
+				for it, idx : e.values {
+					if it.i == i {
 						buffer_write_string(fi.buf, e.names[idx]);
 						ok = true;
 						break;
 					}
 				}
 			} else {
-				for val, idx : e.values {
-					if val.f == f {
+				for it, idx : e.values {
+					if it.f == f {
 						buffer_write_string(fi.buf, e.names[idx]);
 						ok = true;
 						break;
@@ -1312,7 +1312,7 @@ bprintf :: proc(b: ^Buffer, fmt: string, args: ...any) -> int {
 			if arg.data == nil || arg.type_info == nil {
 				buffer_write_string(b, "<nil>");
 			} else {
-				fmt_arg(^fi, arg, 'v');
+				fmt_arg(^fi, args[index], 'v');
 			}
 		}
 		buffer_write_string(b, ")");

+ 1 - 1
core/math.odin

@@ -166,7 +166,7 @@ mul :: proc(a, b: Mat4) -> Mat4 {
 	return c;
 }
 
-mul_vec4 :: proc(m: Mat4, v: Vec4) -> Vec4 {
+mul :: proc(m: Mat4, v: Vec4) -> Vec4 {
 	return Vec4{
 		m[0][0]*v.x + m[1][0]*v.y + m[2][0]*v.z + m[3][0]*v.w,
 		m[0][1]*v.x + m[1][1]*v.y + m[2][1]*v.z + m[3][1]*v.w,

+ 3 - 2
src/check_decl.c

@@ -276,8 +276,9 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init,
 
 	check_init_constant(c, e, &operand);
 
-	if (operand.mode == Addressing_Invalid) {
-		error(e->token, "Illegal cyclic declaration");
+	if (operand.mode == Addressing_Invalid ||
+	    base_type(operand.type) == t_invalid) {
+		error(e->token, "Invalid declaration type");
 	}
 }
 

+ 260 - 180
src/check_expr.c

@@ -1,24 +1,24 @@
-void     check_expr                (Checker *c, Operand *operand, AstNode *expression);
-void     check_multi_expr          (Checker *c, Operand *operand, AstNode *expression);
-void     check_expr_or_type        (Checker *c, Operand *operand, AstNode *expression);
-ExprKind check_expr_base           (Checker *c, Operand *operand, AstNode *expression, Type *type_hint);
-Type *   check_type_extra          (Checker *c, AstNode *expression, Type *named_type);
-Type *   check_type                (Checker *c, AstNode *expression);
-void     check_type_decl           (Checker *c, Entity *e, AstNode *type_expr, Type *def);
-Entity * check_selector            (Checker *c, Operand *operand, AstNode *node);
-void     check_not_tuple           (Checker *c, Operand *operand);
-bool     check_value_is_expressible(Checker *c, ExactValue in_value, Type *type, ExactValue *out_value);
-void     convert_to_typed          (Checker *c, Operand *operand, Type *target_type, i32 level);
-gbString expr_to_string            (AstNode *expression);
-void     check_entity_decl         (Checker *c, Entity *e, DeclInfo *decl, Type *named_type);
-void     check_const_decl          (Checker *c, Entity *e, AstNode *type_expr, AstNode *init_expr, Type *named_type);
-void     check_proc_body           (Checker *c, Token token, DeclInfo *decl, Type *type, AstNode *body);
-void     update_expr_type          (Checker *c, AstNode *e, Type *type, bool final);
-bool     check_is_terminating      (AstNode *node);
-bool     check_has_break           (AstNode *stmt, bool implicit);
-void     check_stmt                (Checker *c, AstNode *node, u32 flags);
-void     check_stmt_list           (Checker *c, AstNodeArray stmts, u32 flags);
-void     check_init_constant       (Checker *c, Entity *e, Operand *operand);
+void     check_expr                     (Checker *c, Operand *operand, AstNode *expression);
+void     check_multi_expr               (Checker *c, Operand *operand, AstNode *expression);
+void     check_expr_or_type             (Checker *c, Operand *operand, AstNode *expression);
+ExprKind check_expr_base                (Checker *c, Operand *operand, AstNode *expression, Type *type_hint);
+Type *   check_type_extra               (Checker *c, AstNode *expression, Type *named_type);
+Type *   check_type                     (Checker *c, AstNode *expression);
+void     check_type_decl                (Checker *c, Entity *e, AstNode *type_expr, Type *def);
+Entity * check_selector                 (Checker *c, Operand *operand, AstNode *node);
+void     check_not_tuple                (Checker *c, Operand *operand);
+void     convert_to_typed               (Checker *c, Operand *operand, Type *target_type, i32 level);
+gbString expr_to_string                 (AstNode *expression);
+void     check_entity_decl              (Checker *c, Entity *e, DeclInfo *decl, Type *named_type);
+void     check_const_decl               (Checker *c, Entity *e, AstNode *type_expr, AstNode *init_expr, Type *named_type);
+void     check_proc_body                (Checker *c, Token token, DeclInfo *decl, Type *type, AstNode *body);
+void     update_expr_type               (Checker *c, AstNode *e, Type *type, bool final);
+bool     check_is_terminating           (AstNode *node);
+bool     check_has_break                (AstNode *stmt, bool implicit);
+void     check_stmt                     (Checker *c, AstNode *node, u32 flags);
+void     check_stmt_list                (Checker *c, AstNodeArray stmts, u32 flags);
+void     check_init_constant            (Checker *c, Entity *e, Operand *operand);
+bool     check_representable_as_constant(Checker *c, ExactValue in_value, Type *type, ExactValue *out_value);
 
 
 gb_inline Type *check_type(Checker *c, AstNode *expression) {
@@ -91,56 +91,70 @@ bool check_is_assignable_to_using_subtype(Type *dst, Type *src) {
 }
 
 
-
-bool check_is_assignable_to_with_score(Checker *c, Operand *operand, Type *type, i64 *score) {
-	// IMPORTANT TODO(bill): Determine score for assignments with use with overloaded procedures
+// IMPORTANT TODO(bill): figure out the exact distance rules
+// -1 is not convertable
+// 0 is exact
+// >0 is convertable
+i64 check_distance_between_types(Checker *c, Operand *operand, Type *type) {
 	if (operand->mode == Addressing_Invalid ||
 	    type == t_invalid) {
-		if (score) *score = 0;
-		return true;
+		return 0;
 	}
 
 	if (operand->mode == Addressing_Builtin) {
-		if (score) *score = 0;
-		return false;
+		return -1;
 	}
 
 	Type *s = operand->type;
 
 	if (are_types_identical(s, type)) {
-		if (score) *score = 10;
-		return true;
+		return 0;
 	}
 
 	Type *src = base_type(s);
 	Type *dst = base_type(type);
 
+	if (is_type_untyped_nil(src)) {
+		if (type_has_nil(dst)) {
+			return 1;
+		}
+		return -1;
+	}
 	if (is_type_untyped(src)) {
 		if (dst->kind == Type_Basic) {
 			if (operand->mode == Addressing_Constant) {
-				return check_value_is_expressible(c, operand->value, dst, NULL);
+				if (check_representable_as_constant(c, operand->value, dst, NULL)) {
+					return 1;
+				} else {
+					return -1;
+				}
 			}
 			if (src->kind == Type_Basic && src->Basic.kind == Basic_UntypedBool) {
-				return is_type_boolean(dst);
+				if (is_type_boolean(dst)) {
+					if (is_type_typed(type)) {
+						return 2;
+					}
+					return 1;
+				}
+				return -1;
 			}
 		}
-		if (type_has_nil(dst)) {
-			return operand->mode == Addressing_Value && operand->type == t_untyped_nil;
-		}
 	}
 
 	if (are_types_identical(dst, src) && (!is_type_named(dst) || !is_type_named(src))) {
-		return true;
+		return 1;
 	}
 
 	if (is_type_maybe(dst)) {
 		Type *elem = base_type(dst)->Maybe.elem;
-		bool ok = are_types_identical(elem, s);
-		return ok;
+		if (are_types_identical(elem, s)) {
+			return 1;
+		}
+		return -1;
 	}
 
-	if (is_type_untyped_nil(src)) {
-		return type_has_nil(dst);
+	if (check_is_assignable_to_using_subtype(operand->type, type)) {
+		return 4;
 	}
 
 	// ^T <- rawptr
@@ -151,33 +165,23 @@ bool check_is_assignable_to_with_score(Checker *c, Operand *operand, Type *type,
 	}
 #endif
 #if 1
+
+
+	// TODO(bill): Should I allow this implicit conversion at all?!
 	// rawptr <- ^T
 	if (is_type_rawptr(dst) && is_type_pointer(src)) {
-		// TODO(bill): Handle this properly
 		if (dst != type) {
-			return false;
+			return -1;
 		}
-	    return true;
+	    return 5;
 	}
 #endif
 
-	if (dst->kind == Type_Array && src->kind == Type_Array) {
-		if (are_types_identical(dst->Array.elem, src->Array.elem)) {
-			return dst->Array.count == src->Array.count;
-		}
-	}
-
-	if (dst->kind == Type_Slice && src->kind == Type_Slice) {
-		if (are_types_identical(dst->Slice.elem, src->Slice.elem)) {
-			return true;
-		}
-	}
-
 	if (is_type_union(dst)) {
 		for (isize i = 0; i < dst->Record.field_count; i++) {
 			Entity *f = dst->Record.fields[i];
 			if (are_types_identical(f->type, s)) {
-				return true;
+				return 1;
 			}
 		}
 	}
@@ -186,10 +190,25 @@ bool check_is_assignable_to_with_score(Checker *c, Operand *operand, Type *type,
 	if (is_type_any(dst)) {
 		// NOTE(bill): Anything can cast to `Any`
 		add_type_info_type(c, s);
-		return true;
+		return 10;
 	}
 
-	return false;
+
+
+	return -1;
+}
+
+
+bool check_is_assignable_to_with_score(Checker *c, Operand *operand, Type *type, i64 *score_) {
+	i64 score = 0;
+	i64 distance = check_distance_between_types(c, operand, type);
+	bool ok = distance >= 0;
+	if (ok) {
+		// TODO(bill): A decent score function
+		score = max(1000000 - distance*distance, 0);
+	}
+	if (score_) *score_ = score;
+	return ok;
 }
 
 
@@ -206,53 +225,58 @@ void check_assignment(Checker *c, Operand *operand, Type *type, String context_n
 		return;
 	}
 
+
 	if (is_type_untyped(operand->type)) {
 		Type *target_type = type;
-
-		if (type == NULL || is_type_any(type) || is_type_untyped_nil(type)) {
-			if (type == NULL && base_type(operand->type) == t_untyped_nil) {
+		if (type == NULL || is_type_any(type)) {
+			if (type == NULL && is_type_untyped_nil(operand->type)) {
 				error_node(operand->expr, "Use of untyped nil in %.*s", LIT(context_name));
 				operand->mode = Addressing_Invalid;
 				return;
 			}
-
-			add_type_info_type(c, type);
 			target_type = default_type(operand->type);
+			add_type_info_type(c, type);
+			add_type_info_type(c, target_type);
 		}
+
 		convert_to_typed(c, operand, target_type, 0);
 		if (operand->mode == Addressing_Invalid) {
 			return;
 		}
 	}
 
-	if (type != NULL) {
-		if (!check_is_assignable_to(c, operand, type)) {
-			gbString type_str    = type_to_string(type);
-			gbString op_type_str = type_to_string(operand->type);
-			gbString expr_str    = expr_to_string(operand->expr);
 
-			if (operand->mode == Addressing_Builtin) {
-				// TODO(bill): is this a good enough error message?
-				error_node(operand->expr,
-				           "Cannot assign builtin procedure `%s` in %.*s",
-				           expr_str,
-				           LIT(context_name));
-			} else {
-				// TODO(bill): is this a good enough error message?
-				error_node(operand->expr,
-				           "Cannot assign value `%s` of type `%s` to `%s` in %.*s",
-				           expr_str,
-				           op_type_str,
-				           type_str,
-				           LIT(context_name));
-			}
-			operand->mode = Addressing_Invalid;
 
-			gb_string_free(expr_str);
-			gb_string_free(op_type_str);
-			gb_string_free(type_str);
-			return;
+
+	if (type == NULL) {
+		return;
+	}
+	if (!check_is_assignable_to(c, operand, type)) {
+		gbString type_str    = type_to_string(type);
+		gbString op_type_str = type_to_string(operand->type);
+		gbString expr_str    = expr_to_string(operand->expr);
+
+		if (operand->mode == Addressing_Builtin) {
+			// TODO(bill): is this a good enough error message?
+			error_node(operand->expr,
+			           "Cannot assign builtin procedure `%s` in %.*s",
+			           expr_str,
+			           LIT(context_name));
+		} else {
+			// TODO(bill): is this a good enough error message?
+			error_node(operand->expr,
+			           "Cannot assign value `%s` of type `%s` to `%s` in %.*s",
+			           expr_str,
+			           op_type_str,
+			           type_str,
+			           LIT(context_name));
 		}
+		operand->mode = Addressing_Invalid;
+
+		gb_string_free(expr_str);
+		gb_string_free(op_type_str);
+		gb_string_free(type_str);
+		return;
 	}
 }
 
@@ -727,10 +751,19 @@ Type *check_get_params(Checker *c, Scope *scope, AstNodeArray params, bool *is_v
 			}
 
 			Type *type = check_type(c, type_expr);
+			if (p->flags&FieldFlag_no_alias) {
+				if (!is_type_pointer(type)) {
+					error_node(params.e[i], "`no_alias` can only be applied to fields of pointer type");
+					p->flags &= ~FieldFlag_no_alias; // Remove the flag
+				}
+			}
 			for_array(j, p->names) {
 				AstNode *name = p->names.e[j];
 				if (ast_node_expect(name, AstNode_Ident)) {
 					Entity *param = make_entity_param(c->allocator, scope, name->Ident, type, p->flags&FieldFlag_using);
+					if (p->flags&FieldFlag_no_alias) {
+						param->flags |= EntityFlag_NoAlias;
+					}
 					add_entity(c, scope, name, param);
 					variables[variable_index++] = param;
 				}
@@ -1288,7 +1321,7 @@ bool check_binary_op(Checker *c, Operand *o, Token op) {
 
 }
 
-bool check_value_is_expressible(Checker *c, ExactValue in_value, Type *type, ExactValue *out_value) {
+bool check_representable_as_constant(Checker *c, ExactValue in_value, Type *type, ExactValue *out_value) {
 	if (in_value.kind == ExactValue_Invalid) {
 		// NOTE(bill): There's already been an error
 		return true;
@@ -1374,7 +1407,7 @@ bool check_value_is_expressible(Checker *c, ExactValue in_value, Type *type, Exa
 void check_is_expressible(Checker *c, Operand *o, Type *type) {
 	GB_ASSERT(is_type_constant_type(type));
 	GB_ASSERT(o->mode == Addressing_Constant);
-	if (!check_value_is_expressible(c, o->value, type, &o->value)) {
+	if (!check_representable_as_constant(c, o->value, type, &o->value)) {
 		gbString a = expr_to_string(o->expr);
 		gbString b = type_to_string(type);
 		if (is_type_numeric(o->type) && is_type_numeric(type)) {
@@ -1685,61 +1718,70 @@ bool check_is_castable_to(Checker *c, Operand *operand, Type *y) {
 	}
 
 	Type *x = operand->type;
-	Type *xb = base_type(base_enum_type(x));
-	Type *yb = base_type(base_enum_type(y));
-	if (are_types_identical(xb, yb)) {
+	Type *src = base_type(base_enum_type(x));
+	Type *dst = base_type(base_enum_type(y));
+	if (are_types_identical(src, dst)) {
 		return true;
 	}
 
+	if (dst->kind == Type_Array && src->kind == Type_Array) {
+		if (are_types_identical(dst->Array.elem, src->Array.elem)) {
+			return dst->Array.count == src->Array.count;
+		}
+	}
+
+	if (dst->kind == Type_Slice && src->kind == Type_Slice) {
+		return are_types_identical(dst->Slice.elem, src->Slice.elem);
+	}
 
 	// Cast between booleans and integers
-	if (is_type_boolean(xb) || is_type_integer(xb)) {
-		if (is_type_boolean(yb) || is_type_integer(yb)) {
+	if (is_type_boolean(src) || is_type_integer(src)) {
+		if (is_type_boolean(dst) || is_type_integer(dst)) {
 			return true;
 		}
 	}
 
 	// Cast between numbers
-	if (is_type_integer(xb) || is_type_float(xb)) {
-		if (is_type_integer(yb) || is_type_float(yb)) {
+	if (is_type_integer(src) || is_type_float(src)) {
+		if (is_type_integer(dst) || is_type_float(dst)) {
 			return true;
 		}
 	}
 
 	// Cast between pointers
-	if (is_type_pointer(xb) && is_type_pointer(yb)) {
+	if (is_type_pointer(src) && is_type_pointer(dst)) {
 		return true;
 	}
 
 	// (u)int <-> pointer
-	if (is_type_int_or_uint(xb) && is_type_rawptr(yb)) {
+	if (is_type_int_or_uint(src) && is_type_rawptr(dst)) {
 		return true;
 	}
-	if (is_type_rawptr(xb) && is_type_int_or_uint(yb)) {
+	if (is_type_rawptr(src) && is_type_int_or_uint(dst)) {
 		return true;
 	}
 
 	// []byte/[]u8 <-> string
-	if (is_type_u8_slice(xb) && is_type_string(yb)) {
+	if (is_type_u8_slice(src) && is_type_string(dst)) {
 		return true;
 	}
-	if (is_type_string(xb) && is_type_u8_slice(yb)) {
-		if (is_type_typed(xb)) {
+	if (is_type_string(src) && is_type_u8_slice(dst)) {
+		if (is_type_typed(src)) {
 			return true;
 		}
 	}
 
 	// proc <-> proc
-	if (is_type_proc(xb) && is_type_proc(yb)) {
+	if (is_type_proc(src) && is_type_proc(dst)) {
 		return true;
 	}
 
 	// proc -> rawptr
-	if (is_type_proc(xb) && is_type_rawptr(yb)) {
+	if (is_type_proc(src) && is_type_rawptr(dst)) {
 		return true;
 	}
 	// rawptr -> proc
-	if (is_type_rawptr(xb) && is_type_proc(yb)) {
+	if (is_type_rawptr(src) && is_type_proc(dst)) {
 		return true;
 	}
 
@@ -1814,6 +1856,48 @@ Operand check_ptr_addition(Checker *c, TokenKind op, Operand *ptr, Operand *offs
 }
 
 
+void check_conversion(Checker *c, Operand *x, Type *type) {
+	bool is_const_expr = x->mode == Addressing_Constant;
+	bool can_convert = false;
+
+	Type *bt = base_type(type);
+	if (is_const_expr && is_type_constant_type(bt)) {
+		if (bt->kind == Type_Basic) {
+			if (check_representable_as_constant(c, x->value, bt, &x->value)) {
+				can_convert = true;
+			}
+		}
+	} else if (check_is_castable_to(c, x, type)) {
+		if (x->mode != Addressing_Constant) {
+			x->mode = Addressing_Value;
+		}
+		can_convert = true;
+	}
+
+	if (!can_convert) {
+		gbString expr_str = expr_to_string(x->expr);
+		gbString to_type  = type_to_string(type);
+		gbString from_type = type_to_string(x->type);
+		error_node(x->expr, "Cannot cast `%s` as `%s` from `%s`", expr_str, to_type, from_type);
+		gb_string_free(from_type);
+		gb_string_free(to_type);
+		gb_string_free(expr_str);
+
+		x->mode = Addressing_Invalid;
+		return;
+	}
+
+	if (is_type_untyped(x->type)) {
+		Type *final_type = type;
+		if (is_const_expr && !is_type_constant_type(type)) {
+			final_type = default_type(x->type);
+		}
+		update_expr_type(c, x->expr, final_type, true);
+	}
+
+	x->type = type;
+}
+
 void check_binary_expr(Checker *c, Operand *x, AstNode *node) {
 	GB_ASSERT(node->kind == AstNode_BinaryExpr);
 	Operand y_ = {0}, *y = &y_;
@@ -1827,46 +1911,7 @@ void check_binary_expr(Checker *c, Operand *x, AstNode *node) {
 		if (x->mode == Addressing_Invalid) {
 			return;
 		}
-
-		bool is_const_expr = x->mode == Addressing_Constant;
-		bool can_convert = false;
-
-		Type *bt = base_type(type);
-		if (is_const_expr && is_type_constant_type(bt)) {
-			if (bt->kind == Type_Basic) {
-				if (check_value_is_expressible(c, x->value, bt, &x->value)) {
-					can_convert = true;
-				}
-			}
-		} else if (check_is_castable_to(c, x, type)) {
-			if (x->mode != Addressing_Constant) {
-				x->mode = Addressing_Value;
-			}
-			can_convert = true;
-		}
-
-		if (!can_convert) {
-			gbString expr_str = expr_to_string(x->expr);
-			gbString to_type  = type_to_string(type);
-			gbString from_type = type_to_string(x->type);
-			error_node(x->expr, "Cannot cast `%s` as `%s` from `%s`", expr_str, to_type, from_type);
-			gb_string_free(from_type);
-			gb_string_free(to_type);
-			gb_string_free(expr_str);
-
-			x->mode = Addressing_Invalid;
-			return;
-		}
-
-		if (is_type_untyped(x->type)) {
-			Type *final_type = type;
-			if (is_const_expr && !is_type_constant_type(type)) {
-				final_type = default_type(x->type);
-			}
-			update_expr_type(c, x->expr, final_type, true);
-		}
-
-		x->type = type;
+		check_conversion(c, x, type);
 		return;
 	} break;
 	case Token_transmute: {
@@ -2291,6 +2336,7 @@ void convert_to_typed(Checker *c, Operand *operand, Type *target_type, i32 level
 		return;
 	}
 
+
 	if (is_type_untyped(target_type)) {
 		GB_ASSERT(operand->type->kind == Type_Basic);
 		GB_ASSERT(target_type->kind == Type_Basic);
@@ -2302,7 +2348,7 @@ 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) {
-			convert_untyped_error(c, operand, target_type);
+			goto error;
 		}
 		return;
 	}
@@ -2320,23 +2366,20 @@ 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)) {
-					convert_untyped_error(c, operand, target_type);
-					return;
+					goto error;
 				}
 				break;
 			case Basic_UntypedInteger:
 			case Basic_UntypedFloat:
 			case Basic_UntypedRune:
 				if (!is_type_numeric(target_type)) {
-					convert_untyped_error(c, operand, target_type);
-					return;
+					goto error;
 				}
 				break;
 
 			case Basic_UntypedNil:
 				if (!type_has_nil(target_type)) {
-					convert_untyped_error(c, operand, target_type);
-					return;
+					goto error;
 				}
 				break;
 			}
@@ -2347,21 +2390,24 @@ void convert_to_typed(Checker *c, Operand *operand, Type *target_type, i32 level
 		if (is_type_untyped_nil(operand->type)) {
 			// Okay
 		} else if (level == 0) {
-			convert_to_typed(c, operand, t->Maybe.elem, level+1);
-			return;
+			goto error;
 		}
 
 	default:
 		if (!is_type_untyped_nil(operand->type) || !type_has_nil(target_type)) {
-			convert_untyped_error(c, operand, target_type);
-			return;
+			goto error;
 		}
+		target_type = t_untyped_nil;
 		break;
 	}
 
-
-
 	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) {
@@ -3525,6 +3571,17 @@ CallArgumentError check_call_arguments_internal(Checker *c, AstNode *call, Type
 	return err;
 }
 
+typedef struct ValidProcAndScore {
+	isize index;
+	i64   score;
+} ValidProcAndScore;
+
+int valid_proc_and_score_cmp(void const *a, void const *b) {
+	i64 si = (cast(ValidProcAndScore const *)a)->score;
+	i64 sj = (cast(ValidProcAndScore const *)b)->score;
+	return sj < si ? -1 : sj > si;
+}
+
 Type *check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNode *call) {
 	GB_ASSERT(call->kind == AstNode_CallExpr);
 
@@ -3553,11 +3610,10 @@ Type *check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNod
 		String name = operand->initial_overload_entity->token.string;
 		HashKey key = hash_string(name);
 
-		isize    overload_count = operand->overload_count;
-		Entity **procs          = gb_alloc_array(heap_allocator(), Entity *, overload_count);
-		isize *  valid_procs    = gb_alloc_array(heap_allocator(), isize, overload_count);
-		i64 *    valid_scores   = gb_alloc_array(heap_allocator(), i64, overload_count);
-		isize    valid_count    = 0;
+		isize              overload_count = operand->overload_count;
+		Entity **          procs          = gb_alloc_array(heap_allocator(), Entity *, overload_count);
+		ValidProcAndScore *valids         = gb_alloc_array(heap_allocator(), ValidProcAndScore, overload_count);
+		isize              valid_count    = 0;
 
 		map_entity_multi_get_all(&s->elements, key, procs);
 
@@ -3576,44 +3632,49 @@ Type *check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNod
 				i64 score = 0;
 				CallArgumentError err = check_call_arguments_internal(c, call, proc_type, operands.e, operands.count, false, &score);
 				if (err == CallArgumentError_None) {
-					valid_procs[valid_count] = i;
-					valid_scores[valid_count] = score;
+					valids[valid_count].index = i;
+					valids[valid_count].score = score;
 					valid_count++;
 				}
 			}
 		}
 
-		// IMPORTANT TODO(bill): Get the best proc by its score
-		// i64 best_score = 0;
-		// isize best_index = 0;
-		// for (isize i = 0; i < valid_count; i++) {
-		// 	if (best_score < valid_scores[i]) {
-		// 		best_score = valid_scores[i];
-		// 		best_index = i;
-		// 	}
-		// }
+		if (valid_count > 1) {
+			gb_sort_array(valids, valid_count, valid_proc_and_score_cmp);
+			i64 best_score = valids[0].score;
+			for (isize i = 0; i < valid_count; i++) {
+				if (best_score > valids[i].score) {
+					valid_count = i;
+					break;
+				}
+				best_score = valids[i].score;
+			}
+		}
 
 
 		if (valid_count == 0) {
-			error_node(operand->expr, "No overloads for `%.*s` that match the specified arguments", LIT(name));
+			error_node(operand->expr, "No overloads for `%.*s` that match with the given arguments", LIT(name));
 			proc_type = t_invalid;
 		} else if (valid_count > 1) {
 			error_node(operand->expr, "Ambiguous procedure call `%.*s`, could be:", LIT(name));
 			for (isize i = 0; i < valid_count; i++) {
-				TokenPos pos = procs[valid_procs[i]]->token.pos;
-				gb_printf_err("\t`%.*s` at %.*s(%td:%td)\n", LIT(name), LIT(pos.file), pos.line, pos.column);
+				Entity *proc = procs[valids[i].index];
+				TokenPos pos = proc->token.pos;
+				gbString pt = type_to_string(proc->type);
+				gb_printf_err("\t%.*s :: %s at %.*s(%td:%td)\n", LIT(name), pt, LIT(pos.file), pos.line, pos.column);
+				gb_string_free(pt);
 			}
 			proc_type = t_invalid;
 		} else {
 			GB_ASSERT(operand->expr->kind == AstNode_Ident);
-			Entity *e = procs[valid_procs[0]];
+			Entity *e = procs[valids[0].index];
 			add_entity_use(c, operand->expr, e);
 			proc_type = e->type;
 			i64 score = 0;
 			CallArgumentError err = check_call_arguments_internal(c, call, proc_type, operands.e, operands.count, true, &score);
 		}
 
-		gb_free(heap_allocator(), valid_procs);
+		gb_free(heap_allocator(), valids);
 		gb_free(heap_allocator(), procs);
 	} else {
 		i64 score = 0;
@@ -3660,6 +3721,25 @@ ExprKind check_call_expr(Checker *c, Operand *operand, AstNode *call) {
 		return Expr_Stmt;
 	}
 
+	if (operand->mode == Addressing_Type) {
+		Type *t = operand->type;
+		gbString str = type_to_string(t);
+		operand->mode = Addressing_Invalid;
+		isize arg_count = ce->args.count;
+		switch (arg_count) {
+		case 0:  error_node(call, "Missing argument in convertion to `%s`", str);   break;
+		default: error_node(call, "Too many arguments in convertion to `%s`", str); break;
+		case 1:
+			check_expr(c, operand, ce->args.e[0]);
+			if (operand->mode != Addressing_Invalid) {
+				check_conversion(c, operand, t);
+			}
+			break;
+		}
+
+		gb_string_free(str);
+		return Expr_Expr;
+	}
 
 	if (operand->mode == Addressing_Builtin) {
 		i32 id = operand->builtin_id;

+ 3 - 1
src/check_stmt.c

@@ -680,11 +680,13 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
 					}
 					break;
 				case Type_Array:
+					// val = make_type_pointer(c->allocator, t->Array.elem);
 					val = t->Array.elem;
 					idx = t_int;
 					break;
 				case Type_Slice:
-					val = t->Array.elem;
+					// val = make_type_pointer(c->allocator, t->Slice.elem);
+					val = t->Slice.elem;
 					idx = t_int;
 					break;
 				}

+ 10 - 6
src/checker.c

@@ -1,11 +1,5 @@
 #include "exact_value.c"
 #include "entity.c"
-#include "types.c"
-
-#define MAP_TYPE Entity *
-#define MAP_PROC map_entity_
-#define MAP_NAME MapEntity
-#include "map.c"
 
 typedef enum AddressingMode {
 	Addressing_Invalid,
@@ -20,6 +14,13 @@ typedef enum AddressingMode {
 	Addressing_Count,
 } AddressingMode;
 
+#include "types.c"
+
+#define MAP_TYPE Entity *
+#define MAP_PROC map_entity_
+#define MAP_NAME MapEntity
+#include "map.c"
+
 typedef struct Operand {
 	AddressingMode mode;
 	Type *         type;
@@ -45,6 +46,9 @@ bool is_operand_value(Operand o) {
 	}
 	return false;
 }
+bool is_operand_nil(Operand o) {
+	return o.mode == Addressing_Value && o.type == t_untyped_nil;
+}
 
 
 

+ 1 - 0
src/entity.c

@@ -35,6 +35,7 @@ typedef enum EntityFlag {
 	EntityFlag_Field      = 1<<3,
 	EntityFlag_Param      = 1<<4,
 	EntityFlag_VectorElem = 1<<5,
+	EntityFlag_NoAlias    = 1<<6,
 } EntityFlag;
 
 typedef enum OverloadKind {

+ 9 - 0
src/ir.c

@@ -2819,6 +2819,13 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv
 
 
 	case_ast_node(ce, CallExpr, expr);
+		if (map_tav_get(&proc->module->info->types, hash_pointer(ce->proc))->mode == Addressing_Type) {
+			GB_ASSERT(ce->args.count == 1);
+			irValue *x = ir_build_expr(proc, ce->args.e[0]);
+			irValue *y = ir_emit_conv(proc, x, tv->type);
+			return y;
+		}
+
 		AstNode *p = unparen_expr(ce->proc);
 		if (p->kind == AstNode_Ident) {
 			Entity **found = map_entity_get(&proc->module->info->uses, hash_pointer(p));
@@ -3960,10 +3967,12 @@ void ir_build_range_indexed(irProcedure *proc, irValue *expr, Type *val_type,
 	if (val_type != NULL) {
 		switch (expr_type->kind) {
 		case Type_Array: {
+			// val = ir_emit_array_ep(proc, expr, idx);
 			val = ir_emit_load(proc, ir_emit_array_ep(proc, expr, idx));
 		} break;
 		case Type_Slice: {
 			irValue *elem = ir_slice_elem(proc, expr);
+			// val = ir_emit_ptr_offset(proc, elem, idx);
 			val = ir_emit_load(proc, ir_emit_ptr_offset(proc, elem, idx));
 		} break;
 		default:

+ 6 - 0
src/ir_print.c

@@ -1078,6 +1078,9 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
 					ir_fprintf(f, ", ");
 				}
 				ir_print_type(f, m, t);
+				if (e->flags&EntityFlag_NoAlias) {
+					ir_fprintf(f, " noalias");
+				}
 				ir_fprintf(f, " ");
 				irValue *arg = call->args[i];
 				ir_print_value(f, m, arg, t);
@@ -1277,6 +1280,9 @@ void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) {
 				ir_fprintf(f, ", ");
 			}
 			ir_print_type(f, m, e->type);
+			if (e->flags&EntityFlag_NoAlias) {
+				ir_fprintf(f, " noalias");
+			}
 			if (proc->body != NULL) {
 				if (!str_eq(e->token.string, str_lit("")) &&
 				    !str_eq(e->token.string, str_lit("_"))) {

+ 40 - 18
src/parser.c

@@ -94,7 +94,8 @@ typedef enum StmtStateFlag {
 
 typedef enum FieldFlag {
 	FieldFlag_using    = 1<<0,
-	FieldFlag_ellipsis = 1<<1,
+	FieldFlag_no_alias = 1<<1,
+	FieldFlag_ellipsis = 1<<2,
 } FieldListTag;
 
 AstNodeArray make_ast_node_array(AstFile *f) {
@@ -1786,6 +1787,7 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
 }
 
 bool is_literal_type(AstNode *node) {
+	node = unparen_expr(node);
 	switch (node->kind) {
 	case AstNode_BadExpr:
 	case AstNode_Ident:
@@ -2232,30 +2234,51 @@ AstNodeArray parse_field_list(AstFile *f, isize *name_count_, u32 flags,
 
 	while (f->curr_token.kind != follow &&
 	       f->curr_token.kind != Token_EOF) {
-		bool is_using = false;
-		if (allow_token(f, Token_using)) {
-			is_using = true;
+		i32 using_count    = 0;
+		i32 no_alias_count = 0;
+		while (f->curr_token.kind == Token_using ||
+		       f->curr_token.kind == Token_no_alias) {
+			if (allow_token(f, Token_using)) {
+				using_count++;
+			}
+			if (allow_token(f, Token_no_alias)) {
+				no_alias_count++;
+			}
 		}
 
+
 		AstNodeArray names = parse_identifier_list(f);
 		if (names.count == 0) {
-			syntax_error(f->curr_token, "Empty parameter declaration");
+			syntax_error(f->curr_token, "Empty field declaration");
 			break;
 		}
 
-		if (names.count > 1 && is_using) {
+		if (names.count > 1 && using_count > 0) {
 			syntax_error(f->curr_token, "Cannot apply `using` to more than one of the same type");
-			is_using = false;
+			using_count = 0;
 		}
 
-		if ((flags&FieldFlag_using) == 0 && is_using) {
-			syntax_error(f->curr_token, "`using` is not allowed within this parameter list");
-			is_using = false;
+		if ((flags&FieldFlag_using) == 0 && using_count > 0) {
+			syntax_error(f->curr_token, "`using` is not allowed within this field list");
+			using_count = 0;
+		}
+		if ((flags&FieldFlag_no_alias) == 0 && no_alias_count > 0) {
+			syntax_error(f->curr_token, "`no_alias` is not allowed within this field list");
+			no_alias_count = 0;
+		}
+		if (using_count > 1) {
+			syntax_error(f->curr_token, "Multiple `using` in this field list");
+			using_count = 1;
+		}
+		if (no_alias_count > 1) {
+			syntax_error(f->curr_token, "Multiple `no_alias` in this field list");
+			no_alias_count = 1;
 		}
 
+
 		name_count += names.count;
 
-		expect_token_after(f, Token_Colon, "parameter list");
+		expect_token_after(f, Token_Colon, "field list");
 
 		AstNode *type = NULL;
 		if ((flags&FieldFlag_ellipsis) != 0 && f->curr_token.kind == Token_Ellipsis) {
@@ -2263,11 +2286,11 @@ AstNodeArray parse_field_list(AstFile *f, isize *name_count_, u32 flags,
 			next_token(f);
 			type = parse_type_attempt(f);
 			if (type == NULL) {
-				syntax_error(f->curr_token, "variadic parameter is missing a type after `..`");
+				syntax_error(f->curr_token, "variadic field is missing a type after `..`");
 				type = make_bad_expr(f, ellipsis, f->curr_token);
 			} else {
 				if (names.count > 1) {
-					syntax_error(f->curr_token, "mutliple variadic parameters, only  `..`");
+					syntax_error(f->curr_token, "mutliple variadic fields, only  `..`");
 				} else {
 					type = make_ellipsis(f, ellipsis, type);
 				}
@@ -2278,13 +2301,12 @@ AstNodeArray parse_field_list(AstFile *f, isize *name_count_, u32 flags,
 
 
 		if (type == NULL) {
-			syntax_error(f->curr_token, "Expected a type for this parameter declaration");
+			syntax_error(f->curr_token, "Expected a type for this field declaration");
 		}
 
 		u32 flags = 0;
-		if (is_using) {
-			flags |= FieldFlag_using;
-		}
+		if (using_count    > 0) flags |= FieldFlag_using;
+		if (no_alias_count > 0) flags |= FieldFlag_no_alias;
 		AstNode *param = make_field(f, names, type, flags);
 		array_add(&params, param);
 
@@ -2491,7 +2513,7 @@ void parse_proc_signature(AstFile *f,
                           AstNodeArray *params,
                           AstNodeArray *results) {
 	expect_token(f, Token_OpenParen);
-	*params = parse_field_list(f, NULL, FieldFlag_using|FieldFlag_ellipsis, Token_Comma, Token_CloseParen);
+	*params = parse_field_list(f, NULL, FieldFlag_using|FieldFlag_no_alias|FieldFlag_ellipsis, Token_Comma, Token_CloseParen);
 	expect_token_after(f, Token_CloseParen, "parameter list");
 	*results = parse_results(f);
 }

+ 1 - 0
src/tokenizer.c

@@ -105,6 +105,7 @@ TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
 	TOKEN_KIND(Token_enum,           "enum"), \
 	TOKEN_KIND(Token_vector,         "vector"), \
 	TOKEN_KIND(Token_using,          "using"), \
+	TOKEN_KIND(Token_no_alias,       "no_alias"), \
 	TOKEN_KIND(Token_asm,            "asm"), \
 	TOKEN_KIND(Token_push_allocator, "push_allocator"), \
 	TOKEN_KIND(Token_push_context,   "push_context"), \

+ 2 - 1
src/types.c

@@ -686,7 +686,8 @@ bool type_has_nil(Type *t) {
 		case Basic_any:
 			return true;
 		}
-	}
+		return false;
+	} break;
 	case Type_Slice:
 	case Type_Proc:
 	case Type_Pointer: