Browse Source

Allow for default arguments after a variadic parameter

gingerBill 7 years ago
parent
commit
5ce6555721
6 changed files with 278 additions and 181 deletions
  1. 76 76
      core/_preload.odin
  2. 18 3
      src/check_expr.cpp
  3. 32 13
      src/check_type.cpp
  4. 100 50
      src/ir.cpp
  5. 50 38
      src/parser.cpp
  6. 2 1
      src/types.cpp

+ 76 - 76
core/_preload.odin

@@ -144,7 +144,7 @@ __argv__: ^^u8;
 
 
 Source_Code_Location :: struct #ordered {
 Source_Code_Location :: struct #ordered {
 	file_path:    string,
 	file_path:    string,
-	line, column: i64,
+	line, column: int,
 	procedure:    string,
 	procedure:    string,
 }
 }
 
 
@@ -259,7 +259,7 @@ foreign __llvm_core {
 
 
 
 
 
 
-make_source_code_location :: inline proc "contextless" (file: string, line, column: i64, procedure: string) -> Source_Code_Location {
+make_source_code_location :: inline proc "contextless" (file: string, line, column: int, procedure: string) -> Source_Code_Location {
 	return Source_Code_Location{file, line, column, procedure};
 	return Source_Code_Location{file, line, column, procedure};
 }
 }
 
 
@@ -296,28 +296,28 @@ __check_context :: proc() {
 }
 }
 */
 */
 
 
-alloc :: inline proc(size: int, alignment: int = DEFAULT_ALIGNMENT, location := #caller_location) -> rawptr {
+alloc :: inline proc(size: int, alignment: int = DEFAULT_ALIGNMENT, loc := #caller_location) -> rawptr {
 	a := context.allocator;
 	a := context.allocator;
-	return a.procedure(a.data, Allocator_Mode.Alloc, size, alignment, nil, 0, 0, location);
+	return a.procedure(a.data, Allocator_Mode.Alloc, size, alignment, nil, 0, 0, loc);
 }
 }
 
 
-free_ptr_with_allocator :: inline proc(a: Allocator, ptr: rawptr, location := #caller_location) {
+free_ptr_with_allocator :: inline proc(a: Allocator, ptr: rawptr, loc := #caller_location) {
 	if ptr == nil do return;
 	if ptr == nil do return;
 	if a.procedure == nil do return;
 	if a.procedure == nil do return;
-	a.procedure(a.data, Allocator_Mode.Free, 0, 0, ptr, 0, 0, location);
+	a.procedure(a.data, Allocator_Mode.Free, 0, 0, ptr, 0, 0, loc);
 }
 }
 
 
