mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-05 15:18:49 +00:00
Implicit parametric polymorphic procedures
This commit is contained in:
@@ -367,7 +367,10 @@ explicit_parametric_polymorphic_procedures :: proc() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
main :: proc() {
|
main :: proc() {
|
||||||
|
/*
|
||||||
general_stuff();
|
general_stuff();
|
||||||
foreign_blocks();
|
foreign_blocks();
|
||||||
default_arguments();
|
default_arguments();
|
||||||
@@ -381,6 +384,7 @@ main :: proc() {
|
|||||||
|
|
||||||
program := "+ + * - /";
|
program := "+ + * - /";
|
||||||
accumulator := 0;
|
accumulator := 0;
|
||||||
|
*/
|
||||||
|
|
||||||
for token in program {
|
for token in program {
|
||||||
match token {
|
match token {
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ import (
|
|||||||
)
|
)
|
||||||
import_load "opengl_constants.odin";
|
import_load "opengl_constants.odin";
|
||||||
|
|
||||||
|
_ := compile_assert(ODIN_OS != "osx");
|
||||||
|
|
||||||
foreign lib {
|
foreign lib {
|
||||||
Clear :: proc(mask: u32) #link_name "glClear" ---;
|
Clear :: proc(mask: u32) #link_name "glClear" ---;
|
||||||
ClearColor :: proc(r, g, b, a: f32) #link_name "glClearColor" ---;
|
ClearColor :: proc(r, g, b, a: f32) #link_name "glClearColor" ---;
|
||||||
|
|||||||
+6
-7
@@ -8,7 +8,6 @@ import "strings.odin";
|
|||||||
Handle :: i32;
|
Handle :: i32;
|
||||||
FileTime :: u64;
|
FileTime :: u64;
|
||||||
Errno :: int;
|
Errno :: int;
|
||||||
AddressSize :: int;
|
|
||||||
|
|
||||||
|
|
||||||
O_RDONLY :: 0x00000;
|
O_RDONLY :: 0x00000;
|
||||||
@@ -125,9 +124,9 @@ F_OK :: 0; // Test for file existance
|
|||||||
foreign libc {
|
foreign libc {
|
||||||
unix_open :: proc(path: ^u8, mode: int) -> Handle #link_name "open" ---;
|
unix_open :: proc(path: ^u8, mode: int) -> Handle #link_name "open" ---;
|
||||||
unix_close :: proc(handle: Handle) #link_name "close" ---;
|
unix_close :: proc(handle: Handle) #link_name "close" ---;
|
||||||
unix_read :: proc(handle: Handle, buffer: rawptr, count: int) -> AddressSize #link_name "read" ---;
|
unix_read :: proc(handle: Handle, buffer: rawptr, count: int) -> int #link_name "read" ---;
|
||||||
unix_write :: proc(handle: Handle, buffer: rawptr, count: int) -> AddressSize #link_name "write" ---;
|
unix_write :: proc(handle: Handle, buffer: rawptr, count: int) -> int #link_name "write" ---;
|
||||||
unix_lseek :: proc(fs: Handle, offset: AddressSize, whence: int) -> AddressSize #link_name "lseek" ---;
|
unix_lseek :: proc(fs: Handle, offset: int, whence: int) -> int #link_name "lseek" ---;
|
||||||
unix_gettid :: proc() -> u64 #link_name "gettid" ---;
|
unix_gettid :: proc() -> u64 #link_name "gettid" ---;
|
||||||
unix_stat :: proc(path: ^u8, stat: ^Stat) -> int #link_name "stat" ---;
|
unix_stat :: proc(path: ^u8, stat: ^Stat) -> int #link_name "stat" ---;
|
||||||
unix_access :: proc(path: ^u8, mask: int) -> int #link_name "access" ---;
|
unix_access :: proc(path: ^u8, mask: int) -> int #link_name "access" ---;
|
||||||
@@ -168,7 +167,7 @@ close :: proc(fd: Handle) {
|
|||||||
unix_close(fd);
|
unix_close(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
write :: proc(fd: Handle, data: []u8) -> (AddressSize, Errno) {
|
write :: proc(fd: Handle, data: []u8) -> (int, Errno) {
|
||||||
assert(fd != -1);
|
assert(fd != -1);
|
||||||
|
|
||||||
bytes_written := unix_write(fd, &data[0], len(data));
|
bytes_written := unix_write(fd, &data[0], len(data));
|
||||||
@@ -178,7 +177,7 @@ write :: proc(fd: Handle, data: []u8) -> (AddressSize, Errno) {
|
|||||||
return bytes_written, 0;
|
return bytes_written, 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
read :: proc(fd: Handle, data: []u8) -> (AddressSize, Errno) {
|
read :: proc(fd: Handle, data: []u8) -> (int, Errno) {
|
||||||
assert(fd != -1);
|
assert(fd != -1);
|
||||||
|
|
||||||
bytes_read := unix_read(fd, &data[0], len(data));
|
bytes_read := unix_read(fd, &data[0], len(data));
|
||||||
@@ -188,7 +187,7 @@ read :: proc(fd: Handle, data: []u8) -> (AddressSize, Errno) {
|
|||||||
return bytes_read, 0;
|
return bytes_read, 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
seek :: proc(fd: Handle, offset: AddressSize, whence: int) -> (AddressSize, Errno) {
|
seek :: proc(fd: Handle, offset: int, whence: int) -> (int, Errno) {
|
||||||
assert(fd != -1);
|
assert(fd != -1);
|
||||||
|
|
||||||
final_offset := unix_lseek(fd, offset, whence);
|
final_offset := unix_lseek(fd, offset, whence);
|
||||||
|
|||||||
@@ -266,12 +266,12 @@ String get_fullpath_core(gbAllocator a, String path) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
String const ODIN_VERSION = str_lit("0.6.0-dev");
|
||||||
|
|
||||||
void init_build_context(void) {
|
void init_build_context(void) {
|
||||||
BuildContext *bc = &build_context;
|
BuildContext *bc = &build_context;
|
||||||
bc->ODIN_VENDOR = str_lit("odin");
|
bc->ODIN_VENDOR = str_lit("odin");
|
||||||
bc->ODIN_VERSION = str_lit("0.6.0-dev");
|
bc->ODIN_VERSION = ODIN_VERSION;
|
||||||
bc->ODIN_ROOT = odin_root_dir();
|
bc->ODIN_ROOT = odin_root_dir();
|
||||||
|
|
||||||
#if defined(GB_SYSTEM_WINDOWS)
|
#if defined(GB_SYSTEM_WINDOWS)
|
||||||
|
|||||||
+20
-6
@@ -329,7 +329,16 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
|
|||||||
check_open_scope(c, pl->type);
|
check_open_scope(c, pl->type);
|
||||||
defer (check_close_scope(c));
|
defer (check_close_scope(c));
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
if (e->token.string == "sort") {
|
||||||
|
gb_printf_err("%.*s\n", LIT(e->token.string));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool prev_allow_polymorphic_types = c->context.allow_polymorphic_types;
|
||||||
|
c->context.allow_polymorphic_types = true;
|
||||||
check_procedure_type(c, proc_type, pl->type);
|
check_procedure_type(c, proc_type, pl->type);
|
||||||
|
c->context.allow_polymorphic_types = prev_allow_polymorphic_types;
|
||||||
|
|
||||||
bool is_foreign = (pl->tags & ProcTag_foreign) != 0;
|
bool is_foreign = (pl->tags & ProcTag_foreign) != 0;
|
||||||
bool is_link_name = (pl->tags & ProcTag_link_name) != 0;
|
bool is_link_name = (pl->tags & ProcTag_link_name) != 0;
|
||||||
@@ -348,11 +357,11 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
|
|||||||
error(e->token, "Procedure type of `main` was expected to be `proc()`, got %s", str);
|
error(e->token, "Procedure type of `main` was expected to be `proc()`, got %s", str);
|
||||||
gb_string_free(str);
|
gb_string_free(str);
|
||||||
}
|
}
|
||||||
if (proc_type->Proc.calling_convention != ProcCC_Odin &&
|
if (pt->calling_convention != ProcCC_Odin &&
|
||||||
proc_type->Proc.calling_convention != ProcCC_Contextless) {
|
pt->calling_convention != ProcCC_Contextless) {
|
||||||
error(e->token, "Procedure `main` cannot have a custom calling convention");
|
error(e->token, "Procedure `main` cannot have a custom calling convention");
|
||||||
}
|
}
|
||||||
proc_type->Proc.calling_convention = ProcCC_Contextless;
|
pt->calling_convention = ProcCC_Contextless;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_inline && is_no_inline) {
|
if (is_inline && is_no_inline) {
|
||||||
@@ -363,7 +372,6 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
|
|||||||
error(pl->type, "A foreign procedure cannot have an `export` tag");
|
error(pl->type, "A foreign procedure cannot have an `export` tag");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (pt->is_polymorphic) {
|
if (pt->is_polymorphic) {
|
||||||
if (pl->body == NULL) {
|
if (pl->body == NULL) {
|
||||||
error(e->token, "Polymorphic procedures must have a body");
|
error(e->token, "Polymorphic procedures must have a body");
|
||||||
@@ -472,9 +480,15 @@ void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count
|
|||||||
}
|
}
|
||||||
e->flags |= EntityFlag_Visited;
|
e->flags |= EntityFlag_Visited;
|
||||||
|
|
||||||
|
String context_name = str_lit("variable declaration");
|
||||||
|
|
||||||
if (type_expr != NULL) {
|
if (type_expr != NULL) {
|
||||||
e->type = check_type(c, type_expr);
|
e->type = check_type(c, type_expr);
|
||||||
}
|
}
|
||||||
|
if (e->type != NULL && is_type_polymorphic(e->type)) {
|
||||||
|
error(e->token, "Invalid use of a polymorphic type in %.*s", LIT(context_name));
|
||||||
|
e->type = t_invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (e->Variable.is_foreign) {
|
if (e->Variable.is_foreign) {
|
||||||
@@ -514,7 +528,7 @@ void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count
|
|||||||
GB_ASSERT(entities == NULL || entities[0] == e);
|
GB_ASSERT(entities == NULL || entities[0] == e);
|
||||||
Operand operand = {};
|
Operand operand = {};
|
||||||
check_expr(c, &operand, init_expr);
|
check_expr(c, &operand, init_expr);
|
||||||
check_init_variable(c, e, &operand, str_lit("variable declaration"));
|
check_init_variable(c, e, &operand, context_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type_expr != NULL) {
|
if (type_expr != NULL) {
|
||||||
@@ -527,7 +541,7 @@ void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count
|
|||||||
Array<AstNode *> inits;
|
Array<AstNode *> inits;
|
||||||
array_init(&inits, c->allocator, 1);
|
array_init(&inits, c->allocator, 1);
|
||||||
array_add(&inits, init_expr);
|
array_add(&inits, init_expr);
|
||||||
check_init_variables(c, entities, entity_count, inits, str_lit("variable declaration"));
|
check_init_variables(c, entities, entity_count, inits, context_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type) {
|
void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type) {
|
||||||
|
|||||||
+157
-23
@@ -1073,14 +1073,105 @@ void check_bit_field_type(Checker *c, Type *bit_field_type, Type *named_type, As
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool is_polymorphic_type_assignable(Checker *c, Type *poly, Type *source, bool compound) {
|
||||||
|
Operand o = {Addressing_Value};
|
||||||
|
o.type = source;
|
||||||
|
switch (poly->kind) {
|
||||||
|
case Type_Basic:
|
||||||
|
if (compound) return are_types_identical(poly, source);
|
||||||
|
return check_is_assignable_to(c, &o, poly);
|
||||||
|
case Type_Named:
|
||||||
|
if (compound) return are_types_identical(poly, source);
|
||||||
|
return check_is_assignable_to(c, &o, poly);
|
||||||
|
|
||||||
|
case Type_Generic: {
|
||||||
|
Type *ds = default_type(source);
|
||||||
|
gb_memmove(poly, ds, gb_size_of(Type));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case Type_Pointer:
|
||||||
|
if (source->kind == Type_Pointer) {
|
||||||
|
return is_polymorphic_type_assignable(c, poly->Pointer.elem, source->Pointer.elem, true);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
case Type_Atomic:
|
||||||
|
if (source->kind == Type_Atomic) {
|
||||||
|
return is_polymorphic_type_assignable(c, poly->Atomic.elem, source->Atomic.elem, true);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
case Type_Array:
|
||||||
|
if (source->kind == Type_Array &&
|
||||||
|
poly->Array.count == source->Array.count) {
|
||||||
|
return is_polymorphic_type_assignable(c, poly->Array.elem, source->Array.elem, true);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
case Type_DynamicArray:
|
||||||
|
if (source->kind == Type_DynamicArray) {
|
||||||
|
return is_polymorphic_type_assignable(c, poly->DynamicArray.elem, source->DynamicArray.elem, true);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
case Type_Vector:
|
||||||
|
if (source->kind == Type_Vector &&
|
||||||
|
poly->Vector.count == source->Vector.count) {
|
||||||
|
return is_polymorphic_type_assignable(c, poly->Vector.elem, source->Vector.elem, true);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
case Type_Slice:
|
||||||
|
if (source->kind == Type_Slice) {
|
||||||
|
return is_polymorphic_type_assignable(c, poly->Slice.elem, source->Slice.elem, true);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
|
||||||
|
case Type_Record:
|
||||||
|
if (source->kind == Type_Record) {
|
||||||
|
// TODO(bill): Polymorphic type assignment
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
case Type_Tuple:
|
||||||
|
GB_PANIC("This should never happen");
|
||||||
|
return false;
|
||||||
|
case Type_Proc:
|
||||||
|
if (source->kind == Type_Proc) {
|
||||||
|
// TODO(bill): Polymorphic type assignment
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
case Type_Map:
|
||||||
|
if (source->kind == Type_Map) {
|
||||||
|
bool key = is_polymorphic_type_assignable(c, poly->Map.key, source->Map.key, true);
|
||||||
|
bool value = is_polymorphic_type_assignable(c, poly->Map.value, source->Map.value, true);
|
||||||
|
return key || value;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Type *determine_type_from_polymorphic(Checker *c, Type *poly_type, Operand operand) {
|
||||||
|
if (!is_operand_value(operand)) {
|
||||||
|
error(operand.expr, "Cannot determine polymorphic type from parameter");
|
||||||
|
return t_invalid;
|
||||||
|
}
|
||||||
|
if (is_polymorphic_type_assignable(c, poly_type, operand.type, false)) {
|
||||||
|
return poly_type;
|
||||||
|
}
|
||||||
|
gbString pts = type_to_string(poly_type);
|
||||||
|
gbString ots = type_to_string(operand.type);
|
||||||
|
defer (gb_string_free(pts));
|
||||||
|
defer (gb_string_free(ots));
|
||||||
|
error(operand.expr,
|
||||||
|
"Cannot determine polymorphic type from parameter: `%s` to `%s`\n"
|
||||||
|
"\tNote: Record and procedure types are not yet supported",
|
||||||
|
ots, pts);
|
||||||
|
return t_invalid;
|
||||||
|
}
|
||||||
|
|
||||||
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_, Array<Operand> *operands) {
|
||||||
if (_params == NULL) {
|
if (_params == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool allow_polymorphic_types = c->context.allow_polymorphic_types;
|
||||||
|
|
||||||
bool success = true;
|
bool success = true;
|
||||||
ast_node(field_list, FieldList, _params);
|
ast_node(field_list, FieldList, _params);
|
||||||
Array<AstNode *> params = field_list->list;
|
Array<AstNode *> params = field_list->list;
|
||||||
@@ -1123,6 +1214,8 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
|
|||||||
bool default_is_nil = false;
|
bool default_is_nil = false;
|
||||||
bool default_is_location = false;
|
bool default_is_location = false;
|
||||||
bool is_type_param = false;
|
bool is_type_param = false;
|
||||||
|
bool is_type_polymorphic_type = false;
|
||||||
|
bool detemine_type_from_operand = false;
|
||||||
|
|
||||||
|
|
||||||
if (type_expr == NULL) {
|
if (type_expr == NULL) {
|
||||||
@@ -1157,24 +1250,23 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
|
|||||||
if (type_expr->kind == AstNode_HelperType) {
|
if (type_expr->kind == AstNode_HelperType) {
|
||||||
is_type_param = true;
|
is_type_param = true;
|
||||||
if (operands != NULL) {
|
if (operands != NULL) {
|
||||||
Operand o = (*operands)[variable_index];
|
detemine_type_from_operand = true;
|
||||||
if (o.mode == Addressing_Type) {
|
type = t_invalid;
|
||||||
type = o.type;
|
|
||||||
} else {
|
|
||||||
error(o.expr, "Expected a type to assign to the type parameter");
|
|
||||||
type = t_invalid;
|
|
||||||
success = false;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
type = make_type_generic(c->allocator, 0, str_lit(""));
|
type = make_type_generic(c->allocator, 0, str_lit(""));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
type = check_type(c, type_expr);
|
bool prev = c->context.allow_polymorphic_types;
|
||||||
if (p->flags&FieldFlag_dollar) {
|
if (operands != NULL) {
|
||||||
error(type_expr, "`$` is only allowed for polymorphic type parameters at the moment");
|
c->context.allow_polymorphic_types = true;
|
||||||
type = NULL;
|
|
||||||
}
|
}
|
||||||
|
type = check_type(c, type_expr);
|
||||||
|
|
||||||
|
c->context.allow_polymorphic_types = prev;
|
||||||
|
|
||||||
|
if (is_type_polymorphic(type)) {
|
||||||
|
is_type_polymorphic_type = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (default_value != NULL) {
|
if (default_value != NULL) {
|
||||||
@@ -1218,12 +1310,7 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
|
|||||||
type = t_invalid;
|
type = t_invalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p->flags&FieldFlag_no_alias) {
|
|
||||||
if (!is_type_pointer(type)) {
|
|
||||||
error(params[i], "`#no_alias` can only be applied to fields of pointer type");
|
|
||||||
p->flags &= ~FieldFlag_no_alias; // Remove the flag
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (p->flags&FieldFlag_c_vararg) {
|
if (p->flags&FieldFlag_c_vararg) {
|
||||||
if (p->type == NULL ||
|
if (p->type == NULL ||
|
||||||
p->type->kind != AstNode_Ellipsis) {
|
p->type->kind != AstNode_Ellipsis) {
|
||||||
@@ -1234,19 +1321,44 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
for_array(j, p->names) {
|
for_array(j, p->names) {
|
||||||
AstNode *name = p->names[j];
|
AstNode *name = p->names[j];
|
||||||
if (ast_node_expect(name, AstNode_Ident)) {
|
if (ast_node_expect(name, AstNode_Ident)) {
|
||||||
Entity *param = NULL;
|
Entity *param = NULL;
|
||||||
if (is_type_param) {
|
if (is_type_param) {
|
||||||
|
if (operands != NULL) {
|
||||||
|
Operand o = (*operands)[variable_index];
|
||||||
|
if (o.mode == Addressing_Type) {
|
||||||
|
type = o.type;
|
||||||
|
} else {
|
||||||
|
error(o.expr, "Expected a type to assign to the type parameter");
|
||||||
|
type = t_invalid;
|
||||||
|
}
|
||||||
|
}
|
||||||
param = make_entity_type_name(c->allocator, scope, name->Ident.token, type);
|
param = make_entity_type_name(c->allocator, scope, name->Ident.token, type);
|
||||||
param->TypeName.is_type_alias = true;
|
param->TypeName.is_type_alias = true;
|
||||||
} else {
|
} else {
|
||||||
|
if (operands != NULL && is_type_polymorphic_type) {
|
||||||
|
type = determine_type_from_polymorphic(c, type, (*operands)[variable_index]);
|
||||||
|
if (type == t_invalid) {
|
||||||
|
success = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p->flags&FieldFlag_no_alias) {
|
||||||
|
if (!is_type_pointer(type)) {
|
||||||
|
error(params[i], "`#no_alias` can only be applied to fields of pointer type");
|
||||||
|
p->flags &= ~FieldFlag_no_alias; // Remove the flag
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
param = make_entity_param(c->allocator, scope, name->Ident.token, type,
|
param = make_entity_param(c->allocator, scope, name->Ident.token, type,
|
||||||
(p->flags&FieldFlag_using) != 0, false);
|
(p->flags&FieldFlag_using) != 0, false);
|
||||||
param->Variable.default_value = value;
|
param->Variable.default_value = value;
|
||||||
param->Variable.default_is_nil = default_is_nil;
|
param->Variable.default_is_nil = default_is_nil;
|
||||||
param->Variable.default_is_location = default_is_location;
|
param->Variable.default_is_location = default_is_location;
|
||||||
|
|
||||||
}
|
}
|
||||||
if (p->flags&FieldFlag_no_alias) {
|
if (p->flags&FieldFlag_no_alias) {
|
||||||
param->flags |= EntityFlag_NoAlias;
|
param->flags |= EntityFlag_NoAlias;
|
||||||
@@ -1629,11 +1741,12 @@ bool check_procedure_type(Checker *c, Type *type, AstNode *proc_type_node, Array
|
|||||||
if (e->kind != Entity_Variable) {
|
if (e->kind != Entity_Variable) {
|
||||||
is_polymorphic = true;
|
is_polymorphic = true;
|
||||||
break;
|
break;
|
||||||
|
} else if (is_type_polymorphic(e->type)) {
|
||||||
|
is_polymorphic = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (operands == NULL) {
|
type->Proc.is_polymorphic = is_polymorphic;
|
||||||
// GB_ASSERT(type->Proc.is_polymorphic == is_polymorphic);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
type->Proc.abi_compat_params = gb_alloc_array(c->allocator, Type *, param_count);
|
type->Proc.abi_compat_params = gb_alloc_array(c->allocator, Type *, param_count);
|
||||||
@@ -2005,6 +2118,26 @@ bool check_type_internal(Checker *c, AstNode *e, Type **type, Type *named_type)
|
|||||||
}
|
}
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
|
case_ast_node(pt, PolyType, e);
|
||||||
|
AstNode *ident = pt->type;
|
||||||
|
if (ident->kind != AstNode_Ident) {
|
||||||
|
error(ident, "Expected an identifier after the $");
|
||||||
|
*type = t_invalid;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Token token = ident->Ident.token;
|
||||||
|
Type *t = make_type_generic(c->allocator, 0, token.string);
|
||||||
|
if (c->context.allow_polymorphic_types) {
|
||||||
|
Scope *s = c->context.scope;
|
||||||
|
Entity *e = make_entity_type_name(c->allocator, s, token, t);
|
||||||
|
e->TypeName.is_type_alias = true;
|
||||||
|
add_entity(c, s, ident, e);
|
||||||
|
}
|
||||||
|
*type = t;
|
||||||
|
return true;
|
||||||
|
case_end;
|
||||||
|
|
||||||
case_ast_node(se, SelectorExpr, e);
|
case_ast_node(se, SelectorExpr, e);
|
||||||
Operand o = {};
|
Operand o = {};
|
||||||
check_selector(c, &o, e, NULL);
|
check_selector(c, &o, e, NULL);
|
||||||
@@ -2224,13 +2357,14 @@ Type *check_type(Checker *c, AstNode *e, Type *named_type) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if (is_type_polymorphic(type)) {
|
#if 0
|
||||||
if (is_type_poly_proc(type)) {
|
if (!c->context.allow_polymorphic_types && is_type_polymorphic(type)) {
|
||||||
gbString str = type_to_string(type);
|
gbString str = type_to_string(type);
|
||||||
error(e, "Invalid use of a polymorphic type `%s`", str);
|
error(e, "Invalid use of a polymorphic type `%s`", str);
|
||||||
gb_string_free(str);
|
gb_string_free(str);
|
||||||
type = t_invalid;
|
type = t_invalid;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (is_type_typed(type)) {
|
if (is_type_typed(type)) {
|
||||||
add_type_and_value(&c->info, e, Addressing_Type, type, empty_exact_value);
|
add_type_and_value(&c->info, e, Addressing_Type, type, empty_exact_value);
|
||||||
|
|||||||
@@ -1717,6 +1717,9 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
|||||||
init_type = check_type(c, vd->type, NULL);
|
init_type = check_type(c, vd->type, NULL);
|
||||||
if (init_type == NULL) {
|
if (init_type == NULL) {
|
||||||
init_type = t_invalid;
|
init_type = t_invalid;
|
||||||
|
} else if (is_type_polymorphic(init_type)) {
|
||||||
|
error(vd->type, "Invalid use of a polymorphic type in variable declaration");
|
||||||
|
init_type = t_invalid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -261,6 +261,7 @@ struct CheckerContext {
|
|||||||
DeclInfo * decl;
|
DeclInfo * decl;
|
||||||
u32 stmt_state_flags;
|
u32 stmt_state_flags;
|
||||||
bool in_defer; // TODO(bill): Actually handle correctly
|
bool in_defer; // TODO(bill): Actually handle correctly
|
||||||
|
bool allow_polymorphic_types;
|
||||||
String proc_name;
|
String proc_name;
|
||||||
Type * type_hint;
|
Type * type_hint;
|
||||||
DeclInfo * curr_proc_decl;
|
DeclInfo * curr_proc_decl;
|
||||||
|
|||||||
+1
-1
@@ -375,7 +375,7 @@ int main(int arg_count, char **arg_ptr) {
|
|||||||
return 1;
|
return 1;
|
||||||
#endif
|
#endif
|
||||||
} else if (args[1] == "version") {
|
} else if (args[1] == "version") {
|
||||||
gb_printf("%.*s version %.*s\n", LIT(args[0]), LIT(build_context.ODIN_VERSION));
|
gb_printf("%.*s version %.*s\n", LIT(args[0]), LIT(ODIN_VERSION));
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
usage(args[0]);
|
usage(args[0]);
|
||||||
|
|||||||
+8
-2
@@ -632,6 +632,10 @@ AstNode *clone_ast_node(gbAllocator a, AstNode *node) {
|
|||||||
case AstNode_Undef: break;
|
case AstNode_Undef: break;
|
||||||
case AstNode_BasicLit: break;
|
case AstNode_BasicLit: break;
|
||||||
case AstNode_BasicDirective: break;
|
case AstNode_BasicDirective: break;
|
||||||
|
|
||||||
|
case AstNode_PolyType:
|
||||||
|
n->PolyType.type = clone_ast_node(a, n->PolyType.type);
|
||||||
|
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);
|
||||||
break;
|
break;
|
||||||
@@ -3259,8 +3263,10 @@ u32 check_field_prefixes(AstFile *f, isize name_count, u32 allowed_flags, u32 se
|
|||||||
syntax_error(f->curr_token, "`#c_vararg` is not allowed within this field list");
|
syntax_error(f->curr_token, "`#c_vararg` is not allowed within this field list");
|
||||||
set_flags &= ~FieldFlag_c_vararg;
|
set_flags &= ~FieldFlag_c_vararg;
|
||||||
}
|
}
|
||||||
if ((allowed_flags&FieldFlag_dollar) == 0 && (set_flags&FieldFlag_dollar)) {
|
// if ((allowed_flags&FieldFlag_dollar) == 0 && (set_flags&FieldFlag_dollar)) {
|
||||||
syntax_error(f->curr_token, "`$` is only allowed within procedures");
|
if ((set_flags&FieldFlag_dollar)) {
|
||||||
|
// syntax_error(f->curr_token, "`$` is only allowed within procedures");
|
||||||
|
syntax_error(f->curr_token, "`$` is not yet supported");
|
||||||
set_flags &= ~FieldFlag_dollar;
|
set_flags &= ~FieldFlag_dollar;
|
||||||
}
|
}
|
||||||
return set_flags;
|
return set_flags;
|
||||||
|
|||||||
+32
-27
@@ -36,27 +36,27 @@ TOKEN_KIND(Token__OperatorBegin, "_OperatorBegin"), \
|
|||||||
TOKEN_KIND(Token_CmpAnd, "&&"), \
|
TOKEN_KIND(Token_CmpAnd, "&&"), \
|
||||||
TOKEN_KIND(Token_CmpOr, "||"), \
|
TOKEN_KIND(Token_CmpOr, "||"), \
|
||||||
\
|
\
|
||||||
TOKEN_KIND(Token__AssignOpBegin, "_AssignOpBegin"), \
|
TOKEN_KIND(Token__AssignOpBegin, "_AssignOpBegin"), \
|
||||||
TOKEN_KIND(Token_AddEq, "+="), \
|
TOKEN_KIND(Token_AddEq, "+="), \
|
||||||
TOKEN_KIND(Token_SubEq, "-="), \
|
TOKEN_KIND(Token_SubEq, "-="), \
|
||||||
TOKEN_KIND(Token_MulEq, "*="), \
|
TOKEN_KIND(Token_MulEq, "*="), \
|
||||||
TOKEN_KIND(Token_QuoEq, "/="), \
|
TOKEN_KIND(Token_QuoEq, "/="), \
|
||||||
TOKEN_KIND(Token_ModEq, "%="), \
|
TOKEN_KIND(Token_ModEq, "%="), \
|
||||||
TOKEN_KIND(Token_ModModEq, "%%="), \
|
TOKEN_KIND(Token_ModModEq, "%%="), \
|
||||||
TOKEN_KIND(Token_AndEq, "&="), \
|
TOKEN_KIND(Token_AndEq, "&="), \
|
||||||
TOKEN_KIND(Token_OrEq, "|="), \
|
TOKEN_KIND(Token_OrEq, "|="), \
|
||||||
TOKEN_KIND(Token_XorEq, "~="), \
|
TOKEN_KIND(Token_XorEq, "~="), \
|
||||||
TOKEN_KIND(Token_AndNotEq, "&~="), \
|
TOKEN_KIND(Token_AndNotEq, "&~="), \
|
||||||
TOKEN_KIND(Token_ShlEq, "<<="), \
|
TOKEN_KIND(Token_ShlEq, "<<="), \
|
||||||
TOKEN_KIND(Token_ShrEq, ">>="), \
|
TOKEN_KIND(Token_ShrEq, ">>="), \
|
||||||
TOKEN_KIND(Token_CmpAndEq, "&&="), \
|
TOKEN_KIND(Token_CmpAndEq, "&&="), \
|
||||||
TOKEN_KIND(Token_CmpOrEq, "||="), \
|
TOKEN_KIND(Token_CmpOrEq, "||="), \
|
||||||
TOKEN_KIND(Token__AssignOpEnd, "_AssignOpEnd"), \
|
TOKEN_KIND(Token__AssignOpEnd, "_AssignOpEnd"), \
|
||||||
TOKEN_KIND(Token_ArrowRight, "->"), \
|
TOKEN_KIND(Token_ArrowRight, "->"), \
|
||||||
TOKEN_KIND(Token_ArrowLeft, "<-"), \
|
TOKEN_KIND(Token_ThickArrowRight, "=>"), \
|
||||||
TOKEN_KIND(Token_Inc, "++"), \
|
TOKEN_KIND(Token_Inc, "++"), \
|
||||||
TOKEN_KIND(Token_Dec, "--"), \
|
TOKEN_KIND(Token_Dec, "--"), \
|
||||||
TOKEN_KIND(Token_Undef, "---"), \
|
TOKEN_KIND(Token_Undef, "---"), \
|
||||||
\
|
\
|
||||||
TOKEN_KIND(Token__ComparisonBegin, "_ComparisonBegin"), \
|
TOKEN_KIND(Token__ComparisonBegin, "_ComparisonBegin"), \
|
||||||
TOKEN_KIND(Token_CmpEq, "=="), \
|
TOKEN_KIND(Token_CmpEq, "=="), \
|
||||||
@@ -910,7 +910,16 @@ Token tokenizer_get_token(Tokenizer *t) {
|
|||||||
case '%': token.kind = token_kind_dub_eq(t, '%', Token_Mod, Token_ModEq, Token_ModMod, Token_ModModEq); break;
|
case '%': token.kind = token_kind_dub_eq(t, '%', Token_Mod, Token_ModEq, Token_ModMod, Token_ModModEq); break;
|
||||||
|
|
||||||
case '*': token.kind = token_kind_variant2(t, Token_Mul, Token_MulEq); break;
|
case '*': token.kind = token_kind_variant2(t, Token_Mul, Token_MulEq); break;
|
||||||
case '=': token.kind = token_kind_variant2(t, Token_Eq, Token_CmpEq); break;
|
case '=':
|
||||||
|
token.kind = Token_Eq;
|
||||||
|
if (t->curr_rune == '>') {
|
||||||
|
advance_to_next_rune(t);
|
||||||
|
token.kind = Token_ThickArrowRight;
|
||||||
|
} else if (t->curr_rune == '=') {
|
||||||
|
advance_to_next_rune(t);
|
||||||
|
token.kind = Token_CmpEq;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case '~': token.kind = token_kind_variant2(t, Token_Xor, Token_XorEq); break;
|
case '~': token.kind = token_kind_variant2(t, Token_Xor, Token_XorEq); break;
|
||||||
case '!': token.kind = token_kind_variant2(t, Token_Not, Token_NotEq); break;
|
case '!': token.kind = token_kind_variant2(t, Token_Not, Token_NotEq); break;
|
||||||
case '+': token.kind = token_kind_variant3(t, Token_Add, Token_AddEq, '+', Token_Inc); break;
|
case '+': token.kind = token_kind_variant3(t, Token_Add, Token_AddEq, '+', Token_Inc); break;
|
||||||
@@ -967,11 +976,7 @@ Token tokenizer_get_token(Tokenizer *t) {
|
|||||||
} break;
|
} break;
|
||||||
|
|
||||||
case '<':
|
case '<':
|
||||||
if (t->curr_rune == '-') {
|
token.kind = token_kind_dub_eq(t, '<', Token_Lt, Token_LtEq, Token_Shl, Token_ShlEq);
|
||||||
token.kind = Token_ArrowLeft;
|
|
||||||
} else {
|
|
||||||
token.kind = token_kind_dub_eq(t, '<', Token_Lt, Token_LtEq, Token_Shl, Token_ShlEq);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case '>': token.kind = token_kind_dub_eq(t, '>', Token_Gt, Token_GtEq, Token_Shr, Token_ShrEq); break;
|
case '>': token.kind = token_kind_dub_eq(t, '>', Token_Gt, Token_GtEq, Token_Shr, Token_ShrEq); break;
|
||||||
|
|
||||||
|
|||||||
+35
-23
@@ -944,7 +944,6 @@ bool is_type_indexable(Type *t) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool is_type_polymorphic(Type *t) {
|
bool is_type_polymorphic(Type *t) {
|
||||||
t = core_type(t);
|
|
||||||
switch (t->kind) {
|
switch (t->kind) {
|
||||||
case Type_Generic:
|
case Type_Generic:
|
||||||
return true;
|
return true;
|
||||||
@@ -974,29 +973,36 @@ bool is_type_polymorphic(Type *t) {
|
|||||||
if (t->Proc.is_polymorphic) {
|
if (t->Proc.is_polymorphic) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// if (t->Proc.param_count > 0 &&
|
#if 0
|
||||||
// is_type_polymorphic(t->Proc.params)) {
|
if (t->Proc.param_count > 0 &&
|
||||||
// return true;
|
is_type_polymorphic(t->Proc.params)) {
|
||||||
// }
|
return true;
|
||||||
// if (t->Proc.result_count > 0 &&
|
}
|
||||||
// is_type_polymorphic(t->Proc.results)) {
|
if (t->Proc.result_count > 0 &&
|
||||||
// return true;
|
is_type_polymorphic(t->Proc.results)) {
|
||||||
// }
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// case Type_Record:
|
case Type_Record:
|
||||||
// GB_ASSERT(t->Record.kind != TypeRecord_Enum);
|
if (t->Record.kind == TypeRecord_Enum) {
|
||||||
// for (isize i = 0; i < t->Record.field_count; i++) {
|
if (t->Record.enum_base_type != NULL) {
|
||||||
// if (is_type_polymorphic(t->Record.fields[i]->type)) {
|
return is_type_polymorphic(t->Record.enum_base_type);
|
||||||
// return true;
|
}
|
||||||
// }
|
return false;
|
||||||
// }
|
}
|
||||||
// for (isize i = 1; i < t->Record.variant_count; i++) {
|
for (isize i = 0; i < t->Record.field_count; i++) {
|
||||||
// if (is_type_polymorphic(t->Record.variants[i]->type)) {
|
if (is_type_polymorphic(t->Record.fields[i]->type)) {
|
||||||
// return true;
|
return true;
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
// break;
|
for (isize i = 1; i < t->Record.variant_count; i++) {
|
||||||
|
if (is_type_polymorphic(t->Record.variants[i]->type)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case Type_Map:
|
case Type_Map:
|
||||||
if (is_type_polymorphic(t->Map.key)) {
|
if (is_type_polymorphic(t->Map.key)) {
|
||||||
@@ -2263,7 +2269,13 @@ gbString write_type_to_string(gbString str, Type *type) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case Type_Generic:
|
case Type_Generic:
|
||||||
str = gb_string_appendc(str, "type");
|
if (type->Generic.name.len == 0) {
|
||||||
|
str = gb_string_appendc(str, "type");
|
||||||
|
} else {
|
||||||
|
String name = type->Generic.name;
|
||||||
|
str = gb_string_appendc(str, "$");
|
||||||
|
str = gb_string_append_length(str, name.text, name.len);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Type_Pointer:
|
case Type_Pointer:
|
||||||
|
|||||||
Reference in New Issue
Block a user