Bladeren bron

Err on ambiguous overloaded calls

Ginger Bill 8 jaren geleden
bovenliggende
commit
6dc6b6f8aa
6 gewijzigde bestanden met toevoegingen van 168 en 169 verwijderingen
  1. 15 4
      code/demo.odin
  2. 8 8
      core/_preload.odin
  3. 28 28
      core/atomic.odin
  4. 53 53
      core/math.odin
  5. 55 71
      src/check_expr.c
  6. 9 5
      src/checker.c

+ 15 - 4
code/demo.odin

@@ -1,17 +1,28 @@
+#import "atomic.odin";
 #import "fmt.odin";
+#import "math.odin";
+#import "mem.odin";
+#import "opengl.odin";
 
 main :: proc() {
 	foo :: proc() {
 		fmt.printf("Zero args\n");
 	}
 	foo :: proc(i: int) {
-		fmt.printf("One arg, i=%d\n", i);
+		fmt.printf("int arg, i=%d\n", i);
 	}
-	THING :: 14451;
+	foo :: proc(f: f64) {
+		i := f as int;
+		fmt.printf("f64 arg, f=%d\n", i);
+	}
+	THINGI :: 14451;
+	THINGF :: 14451.1;
 
 	foo();
-	foo(THING);
-	fmt.println(THING);
+	foo(THINGI as int);
+	foo(THINGF);
+	fmt.println(THINGI);
+	fmt.println(THINGF);
 
 	x: proc();
 	x = foo;

+ 8 - 8
core/_preload.odin

@@ -111,16 +111,16 @@ __debug_trap       :: proc()        #foreign "llvm.debugtrap"
 __trap             :: proc()        #foreign "llvm.trap"
 read_cycle_counter :: proc() -> u64 #foreign "llvm.readcyclecounter"
 
-bit_reverse16 :: proc(b: u16) -> u16 #foreign "llvm.bitreverse.i16"
-bit_reverse32 :: proc(b: u32) -> u32 #foreign "llvm.bitreverse.i32"
-bit_reverse64 :: proc(b: u64) -> u64 #foreign "llvm.bitreverse.i64"
+bit_reverse :: proc(b: u16) -> u16 #foreign "llvm.bitreverse.i16"
+bit_reverse :: proc(b: u32) -> u32 #foreign "llvm.bitreverse.i32"
+bit_reverse :: proc(b: u64) -> u64 #foreign "llvm.bitreverse.i64"
 
-byte_swap16 :: proc(b: u16) -> u16 #foreign "llvm.bswap.i16"
-byte_swap32 :: proc(b: u32) -> u32 #foreign "llvm.bswap.i32"
-byte_swap64 :: proc(b: u64) -> u64 #foreign "llvm.bswap.i64"
+byte_swap :: proc(b: u16) -> u16 #foreign "llvm.bswap.i16"
+byte_swap :: proc(b: u32) -> u32 #foreign "llvm.bswap.i32"
+byte_swap :: proc(b: u64) -> u64 #foreign "llvm.bswap.i64"
 
-fmuladd32 :: proc(a, b, c: f32) -> f32 #foreign "llvm.fmuladd.f32"
-fmuladd64 :: proc(a, b, c: f64) -> f64 #foreign "llvm.fmuladd.f64"
+fmuladd :: proc(a, b, c: f32) -> f32 #foreign "llvm.fmuladd.f32"
+fmuladd :: proc(a, b, c: f64) -> f64 #foreign "llvm.fmuladd.f64"
 
 
 

+ 28 - 28
core/atomic.odin

@@ -11,91 +11,91 @@ sfence       :: proc() { win32.WriteBarrier(); }
 lfence       :: proc() { win32.ReadBarrier(); }
 
 
-load32 :: proc(a: ^i32) -> i32 {
+load :: proc(a: ^i32) -> i32 {
 	return a^;
 }
-store32 :: proc(a: ^i32, value: i32) {
+store :: proc(a: ^i32, value: i32) {
 	a^ = value;
 }
-compare_exchange32 :: proc(a: ^i32, expected, desired: i32) -> i32 {
+compare_exchange :: proc(a: ^i32, expected, desired: i32) -> i32 {
 	return win32.InterlockedCompareExchange(a, desired, expected);
 }
-exchanged32 :: proc(a: ^i32, desired: i32) -> i32 {
+exchanged :: proc(a: ^i32, desired: i32) -> i32 {
 	return win32.InterlockedExchange(a, desired);
 }
-fetch_add32 :: proc(a: ^i32, operand: i32) -> i32 {
+fetch_add :: proc(a: ^i32, operand: i32) -> i32 {
 	return win32.InterlockedExchangeAdd(a, operand);
 
 }
-fetch_and32 :: proc(a: ^i32, operand: i32) -> i32 {
+fetch_and :: proc(a: ^i32, operand: i32) -> i32 {
 	return win32.InterlockedAnd(a, operand);
 
 }
-fetch_or32 :: proc(a: ^i32, operand: i32) -> i32 {
+fetch_or :: proc(a: ^i32, operand: i32) -> i32 {
 	return win32.InterlockedOr(a, operand);
 }
-spin_lock32 :: proc(a: ^i32, time_out: int) -> bool { // NOTE(bill) time_out = -1 as default
-	old_value := compare_exchange32(a, 1, 0);
+spin_lock :: proc(a: ^i32, time_out: int) -> bool { // NOTE(bill) time_out = -1 as default
+	old_value := compare_exchange(a, 1, 0);
 	counter := 0;
 	while old_value != 0 && (time_out < 0 || counter < time_out) {
 		counter += 1;
 		yield_thread();
-		old_value = compare_exchange32(a, 1, 0);
+		old_value = compare_exchange(a, 1, 0);
 		mfence();
 	}
 	return old_value == 0;
 }
-spin_unlock32 :: proc(a: ^i32) {
-	store32(a, 0);
+spin_unlock :: proc(a: ^i32) {
+	store(a, 0);
 	mfence();
 }
-try_acquire_lock32 :: proc(a: ^i32) -> bool {
+try_acquire_lock :: proc(a: ^i32) -> bool {
 	yield_thread();
-	old_value := compare_exchange32(a, 1, 0);
+	old_value := compare_exchange(a, 1, 0);
 	mfence();
 	return old_value == 0;
 }
 
 
-load64 :: proc(a: ^i64) -> i64 {
+load :: proc(a: ^i64) -> i64 {
 	return a^;
 }
-store64 :: proc(a: ^i64, value: i64) {
+store :: proc(a: ^i64, value: i64) {
 	a^ = value;
 }
-compare_exchange64 :: proc(a: ^i64, expected, desired: i64) -> i64 {
+compare_exchange :: proc(a: ^i64, expected, desired: i64) -> i64 {
 	return win32.InterlockedCompareExchange64(a, desired, expected);
 }
-exchanged64 :: proc(a: ^i64, desired: i64) -> i64 {
+exchanged :: proc(a: ^i64, desired: i64) -> i64 {
 	return win32.InterlockedExchange64(a, desired);
 }
-fetch_add64 :: proc(a: ^i64, operand: i64) -> i64 {
+fetch_add :: proc(a: ^i64, operand: i64) -> i64 {
 	return win32.InterlockedExchangeAdd64(a, operand);
 }
-fetch_and64 :: proc(a: ^i64, operand: i64) -> i64 {
+fetch_and :: proc(a: ^i64, operand: i64) -> i64 {
 	return win32.InterlockedAnd64(a, operand);
 }
-fetch_or64 :: proc(a: ^i64, operand: i64) -> i64 {
+fetch_or :: proc(a: ^i64, operand: i64) -> i64 {
 	return win32.InterlockedOr64(a, operand);
 }
-spin_lock64 :: proc(a: ^i64, time_out: int) -> bool { // NOTE(bill) time_out = -1 as default
-	old_value := compare_exchange64(a, 1, 0);
+spin_lock :: proc(a: ^i64, time_out: int) -> bool { // NOTE(bill) time_out = -1 as default
+	old_value := compare_exchange(a, 1, 0);
 	counter := 0;
 	while old_value != 0 && (time_out < 0 || counter < time_out) {
 		counter += 1;
 		yield_thread();
-		old_value = compare_exchange64(a, 1, 0);
+		old_value = compare_exchange(a, 1, 0);
 		mfence();
 	}
 	return old_value == 0;
 }
-spin_unlock64 :: proc(a: ^i64) {
-	store64(a, 0);
+spin_unlock :: proc(a: ^i64) {
+	store(a, 0);
 	mfence();
 }
-try_acquire_lock64 :: proc(a: ^i64) -> bool {
+try_acquire_lock :: proc(a: ^i64) -> bool {
 	yield_thread();
-	old_value := compare_exchange64(a, 1, 0);
+	old_value := compare_exchange(a, 1, 0);
 	mfence();
 	return old_value == 0;
 }

+ 53 - 53
core/math.odin

@@ -24,46 +24,46 @@ Mat2 :: [2]Vec2;
 Mat3 :: [3]Vec3;
 Mat4 :: [4]Vec4;
 
-sqrt32 :: proc(x: f32) -> f32 #foreign "llvm.sqrt.f32"
-sqrt64 :: proc(x: f64) -> f64 #foreign "llvm.sqrt.f64"
+sqrt :: proc(x: f32) -> f32 #foreign "llvm.sqrt.f32"
+sqrt :: proc(x: f64) -> f64 #foreign "llvm.sqrt.f64"
 
-sin32 :: proc(x: f32) -> f32 #foreign "llvm.sin.f32"
-sin64 :: proc(x: f64) -> f64 #foreign "llvm.sin.f64"
+sin :: proc(x: f32) -> f32 #foreign "llvm.sin.f32"
+sin :: proc(x: f64) -> f64 #foreign "llvm.sin.f64"
 
-cos32 :: proc(x: f32) -> f32 #foreign "llvm.cos.f32"
-cos64 :: proc(x: f64) -> f64 #foreign "llvm.cos.f64"
+cos :: proc(x: f32) -> f32 #foreign "llvm.cos.f32"
+cos :: proc(x: f64) -> f64 #foreign "llvm.cos.f64"
 
-tan32 :: proc(x: f32) -> f32 #inline { return sin32(x)/cos32(x); }
-tan64 :: proc(x: f64) -> f64 #inline { return sin64(x)/cos64(x); }
+tan :: proc(x: f32) -> f32 #inline { return sin(x)/cos(x); }
+tan :: proc(x: f64) -> f64 #inline { return sin(x)/cos(x); }
 
-lerp32 :: proc(a, b, t: f32) -> f32 { return a*(1-t) + b*t; }
-lerp64 :: proc(a, b, t: f64) -> f64 { return a*(1-t) + b*t; }
+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; }
 
-sign32 :: proc(x: f32) -> f32 { if x >= 0 { return +1; } return -1; }
-sign64 :: proc(x: f64) -> f64 { if x >= 0 { return +1; } return -1; }
+sign :: proc(x: f32) -> f32 { if x >= 0 { return +1; } return -1; }
+sign :: proc(x: f64) -> f64 { if x >= 0 { return +1; } return -1; }
 
 
 
-copy_sign32 :: proc(x, y: f32) -> f32 {
+copy_sign :: proc(x, y: f32) -> f32 {
 	ix := x transmute u32;
 	iy := y transmute u32;
 	ix &= 0x7fffffff;
 	ix |= iy & 0x80000000;
 	return ix transmute f32;
 }
-round32 :: proc(x: f32) -> f32 {
+round :: proc(x: f32) -> f32 {
 	if x >= 0 {
-		return floor32(x + 0.5);
+		return floor(x + 0.5);
 	}
-	return ceil32(x - 0.5);
+	return ceil(x - 0.5);
 }
-floor32 :: proc(x: f32) -> f32 {
+floor :: proc(x: f32) -> f32 {
 	if x >= 0 {
 		return x as int as f32;
 	}
 	return (x-0.5) as int as f32;
 }
-ceil32 :: proc(x: f32) -> f32 {
+ceil :: proc(x: f32) -> f32 {
 	if x < 0 {
 		return x as int as f32;
 	}
@@ -71,16 +71,16 @@ ceil32 :: proc(x: f32) -> f32 {
 }
 
 remainder32 :: proc(x, y: f32) -> f32 {
-	return x - round32(x/y) * y;
+	return x - round(x/y) * y;
 }
 
 fmod32 :: proc(x, y: f32) -> f32 {
 	y = abs(y);
 	result := remainder32(abs(x), y);
-	if sign32(result) < 0 {
+	if sign(result) < 0 {
 		result += y;
 	}
-	return copy_sign32(result, x);
+	return copy_sign(result, x);
 }
 
 
@@ -90,43 +90,43 @@ to_degrees :: proc(radians: f32) -> f32 { return radians * 360 / TAU; }
 
 
 
-dot2 :: proc(a, b: Vec2) -> f32 { c := a*b; return c.x + c.y; }
-dot3 :: proc(a, b: Vec3) -> f32 { c := a*b; return c.x + c.y + c.z; }
-dot4 :: proc(a, b: Vec4) -> f32 { c := a*b; return c.x + c.y + c.z + c.w; }
+dot :: proc(a, b: Vec2) -> f32 { c := a*b; return c.x + c.y; }
+dot :: proc(a, b: Vec3) -> f32 { c := a*b; return c.x + c.y + c.z; }
+dot :: proc(a, b: Vec4) -> f32 { c := a*b; return c.x + c.y + c.z + c.w; }
 
-cross3 :: proc(x, y: Vec3) -> Vec3 {
+cross :: proc(x, y: Vec3) -> Vec3 {
 	a := swizzle(x, 1, 2, 0) * swizzle(y, 2, 0, 1);
 	b := swizzle(x, 2, 0, 1) * swizzle(y, 1, 2, 0);
 	return a - b;
 }
 
 
-vec2_mag :: proc(v: Vec2) -> f32 { return sqrt32(dot2(v, v)); }
-vec3_mag :: proc(v: Vec3) -> f32 { return sqrt32(dot3(v, v)); }
-vec4_mag :: proc(v: Vec4) -> f32 { return sqrt32(dot4(v, v)); }
+mag :: proc(v: Vec2) -> f32 { return sqrt(dot(v, v)); }
+mag :: proc(v: Vec3) -> f32 { return sqrt(dot(v, v)); }
+mag :: proc(v: Vec4) -> f32 { return sqrt(dot(v, v)); }
 
-vec2_norm :: proc(v: Vec2) -> Vec2 { return v / Vec2{vec2_mag(v)}; }
-vec3_norm :: proc(v: Vec3) -> Vec3 { return v / Vec3{vec3_mag(v)}; }
-vec4_norm :: proc(v: Vec4) -> Vec4 { return v / Vec4{vec4_mag(v)}; }
+norm :: proc(v: Vec2) -> Vec2 { return v / Vec2{mag(v)}; }
+norm :: proc(v: Vec3) -> Vec3 { return v / Vec3{mag(v)}; }
+norm :: proc(v: Vec4) -> Vec4 { return v / Vec4{mag(v)}; }
 
-vec2_norm0 :: proc(v: Vec2) -> Vec2 {
-	m := vec2_mag(v);
+norm0 :: proc(v: Vec2) -> Vec2 {
+	m := mag(v);
 	if m == 0 {
 		return Vec2{0};
 	}
 	return v / Vec2{m};
 }
 
-vec3_norm0 :: proc(v: Vec3) -> Vec3 {
-	m := vec3_mag(v);
+norm0 :: proc(v: Vec3) -> Vec3 {
+	m := mag(v);
 	if m == 0 {
 		return Vec3{0};
 	}
 	return v / Vec3{m};
 }
 
-vec4_norm0 :: proc(v: Vec4) -> Vec4 {
-	m := vec4_mag(v);
+norm0 :: proc(v: Vec4) -> Vec4 {
+	m := mag(v);
 	if m == 0 {
 		return Vec4{0};
 	}
@@ -153,7 +153,7 @@ mat4_transpose :: proc(m: Mat4) -> Mat4 {
 	return m;
 }
 
-mat4_mul :: proc(a, b: Mat4) -> Mat4 {
+mul :: proc(a, b: Mat4) -> Mat4 {
 	c: Mat4;
 	for j : 0..<4 {
 		for i : 0..<4 {
@@ -166,7 +166,7 @@ mat4_mul :: proc(a, b: Mat4) -> Mat4 {
 	return c;
 }
 
-mat4_mul_vec4 :: proc(m: Mat4, v: Vec4) -> Vec4 {
+mul_vec4 :: 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,
@@ -175,7 +175,7 @@ mat4_mul_vec4 :: proc(m: Mat4, v: Vec4) -> Vec4 {
 	};
 }
 
-mat4_inverse :: proc(m: Mat4) -> Mat4 {
+inverse :: proc(m: Mat4) -> Mat4 {
 	o: Mat4;
 
 	sf00 := m[2][2] * m[3][3] - m[3][2] * m[2][3];
@@ -254,10 +254,10 @@ mat4_translate :: proc(v: Vec3) -> Mat4 {
 }
 
 mat4_rotate :: proc(v: Vec3, angle_radians: f32) -> Mat4 {
-	c := cos32(angle_radians);
-	s := sin32(angle_radians);
+	c := cos(angle_radians);
+	s := sin(angle_radians);
 
-	a := vec3_norm(v);
+	a := norm(v);
 	t := a * Vec3{1-c};
 
 	rot := mat4_identity();
@@ -280,14 +280,14 @@ mat4_rotate :: proc(v: Vec3, angle_radians: f32) -> Mat4 {
 	return rot;
 }
 
-mat4_scale :: proc(m: Mat4, v: Vec3) -> Mat4 {
+scale :: proc(m: Mat4, v: Vec3) -> Mat4 {
 	m[0][0] *= v.x;
 	m[1][1] *= v.y;
 	m[2][2] *= v.z;
 	return m;
 }
 
-mat4_scalef :: proc(m: Mat4, s: f32) -> Mat4 {
+scale :: proc(m: Mat4, s: f32) -> Mat4 {
 	m[0][0] *= s;
 	m[1][1] *= s;
 	m[2][2] *= s;
@@ -295,23 +295,23 @@ mat4_scalef :: proc(m: Mat4, s: f32) -> Mat4 {
 }
 
 
-mat4_look_at :: proc(eye, centre, up: Vec3) -> Mat4 {
-	f := vec3_norm(centre - eye);
-	s := vec3_norm(cross3(f, up));
-	u := cross3(s, f);
+look_at :: proc(eye, centre, up: Vec3) -> Mat4 {
+	f := norm(centre - eye);
+	s := norm(cross(f, up));
+	u := cross(s, f);
 
 	m: Mat4;
 
 	m[0] = Vec4{+s.x, +s.y, +s.z, 0};
 	m[1] = Vec4{+u.x, +u.y, +u.z, 0};
 	m[2] = Vec4{-f.x, -f.y, -f.z, 0};
-	m[3] = Vec4{dot3(s, eye), dot3(u, eye), dot3(f, eye), 1};
+	m[3] = Vec4{dot(s, eye), dot(u, eye), dot(f, eye), 1};
 
 	return m;
 }
-mat4_perspective :: proc(fovy, aspect, near, far: f32) -> Mat4 {
+perspective :: proc(fovy, aspect, near, far: f32) -> Mat4 {
 	m: Mat4;
-	tan_half_fovy := tan32(0.5 * fovy);
+	tan_half_fovy := tan(0.5 * fovy);
 	m[0][0] = 1.0 / (aspect*tan_half_fovy);
 	m[1][1] = 1.0 / (tan_half_fovy);
 	m[2][2] = -(far + near) / (far - near);
@@ -321,7 +321,7 @@ mat4_perspective :: proc(fovy, aspect, near, far: f32) -> Mat4 {
 }
 
 
-mat4_ortho3d :: proc(left, right, bottom, top, near, far: f32) -> Mat4 {
+ortho3d :: proc(left, right, bottom, top, near, far: f32) -> Mat4 {
 	m := mat4_identity();
 	m[0][0] = +2.0 / (right - left);
 	m[1][1] = +2.0 / (top - bottom);

+ 55 - 71
src/check_expr.c

@@ -91,19 +91,24 @@ bool check_is_assignable_to_using_subtype(Type *dst, Type *src) {
 }
 
 
-bool check_is_assignable_to(Checker *c, Operand *operand, Type *type) {
+
+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
 	if (operand->mode == Addressing_Invalid ||
 	    type == t_invalid) {
+		if (score) *score = 0;
 		return true;
 	}
 
 	if (operand->mode == Addressing_Builtin) {
+		if (score) *score = 0;
 		return false;
 	}
 
 	Type *s = operand->type;
 
 	if (are_types_identical(s, type)) {
+		if (score) *score = 10;
 		return true;
 	}
 
@@ -111,15 +116,13 @@ bool check_is_assignable_to(Checker *c, Operand *operand, Type *type) {
 	Type *dst = base_type(type);
 
 	if (is_type_untyped(src)) {
-		switch (dst->kind) {
-		case Type_Basic:
+		if (dst->kind == Type_Basic) {
 			if (operand->mode == Addressing_Constant) {
 				return check_value_is_expressible(c, operand->value, dst, NULL);
 			}
 			if (src->kind == Type_Basic && src->Basic.kind == Basic_UntypedBool) {
 				return is_type_boolean(dst);
 			}
-			break;
 		}
 		if (type_has_nil(dst)) {
 			return operand->mode == Addressing_Value && operand->type == t_untyped_nil;
@@ -132,7 +135,8 @@ bool check_is_assignable_to(Checker *c, Operand *operand, Type *type) {
 
 	if (is_type_maybe(dst)) {
 		Type *elem = base_type(dst)->Maybe.elem;
-		return are_types_identical(elem, s);
+		bool ok = are_types_identical(elem, s);
+		return ok;
 	}
 
 	if (is_type_untyped_nil(src)) {
@@ -189,6 +193,12 @@ bool check_is_assignable_to(Checker *c, Operand *operand, Type *type) {
 }
 
 
+bool check_is_assignable_to(Checker *c, Operand *operand, Type *type) {
+	i64 score = 0;
+	return check_is_assignable_to_with_score(c, operand, type, &score);
+}
+
+
 // NOTE(bill): `content_name` is for debugging and error messages
 void check_assignment(Checker *c, Operand *operand, Type *type, String context_name) {
 	check_not_tuple(c, operand);
@@ -3407,11 +3417,13 @@ typedef enum CallArgumentError {
 	CallArgumentError_TooManyArguments,
 } CallArgumentError;
 
-CallArgumentError check_call_arguments_internal(Checker *c, AstNode *call, Type *proc_type, Operand *operands, isize operand_count, bool show_error, i64 *score) {
+CallArgumentError check_call_arguments_internal(Checker *c, AstNode *call, Type *proc_type, Operand *operands, isize operand_count,
+                                                bool show_error, i64 *score_) {
 	ast_node(ce, CallExpr, call);
 	isize param_count = 0;
 	bool variadic = proc_type->Proc.variadic;
 	bool vari_expand = (ce->ellipsis.pos.line != 0);
+	i64 score = 0;
 
 	if (proc_type->Proc.params != NULL) {
 		param_count = proc_type->Proc.params->Tuple.variable_count;
@@ -3426,10 +3438,12 @@ CallArgumentError check_call_arguments_internal(Checker *c, AstNode *call, Type
 			      "Cannot use `..` in call to a non-variadic procedure: `%.*s`",
 			      LIT(ce->proc->Ident.string));
 		}
+		if (score_) *score_ = score;
 		return CallArgumentError_NonVariadicExpand;
 	}
 
 	if (operand_count == 0 && param_count == 0) {
+		if (score_) *score_ = score;
 		return CallArgumentError_None;
 	}
 
@@ -3452,6 +3466,7 @@ CallArgumentError check_call_arguments_internal(Checker *c, AstNode *call, Type
 			error_node(call, err_fmt, proc_str, param_count);
 			gb_string_free(proc_str);
 		}
+		if (score_) *score_ = score;
 		return err;
 	}
 
@@ -3466,12 +3481,14 @@ CallArgumentError check_call_arguments_internal(Checker *c, AstNode *call, Type
 		if (variadic) {
 			o = operands[operand_index];
 		}
-		if (!check_is_assignable_to(c, &o, t)) {
+		i64 s = 0;
+		if (!check_is_assignable_to_with_score(c, &o, t, &s)) {
 			if (show_error) {
 				check_assignment(c, &o, t, str_lit("argument"));
 			}
 			err = CallArgumentError_WrongTypes;
 		}
+		score += s;
 	}
 
 	if (variadic) {
@@ -3489,18 +3506,22 @@ CallArgumentError check_call_arguments_internal(Checker *c, AstNode *call, Type
 					if (show_error) {
 						error_node(o.expr, "`..` in a variadic procedure can only have one variadic argument at the end");
 					}
+					if (score_) *score_ = score;
 					return CallArgumentError_MultipleVariadicExpand;
 				}
 			}
-			if (!check_is_assignable_to(c, &o, t)) {
+			i64 s = 0;
+			if (!check_is_assignable_to_with_score(c, &o, t, &s)) {
 				if (show_error) {
 					check_assignment(c, &o, t, str_lit("argument"));
 				}
 				err = CallArgumentError_WrongTypes;
 			}
+			score += s;
 		}
 	}
 
+	if (score_) *score_ = score;
 	return err;
 }
 
@@ -3532,10 +3553,11 @@ 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);
-		isize valid_proc_count = 0;
+		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;
 
 		map_entity_multi_get_all(&s->elements, key, procs);
 
@@ -3554,18 +3576,36 @@ 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_proc_count++] = i;
+					valid_procs[valid_count] = i;
+					valid_scores[valid_count] = 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_proc_count == 0) {
+		if (valid_count == 0) {
 			error_node(operand->expr, "No overloads for `%.*s` that match the specified 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);
+			}
+			proc_type = t_invalid;
 		} else {
 			GB_ASSERT(operand->expr->kind == AstNode_Ident);
-			// IMPORTANT TODO(bill): Get the best proc by its score
 			Entity *e = procs[valid_procs[0]];
 			add_entity_use(c, operand->expr, e);
 			proc_type = e->type;
@@ -3581,62 +3621,6 @@ Type *check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNod
 		array_free(&operands);
 	}
 	return proc_type;
-
-/*
-	i32 error_code = 0;
-	if (operands.count < param_count) {
-		error_code = -1;
-	} else if (!variadic && operands.count > param_count) {
-		error_code = +1;
-	}
-	if (error_code != 0) {
-		char *err_fmt = "Too many arguments for `%s`, expected %td arguments";
-		if (error_code < 0) {
-			err_fmt = "Too few arguments for `%s`, expected %td arguments";
-		}
-
-		gbString proc_str = expr_to_string(ce->proc);
-		error_node(call, err_fmt, proc_str, param_count);
-		gb_string_free(proc_str);
-		operand->mode = Addressing_Invalid;
-		goto end;
-	}
-
-	GB_ASSERT(proc_type->Proc.params != NULL);
-	Entity **sig_params = proc_type->Proc.params->Tuple.variables;
-	isize operand_index = 0;
-	for (; operand_index < param_count; operand_index++) {
-		Type *arg_type = sig_params[operand_index]->type;
-		Operand o = operands.e[operand_index];
-		if (variadic) {
-			o = operands.e[operand_index];
-		}
-		check_assignment(c, &o, arg_type, str_lit("argument"));
-	}
-
-	if (variadic) {
-		bool variadic_expand = false;
-		Type *slice = sig_params[param_count]->type;
-		GB_ASSERT(is_type_slice(slice));
-		Type *elem = base_type(slice)->Slice.elem;
-		Type *t = elem;
-		for (; operand_index < operands.count; operand_index++) {
-			Operand o = operands.e[operand_index];
-			if (vari_expand) {
-				variadic_expand = true;
-				t = slice;
-				if (operand_index != param_count) {
-					error_node(o.expr, "`..` in a variadic procedure can only have one variadic argument at the end");
-					break;
-				}
-			}
-			check_assignment(c, &o, t, str_lit("argument"));
-		}
-	}
-end:
-
-	return proc_type;
-*/
 }
 
 

+ 9 - 5
src/checker.c

@@ -505,6 +505,9 @@ Entity *scope_insert_entity(Scope *s, Entity *entity) {
 	String name = entity->token.string;
 	HashKey key = hash_string(name);
 	Entity **found = map_entity_get(&s->elements, key);
+
+#if 1
+	// IMPORTANT NOTE(bill): Procedure overloading code
 	Entity *prev = NULL;
 	if (found) {
 		prev = *found;
@@ -517,15 +520,16 @@ Entity *scope_insert_entity(Scope *s, Entity *entity) {
 	}
 
 	if (prev != NULL && entity->kind == Entity_Procedure) {
-		// TODO(bill): Remove from final release
-		isize prev_count, next_count;
-		prev_count = map_entity_multi_count(&s->elements, key);
 		map_entity_multi_insert(&s->elements, key, entity);
-		next_count = map_entity_multi_count(&s->elements, key);
-		GB_ASSERT(prev_count < next_count);
 	} else {
 		map_entity_set(&s->elements, key, entity);
 	}
+#else
+	if (found) {
+		return *found;
+	}
+	map_entity_set(&s->elements, key, entity);
+#endif
 	if (entity->scope == NULL) {
 		entity->scope = s;
 	}