mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-05 07:08:48 +00:00
Allow for named arguments for polymorphic procedures
This commit is contained in:
@@ -8,7 +8,6 @@ The Odin programming language is fast, concise, readable, pragmatic and open sou
|
|||||||
* built for modern systems
|
* built for modern systems
|
||||||
* joy of programming
|
* joy of programming
|
||||||
* metaprogramming
|
* metaprogramming
|
||||||
* designed for good programmers
|
|
||||||
|
|
||||||
Website: [https://odin.handmade.network/](https://odin.handmade.network/)
|
Website: [https://odin.handmade.network/](https://odin.handmade.network/)
|
||||||
|
|
||||||
@@ -20,8 +19,7 @@ Website: [https://odin.handmade.network/](https://odin.handmade.network/)
|
|||||||
* [Composition & Refactorability](https://www.youtube.com/watch?v=n1wemZfcbXM)
|
* [Composition & Refactorability](https://www.youtube.com/watch?v=n1wemZfcbXM)
|
||||||
* [Introspection, Modules, and Record Layout](https://www.youtube.com/watch?v=UFq8rhWhx4s)
|
* [Introspection, Modules, and Record Layout](https://www.youtube.com/watch?v=UFq8rhWhx4s)
|
||||||
* [push_allocator & Minimal Dependency Building](https://www.youtube.com/watch?v=f_LGVOAMb78)
|
* [push_allocator & Minimal Dependency Building](https://www.youtube.com/watch?v=f_LGVOAMb78)
|
||||||
* [when, for, & procedure overloading](https://www.youtube.com/watch?v=OzeOekzyZK8)
|
* [when, for & procedure overloading](https://www.youtube.com/watch?v=OzeOekzyZK8)
|
||||||
* [when, for, & procedure overloading](https://www.youtube.com/watch?v=OzeOekzyZK8)
|
|
||||||
* [Context Types, Unexported Entities, Labelled Branches](https://www.youtube.com/watch?v=CkHVwT1Qk-g)
|
* [Context Types, Unexported Entities, Labelled Branches](https://www.youtube.com/watch?v=CkHVwT1Qk-g)
|
||||||
* [Bit Fields, i128 & u128, Syntax Changes](https://www.youtube.com/watch?v=NlTutcLyF64)
|
* [Bit Fields, i128 & u128, Syntax Changes](https://www.youtube.com/watch?v=NlTutcLyF64)
|
||||||
|
|
||||||
|
|||||||
+153
-113
@@ -4967,8 +4967,99 @@ bool check_unpack_arguments(Checker *c, isize lhs_count, Array<Operand> *operand
|
|||||||
return optional_ok;
|
return optional_ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NOTE(bill): Returns `NULL` on failure
|
||||||
|
Entity *find_or_generate_polymorphic_procedure(Checker *c, Entity *base_entity, Array<Operand> *operands, ProcedureInfo *proc_info_) {
|
||||||
|
if (base_entity == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_type_proc(base_entity->type)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
TypeProc *pt = &base_type(base_entity->type)->Proc;
|
||||||
|
if (!pt->is_generic || pt->is_generic_specialized) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pt->param_count != operands->count) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
DeclInfo *old_decl = decl_info_of_entity(&c->info, base_entity);
|
||||||
|
GB_ASSERT(old_decl != NULL);
|
||||||
|
|
||||||
|
gbAllocator a = heap_allocator();
|
||||||
|
|
||||||
|
CheckerContext prev_context = c->context;
|
||||||
|
defer (c->context = prev_context);
|
||||||
|
|
||||||
|
Scope *scope = make_scope(base_entity->scope, a);
|
||||||
|
scope->is_proc = true;
|
||||||
|
c->context.scope = scope;
|
||||||
|
|
||||||
|
// NOTE(bill): This is slightly memory leaking if the type already exists
|
||||||
|
// Maybe it's better to check with the previous types first?
|
||||||
|
Type *final_proc_type = make_type_proc(c->allocator, c->context.scope, NULL, 0, NULL, 0, false, pt->calling_convention);
|
||||||
|
check_procedure_type(c, final_proc_type, pt->node, operands);
|
||||||
|
|
||||||
|
auto *found = map_get(&c->info.gen_procs, hash_pointer(base_entity->identifier));
|
||||||
|
if (found) {
|
||||||
|
for_array(i, *found) {
|
||||||
|
Entity *other = (*found)[i];
|
||||||
|
if (are_types_identical(other->type, final_proc_type)) {
|
||||||
|
// NOTE(bill): This scope is not needed any more, destroy it
|
||||||
|
destroy_scope(scope);
|
||||||
|
return other;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
AstNode *proc_decl = clone_ast_node(a, old_decl->proc_decl);
|
||||||
|
ast_node(pd, ProcDecl, proc_decl);
|
||||||
|
// NOTE(bill): Associate the scope declared above with this procedure declaration's type
|
||||||
|
add_scope(c, pd->type, final_proc_type->Proc.scope);
|
||||||
|
final_proc_type->Proc.is_generic_specialized = true;
|
||||||
|
|
||||||
|
u64 tags = base_entity->Procedure.tags;
|
||||||
|
AstNode *ident = clone_ast_node(a, base_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;
|
||||||
|
|
||||||
|
|
||||||
|
Entity *entity = make_entity_procedure(c->allocator, NULL, token, final_proc_type, tags);
|
||||||
|
entity->identifier = ident;
|
||||||
|
|
||||||
|
add_entity_and_decl_info(c, ident, entity, d);
|
||||||
|
entity->scope = base_entity->scope;
|
||||||
|
|
||||||
|
ProcedureInfo proc_info = {};
|
||||||
|
proc_info.file = c->curr_ast_file;
|
||||||
|
proc_info.token = token;
|
||||||
|
proc_info.decl = d;
|
||||||
|
proc_info.type = final_proc_type;
|
||||||
|
proc_info.body = pd->body;
|
||||||
|
proc_info.tags = tags;
|
||||||
|
|
||||||
|
if (found) {
|
||||||
|
array_add(found, entity);
|
||||||
|
} else {
|
||||||
|
Array<Entity *> array = {};
|
||||||
|
array_init(&array, heap_allocator());
|
||||||
|
array_add(&array, entity);
|
||||||
|
map_set(&c->info.gen_procs, hash_pointer(entity->identifier), array);
|
||||||
|
}
|
||||||
|
|
||||||
|
GB_ASSERT(entity != NULL);
|
||||||
|
|
||||||
|
|
||||||
|
if (proc_info_) *proc_info_ = proc_info;
|
||||||
|
return entity;
|
||||||
|
}
|
||||||
|
|
||||||
CALL_ARGUMENT_CHECKER(check_call_arguments_internal) {
|
CALL_ARGUMENT_CHECKER(check_call_arguments_internal) {
|
||||||
ast_node(ce, CallExpr, call);
|
ast_node(ce, CallExpr, call);
|
||||||
@@ -5056,89 +5147,17 @@ CALL_ARGUMENT_CHECKER(check_call_arguments_internal) {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// NOTE(bill): Generate the procedure type for this generic instance
|
// NOTE(bill): Generate the procedure type for this generic instance
|
||||||
// TODO(bill): Clean this shit up!
|
|
||||||
|
|
||||||
ProcedureInfo proc_info = {};
|
ProcedureInfo proc_info = {};
|
||||||
|
|
||||||
if (pt->is_generic && !pt->is_generic_specialized) {
|
if (pt->is_generic && !pt->is_generic_specialized) {
|
||||||
GB_ASSERT(entity != NULL);
|
gen_entity = find_or_generate_polymorphic_procedure(c, entity, &operands, &proc_info);
|
||||||
|
if (gen_entity != NULL) {
|
||||||
DeclInfo *old_decl = decl_info_of_entity(&c->info, entity);
|
GB_ASSERT(is_type_proc(gen_entity->type));
|
||||||
GB_ASSERT(old_decl != NULL);
|
final_proc_type = gen_entity->type;
|
||||||
|
|
||||||
gbAllocator a = heap_allocator();
|
|
||||||
|
|
||||||
CheckerContext prev_context = c->context;
|
|
||||||
defer (c->context = prev_context);
|
|
||||||
|
|
||||||
Scope *scope = make_scope(entity->scope, a);
|
|
||||||
scope->is_proc = true;
|
|
||||||
c->context.scope = scope;
|
|
||||||
|
|
||||||
// NOTE(bill): This is slightly memory leaking if the type already exists
|
|
||||||
// Maybe it's better to check with the previous types first?
|
|
||||||
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);
|
|
||||||
|
|
||||||
bool skip = false;
|
|
||||||
auto *found = map_get(&c->info.gen_procs, hash_pointer(entity->identifier));
|
|
||||||
if (found) {
|
|
||||||
for_array(i, *found) {
|
|
||||||
Entity *other = (*found)[i];
|
|
||||||
if (are_types_identical(other->type, final_proc_type)) {
|
|
||||||
skip = true;
|
|
||||||
gen_entity = other;
|
|
||||||
final_proc_type = other->type;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (skip) {
|
|
||||||
// NOTE(bill): It is not needed any more, destroy it
|
|
||||||
destroy_scope(scope);
|
|
||||||
} else {
|
|
||||||
AstNode *proc_decl = clone_ast_node(a, old_decl->proc_decl);
|
|
||||||
ast_node(pd, ProcDecl, proc_decl);
|
|
||||||
// NOTE(bill): Associate the scope declared above with this procedure declaration's type
|
|
||||||
add_scope(c, pd->type, final_proc_type->Proc.scope);
|
|
||||||
final_proc_type->Proc.is_generic_specialized = true;
|
|
||||||
|
|
||||||
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, NULL, token, final_proc_type, tags);
|
|
||||||
gen_entity->identifier = ident;
|
|
||||||
|
|
||||||
add_entity_and_decl_info(c, ident, gen_entity, d);
|
|
||||||
gen_entity->scope = entity->scope;
|
|
||||||
add_entity_use(c, ident, gen_entity);
|
|
||||||
|
|
||||||
proc_info.file = c->curr_ast_file;
|
|
||||||
proc_info.token = token;
|
|
||||||
proc_info.decl = d;
|
|
||||||
proc_info.type = final_proc_type;
|
|
||||||
proc_info.body = pd->body;
|
|
||||||
proc_info.tags = tags;
|
|
||||||
|
|
||||||
if (found) {
|
|
||||||
array_add(found, gen_entity);
|
|
||||||
} else {
|
|
||||||
Array<Entity *> array = {};
|
|
||||||
array_init(&array, heap_allocator());
|
|
||||||
array_add(&array, gen_entity);
|
|
||||||
map_set(&c->info.gen_procs, hash_pointer(entity->identifier), array);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
GB_ASSERT(gen_entity != NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GB_ASSERT(is_type_proc(final_proc_type));
|
||||||
TypeProc *pt = &final_proc_type->Proc;
|
TypeProc *pt = &final_proc_type->Proc;
|
||||||
|
|
||||||
GB_ASSERT(pt->params != NULL);
|
GB_ASSERT(pt->params != NULL);
|
||||||
@@ -5154,7 +5173,7 @@ CALL_ARGUMENT_CHECKER(check_call_arguments_internal) {
|
|||||||
if (o.mode == Addressing_Invalid) {
|
if (o.mode == Addressing_Invalid) {
|
||||||
continue;
|
continue;
|
||||||
} else if (o.mode != Addressing_Type) {
|
} else if (o.mode != Addressing_Type) {
|
||||||
error(o.expr, "Expected a type for the argument");
|
error(o.expr, "Expected a type for the argument `%.*s`", LIT(e->token.string));
|
||||||
err = CallArgumentError_WrongTypes;
|
err = CallArgumentError_WrongTypes;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5214,7 +5233,10 @@ CALL_ARGUMENT_CHECKER(check_call_arguments_internal) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (gen_entity != NULL && err == CallArgumentError_None) {
|
if (gen_entity != NULL && err == CallArgumentError_None) {
|
||||||
check_procedure_later(c, proc_info);
|
if (proc_info.decl != NULL) {
|
||||||
|
// NOTE(bill): Check the newly generated procedure body
|
||||||
|
check_procedure_later(c, proc_info);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5278,6 +5300,10 @@ CALL_ARGUMENT_CHECKER(check_named_call_arguments) {
|
|||||||
isize param_count = pt->param_count;
|
isize param_count = pt->param_count;
|
||||||
bool *visited = gb_alloc_array(c->allocator, bool, param_count);
|
bool *visited = gb_alloc_array(c->allocator, bool, param_count);
|
||||||
|
|
||||||
|
Array<Operand> ordered_operands = {};
|
||||||
|
array_init_count(&ordered_operands, heap_allocator(), param_count);
|
||||||
|
defer (array_free(&ordered_operands));
|
||||||
|
|
||||||
for_array(i, ce->args) {
|
for_array(i, ce->args) {
|
||||||
AstNode *arg = ce->args[i];
|
AstNode *arg = ce->args[i];
|
||||||
ast_node(fv, FieldValue, arg);
|
ast_node(fv, FieldValue, arg);
|
||||||
@@ -5308,36 +5334,9 @@ CALL_ARGUMENT_CHECKER(check_named_call_arguments) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
visited[index] = true;
|
visited[index] = true;
|
||||||
Operand *o = &operands[i];
|
ordered_operands[index] = operands[i];
|
||||||
Entity *e = pt->params->Tuple.variables[index];
|
|
||||||
|
|
||||||
if (e->kind == Entity_TypeName) {
|
|
||||||
GB_ASSERT(pt->is_generic);
|
|
||||||
GB_ASSERT(!pt->variadic);
|
|
||||||
if (o->mode == Addressing_Invalid) {
|
|
||||||
continue;
|
|
||||||
} else if (o->mode != Addressing_Type) {
|
|
||||||
error(o->expr, "Expected a type for the argument");
|
|
||||||
}
|
|
||||||
if (are_types_identical(e->type, o->type)) {
|
|
||||||
score += assign_score_function(1);
|
|
||||||
} else {
|
|
||||||
score += assign_score_function(5);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
i64 s = 0;
|
|
||||||
if (!check_is_assignable_to_with_score(c, o, e->type, &s)) {
|
|
||||||
if (show_error) {
|
|
||||||
check_assignment(c, o, e->type, str_lit("procedure argument"));
|
|
||||||
}
|
|
||||||
err = CallArgumentError_WrongTypes;
|
|
||||||
}
|
|
||||||
score += s;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#if 1
|
|
||||||
isize param_count_to_check = param_count;
|
isize param_count_to_check = param_count;
|
||||||
if (pt->variadic) {
|
if (pt->variadic) {
|
||||||
param_count_to_check--;
|
param_count_to_check--;
|
||||||
@@ -5368,19 +5367,58 @@ CALL_ARGUMENT_CHECKER(check_named_call_arguments) {
|
|||||||
err = CallArgumentError_ParameterMissing;
|
err = CallArgumentError_ParameterMissing;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
if (pt->is_generic) {
|
Entity *gen_entity = NULL;
|
||||||
if (show_error) {
|
if (pt->is_generic && err == CallArgumentError_None) {
|
||||||
error(call, "Generic procedures do not yet support named arguments");
|
// err = CallArgumentError_GenericProcedureNotSupported;
|
||||||
|
ProcedureInfo proc_info = {};
|
||||||
|
gen_entity = find_or_generate_polymorphic_procedure(c, entity, &ordered_operands, &proc_info);
|
||||||
|
if (gen_entity != NULL) {
|
||||||
|
if (proc_info.decl != NULL) {
|
||||||
|
check_procedure_later(c, proc_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
pt = &base_type(gen_entity->type)->Proc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (isize i = 0; i < param_count; i++) {
|
||||||
|
Operand *o = &ordered_operands[i];
|
||||||
|
if (o->mode == Addressing_Invalid) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Entity *e = pt->params->Tuple.variables[i];
|
||||||
|
|
||||||
|
if (e->kind == Entity_TypeName) {
|
||||||
|
GB_ASSERT(pt->is_generic);
|
||||||
|
GB_ASSERT(!pt->variadic);
|
||||||
|
if (o->mode != Addressing_Type) {
|
||||||
|
if (show_error) {
|
||||||
|
error(o->expr, "Expected a type for the argument `%.*s`", LIT(e->token.string));
|
||||||
|
}
|
||||||
|
err = CallArgumentError_WrongTypes;
|
||||||
|
}
|
||||||
|
if (are_types_identical(e->type, o->type)) {
|
||||||
|
score += assign_score_function(1);
|
||||||
|
} else {
|
||||||
|
score += assign_score_function(10);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
i64 s = 0;
|
||||||
|
if (!check_is_assignable_to_with_score(c, o, e->type, &s)) {
|
||||||
|
if (show_error) {
|
||||||
|
check_assignment(c, o, e->type, str_lit("procedure argument"));
|
||||||
|
}
|
||||||
|
err = CallArgumentError_WrongTypes;
|
||||||
|
}
|
||||||
|
score += s;
|
||||||
}
|
}
|
||||||
err = CallArgumentError_GenericProcedureNotSupported;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data) {
|
if (data) {
|
||||||
data->score = score;
|
data->score = score;
|
||||||
data->result_type = pt->results;
|
data->result_type = pt->results;
|
||||||
data->gen_entity = NULL;
|
data->gen_entity = gen_entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
@@ -5487,12 +5525,14 @@ CallArgumentData check_call_arguments(Checker *c, Operand *operand, Type *proc_t
|
|||||||
proc_type = e->type;
|
proc_type = e->type;
|
||||||
CallArgumentData data = {};
|
CallArgumentData data = {};
|
||||||
CallArgumentError err = call_checker(c, call, proc_type, e, operands, CallArgumentMode_ShowErrors, &data);
|
CallArgumentError err = call_checker(c, call, proc_type, e, operands, CallArgumentMode_ShowErrors, &data);
|
||||||
|
if (data.gen_entity != NULL) add_entity_use(c, ce->proc, data.gen_entity);
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Entity *e = entity_of_ident(&c->info, operand->expr);
|
Entity *e = entity_of_ident(&c->info, operand->expr);
|
||||||
CallArgumentData data = {};
|
CallArgumentData data = {};
|
||||||
CallArgumentError err = call_checker(c, call, proc_type, e, operands, CallArgumentMode_ShowErrors, &data);
|
CallArgumentError err = call_checker(c, call, proc_type, e, operands, CallArgumentMode_ShowErrors, &data);
|
||||||
|
if (data.gen_entity != NULL) add_entity_use(c, ce->proc, data.gen_entity);
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+7
-3
@@ -1169,7 +1169,9 @@ void add_type_info_type(Checker *c, Type *t) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void check_procedure_later(Checker *c, ProcedureInfo info) {
|
void check_procedure_later(Checker *c, ProcedureInfo info) {
|
||||||
map_set(&c->procs, hash_decl_info(info.decl), info);
|
if (info.decl != NULL) {
|
||||||
|
map_set(&c->procs, hash_decl_info(info.decl), info);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void check_procedure_later(Checker *c, AstFile *file, Token token, DeclInfo *decl, Type *type, AstNode *body, u64 tags) {
|
void check_procedure_later(Checker *c, AstFile *file, Token token, DeclInfo *decl, Type *type, AstNode *body, u64 tags) {
|
||||||
@@ -1247,8 +1249,10 @@ Map<Entity *> generate_minimum_dependency_map(CheckerInfo *info, Entity *start)
|
|||||||
for_array(i, info->definitions.entries) {
|
for_array(i, info->definitions.entries) {
|
||||||
Entity *e = info->definitions.entries[i].value;
|
Entity *e = info->definitions.entries[i].value;
|
||||||
if (e->scope->is_global) {
|
if (e->scope->is_global) {
|
||||||
// NOTE(bill): Require runtime stuff
|
if (!is_type_gen_proc(e->type)) {
|
||||||
add_dependency_to_map(&map, info, e);
|
// NOTE(bill): Require runtime stuff
|
||||||
|
add_dependency_to_map(&map, info, e);
|
||||||
|
}
|
||||||
} else if (e->kind == Entity_Procedure) {
|
} else if (e->kind == Entity_Procedure) {
|
||||||
if ((e->Procedure.tags & ProcTag_export) != 0) {
|
if ((e->Procedure.tags & ProcTag_export) != 0) {
|
||||||
add_dependency_to_map(&map, info, e);
|
add_dependency_to_map(&map, info, e);
|
||||||
|
|||||||
+12
-8
@@ -4680,15 +4680,19 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) {
|
|||||||
TypeTuple *pt = &type->params->Tuple;
|
TypeTuple *pt = &type->params->Tuple;
|
||||||
for (isize i = 0; i < param_count; i++) {
|
for (isize i = 0; i < param_count; i++) {
|
||||||
Entity *e = pt->variables[i];
|
Entity *e = pt->variables[i];
|
||||||
GB_ASSERT(e->kind == Entity_Variable);
|
if (e->kind == Entity_TypeName) {
|
||||||
if (args[i] == NULL) {
|
args[i] = ir_value_nil(proc->module->allocator, e->type);
|
||||||
if (e->Variable.default_value.kind != ExactValue_Invalid) {
|
|
||||||
args[i] = ir_value_constant(proc->module->allocator, e->type, e->Variable.default_value);
|
|
||||||
} else {
|
|
||||||
args[i] = ir_value_nil(proc->module->allocator, e->type);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
args[i] = ir_emit_conv(proc, args[i], e->type);
|
GB_ASSERT(e->kind == Entity_Variable);
|
||||||
|
if (args[i] == NULL) {
|
||||||
|
if (e->Variable.default_value.kind != ExactValue_Invalid) {
|
||||||
|
args[i] = ir_value_constant(proc->module->allocator, e->type, e->Variable.default_value);
|
||||||
|
} else {
|
||||||
|
args[i] = ir_value_nil(proc->module->allocator, e->type);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
args[i] = ir_emit_conv(proc, args[i], e->type);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user