mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-06 07:38:48 +00:00
Fix polymorphic element types usage; Empty union as opaque type
This commit is contained in:
+6
-1
@@ -1,6 +1,11 @@
|
|||||||
import "fmt.odin";
|
import "fmt.odin";
|
||||||
|
import "strconv.odin";
|
||||||
|
|
||||||
|
Opaque :: union{};
|
||||||
|
|
||||||
main :: proc() {
|
main :: proc() {
|
||||||
fmt.println("Hellope!");
|
buf := make([]u8, 0, 10);
|
||||||
|
s := strconv.append_bool(buf, true);
|
||||||
|
fmt.println(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+13
-1
@@ -314,7 +314,6 @@ copy :: proc(dst, src: $T/[]$E) -> int #cc_contextless {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
append :: proc(array: ^$T/[]$E, args: ...E) -> int #cc_contextless {
|
append :: proc(array: ^$T/[]$E, args: ...E) -> int #cc_contextless {
|
||||||
if array == nil do return 0;
|
if array == nil do return 0;
|
||||||
|
|
||||||
@@ -356,6 +355,19 @@ append :: proc(array: ^$T/[dynamic]$E, args: ...E) -> int {
|
|||||||
return len(array);
|
return len(array);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
append :: proc(array: ^$T/[]u8, args: ...string) -> int {
|
||||||
|
for arg in args {
|
||||||
|
append(array, ...cast([]u8)arg);
|
||||||
|
}
|
||||||
|
return len(array);
|
||||||
|
}
|
||||||
|
append :: proc(array: ^$T/[dynamic]u8, args: ...string) -> int {
|
||||||
|
for arg in args {
|
||||||
|
append(array, ...cast([]u8)arg);
|
||||||
|
}
|
||||||
|
return len(array);
|
||||||
|
}
|
||||||
|
|
||||||
pop :: proc(array: ^$T/[]$E) -> E #cc_contextless {
|
pop :: proc(array: ^$T/[]$E) -> E #cc_contextless {
|
||||||
if array == nil do return E{};
|
if array == nil do return E{};
|
||||||
assert(len(array) > 0);
|
assert(len(array) > 0);
|
||||||
|
|||||||
+12
-5
@@ -186,7 +186,8 @@ write_type :: proc(buf: ^StringBuffer, ti: ^TypeInfo) {
|
|||||||
case ti == type_info_of(int): write_string(buf, "int");
|
case ti == type_info_of(int): write_string(buf, "int");
|
||||||
case ti == type_info_of(uint): write_string(buf, "uint");
|
case ti == type_info_of(uint): write_string(buf, "uint");
|
||||||
case:
|
case:
|
||||||
write_string(buf, info.signed ? "i" : "u");
|
if info.signed do write_byte(buf, 'i');
|
||||||
|
else do write_byte(buf, 'u');
|
||||||
write_int(buf, i64(8*ti.size), 10);
|
write_int(buf, i64(8*ti.size), 10);
|
||||||
}
|
}
|
||||||
case Rune:
|
case Rune:
|
||||||
@@ -424,7 +425,9 @@ fmt_bad_verb :: proc(using fi: ^FmtInfo, verb: rune) {
|
|||||||
fmt_bool :: proc(using fi: ^FmtInfo, b: bool, verb: rune) {
|
fmt_bool :: proc(using fi: ^FmtInfo, b: bool, verb: rune) {
|
||||||
match verb {
|
match verb {
|
||||||
case 't', 'v':
|
case 't', 'v':
|
||||||
write_string(buf, b ? "true" : "false");
|
s := "false";
|
||||||
|
if b do s = "true";
|
||||||
|
write_string(buf, s);
|
||||||
case:
|
case:
|
||||||
fmt_bad_verb(fi, verb);
|
fmt_bad_verb(fi, verb);
|
||||||
}
|
}
|
||||||
@@ -434,7 +437,8 @@ fmt_bool :: proc(using fi: ^FmtInfo, b: bool, verb: rune) {
|
|||||||
fmt_write_padding :: proc(fi: ^FmtInfo, width: int) {
|
fmt_write_padding :: proc(fi: ^FmtInfo, width: int) {
|
||||||
if width <= 0 do return;
|
if width <= 0 do return;
|
||||||
|
|
||||||
pad_byte: u8 = fi.space ? ' ' : '0';
|
pad_byte: u8 = '0';
|
||||||
|
if fi.space do pad_byte = ' ';
|
||||||
|
|
||||||
for _ in 0..width {
|
for _ in 0..width {
|
||||||
write_byte(fi.buf, pad_byte);
|
write_byte(fi.buf, pad_byte);
|
||||||
@@ -569,7 +573,8 @@ fmt_float :: proc(fi: ^FmtInfo, v: f64, bit_size: int, verb: rune) {
|
|||||||
// case 'f', 'F', 'v':
|
// case 'f', 'F', 'v':
|
||||||
|
|
||||||
case 'f', 'F', 'v':
|
case 'f', 'F', 'v':
|
||||||
prec: int = fi.prec_set ? fi.prec : 3;
|
prec: int = 3;
|
||||||
|
if fi.prec_set do prec = fi.prec;
|
||||||
buf: [386]u8;
|
buf: [386]u8;
|
||||||
|
|
||||||
str := strconv.append_float(buf[1..1], v, 'f', prec, bit_size);
|
str := strconv.append_float(buf[1..1], v, 'f', prec, bit_size);
|
||||||
@@ -617,7 +622,9 @@ fmt_string :: proc(fi: ^FmtInfo, s: string, verb: rune) {
|
|||||||
|
|
||||||
for i in 0..len(s) {
|
for i in 0..len(s) {
|
||||||
if i > 0 && space do write_byte(fi.buf, ' ');
|
if i > 0 && space do write_byte(fi.buf, ' ');
|
||||||
_fmt_int(fi, u128(s[i]), 16, false, 8, verb == 'x' ? __DIGITS_LOWER : __DIGITS_UPPER);
|
char_set := __DIGITS_UPPER;
|
||||||
|
if verb == 'x' do char_set = __DIGITS_LOWER;
|
||||||
|
_fmt_int(fi, u128(s[i]), 16, false, 8, char_set);
|
||||||
}
|
}
|
||||||
|
|
||||||
case:
|
case:
|
||||||
|
|||||||
+14
-11
@@ -54,8 +54,8 @@ unlerp :: proc(a, b, x: f32) -> (t: f32) do return (x-a)/(b-a);
|
|||||||
unlerp :: proc(a, b, x: f64) -> (t: f64) do return (x-a)/(b-a);
|
unlerp :: proc(a, b, x: f64) -> (t: f64) do return (x-a)/(b-a);
|
||||||
|
|
||||||
|
|
||||||
sign :: proc(x: f32) -> f32 do return x >= 0 ? +1 : -1;
|
sign :: proc(x: f32) -> f32 { if x >= 0 do return +1; return -1; }
|
||||||
sign :: proc(x: f64) -> f64 do return x >= 0 ? +1 : -1;
|
sign :: proc(x: f64) -> f64 { if x >= 0 do return +1; return -1; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -75,14 +75,14 @@ copy_sign :: proc(x, y: f64) -> f64 {
|
|||||||
return transmute(f64, ix);
|
return transmute(f64, ix);
|
||||||
}
|
}
|
||||||
|
|
||||||
round :: proc(x: f32) -> f32 do return x >= 0 ? floor(x + 0.5) : ceil(x - 0.5);
|
round :: proc(x: f32) -> f32 { if x >= 0 do return floor(x + 0.5); return ceil(x - 0.5); }
|
||||||
round :: proc(x: f64) -> f64 do return x >= 0 ? floor(x + 0.5) : ceil(x - 0.5);
|
round :: proc(x: f64) -> f64 { if x >= 0 do return floor(x + 0.5); return ceil(x - 0.5); }
|
||||||
|
|
||||||
floor :: proc(x: f32) -> f32 do return x >= 0 ? f32(i64(x)) : f32(i64(x-0.5)); // TODO: Get accurate versions
|
floor :: proc(x: f32) -> f32 { if x >= 0 do f32(i64(x)) return f32(i64(x-0.5)); } // TODO: Get accurate versions
|
||||||
floor :: proc(x: f64) -> f64 do return x >= 0 ? f64(i64(x)) : f64(i64(x-0.5)); // TODO: Get accurate versions
|
floor :: proc(x: f64) -> f64 { if x >= 0 do f64(i64(x)) return f64(i64(x-0.5)); } // TODO: Get accurate versions
|
||||||
|
|
||||||
ceil :: proc(x: f32) -> f32 do return x < 0 ? f32(i64(x)) : f32(i64(x+1)); // TODO: Get accurate versions
|
ceil :: proc(x: f32) -> f32 { if x < 0 do f32(i64(x)) return f32(i64(x+1)); }// TODO: Get accurate versions
|
||||||
ceil :: proc(x: f64) -> f64 do return x < 0 ? f64(i64(x)) : f64(i64(x+1)); // TODO: Get accurate versions
|
ceil :: proc(x: f64) -> f64 { if x < 0 do f64(i64(x)) return f64(i64(x+1)); }// TODO: Get accurate versions
|
||||||
|
|
||||||
remainder :: proc(x, y: f32) -> f32 do return x - round(x/y) * y;
|
remainder :: proc(x, y: f32) -> f32 do return x - round(x/y) * y;
|
||||||
remainder :: proc(x, y: f64) -> f64 do return x - round(x/y) * y;
|
remainder :: proc(x, y: f64) -> f64 do return x - round(x/y) * y;
|
||||||
@@ -133,17 +133,20 @@ norm :: proc(v: $T/[vector 4]$E) -> T do return v / mag(v);
|
|||||||
|
|
||||||
norm0 :: proc(v: $T/[vector 2]$E) -> T {
|
norm0 :: proc(v: $T/[vector 2]$E) -> T {
|
||||||
m := mag(v);
|
m := mag(v);
|
||||||
return m == 0 ? 0 : v/m;
|
if m == 0 do return 0;
|
||||||
|
return v/m;
|
||||||
}
|
}
|
||||||
|
|
||||||
norm0 :: proc(v: $T/[vector 3]$E) -> T {
|
norm0 :: proc(v: $T/[vector 3]$E) -> T {
|
||||||
m := mag(v);
|
m := mag(v);
|
||||||
return m == 0 ? 0 : v/m;
|
if m == 0 do return 0;
|
||||||
|
return v/m;
|
||||||
}
|
}
|
||||||
|
|
||||||
norm0 :: proc(v: $T/[vector 4]$E) -> T {
|
norm0 :: proc(v: $T/[vector 4]$E) -> T {
|
||||||
m := mag(v);
|
m := mag(v);
|
||||||
return m == 0 ? 0 : v/m;
|
if m == 0 do return 0;
|
||||||
|
return v/m;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+20
-24
@@ -67,7 +67,8 @@ parse_i128 :: proc(s: string) -> i128 {
|
|||||||
value += v;
|
value += v;
|
||||||
}
|
}
|
||||||
|
|
||||||
return neg ? -value : value;
|
if neg do return -value;
|
||||||
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
parse_u128 :: proc(s: string) -> u128 {
|
parse_u128 :: proc(s: string) -> u128 {
|
||||||
@@ -91,19 +92,15 @@ parse_u128 :: proc(s: string) -> u128 {
|
|||||||
|
|
||||||
value: u128;
|
value: u128;
|
||||||
for r in s {
|
for r in s {
|
||||||
if r == '_' {
|
if r == '_' do continue;
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
v := u128(_digit_value(r));
|
v := u128(_digit_value(r));
|
||||||
if v >= base {
|
if v >= base do break;
|
||||||
break;
|
|
||||||
}
|
|
||||||
value *= base;
|
value *= base;
|
||||||
value += u128(v);
|
value += u128(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
return neg ? -value : value;
|
if neg do return -value;
|
||||||
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -127,6 +124,7 @@ parse_f64 :: proc(s: string) -> f64 {
|
|||||||
for ; i < len(s); i += 1 {
|
for ; i < len(s); i += 1 {
|
||||||
r := rune(s[i]);
|
r := rune(s[i]);
|
||||||
if r == '_' do continue;
|
if r == '_' do continue;
|
||||||
|
|
||||||
v := _digit_value(r);
|
v := _digit_value(r);
|
||||||
if v >= 10 do break;
|
if v >= 10 do break;
|
||||||
value *= 10;
|
value *= 10;
|
||||||
@@ -139,13 +137,10 @@ parse_f64 :: proc(s: string) -> f64 {
|
|||||||
|
|
||||||
for ; i < len(s); i += 1 {
|
for ; i < len(s); i += 1 {
|
||||||
r := rune(s[i]);
|
r := rune(s[i]);
|
||||||
if r == '_' {
|
if r == '_' do continue;
|
||||||
continue;
|
|
||||||
}
|
|
||||||
v := _digit_value(r);
|
v := _digit_value(r);
|
||||||
if v >= 10 {
|
if v >= 10 do break;
|
||||||
break;
|
|
||||||
}
|
|
||||||
value += f64(v)/pow10;
|
value += f64(v)/pow10;
|
||||||
pow10 *= 10;
|
pow10 *= 10;
|
||||||
}
|
}
|
||||||
@@ -165,13 +160,10 @@ parse_f64 :: proc(s: string) -> f64 {
|
|||||||
exp: u32 = 0;
|
exp: u32 = 0;
|
||||||
for ; i < len(s); i += 1 {
|
for ; i < len(s); i += 1 {
|
||||||
r := rune(s[i]);
|
r := rune(s[i]);
|
||||||
if r == '_' {
|
if r == '_' do continue;
|
||||||
continue;
|
|
||||||
}
|
|
||||||
d := u32(_digit_value(r));
|
d := u32(_digit_value(r));
|
||||||
if d >= 10 {
|
if d >= 10 do break;
|
||||||
break;
|
|
||||||
}
|
|
||||||
exp = exp * 10 + d;
|
exp = exp * 10 + d;
|
||||||
}
|
}
|
||||||
if exp > 308 { exp = 308; }
|
if exp > 308 { exp = 308; }
|
||||||
@@ -181,13 +173,17 @@ parse_f64 :: proc(s: string) -> f64 {
|
|||||||
for exp > 0 { scale *= 10; exp -= 1; }
|
for exp > 0 { scale *= 10; exp -= 1; }
|
||||||
}
|
}
|
||||||
|
|
||||||
return sign * (frac ? (value/scale) : (value*scale));
|
if frac do return sign * (value/scale);
|
||||||
|
return sign * (value*scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
append_bool :: proc(buf: []u8, b: bool) -> string {
|
append_bool :: proc(buf: []u8, b: bool) -> string {
|
||||||
s := b ? "true" : "false";
|
if b {
|
||||||
append(&buf, ...cast([]u8)s);
|
append(&buf, "true");
|
||||||
|
} else {
|
||||||
|
append(&buf, "false");
|
||||||
|
}
|
||||||
return string(buf);
|
return string(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+6
-2
@@ -10,12 +10,16 @@ struct Array {
|
|||||||
isize capacity;
|
isize capacity;
|
||||||
|
|
||||||
T &operator[](isize index) {
|
T &operator[](isize index) {
|
||||||
GB_ASSERT_MSG(0 <= index && index < count, "Index %td is out of bounds ranges 0..<%td", index, count);
|
#if !defined(NO_ARRAY_BOUNDS_CHECK)
|
||||||
|
GB_ASSERT_MSG(0 <= index && index < count, "Index %td is out of bounds ranges 0..<%td", index, count);
|
||||||
|
#endif
|
||||||
return data[index];
|
return data[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
T const &operator[](isize index) const {
|
T const &operator[](isize index) const {
|
||||||
GB_ASSERT_MSG(0 <= index && index < count, "Index %td is out of bounds ranges 0..<%td", index, count);
|
#if !defined(NO_ARRAY_BOUNDS_CHECK)
|
||||||
|
GB_ASSERT_MSG(0 <= index && index < count, "Index %td is out of bounds ranges 0..<%td", index, count);
|
||||||
|
#endif
|
||||||
return data[index];
|
return data[index];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
+18
-5
@@ -65,6 +65,12 @@ Type *check_init_variable(Checker *c, Entity *e, Operand *operand, String contex
|
|||||||
error(e->token, "Invalid use of a polymorphic type `%s` in %.*s", str, LIT(context_name));
|
error(e->token, "Invalid use of a polymorphic type `%s` in %.*s", str, LIT(context_name));
|
||||||
e->type = t_invalid;
|
e->type = t_invalid;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
} else if (is_type_empty_union(t)) {
|
||||||
|
gbString str = type_to_string(t);
|
||||||
|
defer (gb_string_free(str));
|
||||||
|
error(e->token, "An empty union `%s` cannot be instantiated in %.*s", str, LIT(context_name));
|
||||||
|
e->type = t_invalid;
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
if (is_type_bit_field_value(t)) {
|
if (is_type_bit_field_value(t)) {
|
||||||
t = default_bit_field_value_type(t);
|
t = default_bit_field_value_type(t);
|
||||||
@@ -558,11 +564,18 @@ void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count
|
|||||||
if (type_expr != nullptr) {
|
if (type_expr != nullptr) {
|
||||||
e->type = check_type(c, type_expr);
|
e->type = check_type(c, type_expr);
|
||||||
}
|
}
|
||||||
if (e->type != nullptr && is_type_polymorphic(base_type(e->type))) {
|
if (e->type != nullptr) {
|
||||||
gbString str = type_to_string(e->type);
|
if (is_type_polymorphic(base_type(e->type))) {
|
||||||
defer (gb_string_free(str));
|
gbString str = type_to_string(e->type);
|
||||||
error(e->token, "Invalid use of a polymorphic type `%s` in %.*s", str, LIT(context_name));
|
defer (gb_string_free(str));
|
||||||
e->type = t_invalid;
|
error(e->token, "Invalid use of a polymorphic type `%s` in %.*s", str, LIT(context_name));
|
||||||
|
e->type = t_invalid;
|
||||||
|
} else if (is_type_empty_union(e->type)) {
|
||||||
|
gbString str = type_to_string(e->type);
|
||||||
|
defer (gb_string_free(str));
|
||||||
|
error(e->token, "An empty union `%s` cannot be instantiated in %.*s", str, LIT(context_name));
|
||||||
|
e->type = t_invalid;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+87
-72
@@ -149,8 +149,7 @@ bool check_is_assignable_to_using_subtype(Type *src, Type *dst) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool find_or_generate_polymorphic_procedure(Checker *c, Entity *base_entity, Type *type,
|
bool find_or_generate_polymorphic_procedure(Checker *c, Entity *base_entity, Type *type,
|
||||||
Array<Operand> *param_operands, PolyProcData *poly_proc_data,
|
Array<Operand> *param_operands, PolyProcData *poly_proc_data) {
|
||||||
bool check_later) {
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
// //
|
// //
|
||||||
// TODO CLEANUP(bill): This procedure is very messy and hacky. Clean this!!! //
|
// TODO CLEANUP(bill): This procedure is very messy and hacky. Clean this!!! //
|
||||||
@@ -223,7 +222,6 @@ bool find_or_generate_polymorphic_procedure(Checker *c, Entity *base_entity, Typ
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
CheckerContext prev_context = c->context;
|
CheckerContext prev_context = c->context;
|
||||||
defer (c->context = prev_context);
|
defer (c->context = prev_context);
|
||||||
|
|
||||||
@@ -238,6 +236,7 @@ bool find_or_generate_polymorphic_procedure(Checker *c, Entity *base_entity, Typ
|
|||||||
// c->context.no_polymorphic_errors = false;
|
// c->context.no_polymorphic_errors = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool generate_type_again = c->context.no_polymorphic_errors;
|
bool generate_type_again = c->context.no_polymorphic_errors;
|
||||||
|
|
||||||
auto *pt = &src->Proc;
|
auto *pt = &src->Proc;
|
||||||
@@ -251,6 +250,8 @@ bool find_or_generate_polymorphic_procedure(Checker *c, Entity *base_entity, Typ
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
auto *found_gen_procs = map_get(&c->info.gen_procs, hash_pointer(base_entity->identifier));
|
auto *found_gen_procs = map_get(&c->info.gen_procs, hash_pointer(base_entity->identifier));
|
||||||
if (found_gen_procs) {
|
if (found_gen_procs) {
|
||||||
auto procs = *found_gen_procs;
|
auto procs = *found_gen_procs;
|
||||||
@@ -269,7 +270,6 @@ bool find_or_generate_polymorphic_procedure(Checker *c, Entity *base_entity, Typ
|
|||||||
|
|
||||||
if (generate_type_again) {
|
if (generate_type_again) {
|
||||||
// LEAK TODO(bill): This is technically a memory leak as it has to generate the type twice
|
// 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;
|
bool prev_no_polymorphic_errors = c->context.no_polymorphic_errors;
|
||||||
defer (c->context.no_polymorphic_errors = prev_no_polymorphic_errors);
|
defer (c->context.no_polymorphic_errors = prev_no_polymorphic_errors);
|
||||||
c->context.no_polymorphic_errors = false;
|
c->context.no_polymorphic_errors = false;
|
||||||
@@ -283,6 +283,7 @@ bool find_or_generate_polymorphic_procedure(Checker *c, Entity *base_entity, Typ
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (found_gen_procs) {
|
if (found_gen_procs) {
|
||||||
auto procs = *found_gen_procs;
|
auto procs = *found_gen_procs;
|
||||||
for_array(i, procs) {
|
for_array(i, procs) {
|
||||||
@@ -298,9 +299,10 @@ bool find_or_generate_polymorphic_procedure(Checker *c, Entity *base_entity, Typ
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
AstNode *proc_lit = clone_ast_node(a, old_decl->proc_lit);
|
AstNode *proc_lit = clone_ast_node(a, old_decl->proc_lit);
|
||||||
ast_node(pl, ProcLit, proc_lit);
|
ast_node(pl, ProcLit, proc_lit);
|
||||||
// NOTE(bill): Associate the scope declared above with this procedure declaration's type
|
// NOTE(bill): Associate the scope declared above withinth this procedure declaration's type
|
||||||
add_scope(c, pl->type, final_proc_type->Proc.scope);
|
add_scope(c, pl->type, final_proc_type->Proc.scope);
|
||||||
final_proc_type->Proc.is_poly_specialized = true;
|
final_proc_type->Proc.is_poly_specialized = true;
|
||||||
final_proc_type->Proc.is_polymorphic = true;
|
final_proc_type->Proc.is_polymorphic = true;
|
||||||
@@ -350,16 +352,13 @@ bool find_or_generate_polymorphic_procedure(Checker *c, Entity *base_entity, Typ
|
|||||||
|
|
||||||
GB_ASSERT(entity != nullptr);
|
GB_ASSERT(entity != nullptr);
|
||||||
|
|
||||||
|
|
||||||
if (poly_proc_data) {
|
if (poly_proc_data) {
|
||||||
poly_proc_data->gen_entity = entity;
|
poly_proc_data->gen_entity = entity;
|
||||||
poly_proc_data->proc_info = proc_info;
|
poly_proc_data->proc_info = proc_info;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (check_later) {
|
// NOTE(bill): Check the newly generated procedure body
|
||||||
// NOTE(bill): Check the newly generated procedure body
|
check_procedure_later(c, proc_info);
|
||||||
check_procedure_later(c, proc_info);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -368,11 +367,11 @@ bool check_polymorphic_procedure_assignment(Checker *c, Operand *operand, Type *
|
|||||||
if (operand->expr == NULL) return false;
|
if (operand->expr == NULL) return false;
|
||||||
Entity *base_entity = entity_of_ident(&c->info, operand->expr);
|
Entity *base_entity = entity_of_ident(&c->info, operand->expr);
|
||||||
if (base_entity == nullptr) return false;
|
if (base_entity == nullptr) return false;
|
||||||
return find_or_generate_polymorphic_procedure(c, base_entity, type, nullptr, poly_proc_data, true);
|
return find_or_generate_polymorphic_procedure(c, base_entity, type, nullptr, poly_proc_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool find_or_generate_polymorphic_procedure_from_parameters(Checker *c, Entity *base_entity, Array<Operand> *operands, PolyProcData *poly_proc_data) {
|
bool find_or_generate_polymorphic_procedure_from_parameters(Checker *c, Entity *base_entity, Array<Operand> *operands, PolyProcData *poly_proc_data) {
|
||||||
return find_or_generate_polymorphic_procedure(c, base_entity, nullptr, operands, poly_proc_data, false);
|
return find_or_generate_polymorphic_procedure(c, base_entity, nullptr, operands, poly_proc_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool check_type_specialization_to(Checker *c, Type *specialization, Type *type, bool compound, bool modify_type);
|
bool check_type_specialization_to(Checker *c, Type *specialization, Type *type, bool compound, bool modify_type);
|
||||||
@@ -829,6 +828,16 @@ void check_struct_field_decl(Checker *c, AstNode *decl, Array<Entity *> *fields,
|
|||||||
type = t_invalid;
|
type = t_invalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (is_type_empty_union(type)) {
|
||||||
|
error(vd->names[0], "An empty union cannot be used as a field type in %.*s", LIT(context));
|
||||||
|
type = t_invalid;
|
||||||
|
}
|
||||||
|
if (!c->context.allow_polymorphic_types && is_type_polymorphic(base_type(type))) {
|
||||||
|
error(vd->names[0], "Invalid use of a polymorphic type in %.*s", LIT(context));
|
||||||
|
type = t_invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Array<Operand> default_values = {};
|
Array<Operand> default_values = {};
|
||||||
defer (array_free(&default_values));
|
defer (array_free(&default_values));
|
||||||
if (vd->values.count > 0 && allow_default_values) {
|
if (vd->values.count > 0 && allow_default_values) {
|
||||||
@@ -1836,7 +1845,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_, Array<Operand> *operands) {
|
Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_variadic_, bool *success_, isize *specialization_count_, Array<Operand> *operands) {
|
||||||
if (_params == nullptr) {
|
if (_params == nullptr) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@@ -2006,6 +2015,12 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
|
|||||||
}
|
}
|
||||||
type = t_invalid;
|
type = t_invalid;
|
||||||
}
|
}
|
||||||
|
if (is_type_empty_union(type)) {
|
||||||
|
gbString str = type_to_string(type);
|
||||||
|
error(params[i], "Invalid use of an empty union `%s`", str);
|
||||||
|
gb_string_free(str);
|
||||||
|
type = t_invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (p->flags&FieldFlag_c_vararg) {
|
if (p->flags&FieldFlag_c_vararg) {
|
||||||
@@ -2046,6 +2061,7 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
|
|||||||
type = t_invalid;
|
type = t_invalid;
|
||||||
}
|
}
|
||||||
bool modify_type = !c->context.no_polymorphic_errors;
|
bool modify_type = !c->context.no_polymorphic_errors;
|
||||||
|
|
||||||
if (specialization != nullptr && !check_type_specialization_to(c, specialization, type, false, modify_type)) {
|
if (specialization != nullptr && !check_type_specialization_to(c, specialization, type, false, modify_type)) {
|
||||||
if (!c->context.no_polymorphic_errors) {
|
if (!c->context.no_polymorphic_errors) {
|
||||||
gbString t = type_to_string(type);
|
gbString t = type_to_string(type);
|
||||||
@@ -2105,10 +2121,25 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isize specialization_count = 0;
|
||||||
|
if (scope != nullptr) {
|
||||||
|
for_array(i, scope->elements.entries) {
|
||||||
|
Entity *e = scope->elements.entries[i].value;
|
||||||
|
if (e->kind == Type_Named) {
|
||||||
|
Type *t = e->type;
|
||||||
|
if (t->kind == Type_Generic &&
|
||||||
|
t->Generic.specialized != nullptr) {
|
||||||
|
specialization_count += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Type *tuple = make_type_tuple(c->allocator);
|
Type *tuple = make_type_tuple(c->allocator);
|
||||||
tuple->Tuple.variables = variables;
|
tuple->Tuple.variables = variables;
|
||||||
|
|
||||||
if (success_) *success_ = success;
|
if (success_) *success_ = success;
|
||||||
|
if (specialization_count_) *specialization_count_ = specialization_count;
|
||||||
if (is_variadic_) *is_variadic_ = is_variadic;
|
if (is_variadic_) *is_variadic_ = is_variadic;
|
||||||
|
|
||||||
return tuple;
|
return tuple;
|
||||||
@@ -2425,7 +2456,8 @@ bool check_procedure_type(Checker *c, Type *type, AstNode *proc_type_node, Array
|
|||||||
|
|
||||||
bool variadic = false;
|
bool variadic = false;
|
||||||
bool success = true;
|
bool success = true;
|
||||||
Type *params = check_get_params(c, c->context.scope, pt->params, &variadic, &success, operands);
|
isize specialization_count = 0;
|
||||||
|
Type *params = check_get_params(c, c->context.scope, pt->params, &variadic, &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);
|
||||||
|
|
||||||
isize param_count = 0;
|
isize param_count = 0;
|
||||||
@@ -2433,15 +2465,16 @@ bool check_procedure_type(Checker *c, Type *type, AstNode *proc_type_node, Array
|
|||||||
if (params) param_count = params ->Tuple.variables.count;
|
if (params) param_count = params ->Tuple.variables.count;
|
||||||
if (results) result_count = results->Tuple.variables.count;
|
if (results) result_count = results->Tuple.variables.count;
|
||||||
|
|
||||||
type->Proc.node = proc_type_node;
|
type->Proc.node = proc_type_node;
|
||||||
type->Proc.scope = c->context.scope;
|
type->Proc.scope = c->context.scope;
|
||||||
type->Proc.params = params;
|
type->Proc.params = params;
|
||||||
type->Proc.param_count = param_count;
|
type->Proc.param_count = param_count;
|
||||||
type->Proc.results = results;
|
type->Proc.results = results;
|
||||||
type->Proc.result_count = result_count;
|
type->Proc.result_count = result_count;
|
||||||
type->Proc.variadic = variadic;
|
type->Proc.variadic = variadic;
|
||||||
type->Proc.calling_convention = pt->calling_convention;
|
type->Proc.calling_convention = pt->calling_convention;
|
||||||
type->Proc.is_polymorphic = pt->generic;
|
type->Proc.is_polymorphic = pt->generic;
|
||||||
|
type->Proc.specialization_count = specialization_count;
|
||||||
|
|
||||||
if (param_count > 0) {
|
if (param_count > 0) {
|
||||||
Entity *end = params->Tuple.variables[param_count-1];
|
Entity *end = params->Tuple.variables[param_count-1];
|
||||||
@@ -2886,6 +2919,10 @@ bool check_type_internal(Checker *c, AstNode *e, Type **type, Type *named_type)
|
|||||||
e->TypeName.is_type_alias = true;
|
e->TypeName.is_type_alias = true;
|
||||||
add_entity(c, ps, ident, e);
|
add_entity(c, ps, ident, e);
|
||||||
add_entity(c, s, ident, e);
|
add_entity(c, s, ident, e);
|
||||||
|
} else {
|
||||||
|
error(ident, "Invalid use of a polymorphic type `$%.*s`", LIT(token.string));
|
||||||
|
*type = t_invalid;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
*type = t;
|
*type = t;
|
||||||
return true;
|
return true;
|
||||||
@@ -2945,25 +2982,19 @@ bool check_type_internal(Checker *c, AstNode *e, Type **type, Type *named_type)
|
|||||||
error(at->count, "... can only be used in conjuction with compound literals");
|
error(at->count, "... can only be used in conjuction with compound literals");
|
||||||
count = 0;
|
count = 0;
|
||||||
}
|
}
|
||||||
#if 0
|
if (is_type_empty_union(elem)) {
|
||||||
i64 esz = type_size_of(c->allocator, elem);
|
|
||||||
if (esz == 0) {
|
|
||||||
gbString str = type_to_string(elem);
|
gbString str = type_to_string(elem);
|
||||||
error(at->elem, "Zero sized element type `%s` is not allowed", str);
|
error(at->elem, "An empty union `%s` is not allowed as an array element type", str);
|
||||||
gb_string_free(str);
|
gb_string_free(str);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
*type = make_type_array(c->allocator, elem, count);
|
*type = make_type_array(c->allocator, elem, count);
|
||||||
} else {
|
} else {
|
||||||
Type *elem = check_type(c, at->elem);
|
Type *elem = check_type(c, at->elem);
|
||||||
#if 0
|
if (is_type_empty_union(elem)) {
|
||||||
i64 esz = type_size_of(c->allocator, elem);
|
|
||||||
if (esz == 0) {
|
|
||||||
gbString str = type_to_string(elem);
|
gbString str = type_to_string(elem);
|
||||||
error(at->elem, "Zero sized element type `%s` is not allowed", str);
|
error(at->elem, "An empty union `%s` is not allowed as an slice element type", str);
|
||||||
gb_string_free(str);
|
gb_string_free(str);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
*type = make_type_slice(c->allocator, elem);
|
*type = make_type_slice(c->allocator, elem);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -2971,14 +3002,11 @@ bool check_type_internal(Checker *c, AstNode *e, Type **type, Type *named_type)
|
|||||||
|
|
||||||
case_ast_node(dat, DynamicArrayType, e);
|
case_ast_node(dat, DynamicArrayType, e);
|
||||||
Type *elem = check_type(c, dat->elem);
|
Type *elem = check_type(c, dat->elem);
|
||||||
i64 esz = type_size_of(c->allocator, elem);
|
if (is_type_empty_union(elem)) {
|
||||||
#if 0
|
|
||||||
if (esz == 0) {
|
|
||||||
gbString str = type_to_string(elem);
|
gbString str = type_to_string(elem);
|
||||||
error(dat->elem, "Zero sized element type `%s` is not allowed", str);
|
error(dat->elem, "An empty union `%s` is not allowed as an dynamic array element type", str);
|
||||||
gb_string_free(str);
|
gb_string_free(str);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
*type = make_type_dynamic_array(c->allocator, elem);
|
*type = make_type_dynamic_array(c->allocator, elem);
|
||||||
return true;
|
return true;
|
||||||
case_end;
|
case_end;
|
||||||
@@ -2989,7 +3017,11 @@ bool check_type_internal(Checker *c, AstNode *e, Type **type, Type *named_type)
|
|||||||
Type *elem = check_type(c, vt->elem);
|
Type *elem = check_type(c, vt->elem);
|
||||||
Type *be = base_type(elem);
|
Type *be = base_type(elem);
|
||||||
i64 count = check_array_or_map_count(c, vt->count, false);
|
i64 count = check_array_or_map_count(c, vt->count, false);
|
||||||
if (is_type_vector(be) || (!is_type_boolean(be) && !is_type_numeric(be) && be->kind != Type_Generic)) {
|
if (!c->context.allow_polymorphic_types && is_type_polymorphic(base_type(elem))) {
|
||||||
|
gbString str = type_to_string(elem);
|
||||||
|
error(vt->elem, "Invalid use of a polymorphic type `%s` as an dynamic array element type", str);
|
||||||
|
gb_string_free(str);
|
||||||
|
} else if (is_type_vector(be) || (!is_type_boolean(be) && !is_type_numeric(be) && !is_type_polymorphic(base_type(elem)))) {
|
||||||
gbString err_str = type_to_string(elem);
|
gbString err_str = type_to_string(elem);
|
||||||
error(vt->elem, "Vector element type must be numerical or a boolean, got `%s`", err_str);
|
error(vt->elem, "Vector element type must be numerical or a boolean, got `%s`", err_str);
|
||||||
gb_string_free(err_str);
|
gb_string_free(err_str);
|
||||||
@@ -3018,16 +3050,6 @@ bool check_type_internal(Checker *c, AstNode *e, Type **type, Type *named_type)
|
|||||||
return true;
|
return true;
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
/* case_ast_node(rut, RawUnionType, e);
|
|
||||||
*type = make_type_raw_union(c->allocator);
|
|
||||||
set_base_type(named_type, *type);
|
|
||||||
check_open_scope(c, e);
|
|
||||||
check_raw_union_type(c, *type, e);
|
|
||||||
check_close_scope(c);
|
|
||||||
(*type)->Struct.node = e;
|
|
||||||
return true;
|
|
||||||
case_end;
|
|
||||||
*/
|
|
||||||
case_ast_node(et, EnumType, e);
|
case_ast_node(et, EnumType, e);
|
||||||
*type = make_type_enum(c->allocator);
|
*type = make_type_enum(c->allocator);
|
||||||
set_base_type(named_type, *type);
|
set_base_type(named_type, *type);
|
||||||
@@ -4815,7 +4837,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
|
|||||||
|
|
||||||
bool vari_expand = (ce->ellipsis.pos.line != 0);
|
bool vari_expand = (ce->ellipsis.pos.line != 0);
|
||||||
// if (vari_expand && id != BuiltinProc_append) {
|
// if (vari_expand && id != BuiltinProc_append) {
|
||||||
// error(ce->ellipsis, "Invalid use of `..` with built-in procedure `append`");
|
// error(ce->ellipsis, "Invalid use of `...` with built-in procedure `append`");
|
||||||
// return false;
|
// return false;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
@@ -5914,6 +5936,7 @@ int valid_proc_and_score_cmp(void const *a, void const *b) {
|
|||||||
return sj < si ? -1 : sj > si;
|
return sj < si ? -1 : sj > si;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool check_unpack_arguments(Checker *c, isize lhs_count, Array<Operand> *operands, Array<AstNode *> rhs, bool allow_ok) {
|
bool check_unpack_arguments(Checker *c, isize lhs_count, Array<Operand> *operands, Array<AstNode *> rhs, bool allow_ok) {
|
||||||
bool optional_ok = false;
|
bool optional_ok = false;
|
||||||
for_array(i, rhs) {
|
for_array(i, rhs) {
|
||||||
@@ -6009,14 +6032,14 @@ CALL_ARGUMENT_CHECKER(check_call_arguments_internal) {
|
|||||||
if (vari_expand && !variadic) {
|
if (vari_expand && !variadic) {
|
||||||
if (show_error) {
|
if (show_error) {
|
||||||
error(ce->ellipsis,
|
error(ce->ellipsis,
|
||||||
"Cannot use `..` in call to a non-variadic procedure: `%.*s`",
|
"Cannot use `...` in call to a non-variadic procedure: `%.*s`",
|
||||||
LIT(ce->proc->Ident.token.string));
|
LIT(ce->proc->Ident.token.string));
|
||||||
}
|
}
|
||||||
err = CallArgumentError_NonVariadicExpand;
|
err = CallArgumentError_NonVariadicExpand;
|
||||||
} else if (vari_expand && pt->c_vararg) {
|
} else if (vari_expand && pt->c_vararg) {
|
||||||
if (show_error) {
|
if (show_error) {
|
||||||
error(ce->ellipsis,
|
error(ce->ellipsis,
|
||||||
"Cannot use `..` in call to a `#c_vararg` variadic procedure: `%.*s`",
|
"Cannot use `...` in call to a `#c_vararg` variadic procedure: `%.*s`",
|
||||||
LIT(ce->proc->Ident.token.string));
|
LIT(ce->proc->Ident.token.string));
|
||||||
}
|
}
|
||||||
err = CallArgumentError_NonVariadicExpand;
|
err = CallArgumentError_NonVariadicExpand;
|
||||||
@@ -6110,7 +6133,7 @@ CALL_ARGUMENT_CHECKER(check_call_arguments_internal) {
|
|||||||
t = slice;
|
t = slice;
|
||||||
if (operand_index != param_count) {
|
if (operand_index != param_count) {
|
||||||
if (show_error) {
|
if (show_error) {
|
||||||
error(o.expr, "`..` in a variadic procedure can only have one variadic argument at the end");
|
error(o.expr, "`...` in a variadic procedure can only have one variadic argument at the end");
|
||||||
}
|
}
|
||||||
if (data) {
|
if (data) {
|
||||||
data->score = score;
|
data->score = score;
|
||||||
@@ -6130,15 +6153,6 @@ CALL_ARGUMENT_CHECKER(check_call_arguments_internal) {
|
|||||||
score += s;
|
score += s;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gen_entity != nullptr && gen_entity->token.string == "append" && err != CallArgumentError_None) {
|
|
||||||
gb_printf_err("append %s with score %lld %d\n", type_to_string(final_proc_type), score, err);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (err == CallArgumentError_None && poly_proc_data.proc_info.decl != nullptr) {
|
|
||||||
// NOTE(bill): Check the newly generated procedure body
|
|
||||||
check_procedure_later(c, poly_proc_data.proc_info);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -6281,9 +6295,6 @@ CALL_ARGUMENT_CHECKER(check_named_call_arguments) {
|
|||||||
PolyProcData poly_proc_data = {};
|
PolyProcData poly_proc_data = {};
|
||||||
if (find_or_generate_polymorphic_procedure_from_parameters(c, entity, &ordered_operands, &poly_proc_data)) {
|
if (find_or_generate_polymorphic_procedure_from_parameters(c, entity, &ordered_operands, &poly_proc_data)) {
|
||||||
gen_entity = poly_proc_data.gen_entity;
|
gen_entity = poly_proc_data.gen_entity;
|
||||||
if (poly_proc_data.proc_info.decl != nullptr) {
|
|
||||||
check_procedure_later(c, poly_proc_data.proc_info);
|
|
||||||
}
|
|
||||||
Type *gept = base_type(gen_entity->type);
|
Type *gept = base_type(gen_entity->type);
|
||||||
GB_ASSERT(is_type_proc(gept));
|
GB_ASSERT(is_type_proc(gept));
|
||||||
pt = &gept->Proc;
|
pt = &gept->Proc;
|
||||||
@@ -6354,7 +6365,7 @@ CallArgumentData check_call_arguments(Checker *c, Operand *operand, Type *proc_t
|
|||||||
|
|
||||||
bool vari_expand = (ce->ellipsis.pos.line != 0);
|
bool vari_expand = (ce->ellipsis.pos.line != 0);
|
||||||
if (vari_expand) {
|
if (vari_expand) {
|
||||||
// error(ce->ellipsis, "Invalid use of `..` with `field = value` call`");
|
// error(ce->ellipsis, "Invalid use of `...` with `field = value` call`");
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@@ -6594,7 +6605,7 @@ CallArgumentError check_polymorphic_struct_type(Checker *c, Operand *operand, As
|
|||||||
|
|
||||||
bool vari_expand = (ce->ellipsis.pos.line != 0);
|
bool vari_expand = (ce->ellipsis.pos.line != 0);
|
||||||
if (vari_expand) {
|
if (vari_expand) {
|
||||||
error(ce->ellipsis, "Invalid use of `..` in a polymorphic type call`");
|
error(ce->ellipsis, "Invalid use of `...` in a polymorphic type call`");
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@@ -7735,9 +7746,13 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t
|
|||||||
if (!ok) {
|
if (!ok) {
|
||||||
gbString expr_str = expr_to_string(o->expr);
|
gbString expr_str = expr_to_string(o->expr);
|
||||||
gbString dst_type_str = type_to_string(t);
|
gbString dst_type_str = type_to_string(t);
|
||||||
error(o->expr, "Cannot type assert `%s` to `%s` as it is not a variant of that union", expr_str, dst_type_str);
|
defer (gb_string_free(expr_str));
|
||||||
gb_string_free(dst_type_str);
|
defer (gb_string_free(dst_type_str));
|
||||||
gb_string_free(expr_str);
|
if (bsrc->Union.variants.count == 0) {
|
||||||
|
error(o->expr, "Cannot type assert `%s` to `%s` as this is an empty union", expr_str, dst_type_str);
|
||||||
|
} else {
|
||||||
|
error(o->expr, "Cannot type assert `%s` to `%s` as it is not a variant of that union", expr_str, dst_type_str);
|
||||||
|
}
|
||||||
o->mode = Addressing_Invalid;
|
o->mode = Addressing_Invalid;
|
||||||
o->expr = node;
|
o->expr = node;
|
||||||
return kind;
|
return kind;
|
||||||
@@ -8021,7 +8036,7 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t
|
|||||||
return kind;
|
return kind;
|
||||||
} else {
|
} else {
|
||||||
Type *t = base_type(o->type);
|
Type *t = base_type(o->type);
|
||||||
if (t->kind == Type_Pointer) {
|
if (t->kind == Type_Pointer && !is_type_empty_union(t->Pointer.elem)) {
|
||||||
if (o->mode != Addressing_Immutable) {
|
if (o->mode != Addressing_Immutable) {
|
||||||
o->mode = Addressing_Variable;
|
o->mode = Addressing_Variable;
|
||||||
}
|
}
|
||||||
@@ -8315,7 +8330,7 @@ gbString write_expr_to_string(gbString str, AstNode *node) {
|
|||||||
if (at->count != nullptr &&
|
if (at->count != nullptr &&
|
||||||
at->count->kind == AstNode_UnaryExpr &&
|
at->count->kind == AstNode_UnaryExpr &&
|
||||||
at->count->UnaryExpr.op.kind == Token_Ellipsis) {
|
at->count->UnaryExpr.op.kind == Token_Ellipsis) {
|
||||||
str = gb_string_appendc(str, "..");
|
str = gb_string_appendc(str, "...");
|
||||||
} else {
|
} else {
|
||||||
str = write_expr_to_string(str, at->count);
|
str = write_expr_to_string(str, at->count);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1733,6 +1733,11 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
|||||||
error(vd->type, "Invalid use of a polymorphic type `%s` in variable declaration", str);
|
error(vd->type, "Invalid use of a polymorphic type `%s` in variable declaration", str);
|
||||||
gb_string_free(str);
|
gb_string_free(str);
|
||||||
init_type = t_invalid;
|
init_type = t_invalid;
|
||||||
|
} else if (is_type_empty_union(init_type)) {
|
||||||
|
gbString str = type_to_string(init_type);
|
||||||
|
error(vd->type, "An empty union `%s` cannot be instantiated in variable declaration", str);
|
||||||
|
gb_string_free(str);
|
||||||
|
init_type = t_invalid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -185,7 +185,7 @@ struct DeclInfo {
|
|||||||
|
|
||||||
AstNode * type_expr;
|
AstNode * type_expr;
|
||||||
AstNode * init_expr;
|
AstNode * init_expr;
|
||||||
AstNode * proc_lit; // AstNode_ProcLit
|
AstNode * proc_lit; // AstNode_ProcLit
|
||||||
Type * gen_proc_type; // Precalculated
|
Type * gen_proc_type; // Precalculated
|
||||||
|
|
||||||
Map<bool> deps; // Key: Entity *
|
Map<bool> deps; // Key: Entity *
|
||||||
|
|||||||
@@ -98,6 +98,7 @@ struct Entity {
|
|||||||
} Variable;
|
} Variable;
|
||||||
struct {
|
struct {
|
||||||
bool is_type_alias;
|
bool is_type_alias;
|
||||||
|
Type *type_parameter_specialization;
|
||||||
} TypeName;
|
} TypeName;
|
||||||
struct {
|
struct {
|
||||||
OverloadKind overload_kind;
|
OverloadKind overload_kind;
|
||||||
|
|||||||
+15
-14
@@ -282,21 +282,20 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t) {
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
case Type_Union: {
|
case Type_Union: {
|
||||||
// NOTE(bill): The zero size array is used to fix the alignment used in a structure as
|
if (t->Union.variants.count == 0) {
|
||||||
// LLVM takes the first element's alignment as the entire alignment (like C)
|
ir_fprintf(f, "%%..opaque");
|
||||||
i64 align = type_align_of(heap_allocator(), t);
|
} else {
|
||||||
i64 total_size = type_size_of(heap_allocator(), t);
|
// NOTE(bill): The zero size array is used to fix the alignment used in a structure as
|
||||||
#if 1
|
// LLVM takes the first element's alignment as the entire alignment (like C)
|
||||||
i64 block_size = t->Union.variant_block_size;
|
i64 align = type_align_of(heap_allocator(), t);
|
||||||
|
i64 total_size = type_size_of(heap_allocator(), t);
|
||||||
|
i64 block_size = t->Union.variant_block_size;
|
||||||
|
|
||||||
ir_fprintf(f, "{[0 x <%lld x i8>], ", align);
|
ir_fprintf(f, "{[0 x <%lld x i8>], ", align);
|
||||||
ir_fprintf(f, "[%lld x i8], ", block_size);
|
ir_fprintf(f, "[%lld x i8], ", block_size);
|
||||||
ir_print_type(f, m, t_type_info_ptr);
|
ir_print_type(f, m, t_type_info_ptr);
|
||||||
ir_fprintf(f, "}");
|
ir_fprintf(f, "}");
|
||||||
#else
|
}
|
||||||
i64 block_size = total_size - build_context.word_size;
|
|
||||||
ir_fprintf(f, "{[0 x <%lld x i8>], [%lld x i8], i%lld}", align, block_size, word_bits);
|
|
||||||
#endif
|
|
||||||
} return;
|
} return;
|
||||||
|
|
||||||
case Type_Struct: {
|
case Type_Struct: {
|
||||||
@@ -1733,6 +1732,8 @@ void print_llvm_ir(irGen *ir) {
|
|||||||
irFileBuffer buf = {}, *f = &buf;
|
irFileBuffer buf = {}, *f = &buf;
|
||||||
ir_file_buffer_init(f, &ir->output_file);
|
ir_file_buffer_init(f, &ir->output_file);
|
||||||
|
|
||||||
|
ir_print_encoded_local(f, str_lit("..opaque"));
|
||||||
|
ir_fprintf(f, " = type opaque;\n");
|
||||||
ir_print_encoded_local(f, str_lit("..string"));
|
ir_print_encoded_local(f, str_lit("..string"));
|
||||||
ir_fprintf(f, " = type {i8*, ");
|
ir_fprintf(f, " = type {i8*, ");
|
||||||
ir_print_type(f, m, t_int);
|
ir_print_type(f, m, t_int);
|
||||||
|
|||||||
+3
-1
@@ -633,7 +633,8 @@ AstNode *clone_ast_node(gbAllocator a, AstNode *node) {
|
|||||||
case AstNode_BasicDirective: break;
|
case AstNode_BasicDirective: break;
|
||||||
|
|
||||||
case AstNode_PolyType:
|
case AstNode_PolyType:
|
||||||
n->PolyType.type = clone_ast_node(a, n->PolyType.type);
|
n->PolyType.type = clone_ast_node(a, n->PolyType.type);
|
||||||
|
n->PolyType.specialization = clone_ast_node(a, n->PolyType.specialization);
|
||||||
break;
|
break;
|
||||||
case AstNode_Ellipsis:
|
case AstNode_Ellipsis:
|
||||||
n->Ellipsis.expr = clone_ast_node(a, n->Ellipsis.expr);
|
n->Ellipsis.expr = clone_ast_node(a, n->Ellipsis.expr);
|
||||||
@@ -833,6 +834,7 @@ AstNode *clone_ast_node(gbAllocator a, AstNode *node) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case AstNode_TypeType:
|
case AstNode_TypeType:
|
||||||
|
n->TypeType.specialization = clone_ast_node(a, n->TypeType.specialization);
|
||||||
break;
|
break;
|
||||||
case AstNode_HelperType:
|
case AstNode_HelperType:
|
||||||
n->HelperType.type = clone_ast_node(a, n->HelperType.type);
|
n->HelperType.type = clone_ast_node(a, n->HelperType.type);
|
||||||
|
|||||||
+27
-33
@@ -146,6 +146,7 @@ struct TypeStruct {
|
|||||||
bool c_vararg; \
|
bool c_vararg; \
|
||||||
bool is_polymorphic; \
|
bool is_polymorphic; \
|
||||||
bool is_poly_specialized; \
|
bool is_poly_specialized; \
|
||||||
|
isize specialization_count; \
|
||||||
ProcCallingConvention calling_convention; \
|
ProcCallingConvention calling_convention; \
|
||||||
}) \
|
}) \
|
||||||
TYPE_KIND(Map, struct { \
|
TYPE_KIND(Map, struct { \
|
||||||
@@ -873,6 +874,11 @@ bool is_type_untyped_undef(Type *t) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool is_type_empty_union(Type *t) {
|
||||||
|
t = base_type(t);
|
||||||
|
return t->kind == Type_Union && t->Union.variants.count == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool is_type_valid_for_keys(Type *t) {
|
bool is_type_valid_for_keys(Type *t) {
|
||||||
t = core_type(t);
|
t = core_type(t);
|
||||||
@@ -1822,6 +1828,9 @@ i64 type_align_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
|
|||||||
return type_align_of_internal(allocator, t->Enum.base_type, path);
|
return type_align_of_internal(allocator, t->Enum.base_type, path);
|
||||||
|
|
||||||
case Type_Union: {
|
case Type_Union: {
|
||||||
|
if (t->Union.variants.count == 0) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
i64 max = build_context.word_size;
|
i64 max = build_context.word_size;
|
||||||
for_array(i, t->Union.variants) {
|
for_array(i, t->Union.variants) {
|
||||||
Type *variant = t->Union.variants[i];
|
Type *variant = t->Union.variants[i];
|
||||||
@@ -2056,6 +2065,9 @@ i64 type_size_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
|
|||||||
return type_size_of_internal(allocator, t->Enum.base_type, path);
|
return type_size_of_internal(allocator, t->Enum.base_type, path);
|
||||||
|
|
||||||
case Type_Union: {
|
case Type_Union: {
|
||||||
|
if (t->Union.variants.count == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
i64 align = type_align_of_internal(allocator, t, path);
|
i64 align = type_align_of_internal(allocator, t, path);
|
||||||
if (path->failure) {
|
if (path->failure) {
|
||||||
return FAILURE_SIZE;
|
return FAILURE_SIZE;
|
||||||
@@ -2294,7 +2306,7 @@ gbString write_type_to_string(gbString str, Type *type) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case Type_Union:
|
case Type_Union:
|
||||||
str = gb_string_appendc(str, "union{");
|
str = gb_string_appendc(str, "union {");
|
||||||
for_array(i, type->Union.variants) {
|
for_array(i, type->Union.variants) {
|
||||||
Type *t = type->Union.variants[i];
|
Type *t = type->Union.variants[i];
|
||||||
if (i > 0) str = gb_string_appendc(str, ", ");
|
if (i > 0) str = gb_string_appendc(str, ", ");
|
||||||
@@ -2304,40 +2316,22 @@ gbString write_type_to_string(gbString str, Type *type) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case Type_Struct: {
|
case Type_Struct: {
|
||||||
if (type->Struct.is_raw_union) {
|
|
||||||
str = gb_string_appendc(str, "raw_union{");
|
|
||||||
for_array(i, type->Struct.fields) {
|
|
||||||
Entity *f = type->Struct.fields[i];
|
|
||||||
GB_ASSERT(f->kind == Entity_Variable);
|
|
||||||
if (i > 0) {
|
|
||||||
str = gb_string_appendc(str, ", ");
|
|
||||||
}
|
|
||||||
str = gb_string_append_length(str, f->token.string.text, f->token.string.len);
|
|
||||||
str = gb_string_appendc(str, ": ");
|
|
||||||
str = write_type_to_string(str, f->type);
|
|
||||||
}
|
|
||||||
str = gb_string_appendc(str, "}");
|
|
||||||
} else {
|
|
||||||
str = gb_string_appendc(str, "struct");
|
str = gb_string_appendc(str, "struct");
|
||||||
if (type->Struct.is_packed) {
|
if (type->Struct.is_packed) str = gb_string_appendc(str, " #packed");
|
||||||
str = gb_string_appendc(str, " #packed");
|
if (type->Struct.is_ordered) str = gb_string_appendc(str, " #ordered");
|
||||||
|
if (type->Struct.is_raw_union) str = gb_string_appendc(str, " #raw_union");
|
||||||
|
str = gb_string_appendc(str, " {");
|
||||||
|
for_array(i, type->Struct.fields) {
|
||||||
|
Entity *f = type->Struct.fields[i];
|
||||||
|
GB_ASSERT(f->kind == Entity_Variable);
|
||||||
|
if (i > 0) {
|
||||||
|
str = gb_string_appendc(str, ", ");
|
||||||
}
|
}
|
||||||
if (type->Struct.is_ordered) {
|
str = gb_string_append_length(str, f->token.string.text, f->token.string.len);
|
||||||
str = gb_string_appendc(str, " #ordered");
|
str = gb_string_appendc(str, ": ");
|
||||||
}
|
str = write_type_to_string(str, f->type);
|
||||||
str = gb_string_appendc(str, " {");
|
|
||||||
for_array(i, type->Struct.fields) {
|
|
||||||
Entity *f = type->Struct.fields[i];
|
|
||||||
GB_ASSERT(f->kind == Entity_Variable);
|
|
||||||
if (i > 0) {
|
|
||||||
str = gb_string_appendc(str, ", ");
|
|
||||||
}
|
|
||||||
str = gb_string_append_length(str, f->token.string.text, f->token.string.len);
|
|
||||||
str = gb_string_appendc(str, ": ");
|
|
||||||
str = write_type_to_string(str, f->type);
|
|
||||||
}
|
|
||||||
str = gb_string_appendc(str, "}");
|
|
||||||
}
|
}
|
||||||
|
str = gb_string_appendc(str, "}");
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case Type_Map: {
|
case Type_Map: {
|
||||||
@@ -2373,7 +2367,7 @@ gbString write_type_to_string(gbString str, Type *type) {
|
|||||||
}
|
}
|
||||||
if (var->flags&EntityFlag_Ellipsis) {
|
if (var->flags&EntityFlag_Ellipsis) {
|
||||||
Type *slice = base_type(var->type);
|
Type *slice = base_type(var->type);
|
||||||
str = gb_string_appendc(str, "..");
|
str = gb_string_appendc(str, "...");
|
||||||
GB_ASSERT(var->type->kind == Type_Slice);
|
GB_ASSERT(var->type->kind == Type_Slice);
|
||||||
str = write_type_to_string(str, slice->Slice.elem);
|
str = write_type_to_string(str, slice->Slice.elem);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in New Issue
Block a user