mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-06 15:48:51 +00:00
Rudimentary para-poly procedures
This commit is contained in:
+4
-1
@@ -3,11 +3,14 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
proc new_type(T: type) -> ^T {
|
proc new_type(T: type) -> ^T {
|
||||||
return ^T(alloc_align(size_of(T), align_of(T)));
|
return ^T(alloc(size_of(T), align_of(T)));
|
||||||
}
|
}
|
||||||
|
|
||||||
proc main() {
|
proc main() {
|
||||||
var ptr = new_type(int);
|
var ptr = new_type(int);
|
||||||
|
ptr^ = 123;
|
||||||
|
|
||||||
|
fmt.println(ptr^);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
+9
-2
@@ -307,7 +307,12 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Type *proc_type = make_type_proc(c->allocator, e->scope, NULL, 0, NULL, 0, false, ProcCC_Odin);
|
Type *proc_type = e->type;
|
||||||
|
if (d->gen_proc_type != NULL) {
|
||||||
|
proc_type = d->gen_proc_type;
|
||||||
|
} else {
|
||||||
|
proc_type = make_type_proc(c->allocator, e->scope, NULL, 0, NULL, 0, false, ProcCC_Odin);
|
||||||
|
}
|
||||||
e->type = proc_type;
|
e->type = proc_type;
|
||||||
ast_node(pd, ProcDecl, d->proc_decl);
|
ast_node(pd, ProcDecl, d->proc_decl);
|
||||||
|
|
||||||
@@ -575,7 +580,9 @@ void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNod
|
|||||||
TypeTuple *params = &type->Proc.params->Tuple;
|
TypeTuple *params = &type->Proc.params->Tuple;
|
||||||
for (isize i = 0; i < params->variable_count; i++) {
|
for (isize i = 0; i < params->variable_count; i++) {
|
||||||
Entity *e = params->variables[i];
|
Entity *e = params->variables[i];
|
||||||
GB_ASSERT(e->kind == Entity_Variable);
|
if (e->kind != Entity_Variable) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (!(e->flags & EntityFlag_Using)) {
|
if (!(e->flags & EntityFlag_Using)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|||||||
+107
-47
@@ -1,3 +1,37 @@
|
|||||||
|
enum CallArgumentError {
|
||||||
|
CallArgumentError_None,
|
||||||
|
CallArgumentError_NoneProcedureType,
|
||||||
|
CallArgumentError_WrongTypes,
|
||||||
|
CallArgumentError_NonVariadicExpand,
|
||||||
|
CallArgumentError_VariadicTuple,
|
||||||
|
CallArgumentError_MultipleVariadicExpand,
|
||||||
|
CallArgumentError_ArgumentCount,
|
||||||
|
CallArgumentError_TooFewArguments,
|
||||||
|
CallArgumentError_TooManyArguments,
|
||||||
|
CallArgumentError_InvalidFieldValue,
|
||||||
|
CallArgumentError_ParameterNotFound,
|
||||||
|
CallArgumentError_ParameterMissing,
|
||||||
|
CallArgumentError_DuplicateParameter,
|
||||||
|
CallArgumentError_GenericProcedureNotSupported,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum CallArgumentErrorMode {
|
||||||
|
CallArgumentMode_NoErrors,
|
||||||
|
CallArgumentMode_ShowErrors,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CallArgumentData {
|
||||||
|
Entity *gen_entity;
|
||||||
|
i64 score;
|
||||||
|
Type * result_type;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#define CALL_ARGUMENT_CHECKER(name) CallArgumentError name(Checker *c, AstNode *call, Type *proc_type, Entity *entity, Array<Operand> operands, CallArgumentErrorMode show_error_mode, CallArgumentData *data)
|
||||||
|
typedef CALL_ARGUMENT_CHECKER(CallArgumentCheckerType);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void check_expr (Checker *c, Operand *operand, AstNode *expression);
|
void check_expr (Checker *c, Operand *operand, AstNode *expression);
|
||||||
void check_multi_expr (Checker *c, Operand *operand, AstNode *expression);
|
void check_multi_expr (Checker *c, Operand *operand, AstNode *expression);
|
||||||
void check_expr_or_type (Checker *c, Operand *operand, AstNode *expression);
|
void check_expr_or_type (Checker *c, Operand *operand, AstNode *expression);
|
||||||
@@ -19,7 +53,7 @@ void check_stmt (Checker *c, AstNode *node, u32 flags);
|
|||||||
void check_stmt_list (Checker *c, Array<AstNode *> stmts, u32 flags);
|
void check_stmt_list (Checker *c, Array<AstNode *> stmts, u32 flags);
|
||||||
void check_init_constant (Checker *c, Entity *e, Operand *operand);
|
void check_init_constant (Checker *c, Entity *e, Operand *operand);
|
||||||
bool check_representable_as_constant(Checker *c, ExactValue in_value, Type *type, ExactValue *out_value);
|
bool check_representable_as_constant(Checker *c, ExactValue in_value, Type *type, ExactValue *out_value);
|
||||||
Type * check_call_arguments (Checker *c, Operand *operand, Type *proc_type, AstNode *call);
|
CallArgumentData check_call_arguments (Checker *c, Operand *operand, Type *proc_type, AstNode *call);
|
||||||
|
|
||||||
|
|
||||||
void error_operand_not_expression(Operand *o) {
|
void error_operand_not_expression(Operand *o) {
|
||||||
@@ -1173,13 +1207,16 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
|
|||||||
if (ast_node_expect(name, AstNode_Ident)) {
|
if (ast_node_expect(name, AstNode_Ident)) {
|
||||||
Entity *param = NULL;
|
Entity *param = NULL;
|
||||||
bool is_generic = type->kind == Type_Generic;
|
bool is_generic = type->kind == Type_Generic;
|
||||||
|
Type *gen_type = type;
|
||||||
if (operands != NULL) {
|
if (operands != NULL) {
|
||||||
Operand o = (*operands)[j];
|
Operand o = (*operands)[j];
|
||||||
is_generic = o.mode == Addressing_Type && o.type == type;
|
is_generic = o.mode == Addressing_Type && o.type == type;
|
||||||
|
if (is_generic) gen_type = o.type;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_generic) {
|
if (is_generic) {
|
||||||
param = make_entity_type_name(c->allocator, scope, name->Ident, type);
|
param = make_entity_type_name(c->allocator, scope, name->Ident, gen_type);
|
||||||
|
param->TypeName.is_type_alias = true;
|
||||||
} else {
|
} else {
|
||||||
param = make_entity_param(c->allocator, scope, name->Ident, type,
|
param = make_entity_param(c->allocator, scope, name->Ident, type,
|
||||||
(p->flags&FieldFlag_using) != 0, false);
|
(p->flags&FieldFlag_using) != 0, false);
|
||||||
@@ -4858,28 +4895,6 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum CallArgumentError {
|
|
||||||
CallArgumentError_None,
|
|
||||||
CallArgumentError_NoneProcedureType,
|
|
||||||
CallArgumentError_WrongTypes,
|
|
||||||
CallArgumentError_NonVariadicExpand,
|
|
||||||
CallArgumentError_VariadicTuple,
|
|
||||||
CallArgumentError_MultipleVariadicExpand,
|
|
||||||
CallArgumentError_ArgumentCount,
|
|
||||||
CallArgumentError_TooFewArguments,
|
|
||||||
CallArgumentError_TooManyArguments,
|
|
||||||
CallArgumentError_InvalidFieldValue,
|
|
||||||
CallArgumentError_ParameterNotFound,
|
|
||||||
CallArgumentError_ParameterMissing,
|
|
||||||
CallArgumentError_DuplicateParameter,
|
|
||||||
CallArgumentError_GenericProcedureNotSupported,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum CallArgumentErrorMode {
|
|
||||||
CallArgumentMode_NoErrors,
|
|
||||||
CallArgumentMode_ShowErrors,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
struct ValidProcAndScore {
|
struct ValidProcAndScore {
|
||||||
isize index;
|
isize index;
|
||||||
@@ -4934,8 +4949,7 @@ bool check_unpack_arguments(Checker *c, isize lhs_count, Array<Operand> *operand
|
|||||||
return optional_ok;
|
return optional_ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define CALL_ARGUMENT_CHECKER(name) CallArgumentError name(Checker *c, AstNode *call, Type *proc_type, Array<Operand> operands, CallArgumentErrorMode show_error_mode, i64 *score_, Type **result_type_)
|
|
||||||
typedef CALL_ARGUMENT_CHECKER(CallArgumentCheckerType);
|
|
||||||
|
|
||||||
|
|
||||||
CALL_ARGUMENT_CHECKER(check_call_arguments_internal) {
|
CALL_ARGUMENT_CHECKER(check_call_arguments_internal) {
|
||||||
@@ -4984,6 +4998,7 @@ CALL_ARGUMENT_CHECKER(check_call_arguments_internal) {
|
|||||||
|
|
||||||
CallArgumentError err = CallArgumentError_None;
|
CallArgumentError err = CallArgumentError_None;
|
||||||
Type *final_proc_type = proc_type;
|
Type *final_proc_type = proc_type;
|
||||||
|
Entity *gen_entity = NULL;
|
||||||
|
|
||||||
if (vari_expand && !variadic) {
|
if (vari_expand && !variadic) {
|
||||||
if (show_error) {
|
if (show_error) {
|
||||||
@@ -5022,14 +5037,44 @@ CALL_ARGUMENT_CHECKER(check_call_arguments_internal) {
|
|||||||
gb_string_free(proc_str);
|
gb_string_free(proc_str);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// NOTE(bill): Generate the procedure type for this generic instance
|
||||||
|
// TODO(bill): Clean this shit up!
|
||||||
if (pt->is_generic) {
|
if (pt->is_generic) {
|
||||||
Scope *scope = make_scope(pt->scope->parent, c->allocator);
|
GB_ASSERT(entity != NULL);
|
||||||
CheckerContext prev = c->context;
|
DeclInfo *old_decl = decl_info_of_entity(&c->info, entity);
|
||||||
defer (c->context = prev);
|
GB_ASSERT(old_decl != NULL);
|
||||||
c->context.scope = scope;
|
|
||||||
|
|
||||||
final_proc_type = alloc_type(c->allocator, Type_Proc);
|
gbAllocator a = heap_allocator();
|
||||||
|
|
||||||
|
Scope *scope = entity->scope;
|
||||||
|
|
||||||
|
AstNode *proc_decl = clone_ast_node(a, old_decl->proc_decl);
|
||||||
|
ast_node(pd, ProcDecl, proc_decl);
|
||||||
|
|
||||||
|
check_open_scope(c, pd->type);
|
||||||
|
defer (check_close_scope(c));
|
||||||
|
|
||||||
|
final_proc_type = make_type_proc(c->allocator, c->context.scope, NULL, 0, NULL, 0, false, pt->calling_convention);
|
||||||
check_procedure_type(c, final_proc_type, pt->node, &operands);
|
check_procedure_type(c, final_proc_type, pt->node, &operands);
|
||||||
|
|
||||||
|
u64 tags = entity->Procedure.tags;
|
||||||
|
AstNode *ident = clone_ast_node(a, entity->identifier);
|
||||||
|
Token token = ident->Ident;
|
||||||
|
DeclInfo *d = make_declaration_info(c->allocator, c->context.scope, old_decl->parent);
|
||||||
|
d->gen_proc_type = final_proc_type;
|
||||||
|
d->type_expr = pd->type;
|
||||||
|
d->proc_decl = proc_decl;
|
||||||
|
|
||||||
|
gen_entity = make_entity_procedure(c->allocator, entity->scope, token, final_proc_type, tags);
|
||||||
|
gen_entity->identifier = ident;
|
||||||
|
|
||||||
|
add_entity_and_decl_info(c, ident, gen_entity, d);
|
||||||
|
add_entity_definition(&c->info, ident, gen_entity);
|
||||||
|
|
||||||
|
add_entity_use(c, ident, gen_entity);
|
||||||
|
add_entity_use(c, ce->proc, gen_entity);
|
||||||
|
|
||||||
|
check_procedure_later(c, c->curr_ast_file, token, d, final_proc_type, pd->body, tags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -5082,7 +5127,11 @@ CALL_ARGUMENT_CHECKER(check_call_arguments_internal) {
|
|||||||
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 (score_) *score_ = score;
|
if (data) {
|
||||||
|
data->score = score;
|
||||||
|
data->result_type = final_proc_type->Proc.results;
|
||||||
|
data->gen_entity = gen_entity;
|
||||||
|
}
|
||||||
return CallArgumentError_MultipleVariadicExpand;
|
return CallArgumentError_MultipleVariadicExpand;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5099,8 +5148,11 @@ CALL_ARGUMENT_CHECKER(check_call_arguments_internal) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (score_) *score_ = score;
|
if (data) {
|
||||||
if (result_type_) *result_type_ = final_proc_type->Proc.results;
|
data->score = score;
|
||||||
|
data->result_type = final_proc_type->Proc.results;
|
||||||
|
data->gen_entity = gen_entity;
|
||||||
|
}
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@@ -5250,14 +5302,17 @@ CALL_ARGUMENT_CHECKER(check_named_call_arguments) {
|
|||||||
err = CallArgumentError_GenericProcedureNotSupported;
|
err = CallArgumentError_GenericProcedureNotSupported;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (score_) *score_ = score;
|
if (data) {
|
||||||
if (result_type_) *result_type_ = pt->results;
|
data->score = score;
|
||||||
|
data->result_type = pt->results;
|
||||||
|
data->gen_entity = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Type *check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNode *call) {
|
CallArgumentData check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNode *call) {
|
||||||
ast_node(ce, CallExpr, call);
|
ast_node(ce, CallExpr, call);
|
||||||
|
|
||||||
CallArgumentCheckerType *call_checker = check_call_arguments_internal;
|
CallArgumentCheckerType *call_checker = check_call_arguments_internal;
|
||||||
@@ -5310,11 +5365,11 @@ Type *check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNod
|
|||||||
Entity *p = procs[i];
|
Entity *p = procs[i];
|
||||||
Type *pt = base_type(p->type);
|
Type *pt = base_type(p->type);
|
||||||
if (pt != NULL && is_type_proc(pt)) {
|
if (pt != NULL && is_type_proc(pt)) {
|
||||||
i64 score = 0;
|
CallArgumentData data = {};
|
||||||
CallArgumentError err = call_checker(c, call, pt, operands, CallArgumentMode_NoErrors, &score, &result_type);
|
CallArgumentError err = call_checker(c, call, pt, p, operands, CallArgumentMode_NoErrors, &data);
|
||||||
if (err == CallArgumentError_None) {
|
if (err == CallArgumentError_None) {
|
||||||
valids[valid_count].index = i;
|
valids[valid_count].index = i;
|
||||||
valids[valid_count].score = score;
|
valids[valid_count].score = data.score;
|
||||||
valid_count++;
|
valid_count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5355,15 +5410,20 @@ Type *check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNod
|
|||||||
Entity *e = procs[valids[0].index];
|
Entity *e = procs[valids[0].index];
|
||||||
add_entity_use(c, expr, e);
|
add_entity_use(c, expr, e);
|
||||||
proc_type = e->type;
|
proc_type = e->type;
|
||||||
i64 score = 0;
|
CallArgumentData data = {};
|
||||||
CallArgumentError err = call_checker(c, call, proc_type, operands, CallArgumentMode_ShowErrors, &score, &result_type);
|
CallArgumentError err = call_checker(c, call, proc_type, e, operands, CallArgumentMode_ShowErrors, &data);
|
||||||
|
return data;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
i64 score = 0;
|
Entity *e = entity_of_ident(&c->info, operand->expr);
|
||||||
CallArgumentError err = call_checker(c, call, proc_type, operands, CallArgumentMode_ShowErrors, &score, &result_type);
|
CallArgumentData data = {};
|
||||||
|
CallArgumentError err = call_checker(c, call, proc_type, e, operands, CallArgumentMode_ShowErrors, &data);
|
||||||
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result_type;
|
CallArgumentData data = {};
|
||||||
|
data.result_type = t_invalid;
|
||||||
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -5498,8 +5558,8 @@ ExprKind check_call_expr(Checker *c, Operand *operand, AstNode *call) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Type *result_type = check_call_arguments(c, operand, proc_type, call);
|
CallArgumentData data = check_call_arguments(c, operand, proc_type, call);
|
||||||
|
Type *result_type = data.result_type;
|
||||||
gb_zero_item(operand);
|
gb_zero_item(operand);
|
||||||
operand->expr = call;
|
operand->expr = call;
|
||||||
|
|
||||||
|
|||||||
+34
-20
@@ -188,6 +188,7 @@ struct DeclInfo {
|
|||||||
AstNode * type_expr;
|
AstNode * type_expr;
|
||||||
AstNode * init_expr;
|
AstNode * init_expr;
|
||||||
AstNode * proc_decl; // AstNode_ProcDecl
|
AstNode * proc_decl; // AstNode_ProcDecl
|
||||||
|
Type * gen_proc_type; // Precalculated
|
||||||
|
|
||||||
Map<bool> deps; // Key: Entity *
|
Map<bool> deps; // Key: Entity *
|
||||||
Array<BlockLabel> labels;
|
Array<BlockLabel> labels;
|
||||||
@@ -202,7 +203,7 @@ struct ProcedureInfo {
|
|||||||
DeclInfo * decl;
|
DeclInfo * decl;
|
||||||
Type * type; // Type_Procedure
|
Type * type; // Type_Procedure
|
||||||
AstNode * body; // AstNode_BlockStmt
|
AstNode * body; // AstNode_BlockStmt
|
||||||
u32 tags;
|
u64 tags;
|
||||||
};
|
};
|
||||||
|
|
||||||
// ExprInfo stores information used for "untyped" expressions
|
// ExprInfo stores information used for "untyped" expressions
|
||||||
@@ -266,6 +267,7 @@ struct CheckerContext {
|
|||||||
AstNode * curr_foreign_library;
|
AstNode * curr_foreign_library;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// CheckerInfo stores all the symbol information for a type-checked program
|
// CheckerInfo stores all the symbol information for a type-checked program
|
||||||
struct CheckerInfo {
|
struct CheckerInfo {
|
||||||
Map<TypeAndValue> types; // Key: AstNode * | Expression -> Type (and value)
|
Map<TypeAndValue> types; // Key: AstNode * | Expression -> Type (and value)
|
||||||
@@ -277,7 +279,6 @@ struct CheckerInfo {
|
|||||||
Map<DeclInfo *> entities; // Key: Entity *
|
Map<DeclInfo *> entities; // Key: Entity *
|
||||||
Map<Entity *> foreigns; // Key: String
|
Map<Entity *> foreigns; // Key: String
|
||||||
Map<AstFile *> files; // Key: String (full path)
|
Map<AstFile *> files; // Key: String (full path)
|
||||||
|
|
||||||
Map<isize> type_info_map; // Key: Type *
|
Map<isize> type_info_map; // Key: Type *
|
||||||
isize type_info_count;
|
isize type_info_count;
|
||||||
};
|
};
|
||||||
@@ -286,28 +287,29 @@ struct Checker {
|
|||||||
Parser * parser;
|
Parser * parser;
|
||||||
CheckerInfo info;
|
CheckerInfo info;
|
||||||
|
|
||||||
AstFile * curr_ast_file;
|
AstFile * curr_ast_file;
|
||||||
Scope * global_scope;
|
Scope * global_scope;
|
||||||
// NOTE(bill): Procedures to check
|
// NOTE(bill): Procedures to check
|
||||||
Map<ProcedureInfo> procs; // Key: DeclInfo *
|
Map<ProcedureInfo> procs; // Key: DeclInfo *
|
||||||
Array<DelayedDecl> delayed_imports;
|
Map<Array<ProcedureInfo> > gen_procs;
|
||||||
Array<DelayedDecl> delayed_foreign_libraries;
|
Array<DelayedDecl> delayed_imports;
|
||||||
Array<CheckerFileNode> file_nodes;
|
Array<DelayedDecl> delayed_foreign_libraries;
|
||||||
|
Array<CheckerFileNode> file_nodes;
|
||||||
|
|
||||||
gbArena arena;
|
gbArena arena;
|
||||||
gbArena tmp_arena;
|
gbArena tmp_arena;
|
||||||
gbAllocator allocator;
|
gbAllocator allocator;
|
||||||
gbAllocator tmp_allocator;
|
gbAllocator tmp_allocator;
|
||||||
|
|
||||||
CheckerContext context;
|
CheckerContext context;
|
||||||
|
|
||||||
Array<Type *> proc_stack;
|
Array<Type *> proc_stack;
|
||||||
bool done_preload;
|
bool done_preload;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
HashKey hash_node (AstNode *node) { return hash_ptr_and_id(node, 0); }
|
HashKey hash_node (AstNode *node) { return hash_pointer(node); }
|
||||||
HashKey hash_ast_file (AstFile *file) { return hash_pointer(file); }
|
HashKey hash_ast_file (AstFile *file) { return hash_pointer(file); }
|
||||||
HashKey hash_entity (Entity *e) { return hash_pointer(e); }
|
HashKey hash_entity (Entity *e) { return hash_pointer(e); }
|
||||||
HashKey hash_type (Type *t) { return hash_pointer(t); }
|
HashKey hash_type (Type *t) { return hash_pointer(t); }
|
||||||
@@ -741,6 +743,7 @@ void init_checker(Checker *c, Parser *parser) {
|
|||||||
|
|
||||||
array_init(&c->proc_stack, a);
|
array_init(&c->proc_stack, a);
|
||||||
map_init(&c->procs, a);
|
map_init(&c->procs, a);
|
||||||
|
map_init(&c->gen_procs, a);
|
||||||
array_init(&c->delayed_imports, a);
|
array_init(&c->delayed_imports, a);
|
||||||
array_init(&c->delayed_foreign_libraries, a);
|
array_init(&c->delayed_foreign_libraries, a);
|
||||||
array_init(&c->file_nodes, a);
|
array_init(&c->file_nodes, a);
|
||||||
@@ -778,6 +781,7 @@ void destroy_checker(Checker *c) {
|
|||||||
destroy_scope(c->global_scope);
|
destroy_scope(c->global_scope);
|
||||||
array_free(&c->proc_stack);
|
array_free(&c->proc_stack);
|
||||||
map_destroy(&c->procs);
|
map_destroy(&c->procs);
|
||||||
|
map_destroy(&c->gen_procs);
|
||||||
array_free(&c->delayed_imports);
|
array_free(&c->delayed_imports);
|
||||||
array_free(&c->delayed_foreign_libraries);
|
array_free(&c->delayed_foreign_libraries);
|
||||||
array_free(&c->file_nodes);
|
array_free(&c->file_nodes);
|
||||||
@@ -946,7 +950,7 @@ void add_entity_definition(CheckerInfo *i, AstNode *identifier, Entity *entity)
|
|||||||
HashKey key = hash_node(identifier);
|
HashKey key = hash_node(identifier);
|
||||||
map_set(&i->definitions, key, entity);
|
map_set(&i->definitions, key, entity);
|
||||||
} else {
|
} else {
|
||||||
// NOTE(bill): Error should handled elsewhere
|
// NOTE(bill): Error should be handled elsewhere
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1161,7 +1165,7 @@ void add_type_info_type(Checker *c, Type *t) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void check_procedure_later(Checker *c, AstFile *file, Token token, DeclInfo *decl, Type *type, AstNode *body, u32 tags) {
|
void check_procedure_later(Checker *c, AstFile *file, Token token, DeclInfo *decl, Type *type, AstNode *body, u64 tags) {
|
||||||
ProcedureInfo info = {};
|
ProcedureInfo info = {};
|
||||||
info.file = file;
|
info.file = file;
|
||||||
info.token = token;
|
info.token = token;
|
||||||
@@ -1204,6 +1208,14 @@ void add_dependency_to_map(Map<Entity *> *map, CheckerInfo *info, Entity *entity
|
|||||||
if (entity == NULL) {
|
if (entity == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (entity->type != NULL &&
|
||||||
|
is_type_gen_proc(entity->type)) {
|
||||||
|
DeclInfo *decl = decl_info_of_entity(info, entity);
|
||||||
|
if (decl->gen_proc_type == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (map_get(map, hash_entity(entity)) != NULL) {
|
if (map_get(map, hash_entity(entity)) != NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -2241,8 +2253,10 @@ void check_parsed_files(Checker *c) {
|
|||||||
|
|
||||||
TypeProc *pt = &pi->type->Proc;
|
TypeProc *pt = &pi->type->Proc;
|
||||||
if (pt->is_generic) {
|
if (pt->is_generic) {
|
||||||
error(pi->token, "Generic procedures are not yet supported");
|
if (pi->decl->gen_proc_type == NULL) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
// gb_printf_err("Generic procedure `%.*s` -> %s\n", LIT(pi->token.string), type_to_string(pi->decl->gen_proc_type));
|
||||||
}
|
}
|
||||||
|
|
||||||
add_curr_ast_file(c, pi->file);
|
add_curr_ast_file(c, pi->file);
|
||||||
|
|||||||
+1
-1
@@ -3602,7 +3602,7 @@ extern "C" {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
void gb_assert_handler(char const *condition, char const *file, i32 line, char const *msg, ...) {
|
void gb_assert_handler(char const *condition, char const *file, i32 line, char const *msg, ...) {
|
||||||
gb_printf_err("%s:%d: Assert Failure: ", file, line);
|
gb_printf_err("%s(%d): Assert Failure: ", file, line);
|
||||||
if (condition)
|
if (condition)
|
||||||
gb_printf_err( "`%s` ", condition);
|
gb_printf_err( "`%s` ", condition);
|
||||||
if (msg) {
|
if (msg) {
|
||||||
|
|||||||
+17
-2
@@ -1510,7 +1510,11 @@ irValue *ir_emit_call(irProcedure *p, irValue *value, irValue **args, isize arg_
|
|||||||
GB_ASSERT(param_count == arg_count);
|
GB_ASSERT(param_count == arg_count);
|
||||||
}
|
}
|
||||||
for (isize i = 0; i < param_count; i++) {
|
for (isize i = 0; i < param_count; i++) {
|
||||||
Type *original_type = pt->Proc.params->Tuple.variables[i]->type;
|
Entity *e = pt->Proc.params->Tuple.variables[i];
|
||||||
|
if (e->kind != Entity_Variable) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Type *original_type = e->type;
|
||||||
Type *new_type = pt->Proc.abi_compat_params[i];
|
Type *new_type = pt->Proc.abi_compat_params[i];
|
||||||
if (original_type != new_type) {
|
if (original_type != new_type) {
|
||||||
if (is_type_pointer(new_type)) {
|
if (is_type_pointer(new_type)) {
|
||||||
@@ -4360,6 +4364,11 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) {
|
|||||||
TypeAndValue tv = type_and_value_of_expr(proc->module->info, expr);
|
TypeAndValue tv = type_and_value_of_expr(proc->module->info, expr);
|
||||||
GB_ASSERT(tv.mode != Addressing_Invalid);
|
GB_ASSERT(tv.mode != Addressing_Invalid);
|
||||||
|
|
||||||
|
if (tv.mode == Addressing_Type) {
|
||||||
|
// TODO(bill): Handle this correctly
|
||||||
|
return ir_value_nil(proc->module->allocator, tv.type);
|
||||||
|
}
|
||||||
|
|
||||||
if (tv.value.kind != ExactValue_Invalid) {
|
if (tv.value.kind != ExactValue_Invalid) {
|
||||||
// NOTE(bill): Edge case
|
// NOTE(bill): Edge case
|
||||||
if (tv.value.kind != ExactValue_Compound &&
|
if (tv.value.kind != ExactValue_Compound &&
|
||||||
@@ -4417,7 +4426,7 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) {
|
|||||||
} else if (e != NULL && e->kind == Entity_Variable) {
|
} else if (e != NULL && e->kind == Entity_Variable) {
|
||||||
return ir_addr_load(proc, ir_build_addr(proc, expr));
|
return ir_addr_load(proc, ir_build_addr(proc, expr));
|
||||||
}
|
}
|
||||||
GB_PANIC("NULL value for expression from identifier: %.*s", LIT(i->string));
|
GB_PANIC("NULL value for expression from identifier: %.*s @ %p", LIT(i->string), expr);
|
||||||
return NULL;
|
return NULL;
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
@@ -6911,6 +6920,10 @@ void ir_begin_procedure_body(irProcedure *proc) {
|
|||||||
AstNode *name = field->names[q_index++];
|
AstNode *name = field->names[q_index++];
|
||||||
|
|
||||||
Entity *e = params->variables[i];
|
Entity *e = params->variables[i];
|
||||||
|
if (e->kind != Entity_Variable) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
Type *abi_type = proc->type->Proc.abi_compat_params[i];
|
Type *abi_type = proc->type->Proc.abi_compat_params[i];
|
||||||
if (e->token.string != "" &&
|
if (e->token.string != "" &&
|
||||||
e->token.string != "_") {
|
e->token.string != "_") {
|
||||||
@@ -7385,6 +7398,8 @@ void ir_gen_tree(irGen *s) {
|
|||||||
ast_node(pd, ProcDecl, decl->proc_decl);
|
ast_node(pd, ProcDecl, decl->proc_decl);
|
||||||
String original_name = name;
|
String original_name = name;
|
||||||
AstNode *body = pd->body;
|
AstNode *body = pd->body;
|
||||||
|
|
||||||
|
|
||||||
if (e->Procedure.is_foreign) {
|
if (e->Procedure.is_foreign) {
|
||||||
name = e->token.string; // NOTE(bill): Don't use the mangled name
|
name = e->token.string; // NOTE(bill): Don't use the mangled name
|
||||||
ir_add_foreign_library_path(m, e->Procedure.foreign_library);
|
ir_add_foreign_library_path(m, e->Procedure.foreign_library);
|
||||||
|
|||||||
+10
-4
@@ -1280,6 +1280,7 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
isize param_index = 0;
|
||||||
if (call->arg_count > 0) {
|
if (call->arg_count > 0) {
|
||||||
TypeTuple *params = &proc_type->Proc.params->Tuple;
|
TypeTuple *params = &proc_type->Proc.params->Tuple;
|
||||||
if (proc_type->Proc.c_vararg) {
|
if (proc_type->Proc.c_vararg) {
|
||||||
@@ -1287,8 +1288,9 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
|||||||
for (; i < params->variable_count-1; i++) {
|
for (; i < params->variable_count-1; i++) {
|
||||||
Entity *e = params->variables[i];
|
Entity *e = params->variables[i];
|
||||||
GB_ASSERT(e != NULL);
|
GB_ASSERT(e != NULL);
|
||||||
|
if (e->kind != Entity_Variable) continue;
|
||||||
Type *t = proc_type->Proc.abi_compat_params[i];
|
Type *t = proc_type->Proc.abi_compat_params[i];
|
||||||
if (i > 0) {
|
if (param_index > 0) {
|
||||||
ir_fprintf(f, ", ");
|
ir_fprintf(f, ", ");
|
||||||
}
|
}
|
||||||
ir_print_type(f, m, t);
|
ir_print_type(f, m, t);
|
||||||
@@ -1298,9 +1300,10 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
|||||||
ir_fprintf(f, " ");
|
ir_fprintf(f, " ");
|
||||||
irValue *arg = call->args[i];
|
irValue *arg = call->args[i];
|
||||||
ir_print_value(f, m, arg, t);
|
ir_print_value(f, m, arg, t);
|
||||||
|
param_index++;
|
||||||
}
|
}
|
||||||
for (; i < call->arg_count; i++) {
|
for (; i < call->arg_count; i++) {
|
||||||
if (i > 0) {
|
if (param_index > 0) {
|
||||||
ir_fprintf(f, ", ");
|
ir_fprintf(f, ", ");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1309,6 +1312,7 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
|||||||
ir_print_type(f, m, t);
|
ir_print_type(f, m, t);
|
||||||
ir_fprintf(f, " ");
|
ir_fprintf(f, " ");
|
||||||
ir_print_value(f, m, arg, t);
|
ir_print_value(f, m, arg, t);
|
||||||
|
param_index++;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
GB_ASSERT(call->arg_count == params->variable_count);
|
GB_ASSERT(call->arg_count == params->variable_count);
|
||||||
@@ -1316,9 +1320,10 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
|||||||
for (isize i = 0; i < param_count; i++) {
|
for (isize i = 0; i < param_count; i++) {
|
||||||
Entity *e = params->variables[i];
|
Entity *e = params->variables[i];
|
||||||
GB_ASSERT(e != NULL);
|
GB_ASSERT(e != NULL);
|
||||||
|
if (e->kind != Entity_Variable) continue;
|
||||||
irValue *arg = call->args[i];
|
irValue *arg = call->args[i];
|
||||||
Type *t = proc_type->Proc.abi_compat_params[i];
|
Type *t = proc_type->Proc.abi_compat_params[i];
|
||||||
if (i > 0) {
|
if (param_index > 0) {
|
||||||
ir_fprintf(f, ", ");
|
ir_fprintf(f, ", ");
|
||||||
}
|
}
|
||||||
ir_print_type(f, m, t);
|
ir_print_type(f, m, t);
|
||||||
@@ -1327,11 +1332,12 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
|||||||
}
|
}
|
||||||
ir_fprintf(f, " ");
|
ir_fprintf(f, " ");
|
||||||
ir_print_value(f, m, arg, t);
|
ir_print_value(f, m, arg, t);
|
||||||
|
param_index++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (proc_type->Proc.calling_convention == ProcCC_Odin) {
|
if (proc_type->Proc.calling_convention == ProcCC_Odin) {
|
||||||
if (proc_type->Proc.param_count > 0) {
|
if (param_index > 0) {
|
||||||
ir_fprintf(f, ", ");
|
ir_fprintf(f, ", ");
|
||||||
}
|
}
|
||||||
ir_print_type(f, m, t_context_ptr);
|
ir_print_type(f, m, t_context_ptr);
|
||||||
|
|||||||
@@ -2234,6 +2234,10 @@ gbString write_type_to_string(gbString str, Type *type) {
|
|||||||
str = gb_string_append_length(str, type->Basic.name.text, type->Basic.name.len);
|
str = gb_string_append_length(str, type->Basic.name.text, type->Basic.name.len);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case Type_Generic:
|
||||||
|
str = gb_string_appendc(str, "type");
|
||||||
|
break;
|
||||||
|
|
||||||
case Type_Pointer:
|
case Type_Pointer:
|
||||||
str = gb_string_appendc(str, "^");
|
str = gb_string_appendc(str, "^");
|
||||||
str = write_type_to_string(str, type->Pointer.elem);
|
str = write_type_to_string(str, type->Pointer.elem);
|
||||||
|
|||||||
Reference in New Issue
Block a user