Err on ambiguous overloaded calls

This commit is contained in:
Ginger Bill
2017-01-15 20:43:28 +00:00
parent ac736aa4ec
commit 6dc6b6f8aa
6 changed files with 168 additions and 169 deletions
+15 -4
View File
@@ -1,17 +1,28 @@
#import "atomic.odin";
#import "fmt.odin"; #import "fmt.odin";
#import "math.odin";
#import "mem.odin";
#import "opengl.odin";
main :: proc() { main :: proc() {
foo :: proc() { foo :: proc() {
fmt.printf("Zero args\n"); fmt.printf("Zero args\n");
} }
foo :: proc(i: int) { 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();
foo(THING); foo(THINGI as int);
fmt.println(THING); foo(THINGF);
fmt.println(THINGI);
fmt.println(THINGF);
x: proc(); x: proc();
x = foo; x = foo;
+8 -8
View File
@@ -111,16 +111,16 @@ __debug_trap :: proc() #foreign "llvm.debugtrap"
__trap :: proc() #foreign "llvm.trap" __trap :: proc() #foreign "llvm.trap"
read_cycle_counter :: proc() -> u64 #foreign "llvm.readcyclecounter" read_cycle_counter :: proc() -> u64 #foreign "llvm.readcyclecounter"
bit_reverse16 :: proc(b: u16) -> u16 #foreign "llvm.bitreverse.i16" bit_reverse :: proc(b: u16) -> u16 #foreign "llvm.bitreverse.i16"
bit_reverse32 :: proc(b: u32) -> u32 #foreign "llvm.bitreverse.i32" bit_reverse :: proc(b: u32) -> u32 #foreign "llvm.bitreverse.i32"
bit_reverse64 :: proc(b: u64) -> u64 #foreign "llvm.bitreverse.i64" bit_reverse :: proc(b: u64) -> u64 #foreign "llvm.bitreverse.i64"
byte_swap16 :: proc(b: u16) -> u16 #foreign "llvm.bswap.i16" byte_swap :: proc(b: u16) -> u16 #foreign "llvm.bswap.i16"
byte_swap32 :: proc(b: u32) -> u32 #foreign "llvm.bswap.i32" byte_swap :: proc(b: u32) -> u32 #foreign "llvm.bswap.i32"
byte_swap64 :: proc(b: u64) -> u64 #foreign "llvm.bswap.i64" byte_swap :: proc(b: u64) -> u64 #foreign "llvm.bswap.i64"
fmuladd32 :: proc(a, b, c: f32) -> f32 #foreign "llvm.fmuladd.f32" fmuladd :: 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: f64) -> f64 #foreign "llvm.fmuladd.f64"
+28 -28
View File
@@ -11,91 +11,91 @@ sfence :: proc() { win32.WriteBarrier(); }
lfence :: proc() { win32.ReadBarrier(); } lfence :: proc() { win32.ReadBarrier(); }
load32 :: proc(a: ^i32) -> i32 { load :: proc(a: ^i32) -> i32 {
return a^; return a^;
} }
store32 :: proc(a: ^i32, value: i32) { store :: proc(a: ^i32, value: i32) {
a^ = value; 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); 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); 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); 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); 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); return win32.InterlockedOr(a, operand);
} }
spin_lock32 :: proc(a: ^i32, time_out: int) -> bool { // NOTE(bill) time_out = -1 as default spin_lock :: proc(a: ^i32, time_out: int) -> bool { // NOTE(bill) time_out = -1 as default
old_value := compare_exchange32(a, 1, 0); old_value := compare_exchange(a, 1, 0);
counter := 0; counter := 0;
while old_value != 0 && (time_out < 0 || counter < time_out) { while old_value != 0 && (time_out < 0 || counter < time_out) {
counter += 1; counter += 1;
yield_thread(); yield_thread();
old_value = compare_exchange32(a, 1, 0); old_value = compare_exchange(a, 1, 0);
mfence(); mfence();
} }
return old_value == 0; return old_value == 0;
} }
spin_unlock32 :: proc(a: ^i32) { spin_unlock :: proc(a: ^i32) {
store32(a, 0); store(a, 0);
mfence(); mfence();
} }
try_acquire_lock32 :: proc(a: ^i32) -> bool { try_acquire_lock :: proc(a: ^i32) -> bool {
yield_thread(); yield_thread();
old_value := compare_exchange32(a, 1, 0); old_value := compare_exchange(a, 1, 0);
mfence(); mfence();
return old_value == 0; return old_value == 0;
} }
load64 :: proc(a: ^i64) -> i64 { load :: proc(a: ^i64) -> i64 {
return a^; return a^;
} }
store64 :: proc(a: ^i64, value: i64) { store :: proc(a: ^i64, value: i64) {
a^ = value; 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); 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); 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); 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); 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); return win32.InterlockedOr64(a, operand);
} }
spin_lock64 :: proc(a: ^i64, time_out: int) -> bool { // NOTE(bill) time_out = -1 as default spin_lock :: proc(a: ^i64, time_out: int) -> bool { // NOTE(bill) time_out = -1 as default
old_value := compare_exchange64(a, 1, 0); old_value := compare_exchange(a, 1, 0);
counter := 0; counter := 0;
while old_value != 0 && (time_out < 0 || counter < time_out) { while old_value != 0 && (time_out < 0 || counter < time_out) {
counter += 1; counter += 1;
yield_thread(); yield_thread();
old_value = compare_exchange64(a, 1, 0); old_value = compare_exchange(a, 1, 0);
mfence(); mfence();
} }
return old_value == 0; return old_value == 0;
} }
spin_unlock64 :: proc(a: ^i64) { spin_unlock :: proc(a: ^i64) {
store64(a, 0); store(a, 0);
mfence(); mfence();
} }
try_acquire_lock64 :: proc(a: ^i64) -> bool { try_acquire_lock :: proc(a: ^i64) -> bool {
yield_thread(); yield_thread();
old_value := compare_exchange64(a, 1, 0); old_value := compare_exchange(a, 1, 0);
mfence(); mfence();
return old_value == 0; return old_value == 0;
} }
+53 -53
View File
@@ -24,46 +24,46 @@ Mat2 :: [2]Vec2;
Mat3 :: [3]Vec3; Mat3 :: [3]Vec3;
Mat4 :: [4]Vec4; Mat4 :: [4]Vec4;
sqrt32 :: proc(x: f32) -> f32 #foreign "llvm.sqrt.f32" sqrt :: proc(x: f32) -> f32 #foreign "llvm.sqrt.f32"
sqrt64 :: proc(x: f64) -> f64 #foreign "llvm.sqrt.f64" sqrt :: proc(x: f64) -> f64 #foreign "llvm.sqrt.f64"
sin32 :: proc(x: f32) -> f32 #foreign "llvm.sin.f32" sin :: proc(x: f32) -> f32 #foreign "llvm.sin.f32"
sin64 :: proc(x: f64) -> f64 #foreign "llvm.sin.f64" sin :: proc(x: f64) -> f64 #foreign "llvm.sin.f64"
cos32 :: proc(x: f32) -> f32 #foreign "llvm.cos.f32" cos :: proc(x: f32) -> f32 #foreign "llvm.cos.f32"
cos64 :: proc(x: f64) -> f64 #foreign "llvm.cos.f64" cos :: proc(x: f64) -> f64 #foreign "llvm.cos.f64"
tan32 :: proc(x: f32) -> f32 #inline { return sin32(x)/cos32(x); } tan :: proc(x: f32) -> f32 #inline { return sin(x)/cos(x); }
tan64 :: proc(x: f64) -> f64 #inline { return sin64(x)/cos64(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; } lerp :: 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: f64) -> f64 { return a*(1-t) + b*t; }
sign32 :: proc(x: f32) -> f32 { if x >= 0 { return +1; } return -1; } sign :: 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: 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; ix := x transmute u32;
iy := y transmute u32; iy := y transmute u32;
ix &= 0x7fffffff; ix &= 0x7fffffff;
ix |= iy & 0x80000000; ix |= iy & 0x80000000;
return ix transmute f32; return ix transmute f32;
} }
round32 :: proc(x: f32) -> f32 { round :: proc(x: f32) -> f32 {
if x >= 0 { 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 { if x >= 0 {
return x as int as f32; return x as int as f32;
} }
return (x-0.5) 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 { if x < 0 {
return x as int as f32; return x as int as f32;
} }
@@ -71,16 +71,16 @@ ceil32 :: proc(x: f32) -> f32 {
} }
remainder32 :: proc(x, y: 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 { fmod32 :: proc(x, y: f32) -> f32 {
y = abs(y); y = abs(y);
result := remainder32(abs(x), y); result := remainder32(abs(x), y);
if sign32(result) < 0 { if sign(result) < 0 {
result += y; 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; } dot :: 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; } dot :: 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: 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); a := swizzle(x, 1, 2, 0) * swizzle(y, 2, 0, 1);
b := swizzle(x, 2, 0, 1) * swizzle(y, 1, 2, 0); b := swizzle(x, 2, 0, 1) * swizzle(y, 1, 2, 0);
return a - b; return a - b;
} }
vec2_mag :: proc(v: Vec2) -> f32 { return sqrt32(dot2(v, v)); } mag :: proc(v: Vec2) -> f32 { return sqrt(dot(v, v)); }
vec3_mag :: proc(v: Vec3) -> f32 { return sqrt32(dot3(v, v)); } mag :: proc(v: Vec3) -> f32 { return sqrt(dot(v, v)); }
vec4_mag :: proc(v: Vec4) -> f32 { return sqrt32(dot4(v, v)); } mag :: proc(v: Vec4) -> f32 { return sqrt(dot(v, v)); }
vec2_norm :: proc(v: Vec2) -> Vec2 { return v / Vec2{vec2_mag(v)}; } norm :: proc(v: Vec2) -> Vec2 { return v / Vec2{mag(v)}; }
vec3_norm :: proc(v: Vec3) -> Vec3 { return v / Vec3{vec3_mag(v)}; } norm :: proc(v: Vec3) -> Vec3 { return v / Vec3{mag(v)}; }
vec4_norm :: proc(v: Vec4) -> Vec4 { return v / Vec4{vec4_mag(v)}; } norm :: proc(v: Vec4) -> Vec4 { return v / Vec4{mag(v)}; }
vec2_norm0 :: proc(v: Vec2) -> Vec2 { norm0 :: proc(v: Vec2) -> Vec2 {
m := vec2_mag(v); m := mag(v);
if m == 0 { if m == 0 {
return Vec2{0}; return Vec2{0};
} }
return v / Vec2{m}; return v / Vec2{m};
} }
vec3_norm0 :: proc(v: Vec3) -> Vec3 { norm0 :: proc(v: Vec3) -> Vec3 {
m := vec3_mag(v); m := mag(v);
if m == 0 { if m == 0 {
return Vec3{0}; return Vec3{0};
} }
return v / Vec3{m}; return v / Vec3{m};
} }
vec4_norm0 :: proc(v: Vec4) -> Vec4 { norm0 :: proc(v: Vec4) -> Vec4 {
m := vec4_mag(v); m := mag(v);
if m == 0 { if m == 0 {
return Vec4{0}; return Vec4{0};
} }
@@ -153,7 +153,7 @@ mat4_transpose :: proc(m: Mat4) -> Mat4 {
return m; return m;
} }
mat4_mul :: proc(a, b: Mat4) -> Mat4 { mul :: proc(a, b: Mat4) -> Mat4 {
c: Mat4; c: Mat4;
for j : 0..<4 { for j : 0..<4 {
for i : 0..<4 { for i : 0..<4 {
@@ -166,7 +166,7 @@ mat4_mul :: proc(a, b: Mat4) -> Mat4 {
return c; return c;
} }
mat4_mul_vec4 :: proc(m: Mat4, v: Vec4) -> Vec4 { mul_vec4 :: proc(m: Mat4, v: Vec4) -> Vec4 {
return 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][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, 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; o: Mat4;
sf00 := m[2][2] * m[3][3] - m[3][2] * m[2][3]; 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 { mat4_rotate :: proc(v: Vec3, angle_radians: f32) -> Mat4 {
c := cos32(angle_radians); c := cos(angle_radians);
s := sin32(angle_radians); s := sin(angle_radians);
a := vec3_norm(v); a := norm(v);
t := a * Vec3{1-c}; t := a * Vec3{1-c};
rot := mat4_identity(); rot := mat4_identity();
@@ -280,14 +280,14 @@ mat4_rotate :: proc(v: Vec3, angle_radians: f32) -> Mat4 {
return rot; return rot;
} }
mat4_scale :: proc(m: Mat4, v: Vec3) -> Mat4 { scale :: proc(m: Mat4, v: Vec3) -> Mat4 {
m[0][0] *= v.x; m[0][0] *= v.x;
m[1][1] *= v.y; m[1][1] *= v.y;
m[2][2] *= v.z; m[2][2] *= v.z;
return m; return m;
} }
mat4_scalef :: proc(m: Mat4, s: f32) -> Mat4 { scale :: proc(m: Mat4, s: f32) -> Mat4 {
m[0][0] *= s; m[0][0] *= s;
m[1][1] *= s; m[1][1] *= s;
m[2][2] *= 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 { look_at :: proc(eye, centre, up: Vec3) -> Mat4 {
f := vec3_norm(centre - eye); f := norm(centre - eye);
s := vec3_norm(cross3(f, up)); s := norm(cross(f, up));
u := cross3(s, f); u := cross(s, f);
m: Mat4; m: Mat4;
m[0] = Vec4{+s.x, +s.y, +s.z, 0}; m[0] = Vec4{+s.x, +s.y, +s.z, 0};
m[1] = Vec4{+u.x, +u.y, +u.z, 0}; m[1] = Vec4{+u.x, +u.y, +u.z, 0};
m[2] = Vec4{-f.x, -f.y, -f.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; return m;
} }
mat4_perspective :: proc(fovy, aspect, near, far: f32) -> Mat4 { perspective :: proc(fovy, aspect, near, far: f32) -> Mat4 {
m: 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[0][0] = 1.0 / (aspect*tan_half_fovy);
m[1][1] = 1.0 / (tan_half_fovy); m[1][1] = 1.0 / (tan_half_fovy);
m[2][2] = -(far + near) / (far - near); 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 := mat4_identity();
m[0][0] = +2.0 / (right - left); m[0][0] = +2.0 / (right - left);
m[1][1] = +2.0 / (top - bottom); m[1][1] = +2.0 / (top - bottom);
+55 -71
View File
@@ -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 || if (operand->mode == Addressing_Invalid ||
type == t_invalid) { type == t_invalid) {
if (score) *score = 0;
return true; return true;
} }
if (operand->mode == Addressing_Builtin) { if (operand->mode == Addressing_Builtin) {
if (score) *score = 0;
return false; return false;
} }
Type *s = operand->type; Type *s = operand->type;
if (are_types_identical(s, type)) { if (are_types_identical(s, type)) {
if (score) *score = 10;
return true; return true;
} }
@@ -111,15 +116,13 @@ bool check_is_assignable_to(Checker *c, Operand *operand, Type *type) {
Type *dst = base_type(type); Type *dst = base_type(type);
if (is_type_untyped(src)) { if (is_type_untyped(src)) {
switch (dst->kind) { if (dst->kind == Type_Basic) {
case Type_Basic:
if (operand->mode == Addressing_Constant) { if (operand->mode == Addressing_Constant) {
return check_value_is_expressible(c, operand->value, dst, NULL); return check_value_is_expressible(c, operand->value, dst, NULL);
} }
if (src->kind == Type_Basic && src->Basic.kind == Basic_UntypedBool) { if (src->kind == Type_Basic && src->Basic.kind == Basic_UntypedBool) {
return is_type_boolean(dst); return is_type_boolean(dst);
} }
break;
} }
if (type_has_nil(dst)) { if (type_has_nil(dst)) {
return operand->mode == Addressing_Value && operand->type == t_untyped_nil; 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)) { if (is_type_maybe(dst)) {
Type *elem = base_type(dst)->Maybe.elem; 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)) { 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 // NOTE(bill): `content_name` is for debugging and error messages
void check_assignment(Checker *c, Operand *operand, Type *type, String context_name) { void check_assignment(Checker *c, Operand *operand, Type *type, String context_name) {
check_not_tuple(c, operand); check_not_tuple(c, operand);
@@ -3407,11 +3417,13 @@ typedef enum CallArgumentError {
CallArgumentError_TooManyArguments, CallArgumentError_TooManyArguments,
} CallArgumentError; } 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); ast_node(ce, CallExpr, call);
isize param_count = 0; isize param_count = 0;
bool variadic = proc_type->Proc.variadic; bool variadic = proc_type->Proc.variadic;
bool vari_expand = (ce->ellipsis.pos.line != 0); bool vari_expand = (ce->ellipsis.pos.line != 0);
i64 score = 0;
if (proc_type->Proc.params != NULL) { if (proc_type->Proc.params != NULL) {
param_count = proc_type->Proc.params->Tuple.variable_count; 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`", "Cannot use `..` in call to a non-variadic procedure: `%.*s`",
LIT(ce->proc->Ident.string)); LIT(ce->proc->Ident.string));
} }
if (score_) *score_ = score;
return CallArgumentError_NonVariadicExpand; return CallArgumentError_NonVariadicExpand;
} }
if (operand_count == 0 && param_count == 0) { if (operand_count == 0 && param_count == 0) {
if (score_) *score_ = score;
return CallArgumentError_None; 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); error_node(call, err_fmt, proc_str, param_count);
gb_string_free(proc_str); gb_string_free(proc_str);
} }
if (score_) *score_ = score;
return err; return err;
} }
@@ -3466,12 +3481,14 @@ CallArgumentError check_call_arguments_internal(Checker *c, AstNode *call, Type
if (variadic) { if (variadic) {
o = operands[operand_index]; 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) { if (show_error) {
check_assignment(c, &o, t, str_lit("argument")); check_assignment(c, &o, t, str_lit("argument"));
} }
err = CallArgumentError_WrongTypes; err = CallArgumentError_WrongTypes;
} }
score += s;
} }
if (variadic) { if (variadic) {
@@ -3489,18 +3506,22 @@ CallArgumentError check_call_arguments_internal(Checker *c, AstNode *call, Type
if (show_error) { if (show_error) {
error_node(o.expr, "`..` in a variadic procedure can only have one variadic argument at the end"); error_node(o.expr, "`..` in a variadic procedure can only have one variadic argument at the end");
} }
if (score_) *score_ = score;
return CallArgumentError_MultipleVariadicExpand; 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) { if (show_error) {
check_assignment(c, &o, t, str_lit("argument")); check_assignment(c, &o, t, str_lit("argument"));
} }
err = CallArgumentError_WrongTypes; err = CallArgumentError_WrongTypes;
} }
score += s;
} }
} }
if (score_) *score_ = score;
return err; 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; String name = operand->initial_overload_entity->token.string;
HashKey key = hash_string(name); HashKey key = hash_string(name);
isize overload_count = operand->overload_count; isize overload_count = operand->overload_count;
Entity **procs = gb_alloc_array(heap_allocator(), Entity *, 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_procs = gb_alloc_array(heap_allocator(), isize, overload_count);
isize valid_proc_count = 0; i64 * valid_scores = gb_alloc_array(heap_allocator(), i64, overload_count);
isize valid_count = 0;
map_entity_multi_get_all(&s->elements, key, procs); 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; i64 score = 0;
CallArgumentError err = check_call_arguments_internal(c, call, proc_type, operands.e, operands.count, false, &score); CallArgumentError err = check_call_arguments_internal(c, call, proc_type, operands.e, operands.count, false, &score);
if (err == CallArgumentError_None) { 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)); error_node(operand->expr, "No overloads for `%.*s` that match the specified arguments", LIT(name));
proc_type = t_invalid; 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 { } else {
GB_ASSERT(operand->expr->kind == AstNode_Ident); GB_ASSERT(operand->expr->kind == AstNode_Ident);
// IMPORTANT TODO(bill): Get the best proc by its score
Entity *e = procs[valid_procs[0]]; Entity *e = procs[valid_procs[0]];
add_entity_use(c, operand->expr, e); add_entity_use(c, operand->expr, e);
proc_type = e->type; proc_type = e->type;
@@ -3581,62 +3621,6 @@ Type *check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNod
array_free(&operands); array_free(&operands);
} }
return proc_type; 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
View File
@@ -505,6 +505,9 @@ Entity *scope_insert_entity(Scope *s, Entity *entity) {
String name = entity->token.string; String name = entity->token.string;
HashKey key = hash_string(name); HashKey key = hash_string(name);
Entity **found = map_entity_get(&s->elements, key); Entity **found = map_entity_get(&s->elements, key);
#if 1
// IMPORTANT NOTE(bill): Procedure overloading code
Entity *prev = NULL; Entity *prev = NULL;
if (found) { if (found) {
prev = *found; prev = *found;
@@ -517,15 +520,16 @@ Entity *scope_insert_entity(Scope *s, Entity *entity) {
} }
if (prev != NULL && entity->kind == Entity_Procedure) { 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); map_entity_multi_insert(&s->elements, key, entity);
next_count = map_entity_multi_count(&s->elements, key);
GB_ASSERT(prev_count < next_count);
} else { } else {
map_entity_set(&s->elements, key, entity); map_entity_set(&s->elements, key, entity);
} }
#else
if (found) {
return *found;
}
map_entity_set(&s->elements, key, entity);
#endif
if (entity->scope == NULL) { if (entity->scope == NULL) {
entity->scope = s; entity->scope = s;
} }