Allow for overloading of polymorphic procedures

This commit is contained in:
Ginger Bill
2017-07-04 22:42:25 +01:00
parent 689a0c0b49
commit 188bc28f6a
11 changed files with 203 additions and 122 deletions
+8 -3
View File
@@ -207,6 +207,9 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init,
e->kind = Entity_TypeName;
DeclInfo *d = c->context.decl;
if (d->type_expr != NULL) {
error(e->token, "A type declaration cannot have an type parameter");
}
d->type_expr = d->init_expr;
check_type_decl(c, e, d->type_expr, named_type);
return;
@@ -433,7 +436,7 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
}
if (is_foreign) {
error(e->token, "A foreign procedures cannot be a polymorphic");
error(e->token, "A foreign procedure cannot be a polymorphic");
return;
}
}
@@ -443,13 +446,15 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
error(pl->body, "A foreign procedure cannot have a body");
}
if (proc_type->Proc.c_vararg) {
error(pl->body, "A procedure with a `#c_vararg` field cannot have a body");
error(pl->body, "A procedure with a `#c_vararg` field cannot have a body and must be foreign");
}
d->scope = c->context.scope;
GB_ASSERT(pl->body->kind == AstNode_BlockStmt);
check_procedure_later(c, c->curr_ast_file, e->token, d, proc_type, pl->body, pl->tags);
if (!pt->is_polymorphic) {
check_procedure_later(c, c->curr_ast_file, e->token, d, proc_type, pl->body, pl->tags);
}
} else if (!is_foreign) {
error(e->token, "Only a foreign procedure cannot have a body");
}
+87 -33
View File
@@ -193,6 +193,11 @@ i64 check_distance_between_types(Checker *c, Operand *operand, Type *type) {
if (check_representable_as_constant(c, operand->value, dst, NULL)) {
if (is_type_typed(dst) && src->kind == Type_Basic) {
switch (src->Basic.kind) {
case Basic_UntypedRune:
if (is_type_integer(dst) || is_type_rune(dst)) {
return 1;
}
break;
case Basic_UntypedInteger:
if (is_type_integer(dst) || is_type_rune(dst)) {
return 1;
@@ -214,6 +219,15 @@ i64 check_distance_between_types(Checker *c, Operand *operand, Type *type) {
}
return -1;
}
if (src->kind == Type_Basic && src->Basic.kind == Basic_UntypedRune) {
if (is_type_integer(dst) || is_type_rune(dst)) {
if (is_type_typed(type)) {
return 2;
}
return 1;
}
return -1;
}
if (src->kind == Type_Basic && src->Basic.kind == Basic_UntypedBool) {
if (is_type_boolean(dst)) {
if (is_type_typed(type)) {
@@ -1098,8 +1112,7 @@ bool is_polymorphic_type_assignable(Checker *c, Type *poly, Type *source, bool c
}
case Type_Pointer:
if (source->kind == Type_Pointer) {
if (compound) return are_types_identical(poly, source);
return check_is_assignable_to(c, &o, poly);
return is_polymorphic_type_assignable(c, poly->Pointer.elem, source->Atomic.elem, true, modify_type);
}
return false;
case Type_Atomic:
@@ -3983,10 +3996,10 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
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`");
return false;
}
// return false;
// }
switch (id) {
@@ -4268,6 +4281,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
operand->mode = Addressing_NoValue;
} break;
#if 0
case BuiltinProc_append: {
// proc append([dynamic]Type, item: ..Type)
// proc append([]Type, item: ..Type)
@@ -4315,6 +4329,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
operand->mode = Addressing_Value;
operand->type = t_int;
} break;
#endif
case BuiltinProc_delete: {
// proc delete(map[Key]Value, key: Key)
@@ -5155,6 +5170,7 @@ Entity *find_or_generate_polymorphic_procedure(Checker *c, AstNode *call, Entity
Scope *scope = make_scope(base_entity->scope, a);
scope->is_proc = true;
c->context.scope = scope;
c->context.allow_polymorphic_types = true;
bool generate_type_again = c->context.no_polymorphic_errors;
@@ -5219,6 +5235,7 @@ Entity *find_or_generate_polymorphic_procedure(Checker *c, AstNode *call, Entity
// NOTE(bill): Associate the scope declared above with this procedure declaration's type
add_scope(c, pl->type, final_proc_type->Proc.scope);
final_proc_type->Proc.is_poly_specialized = true;
final_proc_type->Proc.is_polymorphic = true;
u64 tags = base_entity->Procedure.tags;
AstNode *ident = clone_ast_node(a, base_entity->identifier);
@@ -5236,17 +5253,24 @@ Entity *find_or_generate_polymorphic_procedure(Checker *c, AstNode *call, Entity
// NOTE(bill): Set the scope afterwards as this is not real overloading
entity->scope = scope->parent;
ProcedureInfo proc_info = {};
if (success) {
proc_info.file = c->curr_ast_file;
proc_info.token = token;
proc_info.decl = d;
proc_info.type = final_proc_type;
proc_info.body = pl->body;
proc_info.tags = tags;
proc_info.generated_from_polymorphic = true;
AstFile *file = NULL;
{
Scope *s = entity->scope;
while (s != NULL && s->file == NULL) {
s = s->parent;
}
file = s->file;
}
ProcedureInfo proc_info = {};
proc_info.file = file;
proc_info.token = token;
proc_info.decl = d;
proc_info.type = final_proc_type;
proc_info.body = pl->body;
proc_info.tags = tags;
proc_info.generated_from_polymorphic = true;
if (found_gen_procs) {
array_add(found_gen_procs, entity);
} else {
@@ -5436,6 +5460,10 @@ CALL_ARGUMENT_CHECKER(check_call_arguments_internal) {
}
}
if (gen_entity != NULL && 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 (gen_entity != NULL && err == CallArgumentError_None) {
if (proc_info.decl != NULL) {
// NOTE(bill): Check the newly generated procedure body
@@ -5690,11 +5718,13 @@ CallArgumentData check_call_arguments(Checker *c, Operand *operand, Type *proc_t
Entity *p = procs[i];
Type *pt = base_type(p->type);
if (pt != NULL && is_type_proc(pt)) {
CallArgumentError err = CallArgumentError_None;
CallArgumentData data = {};
bool prev = c->context.no_polymorphic_errors;
defer (c->context.no_polymorphic_errors = prev);
CheckerContext prev_context = c->context;
c->context.no_polymorphic_errors = true;
CallArgumentError err = call_checker(c, call, pt, p, operands, CallArgumentMode_NoErrors, &data);
c->context.allow_polymorphic_types = is_type_polymorphic(pt);
err = call_checker(c, call, pt, p, operands, CallArgumentMode_NoErrors, &data);
c->context = prev_context;
if (err == CallArgumentError_None) {
valids[valid_count].index = i;
@@ -5747,24 +5777,39 @@ CallArgumentData check_call_arguments(Checker *c, Operand *operand, Type *proc_t
}
result_type = t_invalid;
} else {
AstNode *expr = operand->expr;
while (expr->kind == AstNode_SelectorExpr) {
expr = expr->SelectorExpr.selector;
AstNode *ident = operand->expr;
while (ident->kind == AstNode_SelectorExpr) {
AstNode *s = ident->SelectorExpr.selector;
ident = s;
}
GB_ASSERT(expr->kind == AstNode_Ident);
Entity *e = procs[valids[0].index];
add_entity_use(c, expr, e);
proc_type = e->type;
CallArgumentData 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);
if (data.gen_entity != NULL) {
add_entity_use(c, ident, data.gen_entity);
} else {
add_entity_use(c, ident, e);
}
return data;
}
} else {
Entity *e = entity_of_ident(&c->info, operand->expr);
AstNode *ident = operand->expr;
while (ident->kind == AstNode_SelectorExpr) {
AstNode *s = ident->SelectorExpr.selector;
ident = s;
}
Entity *e = entity_of_ident(&c->info, ident);
CallArgumentData 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);
if (data.gen_entity != NULL) {
add_entity_use(c, ident, data.gen_entity);
} else {
add_entity_use(c, ident, e);
}
return data;
}
@@ -5908,9 +5953,6 @@ ExprKind check_call_expr(Checker *c, Operand *operand, AstNode *call) {
CallArgumentData data = check_call_arguments(c, operand, proc_type, call);
Type *result_type = data.result_type;
if (data.gen_entity != NULL) {
add_entity_use(c, ce->proc, data.gen_entity);
}
gb_zero_item(operand);
operand->expr = call;
@@ -7130,6 +7172,15 @@ gbString write_expr_to_string(gbString str, AstNode *node) {
str = write_expr_to_string(str, be->right);
case_end;
case_ast_node(te, TernaryExpr, node);
str = write_expr_to_string(str, te->cond);
str = gb_string_appendc(str, " ? ");
str = write_expr_to_string(str, te->x);
str = gb_string_appendc(str, " : ");
str = write_expr_to_string(str, te->y);
case_end;
case_ast_node(pe, ParenExpr, node);
str = gb_string_appendc(str, "(");
str = write_expr_to_string(str, pe->expr);
@@ -7171,6 +7222,7 @@ gbString write_expr_to_string(gbString str, AstNode *node) {
case_ast_node(e, Ellipsis, node);
str = gb_string_appendc(str, "..");
str = write_expr_to_string(str, e->expr);
case_end;
case_ast_node(fv, FieldValue, node);
@@ -7184,6 +7236,12 @@ gbString write_expr_to_string(gbString str, AstNode *node) {
str = write_expr_to_string(str, ht->type);
case_end;
case_ast_node(pt, PolyType, node);
str = gb_string_appendc(str, "$");
str = write_expr_to_string(str, pt->type);
case_end;
case_ast_node(pt, PointerType, node);
str = gb_string_appendc(str, "^");
str = write_expr_to_string(str, pt->type);
@@ -7203,7 +7261,7 @@ gbString write_expr_to_string(gbString str, AstNode *node) {
case_end;
case_ast_node(at, DynamicArrayType, node);
str = gb_string_appendc(str, "[..]");
str = gb_string_appendc(str, "[dynamic]");
str = write_expr_to_string(str, at->elem);
case_end;
@@ -7235,9 +7293,6 @@ gbString write_expr_to_string(gbString str, AstNode *node) {
if (f->names.count > 0) {
str = gb_string_appendc(str, ": ");
}
if (f->flags&FieldFlag_ellipsis) {
str = gb_string_appendc(str, "..");
}
str = write_expr_to_string(str, f->type);
case_end;
@@ -7261,7 +7316,6 @@ gbString write_expr_to_string(gbString str, AstNode *node) {
}
}
for_array(i, f->list) {
if (i > 0) {
str = gb_string_appendc(str, ", ");
+10 -10
View File
@@ -33,7 +33,7 @@ enum BuiltinProcId {
BuiltinProc_reserve,
BuiltinProc_clear,
BuiltinProc_append,
// BuiltinProc_append,
BuiltinProc_delete,
BuiltinProc_size_of,
@@ -85,7 +85,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
{STR_LIT("reserve"), 2, false, Expr_Stmt},
{STR_LIT("clear"), 1, false, Expr_Stmt},
{STR_LIT("append"), 1, true, Expr_Expr},
// {STR_LIT("append"), 1, true, Expr_Expr},
{STR_LIT("delete"), 2, false, Expr_Stmt},
{STR_LIT("size_of"), 1, false, Expr_Expr},
@@ -591,11 +591,9 @@ Entity *scope_insert_entity(Scope *s, Entity *entity) {
}
}
if (prev != NULL &&
entity->kind == Entity_Procedure) {
if (s->is_global) {
return prev;
}
if (prev != NULL && entity->kind == Entity_Procedure) {
// if (s->is_global) return prev;
multi_map_insert(&s->elements, key, entity);
} else {
map_set(&s->elements, key, entity);
@@ -1709,6 +1707,9 @@ void check_collect_entities(Checker *c, Array<AstNode *> nodes, bool is_file_sco
if (is_ast_node_type(init)) {
e = make_entity_type_name(c->allocator, d->scope, name->Ident.token, NULL);
if (vd->type != NULL) {
error(name, "A type declaration cannot have an type parameter");
}
d->type_expr = init;
d->init_expr = init;
} else if (init->kind == AstNode_ProcLit) {
@@ -2285,10 +2286,9 @@ void check_parsed_files(Checker *c) {
defer (c->context = prev_context);
TypeProc *pt = &pi->type->Proc;
String name = pi->token.string;
if (pt->is_polymorphic) {
if (pi->decl->gen_proc_type == NULL) {
continue;
}
GB_ASSERT_MSG(pt->is_poly_specialized, "%.*s", LIT(name));
}
add_curr_ast_file(c, pi->file);
+2 -3
View File
@@ -4059,6 +4059,7 @@ irValue *ir_build_builtin_proc(irProcedure *proc, AstNode *expr, TypeAndValue tv
return NULL;
} break;
#if 0
case BuiltinProc_append: {
ir_emit_comment(proc, str_lit("append"));
gbAllocator a = proc->module->allocator;
@@ -4167,6 +4168,7 @@ irValue *ir_build_builtin_proc(irProcedure *proc, AstNode *expr, TypeAndValue tv
}
return ir_emit_global_call(proc, "__dynamic_array_append", daa_args, 5);
} break;
#endif
case BuiltinProc_delete: {
ir_emit_comment(proc, str_lit("delete"));
@@ -7422,9 +7424,6 @@ void ir_gen_tree(irGen *s) {
}
} else if (check_is_entity_overloaded(e)) {
name = ir_mangle_name(s, e->token.pos.file, e);
gb_printf_err("%.*s|%.*s :: %s\n", LIT(original_name), LIT(name), type_to_string(e->type));
}
map_set(&m->entity_names, hash_entity(e), name);
+1 -1
View File
@@ -664,7 +664,7 @@ AstNode *clone_ast_node(gbAllocator a, AstNode *node) {
n->RunExpr.expr = clone_ast_node(a, n->RunExpr.expr);
break;
case AstNode_UnaryExpr:
n->RunExpr.expr = clone_ast_node(a, n->RunExpr.expr);
n->UnaryExpr.expr = clone_ast_node(a, n->UnaryExpr.expr);
break;
case AstNode_BinaryExpr:
n->BinaryExpr.left = clone_ast_node(a, n->BinaryExpr.left);
+1 -1
View File
@@ -2445,7 +2445,7 @@ gbString write_type_to_string(gbString str, Type *type) {
if (var->flags&EntityFlag_Ellipsis) {
Type *slice = base_type(var->type);
str = gb_string_appendc(str, "..");
GB_ASSERT(is_type_slice(var->type));
GB_ASSERT(var->type->kind == Type_Slice);
str = write_type_to_string(str, slice->Slice.elem);
} else {
str = write_type_to_string(str, var->type);