From 6dc6b6f8aaa3289ae32746367089f9f77be9a623 Mon Sep 17 00:00:00 2001 From: Ginger Bill Date: Sun, 15 Jan 2017 20:43:28 +0000 Subject: [PATCH] Err on ambiguous overloaded calls --- code/demo.odin | 19 +++++-- core/_preload.odin | 16 +++--- core/atomic.odin | 56 ++++++++++---------- core/math.odin | 106 +++++++++++++++++++------------------- src/check_expr.c | 126 ++++++++++++++++++++------------------------- src/checker.c | 14 +++-- 6 files changed, 168 insertions(+), 169 deletions(-) diff --git a/code/demo.odin b/code/demo.odin index 7c9e206ba..c7c13ade0 100644 --- a/code/demo.odin +++ b/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; diff --git a/core/_preload.odin b/core/_preload.odin index ba4bd8384..c1ebc8643 100644 --- a/core/_preload.odin +++ b/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" diff --git a/core/atomic.odin b/core/atomic.odin index cb931813b..2ed69c438 100644 --- a/core/atomic.odin +++ b/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; } diff --git a/core/math.odin b/core/math.odin index 9a0f8b1eb..0c4c19a75 100644 --- a/core/math.odin +++ b/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); diff --git a/src/check_expr.c b/src/check_expr.c index 763fc360a..f1c2dd620 100644 --- a/src/check_expr.c +++ b/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; -*/ } diff --git a/src/checker.c b/src/checker.c index 1e6acf382..6594a8e4a 100644 --- a/src/checker.c +++ b/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; }