diff --git a/code/demo.odin b/code/demo.odin index cba0212fb..4b9c27a15 100644 --- a/code/demo.odin +++ b/code/demo.odin @@ -364,9 +364,17 @@ explicit_parametric_polymorphic_procedures :: proc() { } } + main :: proc() { - general_stuff(); + foo :: proc(x: i64, y: f32) do fmt.println("#1", x, y); + foo :: proc(x: type, y: f32) do fmt.println("#2", type_info(x), y); + foo :: proc(x: type) do fmt.println("#3", type_info(x)); + + foo(y = 3785.1546, x = 123); + foo(x = int, y = 897.513); + foo(x = f32); /* + general_stuff(); foreign_blocks(); default_arguments(); named_arguments(); @@ -376,7 +384,6 @@ main :: proc() { // Command line argument(s)! // -opt=0,1,2,3 -*/ program := "+ + * - /"; accumulator := 0; @@ -393,5 +400,9 @@ main :: proc() { fmt.printf("The program \"%s\" calculates the value %d\n", program, accumulator); +*/ } + + + diff --git a/core/_preload.odin b/core/_preload.odin index 269bbdf31..28841d822 100644 --- a/core/_preload.odin +++ b/core/_preload.odin @@ -122,8 +122,7 @@ type_info_base :: proc(info: ^TypeInfo) -> ^TypeInfo { base := info; match i in base { - case TypeInfo.Named: - base = i.base; + case TypeInfo.Named: base = i.base; } return base; } @@ -134,10 +133,8 @@ type_info_base_without_enum :: proc(info: ^TypeInfo) -> ^TypeInfo { base := info; match i in base { - case TypeInfo.Named: - base = i.base; - case TypeInfo.Enum: - base = i.base; + case TypeInfo.Named: base = i.base; + case TypeInfo.Enum: base = i.base; } return base; } @@ -258,8 +255,67 @@ resize :: proc(ptr: rawptr, old_size, new_size: int, alignment: int = DEFAULT_AL return a.procedure(a.data, AllocatorMode.Resize, new_size, alignment, ptr, old_size, 0); } +// append :: proc(s: ^[]$T, args: ..T) -> int { +// if s == nil { +// return 0; +// } +// slice := ^raw.Slice(s); +// arg_len := len(args); +// if arg_len <= 0 { +// return slice.len; +// } + +// arg_len = min(slice.cap-slice.len, arg_len); +// if arg_len > 0 { +// data := ^T(slice.data); +// assert(data != nil); +// sz :: size_of(T); +// __mem_copy(data + slice.len, &args[0], sz*arg_len); +// slice.len += arg_len; +// } +// return slice.len; +// } + +// append :: proc(a: ^[dynamic]$T, args: ..T) -> int { +// array := ^raw.DynamicArray(a); + +// arg_len := len(args); +// if arg_len <= 0 || items == nil { +// return array.len; +// } + + +// ok := true; +// if array.cap <= array.len+arg_len { +// cap := 2 * array.cap + max(8, arg_len); +// ok = __dynamic_array_reserve(array, size_of(T), align_of(T), cap); +// } +// // TODO(bill): Better error handling for failed reservation +// if !ok do return array.len; + +// data := ^T(array.data); +// assert(data != nil); +// __mem_copy(data + array.len, items, size_of(T) * arg_len); +// array.len += arg_len; +// return array.len; +// } + +copy :: proc(dst, src: []$T) -> int #cc_contextless { + n := max(0, min(len(dst), len(src))); + if n > 0 do __mem_copy(&dst[0], &src[0], n*size_of(T)); + return n; +} + + +new :: proc(T: type) -> ^T #inline do return ^T(alloc(size_of(T), align_of(T))); + +/* +free :: proc(array: [dynamic]$T) do free_ptr(^raw.DynamicArray(&array).data); +free :: proc(slice: []$T) do free_ptr(^raw.Slice(&slice).data); +free :: proc(str: string) do free_ptr(^raw.String(&str).data); +free :: proc(ptr: rawptr) do free_ptr(ptr); +*/ -new :: proc(T: type) -> ^T #inline do return ^T(alloc(size_of(T), align_of(T))); @@ -440,10 +496,8 @@ __mem_copy_non_overlapping :: proc(dst, src: rawptr, len: int) -> rawptr #cc_con __mem_compare :: proc(a, b: ^u8, n: int) -> int #cc_contextless { for i in 0.. (b+i)^: - return +1; + case (a+i)^ < (b+i)^: return -1; + case (a+i)^ > (b+i)^: return +1; } } return 0; @@ -569,7 +623,6 @@ __slice_append :: proc(slice_: rawptr, elem_size, elem_align: int, return slice.len; } - // Map stuff __default_hash :: proc(data: []u8) -> u128 { @@ -582,9 +635,7 @@ __default_hash :: proc(data: []u8) -> u128 { } return fnv128a(data); } -__default_hash_string :: proc(s: string) -> u128 { - return __default_hash([]u8(s)); -} +__default_hash_string :: proc(s: string) -> u128 do return __default_hash([]u8(s)); __INITIAL_MAP_CAP :: 16; @@ -634,9 +685,7 @@ __dynamic_map_rehash :: proc(using header: __MapHeader, new_count: int) { for i in 0.. u16 #link_name "llvm.bswap.i16" ---; @@ -8,33 +9,50 @@ foreign __llvm_core { swap :: proc(b: u64) -> u64 #link_name "llvm.bswap.i64" ---; } -set :: proc(data: rawptr, value: i32, len: int) -> rawptr { +set :: proc(data: rawptr, value: i32, len: int) -> rawptr #cc_contextless { return __mem_set(data, value, len); } -zero :: proc(data: rawptr, len: int) -> rawptr { +zero :: proc(data: rawptr, len: int) -> rawptr #cc_contextless { return __mem_zero(data, len); } -copy :: proc(dst, src: rawptr, len: int) -> rawptr { +copy :: proc(dst, src: rawptr, len: int) -> rawptr #cc_contextless { return __mem_copy(dst, src, len); } -copy_non_overlapping :: proc(dst, src: rawptr, len: int) -> rawptr { +copy_non_overlapping :: proc(dst, src: rawptr, len: int) -> rawptr #cc_contextless { return __mem_copy_non_overlapping(dst, src, len); } -compare :: proc(a, b: []u8) -> int { +compare :: proc(a, b: []u8) -> int #cc_contextless { return __mem_compare(&a[0], &b[0], min(len(a), len(b))); } +/* +slice_ptr :: proc(ptr: ^$T, len: int) -> []T #cc_contextless { + assert(len >= 0); + slice := raw.Slice{data = ptr, len = len, cap = len}; + return ^[]T(&slice)^; +} +slice_ptr :: proc(ptr: ^$T, len, cap: int) -> []T #cc_contextless { + assert(0 <= len && len <= cap); + slice := raw.Slice{data = ptr, len = len, cap = cap}; + return ^[]T(&slice)^; +} + +slice_to_bytes :: proc(slice: []$T) -> []u8 #cc_contextless { + s := ^raw.Slice(&slice); + s.len *= size_of(T); + s.cap *= size_of(T); + return ^[]u8(s)^; +} +*/ -kilobytes :: proc(x: int) -> int #inline { return (x) * 1024; } -megabytes :: proc(x: int) -> int #inline { return kilobytes(x) * 1024; } -gigabytes :: proc(x: int) -> int #inline { return megabytes(x) * 1024; } -terabytes :: proc(x: int) -> int #inline { return gigabytes(x) * 1024; } +kilobytes :: proc(x: int) -> int #inline #cc_contextless { return (x) * 1024; } +megabytes :: proc(x: int) -> int #inline #cc_contextless { return kilobytes(x) * 1024; } +gigabytes :: proc(x: int) -> int #inline #cc_contextless { return megabytes(x) * 1024; } +terabytes :: proc(x: int) -> int #inline #cc_contextless { return gigabytes(x) * 1024; } is_power_of_two :: proc(x: int) -> bool { - if x <= 0 { - return false; - } + if x <= 0 do return false; return (x & (x-1)) == 0; } @@ -44,9 +62,7 @@ align_forward :: proc(ptr: rawptr, align: int) -> rawptr { a := uint(align); p := uint(ptr); modulo := p & (a-1); - if modulo != 0 { - p += a - modulo; - } + if modulo != 0 do p += a - modulo; return rawptr(p); } @@ -65,13 +81,9 @@ allocation_header_fill :: proc(header: ^AllocationHeader, data: rawptr, size: in } } allocation_header :: proc(data: rawptr) -> ^AllocationHeader { - if data == nil { - return nil; - } + if data == nil do return nil; p := ^int(data); - for (p-1)^ == -1 { - p = (p-1); - } + for (p-1)^ == -1 do p = (p-1); return ^AllocationHeader(p-1); } @@ -184,9 +196,7 @@ end_arena_temp_memory :: proc(using tmp: ArenaTempMemory) { align_of_type_info :: proc(type_info: ^TypeInfo) -> int { prev_pow2 :: proc(n: i64) -> i64 { - if n <= 0 { - return 0; - } + if n <= 0 do return 0; n |= n >> 1; n |= n >> 2; n |= n >> 4; @@ -271,9 +281,7 @@ size_of_type_info :: proc(type_info: ^TypeInfo) -> int { return WORD_SIZE; case Array: count := info.count; - if count == 0 { - return 0; - } + if count == 0 do return 0; size := size_of_type_info(info.elem); align := align_of_type_info(info.elem); alignment := align_formula(size, align); @@ -284,9 +292,7 @@ size_of_type_info :: proc(type_info: ^TypeInfo) -> int { return 2*WORD_SIZE; case Vector: count := info.count; - if count == 0 { - return 0; - } + if count == 0 do return 0; size := size_of_type_info(info.elem); align := align_of_type_info(info.elem); alignment := align_formula(size, align); diff --git a/core/os_windows.odin b/core/os_windows.odin index 736419bbe..38d16a262 100644 --- a/core/os_windows.odin +++ b/core/os_windows.odin @@ -1,4 +1,5 @@ import win32 "sys/windows.odin"; +import "mem.odin"; Handle :: int; FileTime :: u64; @@ -100,9 +101,8 @@ open :: proc(path: string, mode: int = O_RDONLY, perm: u32 = 0) -> (Handle, Errn copy(buf[..], []u8(path)); handle := Handle(win32.create_file_a(&buf[0], access, share_mode, sa, create_mode, win32.FILE_ATTRIBUTE_NORMAL, nil)); - if handle != INVALID_HANDLE { - return handle, ERROR_NONE; - } + if handle != INVALID_HANDLE do return handle, ERROR_NONE; + err := win32.get_last_error(); return INVALID_HANDLE, Errno(err); } @@ -113,23 +113,18 @@ close :: proc(fd: Handle) { write :: proc(fd: Handle, data: []u8) -> (int, Errno) { - if len(data) == 0 { - return 0, ERROR_NONE; - } + if len(data) == 0 do return 0, ERROR_NONE; + single_write_length: i32; total_write: i64; length := i64(len(data)); for total_write < length { remaining := length - total_write; - to_read: i32; MAX :: 1<<31-1; - if remaining <= MAX { - to_read = i32(remaining); - } else { - to_read = MAX; - } - e := win32.write_file(win32.Handle(fd), &data[total_write], to_read, &single_write_length, nil); + to_write: i32 = min(i32(remaining), MAX); + + e := win32.write_file(win32.Handle(fd), &data[total_write], to_write, &single_write_length, nil); if single_write_length <= 0 || e == win32.FALSE { err := win32.get_last_error(); return int(total_write), Errno(e); @@ -140,9 +135,7 @@ write :: proc(fd: Handle, data: []u8) -> (int, Errno) { } read :: proc(fd: Handle, data: []u8) -> (int, Errno) { - if len(data) == 0 { - return 0, ERROR_NONE; - } + if len(data) == 0 do return 0, ERROR_NONE; single_read_length: i32; total_read: i64; @@ -150,13 +143,8 @@ read :: proc(fd: Handle, data: []u8) -> (int, Errno) { for total_read < length { remaining := length - total_read; - to_read: u32; MAX :: 1<<32-1; - if remaining <= MAX { - to_read = u32(remaining); - } else { - to_read = MAX; - } + to_read: u32 = min(u32(remaining), MAX); e := win32.read_file(win32.Handle(fd), &data[total_read], to_read, &single_read_length, nil); if single_read_length <= 0 || e == win32.FALSE { @@ -178,9 +166,8 @@ seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) { hi := i32(offset>>32); lo := i32(offset); ft := win32.get_file_type(win32.Handle(fd)); - if ft == win32.FILE_TYPE_PIPE { - return 0, ERROR_FILE_IS_PIPE; - } + if ft == win32.FILE_TYPE_PIPE do return 0, ERROR_FILE_IS_PIPE; + dw_ptr := win32.set_file_pointer(win32.Handle(fd), lo, &hi, w); if dw_ptr == win32.INVALID_SET_FILE_POINTER { err := win32.get_last_error(); @@ -253,9 +240,8 @@ heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr { heap_free(ptr); return nil; } - if ptr == nil { - return heap_alloc(new_size); - } + if ptr == nil do return heap_alloc(new_size); + return win32.heap_realloc(win32.get_process_heap(), win32.HEAP_ZERO_MEMORY, ptr, new_size); } heap_free :: proc(ptr: rawptr) { @@ -282,9 +268,8 @@ current_thread_id :: proc() -> int { _alloc_command_line_arguments :: proc() -> []string { alloc_ucs2_to_utf8 :: proc(wstr: ^u16) -> string { wstr_len := 0; - for (wstr+wstr_len)^ != 0 { - wstr_len++; - } + for (wstr+wstr_len)^ != 0 do wstr_len++; + len := 2*wstr_len-1; buf := make([]u8, len+1); str := slice_ptr(wstr, wstr_len+1); @@ -293,22 +278,16 @@ _alloc_command_line_arguments :: proc() -> []string { for str[j] != 0 { match { case str[j] < 0x80: - if i+1 > len { - return ""; - } + if i+1 > len do return ""; buf[i] = u8(str[j]); i++; j++; case str[j] < 0x800: - if i+2 > len { - return ""; - } + if i+2 > len do return ""; buf[i] = u8(0xc0 + (str[j]>>6)); i++; buf[i] = u8(0x80 + (str[j]&0x3f)); i++; j++; case 0xd800 <= str[j] && str[j] < 0xdc00: - if i+4 > len { - return ""; - } + if i+4 > len do return ""; c := rune((str[j] - 0xd800) << 10) + rune((str[j+1]) - 0xdc00) + 0x10000; buf[i] = u8(0xf0 + (c >> 18)); i++; buf[i] = u8(0x80 + ((c >> 12) & 0x3f)); i++; @@ -318,9 +297,7 @@ _alloc_command_line_arguments :: proc() -> []string { case 0xdc00 <= str[j] && str[j] < 0xe000: return ""; case: - if i+3 > len { - return ""; - } + if i+3 > len do return ""; buf[i] = 0xe0 + u8 (str[j] >> 12); i++; buf[i] = 0x80 + u8((str[j] >> 6) & 0x3f); i++; buf[i] = 0x80 + u8((str[j] ) & 0x3f); i++; @@ -334,9 +311,7 @@ _alloc_command_line_arguments :: proc() -> []string { arg_count: i32; arg_list_ptr := win32.command_line_to_argv_w(win32.get_command_line_w(), &arg_count); arg_list := make([]string, arg_count); - for _, i in arg_list { - arg_list[i] = alloc_ucs2_to_utf8((arg_list_ptr+i)^); - } + for _, i in arg_list do arg_list[i] = alloc_ucs2_to_utf8((arg_list_ptr+i)^); return arg_list; } diff --git a/core/sys/wgl.odin b/core/sys/wgl.odin index e74bb6571..10d36d18a 100644 --- a/core/sys/wgl.odin +++ b/core/sys/wgl.odin @@ -68,7 +68,7 @@ GetExtensionsStringARBType :: proc(Hdc) -> ^u8 #cc_c; foreign opengl32 { create_context :: proc(hdc: Hdc) -> Hglrc #link_name "wglCreateContext" ---; make_current :: proc(hdc: Hdc, hglrc: Hglrc) -> Bool #link_name "wglMakeCurrent" ---; - get_proc_address :: proc(c_str: ^u8) -> Proc #link_name "wglGetProcAddress" ---; + get_proc_address :: proc(c_str: ^u8) -> rawptr #link_name "wglGetProcAddress" ---; delete_context :: proc(hglrc: Hglrc) -> Bool #link_name "wglDeleteContext" ---; copy_context :: proc(src, dst: Hglrc, mask: u32) -> Bool #link_name "wglCopyContext" ---; create_layer_context :: proc(hdc: Hdc, layer_plane: i32) -> Hglrc #link_name "wglCreateLayerContext" ---; diff --git a/core/sys/windows.odin b/core/sys/windows.odin index 5af38702f..f485244c3 100644 --- a/core/sys/windows.odin +++ b/core/sys/windows.odin @@ -144,9 +144,6 @@ PixelFormatDescriptor :: struct #ordered { - -Proc :: proc() #cc_c; - MAPVK_VK_TO_VSC :: 0; MAPVK_VSC_TO_VK :: 1; MAPVK_VK_TO_CHAR :: 2; @@ -344,7 +341,7 @@ foreign kernel32 { load_library_a :: proc(c_str: ^u8) -> Hmodule #cc_std #link_name "LoadLibraryA" ---; free_library :: proc(h: Hmodule) #cc_std #link_name "FreeLibrary" ---; - get_proc_address :: proc(h: Hmodule, c_str: ^u8) -> Proc #cc_std #link_name "GetProcAddress" ---; + get_proc_address :: proc(h: Hmodule, c_str: ^u8) -> rawptr #cc_std #link_name "GetProcAddress" ---; } diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 0826f59ca..14fd6f3ec 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -601,6 +601,8 @@ void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNod } CheckerContext old_context = c->context; + defer (c->context = old_context); + c->context.scope = decl->scope; c->context.decl = decl; c->context.proc_name = proc_name; @@ -660,7 +662,6 @@ void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNod check_scope_usage(c, c->context.scope); - c->context = old_context; if (decl->parent != NULL) { // NOTE(bill): Add the dependencies from the procedure literal (lambda) diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 95dd8f659..f8efb0575 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -1084,6 +1084,7 @@ bool is_polymorphic_type_assignable(Checker *c, Type *poly, Type *source, bool c case Type_Basic: if (compound) return are_types_identical(poly, source); return check_is_assignable_to(c, &o, poly); + case Type_Named: if (compound) return are_types_identical(poly, source); return check_is_assignable_to(c, &o, poly); @@ -1097,7 +1098,8 @@ bool is_polymorphic_type_assignable(Checker *c, Type *poly, Type *source, bool c } case Type_Pointer: if (source->kind == Type_Pointer) { - return is_polymorphic_type_assignable(c, poly->Pointer.elem, source->Pointer.elem, true, modify_type); + if (compound) return are_types_identical(poly, source); + return check_is_assignable_to(c, &o, poly); } return false; case Type_Atomic: @@ -1354,7 +1356,8 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari param->TypeName.is_type_alias = true; } else { if (operands != NULL && is_type_polymorphic_type) { - type = determine_type_from_polymorphic(c, type, (*operands)[variable_index]); + Operand op = (*operands)[variable_index]; + type = determine_type_from_polymorphic(c, type, op); if (type == t_invalid) { success = false; } @@ -4177,6 +4180,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id operand->type = type; } break; + #if 1 case BuiltinProc_free: { // proc free(^Type) // proc free([]Type) @@ -4206,6 +4210,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id operand->mode = Addressing_NoValue; } break; + #endif case BuiltinProc_reserve: { @@ -4478,48 +4483,6 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id operand->type = t_untyped_bool; break; - case BuiltinProc_copy: { - // proc copy(x, y: []Type) -> int - Type *dest_type = NULL, *src_type = NULL; - - Type *d = base_type(operand->type); - if (d->kind == Type_Slice) { - dest_type = d->Slice.elem; - } - Operand op = {}; - check_expr(c, &op, ce->args[1]); - if (op.mode == Addressing_Invalid) { - return false; - } - Type *s = base_type(op.type); - if (s->kind == Type_Slice) { - src_type = s->Slice.elem; - } - - if (dest_type == NULL || src_type == NULL) { - error(call, "`copy` only expects slices as arguments"); - return false; - } - - if (!are_types_identical(dest_type, src_type)) { - gbString d_arg = expr_to_string(ce->args[0]); - gbString s_arg = expr_to_string(ce->args[1]); - gbString d_str = type_to_string(dest_type); - gbString s_str = type_to_string(src_type); - error(call, - "Arguments to `copy`, %s, %s, have different elem types: %s vs %s", - d_arg, s_arg, d_str, s_str); - gb_string_free(s_str); - gb_string_free(d_str); - gb_string_free(s_arg); - gb_string_free(d_arg); - return false; - } - - operand->type = t_int; // Returns number of elems copied - operand->mode = Addressing_Value; - } break; - case BuiltinProc_swizzle: { // proc swizzle(v: {N}T, T..) -> {M}T Type *vector_type = base_type(operand->type); @@ -4699,6 +4662,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id } break; + #if 1 case BuiltinProc_slice_ptr: { // proc slice_ptr(a: ^T, len: int) -> []T // proc slice_ptr(a: ^T, len, cap: int) -> []T @@ -4755,6 +4719,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id operand->type = t_u8_slice; operand->mode = Addressing_Value; } break; + #endif case BuiltinProc_expand_to_tuple: { Type *type = base_type(operand->type); @@ -5146,7 +5111,13 @@ bool check_unpack_arguments(Checker *c, isize lhs_count, Array *operand } // NOTE(bill): Returns `NULL` on failure -Entity *find_or_generate_polymorphic_procedure(Checker *c, Entity *base_entity, Array *operands, ProcedureInfo *proc_info_) { +Entity *find_or_generate_polymorphic_procedure(Checker *c, AstNode *call, Entity *base_entity, CallArgumentCheckerType *call_checker, + Array *operands, ProcedureInfo *proc_info_) { + /////////////////////////////////////////////////////////////////////////////// + // // + // TODO CLEANUP(bill): This procedure is very messy and hacky. Clean this!!! // + // // + /////////////////////////////////////////////////////////////////////////////// if (base_entity == NULL) { return NULL; } @@ -5172,19 +5143,25 @@ Entity *find_or_generate_polymorphic_procedure(Checker *c, Entity *base_entity, scope->is_proc = true; c->context.scope = scope; + bool generate_type_again = c->context.no_polymorphic_errors; + // NOTE(bill): This is slightly memory leaking if the type already exists // Maybe it's better to check with the previous types first? - Type *final_proc_type = make_type_proc(c->allocator, c->context.scope, NULL, 0, NULL, 0, false, pt->calling_convention); + Type *final_proc_type = make_type_proc(c->allocator, scope, NULL, 0, NULL, 0, false, pt->calling_convention); bool success = check_procedure_type(c, final_proc_type, pt->node, operands); - // if (!success) { - // return NULL; - // } + if (!success) { + ProcedureInfo proc_info = {}; + if (proc_info_) *proc_info_ = proc_info; + return NULL; + } auto *found_gen_procs = map_get(&c->info.gen_procs, hash_pointer(base_entity->identifier)); if (found_gen_procs) { - for_array(i, *found_gen_procs) { - Entity *other = (*found_gen_procs)[i]; - if (are_types_identical(other->type, final_proc_type)) { + auto procs = *found_gen_procs; + for_array(i, procs) { + Entity *other = procs[i]; + Type *pt = base_type(other->type); + if (are_types_identical(pt, final_proc_type)) { // NOTE(bill): This scope is not needed any more, destroy it // destroy_scope(scope); return other; @@ -5192,6 +5169,37 @@ Entity *find_or_generate_polymorphic_procedure(Checker *c, Entity *base_entity, } } + if (generate_type_again) { + // LEAK TODO(bill): This is technically a memory leak as it has to generate the type twice + + bool prev_no_polymorphic_errors = c->context.no_polymorphic_errors; + defer (c->context.no_polymorphic_errors = prev_no_polymorphic_errors); + c->context.no_polymorphic_errors = false; + + // NOTE(bill): Reset scope from the failed procedure type + scope_reset(scope); + + success = check_procedure_type(c, final_proc_type, pt->node, operands); + + if (!success) { + ProcedureInfo proc_info = {}; + if (proc_info_) *proc_info_ = proc_info; + return NULL; + } + + if (found_gen_procs) { + auto procs = *found_gen_procs; + for_array(i, procs) { + Entity *other = procs[i]; + Type *pt = base_type(other->type); + if (are_types_identical(pt, final_proc_type)) { + // NOTE(bill): This scope is not needed any more, destroy it + // destroy_scope(scope); + return other; + } + } + } + } AstNode *proc_lit = clone_ast_node(a, old_decl->proc_lit); ast_node(pl, ProcLit, proc_lit); @@ -5202,7 +5210,7 @@ Entity *find_or_generate_polymorphic_procedure(Checker *c, Entity *base_entity, u64 tags = base_entity->Procedure.tags; AstNode *ident = clone_ast_node(a, base_entity->identifier); Token token = ident->Ident.token; - DeclInfo *d = make_declaration_info(c->allocator, c->context.scope, old_decl->parent); + DeclInfo *d = make_declaration_info(c->allocator, scope, old_decl->parent); d->gen_proc_type = final_proc_type; d->type_expr = pl->type; d->proc_lit = proc_lit; @@ -5212,16 +5220,18 @@ Entity *find_or_generate_polymorphic_procedure(Checker *c, Entity *base_entity, entity->identifier = ident; add_entity_and_decl_info(c, ident, entity, d); - entity->scope = base_entity->scope; + // NOTE(bill): Set the scope afterwards as this is not real overloading + entity->scope = scope->parent; ProcedureInfo proc_info = {}; if (success) { - proc_info.file = c->curr_ast_file; + proc_info.file = c->curr_ast_file; proc_info.token = token; proc_info.decl = d; proc_info.type = final_proc_type; proc_info.body = pl->body; proc_info.tags = tags; + proc_info.generated_from_polymorphic = true; } if (found_gen_procs) { @@ -5329,7 +5339,7 @@ CALL_ARGUMENT_CHECKER(check_call_arguments_internal) { ProcedureInfo proc_info = {}; if (pt->is_polymorphic && !pt->is_poly_specialized) { - gen_entity = find_or_generate_polymorphic_procedure(c, entity, &operands, &proc_info); + gen_entity = find_or_generate_polymorphic_procedure(c, call, entity, check_call_arguments_internal, &operands, &proc_info); if (gen_entity != NULL) { GB_ASSERT(is_type_proc(gen_entity->type)); final_proc_type = gen_entity->type; @@ -5557,9 +5567,9 @@ CALL_ARGUMENT_CHECKER(check_named_call_arguments) { } Entity *gen_entity = NULL; - if (pt->is_polymorphic && err == CallArgumentError_None) { + if (pt->is_polymorphic && !pt->is_poly_specialized && err == CallArgumentError_None) { ProcedureInfo proc_info = {}; - gen_entity = find_or_generate_polymorphic_procedure(c, entity, &ordered_operands, &proc_info); + gen_entity = find_or_generate_polymorphic_procedure(c, call, entity, check_named_call_arguments, &ordered_operands, &proc_info); if (gen_entity != NULL) { if (proc_info.decl != NULL) { check_procedure_later(c, proc_info); @@ -5684,23 +5694,31 @@ CallArgumentData check_call_arguments(Checker *c, Operand *operand, Type *proc_t if (valid_count > 1) { gb_sort_array(valids, valid_count, valid_proc_and_score_cmp); i64 best_score = valids[0].score; + Entity *best_entity = procs[valids[0].index]; for (isize i = 0; i < valid_count; i++) { if (best_score > valids[i].score) { valid_count = i; break; } + if (best_entity == procs[valids[i].index]) { + valid_count = i; + break; + } best_score = valids[i].score; } } if (valid_count == 0) { - error(operand->expr, "No overloads for `%.*s` that match with the given arguments", LIT(name)); - gb_printf_err("Did you mean to use one of these procedures:\n"); + error(operand->expr, "No overloads or ambiguous call for `%.*s` that match with the given arguments", LIT(name)); + if (overload_count > 0) { + gb_printf_err("Did you mean to use one of the following:\n"); + } for (isize i = 0; i < overload_count; i++) { Entity *proc = procs[i]; TokenPos pos = proc->token.pos; - gbString pt = type_to_string(proc->type); + // gbString pt = type_to_string(proc->type); + gbString pt = expr_to_string(proc->type->Proc.node); gb_printf_err("\t%.*s :: %s at %.*s(%td:%td)\n", LIT(name), pt, LIT(pos.file), pos.line, pos.column, cast(long long)valids[i].score); gb_string_free(pt); } @@ -5711,7 +5729,7 @@ CallArgumentData check_call_arguments(Checker *c, Operand *operand, Type *proc_t 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, cast(long long)valids[i].score); + gb_printf_err("\t%.*s :: %s at %.*s(%td:%td) with score %lld\n", LIT(name), pt, LIT(pos.file), pos.line, pos.column, cast(long long)valids[i].score); gb_string_free(pt); } result_type = t_invalid; @@ -7253,6 +7271,10 @@ gbString write_expr_to_string(gbString str, AstNode *node) { str = gb_string_appendc(str, ")"); case_end; + case_ast_node(ht, HelperType, node); + str = gb_string_appendc(str, "type"); + case_end; + case_ast_node(pt, ProcType, node); str = gb_string_appendc(str, "proc("); str = write_expr_to_string(str, pt->params); diff --git a/src/checker.cpp b/src/checker.cpp index 84f5ad02d..8c692080a 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -44,8 +44,6 @@ enum BuiltinProcId { BuiltinProc_compile_assert, - BuiltinProc_copy, - BuiltinProc_swizzle, BuiltinProc_complex, @@ -92,8 +90,6 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("compile_assert"), 1, false, Expr_Expr}, - {STR_LIT("copy"), 2, false, Expr_Expr}, - {STR_LIT("swizzle"), 1, true, Expr_Expr}, {STR_LIT("complex"), 2, false, Expr_Expr}, @@ -204,6 +200,7 @@ struct ProcedureInfo { Type * type; // Type_Procedure AstNode * body; // AstNode_BlockStmt u64 tags; + bool generated_from_polymorphic; }; // ExprInfo stores information used for "untyped" expressions @@ -241,6 +238,16 @@ struct Scope { }; gb_global Scope *universal_scope = NULL; +void scope_reset(Scope *scope) { + if (scope == NULL) return; + + scope->first_child = NULL; + scope->last_child = NULL; + map_clear (&scope->elements); + map_clear (&scope->implicit); + array_clear(&scope->shared); + array_clear(&scope->imported); +} struct DelayedDecl { diff --git a/src/ir.cpp b/src/ir.cpp index 048349e66..a1141905e 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -3532,7 +3532,7 @@ String ir_mangle_name(irGen *s, String path, Entity *e) { isize base_len = ext-1-base; isize max_len = base_len + 1 + 1 + 10 + 1 + name.len; - bool require_suffix_id = check_is_entity_overloaded(e) || is_type_poly_proc(e->type); + bool require_suffix_id = check_is_entity_overloaded(e) || is_type_polymorphic(e->type); if (require_suffix_id) { max_len += 21; } @@ -3922,6 +3922,7 @@ irValue *ir_build_builtin_proc(irProcedure *proc, AstNode *expr, TypeAndValue tv } } break; + #if 1 case BuiltinProc_free: { ir_emit_comment(proc, str_lit("free")); @@ -3995,6 +3996,7 @@ irValue *ir_build_builtin_proc(irProcedure *proc, AstNode *expr, TypeAndValue tv args[0] = ptr; return ir_emit_global_call(proc, "free_ptr", args, 1); } break; + #endif case BuiltinProc_reserve: { ir_emit_comment(proc, str_lit("reserve")); @@ -4183,39 +4185,7 @@ irValue *ir_build_builtin_proc(irProcedure *proc, AstNode *expr, TypeAndValue tv return ir_emit_global_call(proc, "__dynamic_map_delete", args, 2); } break; - case BuiltinProc_copy: { - ir_emit_comment(proc, str_lit("copy")); - // proc copy(dst, src: []Type) -> int - AstNode *dst_node = ce->args[0]; - AstNode *src_node = ce->args[1]; - irValue *dst_slice = ir_build_expr(proc, dst_node); - irValue *src_slice = ir_build_expr(proc, src_node); - Type *slice_type = base_type(ir_type(dst_slice)); - GB_ASSERT(slice_type->kind == Type_Slice); - Type *elem_type = slice_type->Slice.elem; - i64 size_of_elem = type_size_of(proc->module->allocator, elem_type); - irValue *dst = ir_emit_conv(proc, ir_slice_elem(proc, dst_slice), t_rawptr); - irValue *src = ir_emit_conv(proc, ir_slice_elem(proc, src_slice), t_rawptr); - - irValue *len_dst = ir_slice_count(proc, dst_slice); - irValue *len_src = ir_slice_count(proc, src_slice); - - irValue *cond = ir_emit_comp(proc, Token_Lt, len_dst, len_src); - irValue *len = ir_emit_select(proc, cond, len_dst, len_src); - - irValue *elem_size = ir_const_int(proc->module->allocator, size_of_elem); - irValue *byte_count = ir_emit_arith(proc, Token_Mul, len, elem_size, t_int); - - irValue **args = gb_alloc_array(proc->module->allocator, irValue *, 3); - args[0] = dst; - args[1] = src; - args[2] = byte_count; - - ir_emit_global_call(proc, "__mem_copy", args, 3); - - return len; - } break; case BuiltinProc_swizzle: { ir_emit_comment(proc, str_lit("swizzle.begin")); irAddr vector_addr = ir_build_addr(proc, ce->args[0]); @@ -4288,6 +4258,7 @@ irValue *ir_build_builtin_proc(irProcedure *proc, AstNode *expr, TypeAndValue tv return ir_emit_load(proc, res); } break; + #if 1 case BuiltinProc_slice_ptr: { ir_emit_comment(proc, str_lit("slice_ptr")); irValue *ptr = ir_build_expr(proc, ce->args[0]); @@ -4323,6 +4294,7 @@ irValue *ir_build_builtin_proc(irProcedure *proc, AstNode *expr, TypeAndValue tv ir_fill_slice(proc, slice, ptr, count, capacity); return ir_emit_load(proc, slice); } break; + #endif case BuiltinProc_expand_to_tuple: { ir_emit_comment(proc, str_lit("expand_to_tuple")); @@ -4924,7 +4896,10 @@ irAddr ir_build_addr_from_entity(irProcedure *proc, Entity *e, AstNode *expr) { } if (v == NULL) { - GB_PANIC("Unknown value: %.*s, entity: %p %.*s\n", LIT(e->token.string), e, LIT(entity_strings[e->kind])); + error(expr, "%.*s Unknown value: %.*s, entity: %p %.*s", + LIT(proc->name), + LIT(e->token.string), e, LIT(entity_strings[e->kind])); + GB_PANIC("Unknown value"); } return ir_addr(v); @@ -4937,7 +4912,6 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) { switch (i->kind) { case Token_context: v = ir_find_or_generate_context_ptr(proc); - // v = ir_find_global_variable(proc, str_lit("__context")); break; } @@ -4950,7 +4924,9 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) { irAddr val = {}; return val; } + String name = i->token.string; Entity *e = entity_of_ident(proc->module->info, expr); + // GB_ASSERT(name == e->token.string); return ir_build_addr_from_entity(proc, e, expr); case_end; @@ -7093,7 +7069,6 @@ void ir_build_proc(irValue *value, irProcedure *parent) { proc->module->stmt_state_flags = out; } - ir_begin_procedure_body(proc); ir_insert_code_before_proc(proc, parent); ir_build_stmt(proc, proc->body); @@ -7423,12 +7398,14 @@ void ir_gen_tree(irGen *s) { continue; } - if (map_get(&m->min_dep_map, hash_pointer(e)) == NULL) { + if (map_get(&m->min_dep_map, hash_entity(e)) == NULL) { // NOTE(bill): Nothing depends upon it so doesn't need to be built continue; } - if (!scope->is_global || is_type_poly_proc(e->type)) { + String original_name = name; + + if (!scope->is_global || is_type_polymorphic(e->type)) { if (e->kind == Entity_Procedure && (e->Procedure.tags & ProcTag_export) != 0) { } else if (e->kind == Entity_Procedure && e->Procedure.link_name.len > 0) { // Handle later @@ -7436,8 +7413,14 @@ void ir_gen_tree(irGen *s) { } else { name = ir_mangle_name(s, e->token.pos.file, e); } + } else if (check_is_entity_overloaded(e)) { + name = ir_mangle_name(s, e->token.pos.file, e); + + gb_printf_err("%.*s|%.*s :: %s\n", LIT(original_name), LIT(name), type_to_string(e->type)); + } - map_set(&m->entity_names, hash_pointer(e), name); + + map_set(&m->entity_names, hash_entity(e), name); switch (e->kind) { case Entity_TypeName: diff --git a/src/ir_print.cpp b/src/ir_print.cpp index b9bccc91c..36b0c9855 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -732,7 +732,8 @@ void ir_print_value(irFileBuffer *f, irModule *m, irValue *value, Type *type_hin ir_print_encoded_local(f, value->TypeName.name); break; case irValue_Global: { - Scope *scope = value->Global.entity->scope; + Entity *e = value->Global.entity; + Scope *scope = e->scope; bool in_global_scope = false; if (scope != NULL) { // TODO(bill): Fix this rule. What should it be? diff --git a/src/types.cpp b/src/types.cpp index d49dd6a86..8d7466a32 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -1354,15 +1354,14 @@ ProcTypeOverloadKind are_proc_types_overload_safe(Type *x, Type *y) { TypeProc py = base_type(y)->Proc; - if (px.is_polymorphic != py.is_polymorphic) { - return ProcOverload_Polymorphic; - } - - // if (px.calling_convention != py.calling_convention) { // return ProcOverload_CallingConvention; // } + // if (px.is_polymorphic != py.is_polymorphic) { + // return ProcOverload_Polymorphic; + // } + if (px.param_count != py.param_count) { return ProcOverload_ParamCount; } @@ -1379,6 +1378,11 @@ ProcTypeOverloadKind are_proc_types_overload_safe(Type *x, Type *y) { return ProcOverload_ParamVariadic; } + + if (px.is_polymorphic != py.is_polymorphic) { + return ProcOverload_Polymorphic; + } + if (px.result_count != py.result_count) { return ProcOverload_ResultCount; } @@ -2448,12 +2452,12 @@ gbString write_type_to_string(gbString str, Type *type) { } } else { GB_ASSERT(var->kind == Entity_TypeName); - #if 0 - str = gb_string_appendc(str, "type/"); - str = write_type_to_string(str, var->type); - #else - str = gb_string_appendc(str, "type"); - #endif + if (var->type->kind == Type_Generic) { + str = gb_string_appendc(str, "type/"); + str = write_type_to_string(str, var->type); + } else { + str = gb_string_appendc(str, "type"); + } } } }