-free_ptr :: inline proc(ptr: rawptr, location := #caller_location) do free_ptr_with_allocator(context.allocator, ptr);
+free_ptr :: inline proc(ptr: rawptr, loc := #caller_location) do free_ptr_with_allocator(context.allocator, ptr);
 
 
-free_all :: inline proc(location := #caller_location) {
+free_all :: inline proc(loc := #caller_location) {
 	a := context.allocator;
 	a := context.allocator;
-	a.procedure(a.data, Allocator_Mode.FreeAll, 0, 0, nil, 0, 0, location);
+	a.procedure(a.data, Allocator_Mode.FreeAll, 0, 0, nil, 0, 0, loc);
 }
 }
 
 
 
 
-resize :: inline proc(ptr: rawptr, old_size, new_size: int, alignment: int = DEFAULT_ALIGNMENT, location := #caller_location) -> rawptr {
+resize :: inline proc(ptr: rawptr, old_size, new_size: int, alignment: int = DEFAULT_ALIGNMENT, loc := #caller_location) -> rawptr {
 	a := context.allocator;
 	a := context.allocator;
-	return a.procedure(a.data, Allocator_Mode.Resize, new_size, alignment, ptr, old_size, 0, location);
+	return a.procedure(a.data, Allocator_Mode.Resize, new_size, alignment, ptr, old_size, 0, loc);
 }
 }
 
 
 
 
@@ -345,7 +345,7 @@ append :: proc "contextless" (array: ^$T/[]$E, args: ...E) -> int {
 	return len(array);
 	return len(array);
 }
 }
 
 
-append :: proc(array: ^$T/[dynamic]$E, args: ...E) -> int {
+append :: proc(array: ^$T/[dynamic]$E, args: ...E, loc := #caller_location) -> int {
 	if array == nil do return 0;
 	if array == nil do return 0;
 
 
 	arg_len := len(args);
 	arg_len := len(args);
@@ -355,7 +355,7 @@ append :: proc(array: ^$T/[dynamic]$E, args: ...E) -> int {
 	ok := true;
 	ok := true;
 	if cap(array) <= len(array)+arg_len {
 	if cap(array) <= len(array)+arg_len {
 		cap := 2 * cap(array) + max(8, arg_len);
 		cap := 2 * cap(array) + max(8, arg_len);
-		ok = reserve(array, cap);
+		ok = reserve(array, cap, loc);
 	}
 	}
 	// TODO(bill): Better error handling for failed reservation
 	// TODO(bill): Better error handling for failed reservation
 	if ok {
 	if ok {
@@ -370,13 +370,13 @@ append :: proc(array: ^$T/[dynamic]$E, args: ...E) -> int {
 
 
 append :: proc(array: ^$T/[]u8, args: ...string) -> int {
 append :: proc(array: ^$T/[]u8, args: ...string) -> int {
 	for arg in args {
 	for arg in args {
-		append(array, ...cast([]u8)arg);
+		append(array, ...cast(T)arg);
 	}
 	}
 	return len(array);
 	return len(array);
 }
 }
-append :: proc(array: ^$T/[dynamic]u8, args: ...string) -> int {
+append :: proc(array: ^$T/[dynamic]$E/u8, args: ...string, loc := #caller_location) -> int {
 	for arg in args {
 	for arg in args {
-		append(array, ...cast([]u8)arg);
+		append(array = array, args = cast([]E)arg, loc = loc);
 	}
 	}
 	return len(array);
 	return len(array);
 }
 }
@@ -412,7 +412,7 @@ clear :: inline proc "contextless" (m: ^$T/map[$K]$V) {
 	entries.len = 0;
 	entries.len = 0;
 }
 }
 
 
-reserve :: proc(array: ^$T/[dynamic]$E, capacity: int, location := #caller_location) -> bool {
+reserve :: proc(array: ^$T/[dynamic]$E, capacity: int, loc := #caller_location) -> bool {
 	if array == nil do return false;
 	if array == nil do return false;
 	a := cast(^raw.Dynamic_Array)array;
 	a := cast(^raw.Dynamic_Array)array;
 
 
@@ -429,7 +429,7 @@ reserve :: proc(array: ^$T/[dynamic]$E, capacity: int, location := #caller_locat
 
 
 	new_data := allocator.procedure(
 	new_data := allocator.procedure(
 		allocator.data, Allocator_Mode.Resize, new_size, align_of(E),
 		allocator.data, Allocator_Mode.Resize, new_size, align_of(E),
-		a.data, old_size, 0, location,
+		a.data, old_size, 0, loc,
 	);
 	);
 	if new_data == nil do return false;
 	if new_data == nil do return false;
 
 
@@ -499,39 +499,39 @@ delete :: proc(m: ^$T/map[$K]$V, key: K) {
 
 
 
 
 
 
-new  :: inline proc(T: type, location := #caller_location) -> ^T {
-	ptr := cast(^T)alloc(size_of(T), align_of(T), location);
+new  :: inline proc(T: type, loc := #caller_location) -> ^T {
+	ptr := cast(^T)alloc(size_of(T), align_of(T), loc);
 	ptr^ = T{};
 	ptr^ = T{};
 	return ptr;
 	return ptr;
 }
 }
-new_clone :: inline proc(data: $T, location := #caller_location) -> ^T {
-	ptr := cast(^T)alloc(size_of(T), align_of(T), location);
+new_clone :: inline proc(data: $T, loc := #caller_location) -> ^T {
+	ptr := cast(^T)alloc(size_of(T), align_of(T), loc);
 	ptr^ = data;
 	ptr^ = data;
 	return ptr;
 	return ptr;
 }
 }
 
 
-free :: proc(ptr: rawptr, location := #caller_location) {
-	free_ptr(ptr, location);
+free :: proc(ptr: rawptr, loc := #caller_location) {
+	free_ptr(ptr, loc);
 }
 }
-free :: proc(str: $T/string, location := #caller_location) {
-	free_ptr((^raw.String)(&str).data, location);
+free :: proc(str: $T/string, loc := #caller_location) {
+	free_ptr((^raw.String)(&str).data, loc);
 }
 }
-free :: proc(array: $T/[dynamic]$E, location := #caller_location) {
-	free_ptr((^raw.Dynamic_Array)(&array).data, location);
+free :: proc(array: $T/[dynamic]$E, loc := #caller_location) {
+	free_ptr((^raw.Dynamic_Array)(&array).data, loc);
 }
 }
-free :: proc(slice: $T/[]$E, location := #caller_location) {
-	free_ptr((^raw.Slice)(&slice).data, location);
+free :: proc(slice: $T/[]$E, loc := #caller_location) {
+	free_ptr((^raw.Slice)(&slice).data, loc);
 }
 }
-free :: proc(m: $T/map[$K]$V, location := #caller_location) {
+free :: proc(m: $T/map[$K]$V, loc := #caller_location) {
 	raw := cast(^raw.Map)&m;
 	raw := cast(^raw.Map)&m;
-	free(raw.hashes, location);
-	free(raw.entries.data, location);
+	free(raw.hashes, loc);
+	free(raw.entries.data, loc);
 }
 }
 
 
 // NOTE(bill): This code works but I will prefer having `make` a built-in procedure
 // NOTE(bill): This code works but I will prefer having `make` a built-in procedure
 // to have better error messages
 // to have better error messages
 /*
 /*
-make :: proc(T: type/[]$E, len: int, using location := #caller_location) -> T {
+make :: proc(T: type/[]$E, len: int, using loc := #caller_location) -> T {
 	cap := len;
 	cap := len;
 	__slice_expr_error(file_path, int(line), int(column), 0, len, cap);
 	__slice_expr_error(file_path, int(line), int(column), 0, len, cap);
 	data := cast(^E)alloc(len * size_of(E), align_of(E));
 	data := cast(^E)alloc(len * size_of(E), align_of(E));
@@ -539,14 +539,14 @@ make :: proc(T: type/[]$E, len: int, using location := #caller_location) -> T {
 	s := raw.Slice{data = data, len = len, cap = len};
 	s := raw.Slice{data = data, len = len, cap = len};
 	return (cast(^T)&s)^;
 	return (cast(^T)&s)^;
 }
 }
-make :: proc(T: type/[]$E, len, cap: int, using location := #caller_location) -> T {
+make :: proc(T: type/[]$E, len, cap: int, using loc := #caller_location) -> T {
 	__slice_expr_error(file_path, int(line), int(column), 0, len, cap);
 	__slice_expr_error(file_path, int(line), int(column), 0, len, cap);
 	data := cast(^E)alloc(len * size_of(E), align_of(E));
 	data := cast(^E)alloc(len * size_of(E), align_of(E));
 	for i in 0..len do (data+i)^ = E{};
 	for i in 0..len do (data+i)^ = E{};
 	s := raw.Slice{data = data, len = len, cap = len};
 	s := raw.Slice{data = data, len = len, cap = len};
 	return (cast(^T)&s)^;
 	return (cast(^T)&s)^;
 }
 }
-make :: proc(T: type/[dynamic]$E, len: int = 8, using location := #caller_location) -> T {
+make :: proc(T: type/[dynamic]$E, len: int = 8, using loc := #caller_location) -> T {
 	cap := len;
 	cap := len;
 	__slice_expr_error(file_path, int(line), int(column), 0, len, cap);
 	__slice_expr_error(file_path, int(line), int(column), 0, len, cap);
 	data := cast(^E)alloc(cap * size_of(E), align_of(E));
 	data := cast(^E)alloc(cap * size_of(E), align_of(E));
@@ -554,7 +554,7 @@ make :: proc(T: type/[dynamic]$E, len: int = 8, using location := #caller_locati
 	s := raw.Dynamic_Array{data = data, len = len, cap = cap, allocator = context.allocator};
 	s := raw.Dynamic_Array{data = data, len = len, cap = cap, allocator = context.allocator};
 	return (cast(^T)&s)^;
 	return (cast(^T)&s)^;
 }
 }
-make :: proc(T: type/[dynamic]$E, len, cap: int, using location := #caller_location) -> T {
+make :: proc(T: type/[dynamic]$E, len, cap: int, using loc := #caller_location) -> T {
 	__slice_expr_error(file_path, int(line), int(column), 0, len, cap);
 	__slice_expr_error(file_path, int(line), int(column), 0, len, cap);
 	data := cast(^E)alloc(cap * size_of(E), align_of(E));
 	data := cast(^E)alloc(cap * size_of(E), align_of(E));
 	for i in 0..len do (data+i)^ = E{};
 	for i in 0..len do (data+i)^ = E{};
@@ -562,7 +562,7 @@ make :: proc(T: type/[dynamic]$E, len, cap: int, using location := #caller_locat
 	return (cast(^T)&s)^;
 	return (cast(^T)&s)^;
 }
 }
 
 
-make :: proc(T: type/map[$K]$V, cap: int = 16, using location := #caller_location) -> T {
+make :: proc(T: type/map[$K]$V, cap: int = 16, using loc := #caller_location) -> T {
 	if cap < 0 do cap = 16;
 	if cap < 0 do cap = 16;
 
 
 	m: T;
 	m: T;
@@ -574,28 +574,28 @@ make :: proc(T: type/map[$K]$V, cap: int = 16, using location := #caller_locatio
 
 
 
 
 
 
-default_resize_align :: proc(old_memory: rawptr, old_size, new_size, alignment: int, location := #caller_location) -> rawptr {
-	if old_memory == nil do return alloc(new_size, alignment, location);
+default_resize_align :: proc(old_memory: rawptr, old_size, new_size, alignment: int, loc := #caller_location) -> rawptr {
+	if old_memory == nil do return alloc(new_size, alignment, loc);
 
 
 	if new_size == 0 {
 	if new_size == 0 {
-		free(old_memory, location);
+		free(old_memory, loc);
 		return nil;
 		return nil;
 	}
 	}
 
 
 	if new_size == old_size do return old_memory;
 	if new_size == old_size do return old_memory;
 
 
-	new_memory := alloc(new_size, alignment, location);
+	new_memory := alloc(new_size, alignment, loc);
 	if new_memory == nil do return nil;
 	if new_memory == nil do return nil;
 
 
 	__mem_copy(new_memory, old_memory, min(old_size, new_size));;
 	__mem_copy(new_memory, old_memory, min(old_size, new_size));;
-	free(old_memory, location);
+	free(old_memory, loc);
 	return new_memory;
 	return new_memory;
 }
 }
 
 
 
 
 default_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
 default_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
                                size, alignment: int,
                                size, alignment: int,
-                               old_memory: rawptr, old_size: int, flags: u64, location := #caller_location) -> rawptr {
+                               old_memory: rawptr, old_size: int, flags: u64, loc := #caller_location) -> rawptr {
 	using Allocator_Mode;
 	using Allocator_Mode;
 
 
 	switch mode {
 	switch mode {
@@ -626,7 +626,7 @@ default_allocator :: proc() -> Allocator {
 }
 }
 
 
 
 
-assert :: proc "contextless" (condition: bool, message := "", using location := #caller_location) -> bool {
+assert :: proc "contextless" (condition: bool, message := "", using loc := #caller_location) -> bool {
 	if !condition {
 	if !condition {
 		if len(message) > 0 {
 		if len(message) > 0 {
 			fmt.fprintf(os.stderr, "%s(%d:%d) Runtime assertion: %s\n", file_path, line, column, message);
 			fmt.fprintf(os.stderr, "%s(%d:%d) Runtime assertion: %s\n", file_path, line, column, message);
@@ -638,7 +638,7 @@ assert :: proc "contextless" (condition: bool, message := "", using location :=
 	return condition;
 	return condition;
 }
 }
 
 
-panic :: proc "contextless" (message := "", using location := #caller_location) {
+panic :: proc "contextless" (message := "", using loc := #caller_location) {
 	if len(message) > 0 {
 	if len(message) > 0 {
 		fmt.fprintf(os.stderr, "%s(%d:%d) Panic: %s\n", file_path, line, column, message);
 		fmt.fprintf(os.stderr, "%s(%d:%d) Panic: %s\n", file_path, line, column, message);
 	} else {
 	} else {
@@ -800,18 +800,18 @@ __abs_complex128 :: inline proc "contextless" (x: complex128) -> f64 {
 
 
 
 
 
 
-__dynamic_array_make :: proc(array_: rawptr, elem_size, elem_align: int, len, cap: int) {
+__dynamic_array_make :: proc(array_: rawptr, elem_size, elem_align: int, len, cap: int, loc := #caller_location) {
 	array := cast(^raw.Dynamic_Array)array_;
 	array := cast(^raw.Dynamic_Array)array_;
 	array.allocator = context.allocator;
 	array.allocator = context.allocator;
 	assert(array.allocator.procedure != nil);
 	assert(array.allocator.procedure != nil);
 
 
 	if cap > 0 {
 	if cap > 0 {
-		__dynamic_array_reserve(array_, elem_size, elem_align, cap);
+		__dynamic_array_reserve(array_, elem_size, elem_align, cap, loc);
 		array.len = len;
 		array.len = len;
 	}
 	}
 }
 }
 
 
-__dynamic_array_reserve :: proc(array_: rawptr, elem_size, elem_align: int, cap: int) -> bool {
+__dynamic_array_reserve :: proc(array_: rawptr, elem_size, elem_align: int, cap: int, loc := #caller_location) -> bool {
 	array := cast(^raw.Dynamic_Array)array_;
 	array := cast(^raw.Dynamic_Array)array_;
 
 
 	if cap <= array.cap do return true;
 	if cap <= array.cap do return true;
@@ -825,7 +825,7 @@ __dynamic_array_reserve :: proc(array_: rawptr, elem_size, elem_align: int, cap:
 	new_size  := cap * elem_size;
 	new_size  := cap * elem_size;
 	allocator := array.allocator;
 	allocator := array.allocator;
 
 
-	new_data := allocator.procedure(allocator.data, Allocator_Mode.Resize, new_size, elem_align, array.data, old_size, 0);
+	new_data := allocator.procedure(allocator.data, Allocator_Mode.Resize, new_size, elem_align, array.data, old_size, 0, loc);
 	if new_data == nil do return false;
 	if new_data == nil do return false;
 
 
 	array.data = new_data;
 	array.data = new_data;
@@ -833,17 +833,17 @@ __dynamic_array_reserve :: proc(array_: rawptr, elem_size, elem_align: int, cap:
 	return true;
 	return true;
 }
 }
 
 
-__dynamic_array_resize :: proc(array_: rawptr, elem_size, elem_align: int, len: int) -> bool {
+__dynamic_array_resize :: proc(array_: rawptr, elem_size, elem_align: int, len: int, loc := #caller_location) -> bool {
 	array := cast(^raw.Dynamic_Array)array_;
 	array := cast(^raw.Dynamic_Array)array_;
 
 
-	ok := __dynamic_array_reserve(array_, elem_size, elem_align, len);
+	ok := __dynamic_array_reserve(array_, elem_size, elem_align, len, loc);
 	if ok do array.len = len;
 	if ok do array.len = len;
 	return ok;
 	return ok;
 }
 }
 
 
 
 
 __dynamic_array_append :: proc(array_: rawptr, elem_size, elem_align: int,
 __dynamic_array_append :: proc(array_: rawptr, elem_size, elem_align: int,
-                               items: rawptr, item_count: int) -> int {
+                               items: rawptr, item_count: int, loc := #caller_location) -> int {
 	array := cast(^raw.Dynamic_Array)array_;
 	array := cast(^raw.Dynamic_Array)array_;
 
 
 	if items == nil    do return 0;
 	if items == nil    do return 0;
@@ -853,7 +853,7 @@ __dynamic_array_append :: proc(array_: rawptr, elem_size, elem_align: int,
 	ok := true;
 	ok := true;
 	if array.cap <= array.len+item_count {
 	if array.cap <= array.len+item_count {
 		cap := 2 * array.cap + max(8, item_count);
 		cap := 2 * array.cap + max(8, item_count);
-		ok = __dynamic_array_reserve(array, elem_size, elem_align, cap);
+		ok = __dynamic_array_reserve(array, elem_size, elem_align, cap, loc);
 	}
 	}
 	// TODO(bill): Better error handling for failed reservation
 	// TODO(bill): Better error handling for failed reservation
 	if !ok do return array.len;
 	if !ok do return array.len;
@@ -865,13 +865,13 @@ __dynamic_array_append :: proc(array_: rawptr, elem_size, elem_align: int,
 	return array.len;
 	return array.len;
 }
 }
 
 
-__dynamic_array_append_nothing :: proc(array_: rawptr, elem_size, elem_align: int) -> int {
+__dynamic_array_append_nothing :: proc(array_: rawptr, elem_size, elem_align: int, loc := #caller_location) -> int {
 	array := cast(^raw.Dynamic_Array)array_;
 	array := cast(^raw.Dynamic_Array)array_;
 
 
 	ok := true;
 	ok := true;
 	if array.cap <= array.len+1 {
 	if array.cap <= array.len+1 {
 		cap := 2 * array.cap + max(8, 1);
 		cap := 2 * array.cap + max(8, 1);
-		ok = __dynamic_array_reserve(array, elem_size, elem_align, cap);
+		ok = __dynamic_array_reserve(array, elem_size, elem_align, cap, loc);
 	}
 	}
 	// TODO(bill): Better error handling for failed reservation
 	// TODO(bill): Better error handling for failed reservation
 	if !ok do return array.len;
 	if !ok do return array.len;
@@ -897,12 +897,12 @@ __default_hash :: proc(data: []u8) -> u128 {
 }
 }
 __default_hash_string :: proc(s: string) -> u128 do return __default_hash(cast([]u8)s);
 __default_hash_string :: proc(s: string) -> u128 do return __default_hash(cast([]u8)s);
 
 
-__dynamic_map_reserve :: proc(using header: __Map_Header, cap: int)  {
-	__dynamic_array_reserve(&m.hashes, size_of(int), align_of(int), cap);
-	__dynamic_array_reserve(&m.entries, entry_size, entry_align,    cap);
+__dynamic_map_reserve :: proc(using header: __Map_Header, cap: int, loc := #caller_location)  {
+	__dynamic_array_reserve(&m.hashes, size_of(int), align_of(int), cap, loc);
+	__dynamic_array_reserve(&m.entries, entry_size, entry_align,    cap, loc);
 }
 }
 
 
-__dynamic_map_rehash :: proc(using header: __Map_Header, new_count: int) {
+__dynamic_map_rehash :: proc(using header: __Map_Header, new_count: int, loc := #caller_location) {
 	new_header: __Map_Header = header;
 	new_header: __Map_Header = header;
 	nm: raw.Map;
 	nm: raw.Map;
 	new_header.m = &nm;
 	new_header.m = &nm;
@@ -910,18 +910,18 @@ __dynamic_map_rehash :: proc(using header: __Map_Header, new_count: int) {
 	header_hashes := cast(^raw.Dynamic_Array)&header.m.hashes;
 	header_hashes := cast(^raw.Dynamic_Array)&header.m.hashes;
 	nm_hashes     := cast(^raw.Dynamic_Array)&nm.hashes;
 	nm_hashes     := cast(^raw.Dynamic_Array)&nm.hashes;
 
 
-	__dynamic_array_resize(nm_hashes, size_of(int), align_of(int), new_count);
-	__dynamic_array_reserve(&nm.entries, entry_size, entry_align, m.entries.len);
+	__dynamic_array_resize(nm_hashes, size_of(int), align_of(int), new_count, loc);
+	__dynamic_array_reserve(&nm.entries, entry_size, entry_align, m.entries.len, loc);
 	for i in 0..new_count do nm.hashes[i] = -1;
 	for i in 0..new_count do nm.hashes[i] = -1;
 
 
 	for i in 0..m.entries.len {
 	for i in 0..m.entries.len {
-		if len(nm.hashes) == 0 do __dynamic_map_grow(new_header);
+		if len(nm.hashes) == 0 do __dynamic_map_grow(new_header, loc);
 
 
 		entry_header := __dynamic_map_get_entry(header, i);
 		entry_header := __dynamic_map_get_entry(header, i);
 		data := cast(^u8)entry_header;
 		data := cast(^u8)entry_header;
 
 
 		fr := __dynamic_map_find(new_header, entry_header.key);
 		fr := __dynamic_map_find(new_header, entry_header.key);
-		j := __dynamic_map_add_entry(new_header, entry_header.key);
+		j := __dynamic_map_add_entry(new_header, entry_header.key, loc);
 		if fr.entry_prev < 0 {
 		if fr.entry_prev < 0 {
 			nm.hashes[fr.hash_index] = j;
 			nm.hashes[fr.hash_index] = j;
 		} else {
 		} else {
@@ -934,10 +934,10 @@ __dynamic_map_rehash :: proc(using header: __Map_Header, new_count: int) {
 		ndata := cast(^u8)e;
 		ndata := cast(^u8)e;
 		__mem_copy(ndata+value_offset, data+value_offset, value_size);
 		__mem_copy(ndata+value_offset, data+value_offset, value_size);
 
 
-		if __dynamic_map_full(new_header) do __dynamic_map_grow(new_header);
+		if __dynamic_map_full(new_header) do __dynamic_map_grow(new_header, loc);
 	}
 	}
-	free_ptr_with_allocator(header_hashes.allocator, header_hashes.data);
-	free_ptr_with_allocator(header.m.entries.allocator, header.m.entries.data);
+	free_ptr_with_allocator(header_hashes.allocator, header_hashes.data, loc);
+	free_ptr_with_allocator(header.m.entries.allocator, header.m.entries.data, loc);
 	header.m^ = nm;
 	header.m^ = nm;
 }
 }
 
 
@@ -950,20 +950,20 @@ __dynamic_map_get :: proc(h: __Map_Header, key: __Map_Key) -> rawptr {
 	return nil;
 	return nil;
 }
 }
 
 
-__dynamic_map_set :: proc(using h: __Map_Header, key: __Map_Key, value: rawptr) {
+__dynamic_map_set :: proc(using h: __Map_Header, key: __Map_Key, value: rawptr, loc := #caller_location) {
 	index: int;
 	index: int;
 	assert(value != nil);
 	assert(value != nil);
 
 
 	if len(m.hashes) == 0 {
 	if len(m.hashes) == 0 {
-		__dynamic_map_reserve(h, __INITIAL_MAP_CAP);
-		__dynamic_map_grow(h);
+		__dynamic_map_reserve(h, __INITIAL_MAP_CAP, loc);
+		__dynamic_map_grow(h, loc);
 	}
 	}
 
 
 	fr := __dynamic_map_find(h, key);
 	fr := __dynamic_map_find(h, key);
 	if fr.entry_index >= 0 {
 	if fr.entry_index >= 0 {
 		index = fr.entry_index;
 		index = fr.entry_index;
 	} else {
 	} else {
-		index = __dynamic_map_add_entry(h, key);
+		index = __dynamic_map_add_entry(h, key, loc);
 		if fr.entry_prev >= 0 {
 		if fr.entry_prev >= 0 {
 			entry := __dynamic_map_get_entry(h, fr.entry_prev);
 			entry := __dynamic_map_get_entry(h, fr.entry_prev);
 			entry.next = index;
 			entry.next = index;
@@ -979,14 +979,14 @@ __dynamic_map_set :: proc(using h: __Map_Header, key: __Map_Key, value: rawptr)
 	}
 	}
 
 
 	if __dynamic_map_full(h) {
 	if __dynamic_map_full(h) {
-		__dynamic_map_grow(h);
+		__dynamic_map_grow(h, loc);
 	}
 	}
 }
 }
 
 
 
 
-__dynamic_map_grow :: proc(using h: __Map_Header) {
+__dynamic_map_grow :: proc(using h: __Map_Header, loc := #caller_location) {
 	new_count := max(2*m.entries.cap + 8, __INITIAL_MAP_CAP);
 	new_count := max(2*m.entries.cap + 8, __INITIAL_MAP_CAP);
-	__dynamic_map_rehash(h, new_count);
+	__dynamic_map_rehash(h, new_count, loc);
 }
 }
 
 
 __dynamic_map_full :: inline proc(using h: __Map_Header) -> bool {
 __dynamic_map_full :: inline proc(using h: __Map_Header) -> bool {
@@ -1017,9 +1017,9 @@ __dynamic_map_find :: proc(using h: __Map_Header, key: __Map_Key) -> __Map_Find_
 	return fr;
 	return fr;
 }
 }
 
 
-__dynamic_map_add_entry :: proc(using h: __Map_Header, key: __Map_Key) -> int {
+__dynamic_map_add_entry :: proc(using h: __Map_Header, key: __Map_Key, loc := #caller_location) -> int {
 	prev := m.entries.len;
 	prev := m.entries.len;
-	c := __dynamic_array_append_nothing(&m.entries, entry_size, entry_align);
+	c := __dynamic_array_append_nothing(&m.entries, entry_size, entry_align, loc);
 	if c != prev {
 	if c != prev {
 		end := __dynamic_map_get_entry(h, c-1);
 		end := __dynamic_map_get_entry(h, c-1);
 		end.key = key;
 		end.key = key;

+ 18 - 3
src/check_expr.cpp

@@ -4156,6 +4156,22 @@ CALL_ARGUMENT_CHECKER(check_call_arguments_internal) {
 
 
 		param_count = param_tuple->variables.count;
 		param_count = param_tuple->variables.count;
 		if (variadic) {
 		if (variadic) {
+			for (isize i = param_count-1; i >= 0; i--) {
+				Entity *e = param_tuple->variables[i];
+				if (e->kind == Entity_TypeName) {
+					break;
+				}
+
+				if (e->kind == Entity_Variable) {
+					if (e->Variable.default_value.kind != ExactValue_Invalid ||
+					    e->Variable.default_is_nil ||
+					    e->Variable.default_is_location) {
+						param_count--;
+						continue;
+					}
+				}
+				break;
+			}
 			param_count--;
 			param_count--;
 		}
 		}
 	}
 	}
@@ -4262,9 +4278,8 @@ CALL_ARGUMENT_CHECKER(check_call_arguments_internal) {
 
 
 					continue;
 					continue;
 				}
 				}
-				if (variadic) {
-					o = operands[operand_index];
-				}
+
+
 				i64 s = 0;
 				i64 s = 0;
 				if (!check_is_assignable_to_with_score(c, &o, t, &s)) {
 				if (!check_is_assignable_to_with_score(c, &o, t, &s)) {
 					if (show_error) {
 					if (show_error) {

+ 32 - 13
src/check_type.cpp

@@ -1210,7 +1210,7 @@ Type *determine_type_from_polymorphic(Checker *c, Type *poly_type, Operand opera
 }
 }
 
 
 
 
-Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_variadic_, bool *success_, isize *specialization_count_, Array<Operand> *operands) {
+Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_variadic_, isize *variadic_index_, bool *success_, isize *specialization_count_, Array<Operand> *operands) {
 	if (_params == nullptr) {
 	if (_params == nullptr) {
 		return nullptr;
 		return nullptr;
 	}
 	}
@@ -1250,6 +1250,7 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
 
 
 
 
 	bool is_variadic = false;
 	bool is_variadic = false;
+	isize variadic_index = -1;
 	bool is_c_vararg = false;
 	bool is_c_vararg = false;
 	Array<Entity *> variables = {};
 	Array<Entity *> variables = {};
 	array_init(&variables, c->allocator, variable_count);
 	array_init(&variables, c->allocator, variable_count);
@@ -1270,7 +1271,7 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
 		bool detemine_type_from_operand = false;
 		bool detemine_type_from_operand = false;
 		Type *specialization = nullptr;
 		Type *specialization = nullptr;
 
 
-		bool is_using = (p->flags&FieldFlag_using) != 0;
+		bool is_using          = (p->flags&FieldFlag_using) != 0;
 		bool is_constant_value = (p->flags&FieldFlag_const) != 0;
 		bool is_constant_value = (p->flags&FieldFlag_const) != 0;
 
 
 
 
@@ -1304,6 +1305,7 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
 							add_entity_use(c, e->identifier, e);
 							add_entity_use(c, e->identifier, e);
 						} else {
 						} else {
 							error(default_value, "Default parameter must be a constant");
 							error(default_value, "Default parameter must be a constant");
+							continue;
 						}
 						}
 					}
 					}
 				} else {
 				} else {
@@ -1315,12 +1317,21 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
 		} else {
 		} else {
 			if (type_expr->kind == AstNode_Ellipsis) {
 			if (type_expr->kind == AstNode_Ellipsis) {
 				type_expr = type_expr->Ellipsis.expr;
 				type_expr = type_expr->Ellipsis.expr;
+				#if 1
+					is_variadic = true;
+					variadic_index = variables.count;
+					if (p->names.count != 1) {
+						error(param, "Invalid AST: Invalid variadic parameter with multiple names");
+						success = false;
+					}
+				#else
 				if (i+1 == params.count) {
 				if (i+1 == params.count) {
 					is_variadic = true;
 					is_variadic = true;
 				} else {
 				} else {
 					error(param, "Invalid AST: Invalid variadic parameter");
 					error(param, "Invalid AST: Invalid variadic parameter");
 					success = false;
 					success = false;
 				}
 				}
+				#endif
 			}
 			}
 			if (type_expr->kind == AstNode_TypeType) {
 			if (type_expr->kind == AstNode_TypeType) {
 				ast_node(tt, TypeType, type_expr);
 				ast_node(tt, TypeType, type_expr);
@@ -1360,8 +1371,10 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
 			if (default_value != nullptr) {
 			if (default_value != nullptr) {
 				if (type_expr->kind == AstNode_TypeType) {
 				if (type_expr->kind == AstNode_TypeType) {
 					error(default_value, "A type parameter may not have a default value");
 					error(default_value, "A type parameter may not have a default value");
+					continue;
 				} else if (is_constant_value) {
 				} else if (is_constant_value) {
 					error(default_value, "A constant parameter may not have a default value");
 					error(default_value, "A constant parameter may not have a default value");
+					continue;
 				} else {
 				} else {
 					Operand o = {};
 					Operand o = {};
 					if (default_value->kind == AstNode_BasicDirective &&
 					if (default_value->kind == AstNode_BasicDirective &&
@@ -1404,23 +1417,22 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
 					check_is_assignable_to(c, &o, type);
 					check_is_assignable_to(c, &o, type);
 				}
 				}
 			}
 			}
-
 		}
 		}
 		if (type == nullptr) {
 		if (type == nullptr) {
-			error(params[i], "Invalid parameter type");
+			error(param, "Invalid parameter type");
 			type = t_invalid;
 			type = t_invalid;
 		}
 		}
 		if (is_type_untyped(type)) {
 		if (is_type_untyped(type)) {
 			if (is_type_untyped_undef(type)) {
 			if (is_type_untyped_undef(type)) {
-				error(params[i], "Cannot determine parameter type from ---");
+				error(param, "Cannot determine parameter type from ---");
 			} else {
 			} else {
-				error(params[i], "Cannot determine parameter type from a nil");
+				error(param, "Cannot determine parameter type from a nil");
 			}
 			}
 			type = t_invalid;
 			type = t_invalid;
 		}
 		}
 		if (is_type_empty_union(type)) {
 		if (is_type_empty_union(type)) {
 			gbString str = type_to_string(type);
 			gbString str = type_to_string(type);
-			error(params[i], "Invalid use of an empty union `%s`", str);
+			error(param, "Invalid use of an empty union `%s`", str);
 			gb_string_free(str);
 			gb_string_free(str);
 			type = t_invalid;
 			type = t_invalid;
 		}
 		}
@@ -1429,7 +1441,7 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
 		if (p->flags&FieldFlag_c_vararg) {
 		if (p->flags&FieldFlag_c_vararg) {
 			if (p->type == nullptr ||
 			if (p->type == nullptr ||
 			    p->type->kind != AstNode_Ellipsis) {
 			    p->type->kind != AstNode_Ellipsis) {
-				error(params[i], "`#c_vararg` can only be applied to variadic type fields");
+				error(param, "`#c_vararg` can only be applied to variadic type fields");
 				p->flags &= ~FieldFlag_c_vararg; // Remove the flag
 				p->flags &= ~FieldFlag_c_vararg; // Remove the flag
 			} else {
 			} else {
 				is_c_vararg = true;
 				is_c_vararg = true;
@@ -1438,10 +1450,10 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
 
 
 		if (is_constant_value) {
 		if (is_constant_value) {
 			if (is_type_param) {
 			if (is_type_param) {
-				error(p->type, "`$` is not needed for a `type` parameter");
+				error(param, "`$` is not needed for a `type` parameter");
 			}
 			}
 			if (p->flags&FieldFlag_no_alias) {
 			if (p->flags&FieldFlag_no_alias) {
-				error(p->type, "`#no_alias` can only be applied to variable fields of pointer type");
+				error(param, "`#no_alias` can only be applied to variable fields of pointer type");
 				p->flags &= ~FieldFlag_no_alias; // Remove the flag
 				p->flags &= ~FieldFlag_no_alias; // Remove the flag
 			}
 			}
 
 
@@ -1505,7 +1517,7 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
 
 
 				if (p->flags&FieldFlag_no_alias) {
 				if (p->flags&FieldFlag_no_alias) {
 					if (!is_type_pointer(type)) {
 					if (!is_type_pointer(type)) {
-						error(params[i], "`#no_alias` can only be applied to fields of pointer type");
+						error(name, "`#no_alias` can only be applied to fields of pointer type");
 						p->flags &= ~FieldFlag_no_alias; // Remove the flag
 						p->flags &= ~FieldFlag_no_alias; // Remove the flag
 					}
 					}
 				}
 				}
@@ -1549,11 +1561,15 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
 	}
 	}
 
 
 
 
+	if (is_variadic) {
+		GB_ASSERT(variadic_index >= 0);
+	}
+
 	if (is_variadic) {
 	if (is_variadic) {
 		GB_ASSERT(params.count > 0);
 		GB_ASSERT(params.count > 0);
 		// NOTE(bill): Change last variadic parameter to be a slice
 		// NOTE(bill): Change last variadic parameter to be a slice
 		// Custom Calling convention for variadic parameters
 		// Custom Calling convention for variadic parameters
-		Entity *end = variables[variable_count-1];
+		Entity *end = variables[variadic_index];
 		end->type = make_type_slice(c->allocator, end->type);
 		end->type = make_type_slice(c->allocator, end->type);
 		end->flags |= EntityFlag_Ellipsis;
 		end->flags |= EntityFlag_Ellipsis;
 		if (is_c_vararg) {
 		if (is_c_vararg) {
@@ -1581,6 +1597,7 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
 	if (success_) *success_ = success;
 	if (success_) *success_ = success;
 	if (specialization_count_) *specialization_count_ = specialization_count;
 	if (specialization_count_) *specialization_count_ = specialization_count;
 	if (is_variadic_) *is_variadic_ = is_variadic;
 	if (is_variadic_) *is_variadic_ = is_variadic;
+	if (variadic_index_) *variadic_index_ = variadic_index;
 
 
 	return tuple;
 	return tuple;
 }
 }
@@ -1904,9 +1921,10 @@ bool check_procedure_type(Checker *c, Type *type, AstNode *proc_type_node, Array
 	}
 	}
 
 
 	bool variadic = false;
 	bool variadic = false;
+	isize variadic_index = -1;
 	bool success = true;
 	bool success = true;
 	isize specialization_count = 0;
 	isize specialization_count = 0;
-	Type *params  = check_get_params(c, c->context.scope, pt->params, &variadic, &success, &specialization_count, operands);
+	Type *params  = check_get_params(c, c->context.scope, pt->params, &variadic, &variadic_index, &success, &specialization_count, operands);
 	Type *results = check_get_results(c, c->context.scope, pt->results);
 	Type *results = check_get_results(c, c->context.scope, pt->results);
 
 
 
 
@@ -1941,6 +1959,7 @@ bool check_procedure_type(Checker *c, Type *type, AstNode *proc_type_node, Array
 	type->Proc.results              = results;
 	type->Proc.results              = results;
 	type->Proc.result_count         = cast(i32)result_count;
 	type->Proc.result_count         = cast(i32)result_count;
 	type->Proc.variadic             = variadic;
 	type->Proc.variadic             = variadic;
+	type->Proc.variadic_index       = variadic_index;
 	type->Proc.calling_convention   = cc;
 	type->Proc.calling_convention   = cc;
 	type->Proc.is_polymorphic       = pt->generic;
 	type->Proc.is_polymorphic       = pt->generic;
 	type->Proc.specialization_count = specialization_count;
 	type->Proc.specialization_count = specialization_count;

+ 100 - 50
src/ir.cpp

@@ -1821,6 +1821,11 @@ Type *ir_addr_type(irAddr addr) {
 	return type_deref(t);
 	return type_deref(t);
 }
 }
 
 
+irValue *ir_emit_source_code_location(irProcedure *proc, String procedure, TokenPos pos);
+irValue *ir_emit_source_code_location(irProcedure *proc, AstNode *node);
+irValue *ir_emit_ptr_offset(irProcedure *proc, irValue *ptr, irValue *offset);
+irValue *ir_emit_arith(irProcedure *proc, TokenKind op, irValue *left, irValue *right, Type *type);
+
 irValue *ir_insert_dynamic_map_key_and_value(irProcedure *proc, irValue *addr, Type *map_type,
 irValue *ir_insert_dynamic_map_key_and_value(irProcedure *proc, irValue *addr, Type *map_type,
                                              irValue *map_key, irValue *map_value) {
                                              irValue *map_key, irValue *map_value) {
 	map_type = base_type(map_type);
 	map_type = base_type(map_type);
@@ -1832,17 +1837,15 @@ irValue *ir_insert_dynamic_map_key_and_value(irProcedure *proc, irValue *addr, T
 	irValue *ptr = ir_add_local_generated(proc, ir_type(v));
 	irValue *ptr = ir_add_local_generated(proc, ir_type(v));
 	ir_emit_store(proc, ptr, v);
 	ir_emit_store(proc, ptr, v);
 
 
-	irValue **args = gb_alloc_array(proc->module->allocator, irValue *, 3);
+	irValue **args = gb_alloc_array(proc->module->allocator, irValue *, 4);
 	args[0] = h;
 	args[0] = h;
 	args[1] = key;
 	args[1] = key;
 	args[2] = ir_emit_conv(proc, ptr, t_rawptr);
 	args[2] = ir_emit_conv(proc, ptr, t_rawptr);
-
-	return ir_emit_global_call(proc, "__dynamic_map_set", args, 3);
+	args[3] = ir_emit_source_code_location(proc, nullptr);
+	return ir_emit_global_call(proc, "__dynamic_map_set", args, 4);
 }
 }
 
 
 
 
-irValue *ir_emit_ptr_offset(irProcedure *proc, irValue *ptr, irValue *offset);
-irValue *ir_emit_arith(irProcedure *proc, TokenKind op, irValue *left, irValue *right, Type *type);
 
 
 irValue *ir_addr_store(irProcedure *proc, irAddr addr, irValue *value) {
 irValue *ir_addr_store(irProcedure *proc, irAddr addr, irValue *value) {
 	if (addr.addr == nullptr) {
 	if (addr.addr == nullptr) {
@@ -3943,12 +3946,25 @@ irValue *ir_emit_source_code_location(irProcedure *proc, String procedure, Token
 	gbAllocator a = proc->module->allocator;
 	gbAllocator a = proc->module->allocator;
 	irValue **args = gb_alloc_array(a, irValue *, 4);
 	irValue **args = gb_alloc_array(a, irValue *, 4);
 	args[0] = ir_find_or_add_entity_string(proc->module, pos.file);
 	args[0] = ir_find_or_add_entity_string(proc->module, pos.file);
-	args[1] = ir_const_i64(a, pos.line);
-	args[2] = ir_const_i64(a, pos.column);
+	args[1] = ir_const_int(a, pos.line);
+	args[2] = ir_const_int(a, pos.column);
 	args[3] = ir_find_or_add_entity_string(proc->module, procedure);
 	args[3] = ir_find_or_add_entity_string(proc->module, procedure);
 	return ir_emit_global_call(proc, "make_source_code_location", args, 4);
 	return ir_emit_global_call(proc, "make_source_code_location", args, 4);
 }
 }
 
 
+
+irValue *ir_emit_source_code_location(irProcedure *proc, AstNode *node) {
+	String proc_name = {};
+	if (proc->entity) {
+		proc_name = proc->entity->token.string;
+	}
+	TokenPos pos = {};
+	if (node) {
+		pos = ast_node_token(node).pos;
+	}
+	return ir_emit_source_code_location(proc, proc_name, pos);
+}
+
 void ir_emit_increment(irProcedure *proc, irValue *addr) {
 void ir_emit_increment(irProcedure *proc, irValue *addr) {
 	GB_ASSERT(is_type_pointer(ir_type(addr)));
 	GB_ASSERT(is_type_pointer(ir_type(addr)));
 	Type *type = type_deref(ir_type(addr));
 	Type *type = type_deref(ir_type(addr));
@@ -4182,10 +4198,11 @@ irValue *ir_build_builtin_proc(irProcedure *proc, AstNode *expr, TypeAndValue tv
 
 
 			irValue *map = ir_add_local_generated(proc, type);
 			irValue *map = ir_add_local_generated(proc, type);
 			irValue *header = ir_gen_map_header(proc, map, base_type(type));
 			irValue *header = ir_gen_map_header(proc, map, base_type(type));
-			irValue **args = gb_alloc_array(a, irValue *, 2);
+			irValue **args = gb_alloc_array(a, irValue *, 3);
 			args[0] = header;
 			args[0] = header;
 			args[1] = cap;
 			args[1] = cap;
-			ir_emit_global_call(proc, "__dynamic_map_reserve", args, 2);
+			args[2] = ir_emit_source_code_location(proc, ce->args[0]);
+			ir_emit_global_call(proc, "__dynamic_map_reserve", args, 3);
 
 
 			return ir_emit_load(proc, map);
 			return ir_emit_load(proc, map);
 		} else if (is_type_dynamic_array(type)) {
 		} else if (is_type_dynamic_array(type)) {
@@ -4202,13 +4219,14 @@ irValue *ir_build_builtin_proc(irProcedure *proc, AstNode *expr, TypeAndValue tv
 			ir_emit_slice_bounds_check(proc, ast_node_token(ce->args[0]), v_zero, len, cap, false);
 			ir_emit_slice_bounds_check(proc, ast_node_token(ce->args[0]), v_zero, len, cap, false);
 
 
 			irValue *array = ir_add_local_generated(proc, type);
 			irValue *array = ir_add_local_generated(proc, type);
-			irValue **args = gb_alloc_array(a, irValue *, 5);
+			irValue **args = gb_alloc_array(a, irValue *, 6);
 			args[0] = ir_emit_conv(proc, array, t_rawptr);
 			args[0] = ir_emit_conv(proc, array, t_rawptr);
 			args[1] = ir_const_int(a, type_size_of(a, elem_type));
 			args[1] = ir_const_int(a, type_size_of(a, elem_type));
 			args[2] = ir_const_int(a, type_align_of(a, elem_type));
 			args[2] = ir_const_int(a, type_align_of(a, elem_type));
 			args[3] = len;
 			args[3] = len;
 			args[4] = cap;
 			args[4] = cap;
-			ir_emit_global_call(proc, "__dynamic_array_make", args, 5);
+			args[5] = ir_emit_source_code_location(proc, ce->args[0]);
+			ir_emit_global_call(proc, "__dynamic_array_make", args, 6);
 
 
 			if (ir_type_has_default_values(elem_type)) {
 			if (ir_type_has_default_values(elem_type)) {
 				ir_init_data_with_defaults(proc, ir_dynamic_array_elem(proc, ir_emit_load(proc, array)), len);
 				ir_init_data_with_defaults(proc, ir_dynamic_array_elem(proc, ir_emit_load(proc, array)), len);
@@ -5006,10 +5024,10 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) {
 		GB_ASSERT(value != nullptr);
 		GB_ASSERT(value != nullptr);
 		Type *proc_type_ = base_type(ir_type(value));
 		Type *proc_type_ = base_type(ir_type(value));
 		GB_ASSERT(proc_type_->kind == Type_Proc);
 		GB_ASSERT(proc_type_->kind == Type_Proc);
-		TypeProc *type = &proc_type_->Proc;
+		TypeProc *pt = &proc_type_->Proc;
 
 
 		if (is_call_expr_field_value(ce)) {
 		if (is_call_expr_field_value(ce)) {
-			isize param_count = type->param_count;
+			isize param_count = pt->param_count;
 			irValue **args = gb_alloc_array(proc->module->allocator, irValue *, param_count);
 			irValue **args = gb_alloc_array(proc->module->allocator, irValue *, param_count);
 
 
 			for_array(arg_index, ce->args) {
 			for_array(arg_index, ce->args) {
@@ -5017,7 +5035,7 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) {
 				ast_node(fv, FieldValue, arg);
 				ast_node(fv, FieldValue, arg);
 				GB_ASSERT(fv->field->kind == AstNode_Ident);
 				GB_ASSERT(fv->field->kind == AstNode_Ident);
 				String name = fv->field->Ident.token.string;
 				String name = fv->field->Ident.token.string;
-				isize index = lookup_procedure_parameter(type, name);
+				isize index = lookup_procedure_parameter(pt, name);
 				GB_ASSERT(index >= 0);
 				GB_ASSERT(index >= 0);
 				TypeAndValue tav = type_and_value_of_expr(proc->module->info, fv->value);
 				TypeAndValue tav = type_and_value_of_expr(proc->module->info, fv->value);
 				if (tav.mode == Addressing_Type) {
 				if (tav.mode == Addressing_Type) {
@@ -5026,9 +5044,9 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) {
 					args[index] = ir_build_expr(proc, fv->value);
 					args[index] = ir_build_expr(proc, fv->value);
 				}
 				}
 			}
 			}
-			TypeTuple *pt = &type->params->Tuple;
+			TypeTuple *params = &pt->params->Tuple;
 			for (isize i = 0; i < param_count; i++) {
 			for (isize i = 0; i < param_count; i++) {
-				Entity *e = pt->variables[i];
+				Entity *e = params->variables[i];
 				if (e->kind == Entity_TypeName) {
 				if (e->kind == Entity_TypeName) {
 					args[i] = ir_value_nil(proc->module->allocator, e->type);
 					args[i] = ir_value_nil(proc->module->allocator, e->type);
 				} else if (e->kind == Entity_Constant) {
 				} else if (e->kind == Entity_Constant) {
@@ -5063,10 +5081,29 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) {
 			}
 			}
 		}
 		}
 
 
-		irValue **args = gb_alloc_array(proc->module->allocator, irValue *, gb_max(type->param_count, arg_count));
-		bool variadic = type->variadic;
+		i64 param_count = 0;
+		if (pt->params) {
+			GB_ASSERT(pt->params->kind == Type_Tuple);
+			param_count = pt->params->Tuple.variables.count;
+		}
+
+		irValue **args = gb_alloc_array(proc->module->allocator, irValue *, gb_max(param_count, arg_count));
+		isize variadic_index = pt->variadic_index;
+		bool variadic = pt->variadic && variadic_index >= 0;
 		bool vari_expand = ce->ellipsis.pos.line != 0;
 		bool vari_expand = ce->ellipsis.pos.line != 0;
-		bool is_c_vararg = type->c_vararg;
+		bool is_c_vararg = pt->c_vararg;
+
+		String proc_name = {};
+		if (proc->entity != nullptr) {
+			proc_name = proc->entity->token.string;
+		}
+		TokenPos pos = ast_node_token(ce->proc).pos;
+
+		TypeTuple *param_tuple = nullptr;
+		if (pt->params) {
+			GB_ASSERT(pt->params->kind == Type_Tuple);
+			param_tuple = &pt->params->Tuple;
+		}
 
 
 		for_array(i, ce->args) {
 		for_array(i, ce->args) {
 			AstNode *arg = ce->args[i];
 			AstNode *arg = ce->args[i];
@@ -5088,32 +5125,23 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) {
 			}
 			}
 		}
 		}
 
 
-		i64 param_count = type->param_count;
 
 
-		if (type->param_count > 0) {
-			GB_ASSERT_MSG(type->params != nullptr, "%s %td", expr_to_string(expr), type->param_count);
-			TypeTuple *pt = &type->params->Tuple;
-			param_count = type->param_count;
+		if (param_count > 0) {
+			GB_ASSERT_MSG(pt->params != nullptr, "%s %td", expr_to_string(expr), pt->param_count);
 			GB_ASSERT(param_count < 1000000);
 			GB_ASSERT(param_count < 1000000);
 
 
 			if (arg_count < param_count) {
 			if (arg_count < param_count) {
-				String procedure = {};
-				if (proc->entity != nullptr) {
-					procedure = proc->entity->token.string;
-				}
-				TokenPos pos = ast_node_token(ce->proc).pos;
-
 				isize end = param_count;
 				isize end = param_count;
 				if (variadic) {
 				if (variadic) {
-					end--;
+					end = variadic_index;
 				}
 				}
 				while (arg_index < end) {
 				while (arg_index < end) {
-					Entity *e = pt->variables[arg_index];
+					Entity *e = param_tuple->variables[arg_index];
 					GB_ASSERT(e->kind == Entity_Variable);
 					GB_ASSERT(e->kind == Entity_Variable);
 					if (e->Variable.default_value.kind != ExactValue_Invalid) {
 					if (e->Variable.default_value.kind != ExactValue_Invalid) {
 						args[arg_index++] = ir_value_constant(proc->module->allocator, e->type, e->Variable.default_value);
 						args[arg_index++] = ir_value_constant(proc->module->allocator, e->type, e->Variable.default_value);
 					} else if (e->Variable.default_is_location) {
 					} else if (e->Variable.default_is_location) {
-						args[arg_index++] = ir_emit_source_code_location(proc, procedure, pos);
+						args[arg_index++] = ir_emit_source_code_location(proc, proc_name, pos);
 					} else {
 					} else {
 						args[arg_index++] = ir_value_nil(proc->module->allocator, e->type);
 						args[arg_index++] = ir_value_nil(proc->module->allocator, e->type);
 					}
 					}
@@ -5124,13 +5152,13 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) {
 				GB_ASSERT(variadic);
 				GB_ASSERT(variadic);
 				GB_ASSERT(!vari_expand);
 				GB_ASSERT(!vari_expand);
 				isize i = 0;
 				isize i = 0;
-				for (; i < param_count-1; i++) {
-					Entity *e = pt->variables[i];
+				for (; i < variadic_index; i++) {
+					Entity *e = param_tuple->variables[i];
 					if (e->kind == Entity_Variable) {
 					if (e->kind == Entity_Variable) {
 						args[i] = ir_emit_conv(proc, args[i], e->type);
 						args[i] = ir_emit_conv(proc, args[i], e->type);
 					}
 					}
 				}
 				}
-				Type *variadic_type = pt->variables[i]->type;
+				Type *variadic_type = param_tuple->variables[i]->type;
 				GB_ASSERT(is_type_slice(variadic_type));
 				GB_ASSERT(is_type_slice(variadic_type));
 				variadic_type = base_type(variadic_type)->Slice.elem;
 				variadic_type = base_type(variadic_type)->Slice.elem;
 				if (!is_type_any(variadic_type)) {
 				if (!is_type_any(variadic_type)) {
@@ -5144,14 +5172,14 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) {
 				}
 				}
 			} else if (variadic) {
 			} else if (variadic) {
 				isize i = 0;
 				isize i = 0;
-				for (; i < param_count-1; i++) {
-					Entity *e = pt->variables[i];
+				for (; i < variadic_index; i++) {
+					Entity *e = param_tuple->variables[i];
 					if (e->kind == Entity_Variable) {
 					if (e->kind == Entity_Variable) {
 						args[i] = ir_emit_conv(proc, args[i], e->type);
 						args[i] = ir_emit_conv(proc, args[i], e->type);
 					}
 					}
 				}
 				}
 				if (!vari_expand) {
 				if (!vari_expand) {
-					Type *variadic_type = pt->variables[i]->type;
+					Type *variadic_type = param_tuple->variables[i]->type;
 					GB_ASSERT(is_type_slice(variadic_type));
 					GB_ASSERT(is_type_slice(variadic_type));
 					variadic_type = base_type(variadic_type)->Slice.elem;
 					variadic_type = base_type(variadic_type)->Slice.elem;
 					for (; i < arg_count; i++) {
 					for (; i < arg_count; i++) {
@@ -5160,7 +5188,7 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) {
 				}
 				}
 			} else {
 			} else {
 				for (i64 i = 0; i < param_count; i++) {
 				for (i64 i = 0; i < param_count; i++) {
-					Entity *e = pt->variables[i];
+					Entity *e = param_tuple->variables[i];
 					if (e->kind == Entity_Variable) {
 					if (e->kind == Entity_Variable) {
 						GB_ASSERT(args[i] != nullptr);
 						GB_ASSERT(args[i] != nullptr);
 						args[i] = ir_emit_conv(proc, args[i], e->type);
 						args[i] = ir_emit_conv(proc, args[i], e->type);
@@ -5171,15 +5199,15 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) {
 			if (variadic && !vari_expand && !is_c_vararg) {
 			if (variadic && !vari_expand && !is_c_vararg) {
 				ir_emit_comment(proc, str_lit("variadic call argument generation"));
 				ir_emit_comment(proc, str_lit("variadic call argument generation"));
 				gbAllocator allocator = proc->module->allocator;
 				gbAllocator allocator = proc->module->allocator;
-				Type *slice_type = pt->variables[param_count-1]->type;
+				Type *slice_type = param_tuple->variables[variadic_index]->type;
 				Type *elem_type  = base_type(slice_type)->Slice.elem;
 				Type *elem_type  = base_type(slice_type)->Slice.elem;
 				irValue *slice = ir_add_local_generated(proc, slice_type);
 				irValue *slice = ir_add_local_generated(proc, slice_type);
-				isize slice_len = arg_count+1 - param_count;
+				isize slice_len = arg_count+1 - (variadic_index+1);
 
 
 				if (slice_len > 0) {
 				if (slice_len > 0) {
 					irValue *base_array = ir_add_local_generated(proc, make_type_array(allocator, elem_type, slice_len));
 					irValue *base_array = ir_add_local_generated(proc, make_type_array(allocator, elem_type, slice_len));
 
 
-					for (isize i = param_count-1, j = 0; i < arg_count; i++, j++) {
+					for (isize i = variadic_index, j = 0; i < arg_count; i++, j++) {
 						irValue *addr = ir_emit_array_epi(proc, base_array, cast(i32)j);
 						irValue *addr = ir_emit_array_epi(proc, base_array, cast(i32)j);
 						ir_emit_store(proc, addr, args[i]);
 						ir_emit_store(proc, addr, args[i]);
 					}
 					}
@@ -5190,7 +5218,20 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) {
 				}
 				}
 
 
 				arg_count = param_count;
 				arg_count = param_count;
-				args[arg_count-1] = ir_emit_load(proc, slice);
+				args[variadic_index] = ir_emit_load(proc, slice);
+			}
+		}
+
+		if (variadic && variadic_index+1 < param_count) {
+			for (isize i = variadic_index+1; i < param_count; i++) {
+				Entity *e = param_tuple->variables[i];
+				if (e->Variable.default_value.kind != ExactValue_Invalid) {
+					args[i] = ir_value_constant(proc->module->allocator, e->type, e->Variable.default_value);
+				} else if (e->Variable.default_is_location) {
+					args[i] = ir_emit_source_code_location(proc, proc_name, pos);
+				} else {
+					args[i] = ir_value_nil(proc->module->allocator, e->type);
+				}
 			}
 			}
 		}
 		}
 
 
@@ -5695,6 +5736,12 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
 		case Type_Slice:  et = bt->Slice.elem;  break;
 		case Type_Slice:  et = bt->Slice.elem;  break;
 		}
 		}
 
 
+		String proc_name = {};
+		if (proc->entity) {
+			proc_name = proc->entity->token.string;
+		}
+		TokenPos pos = ast_node_token(expr).pos;
+
 		switch (bt->kind) {
 		switch (bt->kind) {
 		default: GB_PANIC("Unknown CompoundLit type: %s", type_to_string(type)); break;
 		default: GB_PANIC("Unknown CompoundLit type: %s", type_to_string(type)); break;
 
 
@@ -5776,10 +5823,11 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
 			}
 			}
 			gbAllocator a = proc->module->allocator;
 			gbAllocator a = proc->module->allocator;
 			{
 			{
-				irValue **args = gb_alloc_array(a, irValue *, 2);
+				irValue **args = gb_alloc_array(a, irValue *, 3);
 				args[0] = ir_gen_map_header(proc, v, type);
 				args[0] = ir_gen_map_header(proc, v, type);
 				args[1] = ir_const_int(a, 2*cl->elems.count);
 				args[1] = ir_const_int(a, 2*cl->elems.count);
-				ir_emit_global_call(proc, "__dynamic_map_reserve", args, 2);
+				args[2] = ir_emit_source_code_location(proc, proc_name, pos);
+				ir_emit_global_call(proc, "__dynamic_map_reserve", args, 3);
 			}
 			}
 			for_array(field_index, cl->elems) {
 			for_array(field_index, cl->elems) {
 				AstNode *elem = cl->elems[field_index];
 				AstNode *elem = cl->elems[field_index];
@@ -5801,12 +5849,13 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
 			irValue *size  = ir_const_int(a, type_size_of(a, elem));
 			irValue *size  = ir_const_int(a, type_size_of(a, elem));
 			irValue *align = ir_const_int(a, type_align_of(a, elem));
 			irValue *align = ir_const_int(a, type_align_of(a, elem));
 			{
 			{
-				irValue **args = gb_alloc_array(a, irValue *, 4);
+				irValue **args = gb_alloc_array(a, irValue *, 5);
 				args[0] = ir_emit_conv(proc, v, t_rawptr);
 				args[0] = ir_emit_conv(proc, v, t_rawptr);
 				args[1] = size;
 				args[1] = size;
 				args[2] = align;
 				args[2] = align;
 				args[3] = ir_const_int(a, 2*cl->elems.count);
 				args[3] = ir_const_int(a, 2*cl->elems.count);
-				ir_emit_global_call(proc, "__dynamic_array_reserve", args, 4);
+				args[4] = ir_emit_source_code_location(proc, proc_name, pos);
+				ir_emit_global_call(proc, "__dynamic_array_reserve", args, 5);
 			}
 			}
 
 
 			i64 item_count = cl->elems.count;
 			i64 item_count = cl->elems.count;
@@ -5820,13 +5869,14 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
 			}
 			}
 
 
 			{
 			{
-				irValue **args = gb_alloc_array(a, irValue *, 5);
+				irValue **args = gb_alloc_array(a, irValue *, 6);
 				args[0] = ir_emit_conv(proc, v, t_rawptr);
 				args[0] = ir_emit_conv(proc, v, t_rawptr);
 				args[1] = size;
 				args[1] = size;
 				args[2] = align;
 				args[2] = align;
 				args[3] = ir_emit_conv(proc, items, t_rawptr);
 				args[3] = ir_emit_conv(proc, items, t_rawptr);
 				args[4] = ir_const_int(a, item_count);
 				args[4] = ir_const_int(a, item_count);
-				ir_emit_global_call(proc, "__dynamic_array_append", args, 5);
+				args[5] = ir_emit_source_code_location(proc, proc_name, pos);
+				ir_emit_global_call(proc, "__dynamic_array_append", args, 6);
 			}
 			}
 			break;
 			break;
 		}
 		}

+ 50 - 38
src/parser.cpp

@@ -2616,8 +2616,7 @@ AstNode *parse_call_expr(AstFile *f, AstNode *operand) {
 		bool prefix_ellipsis = false;
 		bool prefix_ellipsis = false;
 		if (f->curr_token.kind == Token_Ellipsis) {
 		if (f->curr_token.kind == Token_Ellipsis) {
 			prefix_ellipsis = true;
 			prefix_ellipsis = true;
-			ellipsis = f->curr_token;
-			advance_token(f);
+			ellipsis = expect_token(f, Token_Ellipsis);
 		}
 		}
 
 
 		AstNode *arg = parse_expr(f, false);
 		AstNode *arg = parse_expr(f, false);
@@ -2627,10 +2626,6 @@ AstNode *parse_call_expr(AstFile *f, AstNode *operand) {
 			if (prefix_ellipsis) {
 			if (prefix_ellipsis) {
 				syntax_error(ellipsis, "`...` must be applied to value rather than the field name");
 				syntax_error(ellipsis, "`...` must be applied to value rather than the field name");
 			}
 			}
-			if (f->curr_token.kind == Token_Ellipsis) {
-				ellipsis = f->curr_token;
-				advance_token(f);
-			}
 
 
 			AstNode *value = parse_value(f);
 			AstNode *value = parse_value(f);
 			arg = ast_field_value(f, arg, value, eq);
 			arg = ast_field_value(f, arg, value, eq);
@@ -3339,12 +3334,13 @@ AstNode *parse_var_type(AstFile *f, bool allow_ellipsis, bool allow_type_token)
 
 
 
 
 enum FieldPrefixKind {
 enum FieldPrefixKind {
-	FieldPrefix_Invalid,
+	FieldPrefix_Unknown = -1,
+	FieldPrefix_Invalid = 0,
 
 
-	FieldPrefix_Using,
-	FieldPrefix_NoAlias,
-	FieldPrefix_CVarArg,
-	FieldPrefix_Const,
+	FieldPrefix_using,
+	FieldPrefix_no_alias,
+	FieldPrefix_c_var_arg,
+	FieldPrefix_const,
 };
 };
 
 
 FieldPrefixKind is_token_field_prefix(AstFile *f) {
 FieldPrefixKind is_token_field_prefix(AstFile *f) {
@@ -3353,23 +3349,22 @@ FieldPrefixKind is_token_field_prefix(AstFile *f) {
 		return FieldPrefix_Invalid;
 		return FieldPrefix_Invalid;
 
 
 	case Token_using:
 	case Token_using:
-		return FieldPrefix_Using;
-
+		return FieldPrefix_using;
 
 
-	case Token_Hash: {
+	case Token_Hash:
 		advance_token(f);
 		advance_token(f);
 		switch (f->curr_token.kind) {
 		switch (f->curr_token.kind) {
 		case Token_Ident:
 		case Token_Ident:
 			if (f->curr_token.string == "no_alias") {
 			if (f->curr_token.string == "no_alias") {
-				return FieldPrefix_NoAlias;
+				return FieldPrefix_no_alias;
 			} else if (f->curr_token.string == "c_vararg") {
 			} else if (f->curr_token.string == "c_vararg") {
-				return FieldPrefix_CVarArg;
+				return FieldPrefix_c_var_arg;
 			} else if (f->curr_token.string == "const") {
 			} else if (f->curr_token.string == "const") {
-				return FieldPrefix_Const;
+				return FieldPrefix_const;
 			}
 			}
 			break;
 			break;
 		}
 		}
-	} break;
+		return FieldPrefix_Unknown;
 	}
 	}
 	return FieldPrefix_Invalid;
 	return FieldPrefix_Invalid;
 }
 }
@@ -3386,24 +3381,30 @@ u32 parse_field_prefixes(AstFile *f) {
 		if (kind == FieldPrefix_Invalid) {
 		if (kind == FieldPrefix_Invalid) {
 			break;
 			break;
 		}
 		}
+		if (kind == FieldPrefix_Unknown) {
+			syntax_error(f->curr_token, "Unknown prefix kind `#%.*s`", LIT(f->curr_token.string));
+			advance_token(f);
+			continue;
+		}
+
 		switch (kind) {
 		switch (kind) {
-		case FieldPrefix_Using:   using_count    += 1; advance_token(f); break;
-		case FieldPrefix_NoAlias: no_alias_count += 1; advance_token(f); break;
-		case FieldPrefix_CVarArg: c_vararg_count += 1; advance_token(f); break;
-		case FieldPrefix_Const:   const_count += 1; advance_token(f); break;
+		case FieldPrefix_using:     using_count    += 1; advance_token(f); break;
+		case FieldPrefix_no_alias:  no_alias_count += 1; advance_token(f); break;
+		case FieldPrefix_c_var_arg: c_vararg_count += 1; advance_token(f); break;
+		case FieldPrefix_const:     const_count    += 1; advance_token(f); break;
 		}
 		}
 	}
 	}
 	if (using_count     > 1) syntax_error(f->curr_token, "Multiple `using` in this field list");
 	if (using_count     > 1) syntax_error(f->curr_token, "Multiple `using` in this field list");
 	if (no_alias_count  > 1) syntax_error(f->curr_token, "Multiple `#no_alias` in this field list");
 	if (no_alias_count  > 1) syntax_error(f->curr_token, "Multiple `#no_alias` in this field list");
 	if (c_vararg_count  > 1) syntax_error(f->curr_token, "Multiple `#c_vararg` in this field list");
 	if (c_vararg_count  > 1) syntax_error(f->curr_token, "Multiple `#c_vararg` in this field list");
-	if (const_count     > 1) syntax_error(f->curr_token, "Multiple `$` in this field list");
+	if (const_count     > 1) syntax_error(f->curr_token, "Multiple `#const` in this field list");
 
 
 
 
 	u32 field_flags = 0;
 	u32 field_flags = 0;
 	if (using_count     > 0) field_flags |= FieldFlag_using;
 	if (using_count     > 0) field_flags |= FieldFlag_using;
 	if (no_alias_count  > 0) field_flags |= FieldFlag_no_alias;
 	if (no_alias_count  > 0) field_flags |= FieldFlag_no_alias;
 	if (c_vararg_count  > 0) field_flags |= FieldFlag_c_vararg;
 	if (c_vararg_count  > 0) field_flags |= FieldFlag_c_vararg;
-	if (const_count  > 0)    field_flags |= FieldFlag_const;
+	if (const_count     > 0) field_flags |= FieldFlag_const;
 	return field_flags;
 	return field_flags;
 }
 }
 
 
@@ -3534,10 +3535,10 @@ AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, Tok
 		u32 flags = parse_field_prefixes(f);
 		u32 flags = parse_field_prefixes(f);
 		AstNode *param = parse_var_type(f, allow_ellipsis, allow_type_token);
 		AstNode *param = parse_var_type(f, allow_ellipsis, allow_type_token);
 		if (param->kind == AstNode_Ellipsis) {
 		if (param->kind == AstNode_Ellipsis) {
-			if (seen_ellipsis) syntax_error(param, "Extra variadic parameter");
+			if (seen_ellipsis) syntax_error(param, "Extra variadic parameter after ellipsis");
 			seen_ellipsis = true;
 			seen_ellipsis = true;
 		} else if (seen_ellipsis) {
 		} else if (seen_ellipsis) {
-			syntax_error(param, "Extra parameter have variadic parameters");
+			syntax_error(param, "Extra parameter after ellipsis");
 		}
 		}
 		AstNodeAndFlags naf = {param, flags};
 		AstNodeAndFlags naf = {param, flags};
 		array_add(&list, naf);
 		array_add(&list, naf);
@@ -3566,12 +3567,7 @@ AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, Tok
 		if (f->curr_token.kind != Token_Eq) {
 		if (f->curr_token.kind != Token_Eq) {
 			type = parse_var_type(f, allow_ellipsis, allow_type_token);
 			type = parse_var_type(f, allow_ellipsis, allow_type_token);
 		}
 		}
-		if (type != nullptr && type->kind == AstNode_Ellipsis) {
-			if (seen_ellipsis) syntax_error(type, "Extra variadic parameter");
-			seen_ellipsis = true;
-		} else if (seen_ellipsis) {
-			syntax_error(f->curr_token, "Extra variadic parameter");
-		}
+
 		if (allow_token(f, Token_Eq)) {
 		if (allow_token(f, Token_Eq)) {
 			// TODO(bill): Should this be true==lhs or false==rhs?
 			// TODO(bill): Should this be true==lhs or false==rhs?
 			default_value = parse_expr(f, false);
 			default_value = parse_expr(f, false);
@@ -3584,6 +3580,16 @@ AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, Tok
 			syntax_error(f->curr_token, "Default parameters can only be applied to single values");
 			syntax_error(f->curr_token, "Default parameters can only be applied to single values");
 		}
 		}
 
 
+		if (type != nullptr && type->kind == AstNode_Ellipsis) {
+			if (seen_ellipsis) syntax_error(type, "Extra variadic parameter after ellipsis");
+			seen_ellipsis = true;
+			if (names.count != 1) {
+				syntax_error(type, "Variadic parameters can only have one field name");
+			}
+		} else if (seen_ellipsis && default_value == nullptr) {
+			syntax_error(f->curr_token, "Extra parameter after ellipsis without a default value");
+		}
+
 		parse_expect_field_separator(f, type);
 		parse_expect_field_separator(f, type);
 		AstNode *param = ast_field(f, names, type, default_value, set_flags, docs, f->line_comment);
 		AstNode *param = ast_field(f, names, type, default_value, set_flags, docs, f->line_comment);
 		array_add(&params, param);
 		array_add(&params, param);
@@ -3608,12 +3614,7 @@ AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, Tok
 			if (f->curr_token.kind != Token_Eq) {
 			if (f->curr_token.kind != Token_Eq) {
 				type = parse_var_type(f, allow_ellipsis, allow_type_token);
 				type = parse_var_type(f, allow_ellipsis, allow_type_token);
 			}
 			}
-			if (type != nullptr && type->kind == AstNode_Ellipsis) {
-				if (seen_ellipsis) syntax_error(type, "Extra variadic parameter");
-				seen_ellipsis = true;
-			} else if (seen_ellipsis) {
-				syntax_error(f->curr_token, "Extra variadic parameter");
-			}
+
 			if (allow_token(f, Token_Eq)) {
 			if (allow_token(f, Token_Eq)) {
 				// TODO(bill): Should this be true==lhs or false==rhs?
 				// TODO(bill): Should this be true==lhs or false==rhs?
 				default_value = parse_expr(f, false);
 				default_value = parse_expr(f, false);
@@ -3626,6 +3627,17 @@ AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, Tok
 				syntax_error(f->curr_token, "Default parameters can only be applied to single values");
 				syntax_error(f->curr_token, "Default parameters can only be applied to single values");
 			}
 			}
 
 
+			if (type != nullptr && type->kind == AstNode_Ellipsis) {
+				if (seen_ellipsis) syntax_error(type, "Extra variadic parameter after ellipsis");
+				seen_ellipsis = true;
+				if (names.count != 1) {
+					syntax_error(type, "Variadic parameters can only have one field name");
+				}
+			} else if (seen_ellipsis && default_value == nullptr) {
+				syntax_error(f->curr_token, "Extra parameter after ellipsis without a default value");
+			}
+
+
 			bool ok = parse_expect_field_separator(f, param);
 			bool ok = parse_expect_field_separator(f, param);
 			AstNode *param = ast_field(f, names, type, default_value, set_flags, docs, f->line_comment);
 			AstNode *param = ast_field(f, names, type, default_value, set_flags, docs, f->line_comment);
 			array_add(&params, param);
 			array_add(&params, param);

+ 2 - 1
src/types.cpp

@@ -31,7 +31,7 @@ enum BasicKind {
 	Basic_uintptr,
 	Basic_uintptr,
 	Basic_rawptr,
 	Basic_rawptr,
 	Basic_string, // ^u8 + int
 	Basic_string, // ^u8 + int
-	Basic_any,    // ^Type_Info + rawptr
+	Basic_any,    // rawptr + ^Type_Info
 
 
 	Basic_UntypedBool,
 	Basic_UntypedBool,
 	Basic_UntypedInteger,
 	Basic_UntypedInteger,
@@ -153,6 +153,7 @@ struct TypeStruct {
 		Type *   abi_compat_result_type;                  \
 		Type *   abi_compat_result_type;                  \
 		bool     return_by_pointer;                       \
 		bool     return_by_pointer;                       \
 		bool     variadic;                                \
 		bool     variadic;                                \
+		i32      variadic_index;                          \
 		bool     require_results;                         \
 		bool     require_results;                         \
 		bool     c_vararg;                                \
 		bool     c_vararg;                                \
 		bool     is_polymorphic;                          \
 		bool     is_polymorphic;                          \