Disable polymorphic overloading in the global scope

TODO: Figure out why it does not work in the global scope
This commit is contained in:
Ginger Bill
2017-07-02 22:08:39 +01:00
parent 96d32680fe
commit bc16b290ba
12 changed files with 276 additions and 222 deletions
+2 -1
View File
@@ -601,6 +601,8 @@ void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNod
}
CheckerContext old_context = c->context;
defer (c->context = old_context);
c->context.scope = decl->scope;
c->context.decl = decl;
c->context.proc_name = proc_name;
@@ -660,7 +662,6 @@ void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNod
check_scope_usage(c, c->context.scope);
c->context = old_context;
if (decl->parent != NULL) {
// NOTE(bill): Add the dependencies from the procedure literal (lambda)
+84 -62
View File
@@ -1084,6 +1084,7 @@ bool is_polymorphic_type_assignable(Checker *c, Type *poly, Type *source, bool c
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);
@@ -1097,7 +1098,8 @@ bool is_polymorphic_type_assignable(Checker *c, Type *poly, Type *source, bool c
}
case Type_Pointer:
if (source->kind == Type_Pointer) {
return is_polymorphic_type_assignable(c, poly->Pointer.elem, source->Pointer.elem, true, modify_type);
if (compound) return are_types_identical(poly, source);
return check_is_assignable_to(c, &o, poly);
}
return false;
case Type_Atomic:
@@ -1354,7 +1356,8 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
param->TypeName.is_type_alias = true;
} else {
if (operands != NULL && is_type_polymorphic_type) {
type = determine_type_from_polymorphic(c, type, (*operands)[variable_index]);
Operand op = (*operands)[variable_index];
type = determine_type_from_polymorphic(c, type, op);
if (type == t_invalid) {
success = false;
}
@@ -4177,6 +4180,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
operand->type = type;
} break;
#if 1
case BuiltinProc_free: {
// proc free(^Type)
// proc free([]Type)
@@ -4206,6 +4210,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
operand->mode = Addressing_NoValue;
} break;
#endif
case BuiltinProc_reserve: {
@@ -4478,48 +4483,6 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
operand->type = t_untyped_bool;
break;
case BuiltinProc_copy: {
// proc copy(x, y: []Type) -> int
Type *dest_type = NULL, *src_type = NULL;
Type *d = base_type(operand->type);
if (d->kind == Type_Slice) {
dest_type = d->Slice.elem;
}
Operand op = {};
check_expr(c, &op, ce->args[1]);
if (op.mode == Addressing_Invalid) {
return false;
}
Type *s = base_type(op.type);
if (s->kind == Type_Slice) {
src_type = s->Slice.elem;
}
if (dest_type == NULL || src_type == NULL) {
error(call, "`copy` only expects slices as arguments");
return false;
}
if (!are_types_identical(dest_type, src_type)) {
gbString d_arg = expr_to_string(ce->args[0]);
gbString s_arg = expr_to_string(ce->args[1]);
gbString d_str = type_to_string(dest_type);
gbString s_str = type_to_string(src_type);
error(call,
"Arguments to `copy`, %s, %s, have different elem types: %s vs %s",
d_arg, s_arg, d_str, s_str);
gb_string_free(s_str);
gb_string_free(d_str);
gb_string_free(s_arg);
gb_string_free(d_arg);
return false;
}
operand->type = t_int; // Returns number of elems copied
operand->mode = Addressing_Value;
} break;
case BuiltinProc_swizzle: {
// proc swizzle(v: {N}T, T..) -> {M}T
Type *vector_type = base_type(operand->type);
@@ -4699,6 +4662,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
} break;
#if 1
case BuiltinProc_slice_ptr: {
// proc slice_ptr(a: ^T, len: int) -> []T
// proc slice_ptr(a: ^T, len, cap: int) -> []T
@@ -4755,6 +4719,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
operand->type = t_u8_slice;
operand->mode = Addressing_Value;
} break;
#endif
case BuiltinProc_expand_to_tuple: {
Type *type = base_type(operand->type);
@@ -5146,7 +5111,13 @@ bool check_unpack_arguments(Checker *c, isize lhs_count, Array<Operand> *operand
}
// NOTE(bill): Returns `NULL` on failure
Entity *find_or_generate_polymorphic_procedure(Checker *c, Entity *base_entity, Array<Operand> *operands, ProcedureInfo *proc_info_) {
Entity *find_or_generate_polymorphic_procedure(Checker *c, AstNode *call, Entity *base_entity, CallArgumentCheckerType *call_checker,
Array<Operand> *operands, ProcedureInfo *proc_info_) {
///////////////////////////////////////////////////////////////////////////////
// //
// TODO CLEANUP(bill): This procedure is very messy and hacky. Clean this!!! //
// //
///////////////////////////////////////////////////////////////////////////////
if (base_entity == NULL) {
return NULL;
}
@@ -5172,19 +5143,25 @@ Entity *find_or_generate_polymorphic_procedure(Checker *c, Entity *base_entity,
scope->is_proc = true;
c->context.scope = scope;
bool generate_type_again = c->context.no_polymorphic_errors;
// 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);
Type *final_proc_type = make_type_proc(c->allocator, scope, NULL, 0, NULL, 0, false, pt->calling_convention);
bool success = check_procedure_type(c, final_proc_type, pt->node, operands);
// if (!success) {
// return NULL;
// }
if (!success) {
ProcedureInfo proc_info = {};
if (proc_info_) *proc_info_ = proc_info;
return NULL;
}
auto *found_gen_procs = map_get(&c->info.gen_procs, hash_pointer(base_entity->identifier));
if (found_gen_procs) {
for_array(i, *found_gen_procs) {
Entity *other = (*found_gen_procs)[i];
if (are_types_identical(other->type, final_proc_type)) {
auto procs = *found_gen_procs;
for_array(i, procs) {
Entity *other = procs[i];
Type *pt = base_type(other->type);
if (are_types_identical(pt, final_proc_type)) {
// NOTE(bill): This scope is not needed any more, destroy it
// destroy_scope(scope);
return other;
@@ -5192,6 +5169,37 @@ Entity *find_or_generate_polymorphic_procedure(Checker *c, Entity *base_entity,
}
}
if (generate_type_again) {
// LEAK TODO(bill): This is technically a memory leak as it has to generate the type twice
bool prev_no_polymorphic_errors = c->context.no_polymorphic_errors;
defer (c->context.no_polymorphic_errors = prev_no_polymorphic_errors);
c->context.no_polymorphic_errors = false;
// NOTE(bill): Reset scope from the failed procedure type
scope_reset(scope);
success = check_procedure_type(c, final_proc_type, pt->node, operands);
if (!success) {
ProcedureInfo proc_info = {};
if (proc_info_) *proc_info_ = proc_info;
return NULL;
}
if (found_gen_procs) {
auto procs = *found_gen_procs;
for_array(i, procs) {
Entity *other = procs[i];
Type *pt = base_type(other->type);
if (are_types_identical(pt, final_proc_type)) {
// NOTE(bill): This scope is not needed any more, destroy it
// destroy_scope(scope);
return other;
}
}
}
}
AstNode *proc_lit = clone_ast_node(a, old_decl->proc_lit);
ast_node(pl, ProcLit, proc_lit);
@@ -5202,7 +5210,7 @@ Entity *find_or_generate_polymorphic_procedure(Checker *c, Entity *base_entity,
u64 tags = base_entity->Procedure.tags;
AstNode *ident = clone_ast_node(a, base_entity->identifier);
Token token = ident->Ident.token;
DeclInfo *d = make_declaration_info(c->allocator, c->context.scope, old_decl->parent);
DeclInfo *d = make_declaration_info(c->allocator, scope, old_decl->parent);
d->gen_proc_type = final_proc_type;
d->type_expr = pl->type;
d->proc_lit = proc_lit;
@@ -5212,16 +5220,18 @@ Entity *find_or_generate_polymorphic_procedure(Checker *c, Entity *base_entity,
entity->identifier = ident;
add_entity_and_decl_info(c, ident, entity, d);
entity->scope = base_entity->scope;
// 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.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;
}
if (found_gen_procs) {
@@ -5329,7 +5339,7 @@ CALL_ARGUMENT_CHECKER(check_call_arguments_internal) {
ProcedureInfo proc_info = {};
if (pt->is_polymorphic && !pt->is_poly_specialized) {
gen_entity = find_or_generate_polymorphic_procedure(c, entity, &operands, &proc_info);
gen_entity = find_or_generate_polymorphic_procedure(c, call, entity, check_call_arguments_internal, &operands, &proc_info);
if (gen_entity != NULL) {
GB_ASSERT(is_type_proc(gen_entity->type));
final_proc_type = gen_entity->type;
@@ -5557,9 +5567,9 @@ CALL_ARGUMENT_CHECKER(check_named_call_arguments) {
}
Entity *gen_entity = NULL;
if (pt->is_polymorphic && err == CallArgumentError_None) {
if (pt->is_polymorphic && !pt->is_poly_specialized && err == CallArgumentError_None) {
ProcedureInfo proc_info = {};
gen_entity = find_or_generate_polymorphic_procedure(c, entity, &ordered_operands, &proc_info);
gen_entity = find_or_generate_polymorphic_procedure(c, call, entity, check_named_call_arguments, &ordered_operands, &proc_info);
if (gen_entity != NULL) {
if (proc_info.decl != NULL) {
check_procedure_later(c, proc_info);
@@ -5684,23 +5694,31 @@ CallArgumentData check_call_arguments(Checker *c, Operand *operand, Type *proc_t
if (valid_count > 1) {
gb_sort_array(valids, valid_count, valid_proc_and_score_cmp);
i64 best_score = valids[0].score;
Entity *best_entity = procs[valids[0].index];
for (isize i = 0; i < valid_count; i++) {
if (best_score > valids[i].score) {
valid_count = i;
break;
}
if (best_entity == procs[valids[i].index]) {
valid_count = i;
break;
}
best_score = valids[i].score;
}
}
if (valid_count == 0) {
error(operand->expr, "No overloads for `%.*s` that match with the given arguments", LIT(name));
gb_printf_err("Did you mean to use one of these procedures:\n");
error(operand->expr, "No overloads or ambiguous call for `%.*s` that match with the given arguments", LIT(name));
if (overload_count > 0) {
gb_printf_err("Did you mean to use one of the following:\n");
}
for (isize i = 0; i < overload_count; i++) {
Entity *proc = procs[i];
TokenPos pos = proc->token.pos;
gbString pt = type_to_string(proc->type);
// gbString pt = type_to_string(proc->type);
gbString pt = expr_to_string(proc->type->Proc.node);
gb_printf_err("\t%.*s :: %s at %.*s(%td:%td)\n", LIT(name), pt, LIT(pos.file), pos.line, pos.column, cast(long long)valids[i].score);
gb_string_free(pt);
}
@@ -5711,7 +5729,7 @@ CallArgumentData check_call_arguments(Checker *c, Operand *operand, Type *proc_t
Entity *proc = procs[valids[i].index];
TokenPos pos = proc->token.pos;
gbString pt = type_to_string(proc->type);
gb_printf_err("\t%.*s :: %s at %.*s(%td:%td)\n", LIT(name), pt, LIT(pos.file), pos.line, pos.column, cast(long long)valids[i].score);
gb_printf_err("\t%.*s :: %s at %.*s(%td:%td) with score %lld\n", LIT(name), pt, LIT(pos.file), pos.line, pos.column, cast(long long)valids[i].score);
gb_string_free(pt);
}
result_type = t_invalid;
@@ -7253,6 +7271,10 @@ gbString write_expr_to_string(gbString str, AstNode *node) {
str = gb_string_appendc(str, ")");
case_end;
case_ast_node(ht, HelperType, node);
str = gb_string_appendc(str, "type");
case_end;
case_ast_node(pt, ProcType, node);
str = gb_string_appendc(str, "proc(");
str = write_expr_to_string(str, pt->params);
+11 -4
View File
@@ -44,8 +44,6 @@ enum BuiltinProcId {
BuiltinProc_compile_assert,
BuiltinProc_copy,
BuiltinProc_swizzle,
BuiltinProc_complex,
@@ -92,8 +90,6 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
{STR_LIT("compile_assert"), 1, false, Expr_Expr},
{STR_LIT("copy"), 2, false, Expr_Expr},
{STR_LIT("swizzle"), 1, true, Expr_Expr},
{STR_LIT("complex"), 2, false, Expr_Expr},
@@ -204,6 +200,7 @@ struct ProcedureInfo {
Type * type; // Type_Procedure
AstNode * body; // AstNode_BlockStmt
u64 tags;
bool generated_from_polymorphic;
};
// ExprInfo stores information used for "untyped" expressions
@@ -241,6 +238,16 @@ struct Scope {
};
gb_global Scope *universal_scope = NULL;
void scope_reset(Scope *scope) {
if (scope == NULL) return;
scope->first_child = NULL;
scope->last_child = NULL;
map_clear (&scope->elements);
map_clear (&scope->implicit);
array_clear(&scope->shared);
array_clear(&scope->imported);
}
struct DelayedDecl {
+22 -39
View File
@@ -3532,7 +3532,7 @@ String ir_mangle_name(irGen *s, String path, Entity *e) {
isize base_len = ext-1-base;
isize max_len = base_len + 1 + 1 + 10 + 1 + name.len;
bool require_suffix_id = check_is_entity_overloaded(e) || is_type_poly_proc(e->type);
bool require_suffix_id = check_is_entity_overloaded(e) || is_type_polymorphic(e->type);
if (require_suffix_id) {
max_len += 21;
}
@@ -3922,6 +3922,7 @@ irValue *ir_build_builtin_proc(irProcedure *proc, AstNode *expr, TypeAndValue tv
}
} break;
#if 1
case BuiltinProc_free: {
ir_emit_comment(proc, str_lit("free"));
@@ -3995,6 +3996,7 @@ irValue *ir_build_builtin_proc(irProcedure *proc, AstNode *expr, TypeAndValue tv
args[0] = ptr;
return ir_emit_global_call(proc, "free_ptr", args, 1);
} break;
#endif
case BuiltinProc_reserve: {
ir_emit_comment(proc, str_lit("reserve"));
@@ -4183,39 +4185,7 @@ irValue *ir_build_builtin_proc(irProcedure *proc, AstNode *expr, TypeAndValue tv
return ir_emit_global_call(proc, "__dynamic_map_delete", args, 2);
} break;
case BuiltinProc_copy: {
ir_emit_comment(proc, str_lit("copy"));
// proc copy(dst, src: []Type) -> int
AstNode *dst_node = ce->args[0];
AstNode *src_node = ce->args[1];
irValue *dst_slice = ir_build_expr(proc, dst_node);
irValue *src_slice = ir_build_expr(proc, src_node);
Type *slice_type = base_type(ir_type(dst_slice));
GB_ASSERT(slice_type->kind == Type_Slice);
Type *elem_type = slice_type->Slice.elem;
i64 size_of_elem = type_size_of(proc->module->allocator, elem_type);
irValue *dst = ir_emit_conv(proc, ir_slice_elem(proc, dst_slice), t_rawptr);
irValue *src = ir_emit_conv(proc, ir_slice_elem(proc, src_slice), t_rawptr);
irValue *len_dst = ir_slice_count(proc, dst_slice);
irValue *len_src = ir_slice_count(proc, src_slice);
irValue *cond = ir_emit_comp(proc, Token_Lt, len_dst, len_src);
irValue *len = ir_emit_select(proc, cond, len_dst, len_src);
irValue *elem_size = ir_const_int(proc->module->allocator, size_of_elem);
irValue *byte_count = ir_emit_arith(proc, Token_Mul, len, elem_size, t_int);
irValue **args = gb_alloc_array(proc->module->allocator, irValue *, 3);
args[0] = dst;
args[1] = src;
args[2] = byte_count;
ir_emit_global_call(proc, "__mem_copy", args, 3);
return len;
} break;
case BuiltinProc_swizzle: {
ir_emit_comment(proc, str_lit("swizzle.begin"));
irAddr vector_addr = ir_build_addr(proc, ce->args[0]);
@@ -4288,6 +4258,7 @@ irValue *ir_build_builtin_proc(irProcedure *proc, AstNode *expr, TypeAndValue tv
return ir_emit_load(proc, res);
} break;
#if 1
case BuiltinProc_slice_ptr: {
ir_emit_comment(proc, str_lit("slice_ptr"));
irValue *ptr = ir_build_expr(proc, ce->args[0]);
@@ -4323,6 +4294,7 @@ irValue *ir_build_builtin_proc(irProcedure *proc, AstNode *expr, TypeAndValue tv
ir_fill_slice(proc, slice, ptr, count, capacity);
return ir_emit_load(proc, slice);
} break;
#endif
case BuiltinProc_expand_to_tuple: {
ir_emit_comment(proc, str_lit("expand_to_tuple"));
@@ -4924,7 +4896,10 @@ irAddr ir_build_addr_from_entity(irProcedure *proc, Entity *e, AstNode *expr) {
}
if (v == NULL) {
GB_PANIC("Unknown value: %.*s, entity: %p %.*s\n", LIT(e->token.string), e, LIT(entity_strings[e->kind]));
error(expr, "%.*s Unknown value: %.*s, entity: %p %.*s",
LIT(proc->name),
LIT(e->token.string), e, LIT(entity_strings[e->kind]));
GB_PANIC("Unknown value");
}
return ir_addr(v);
@@ -4937,7 +4912,6 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
switch (i->kind) {
case Token_context:
v = ir_find_or_generate_context_ptr(proc);
// v = ir_find_global_variable(proc, str_lit("__context"));
break;
}
@@ -4950,7 +4924,9 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
irAddr val = {};
return val;
}
String name = i->token.string;
Entity *e = entity_of_ident(proc->module->info, expr);
// GB_ASSERT(name == e->token.string);
return ir_build_addr_from_entity(proc, e, expr);
case_end;
@@ -7093,7 +7069,6 @@ void ir_build_proc(irValue *value, irProcedure *parent) {
proc->module->stmt_state_flags = out;
}
ir_begin_procedure_body(proc);
ir_insert_code_before_proc(proc, parent);
ir_build_stmt(proc, proc->body);
@@ -7423,12 +7398,14 @@ void ir_gen_tree(irGen *s) {
continue;
}
if (map_get(&m->min_dep_map, hash_pointer(e)) == NULL) {
if (map_get(&m->min_dep_map, hash_entity(e)) == NULL) {
// NOTE(bill): Nothing depends upon it so doesn't need to be built
continue;
}
if (!scope->is_global || is_type_poly_proc(e->type)) {
String original_name = name;
if (!scope->is_global || is_type_polymorphic(e->type)) {
if (e->kind == Entity_Procedure && (e->Procedure.tags & ProcTag_export) != 0) {
} else if (e->kind == Entity_Procedure && e->Procedure.link_name.len > 0) {
// Handle later
@@ -7436,8 +7413,14 @@ void ir_gen_tree(irGen *s) {
} else {
name = ir_mangle_name(s, e->token.pos.file, e);
}
} 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_pointer(e), name);
map_set(&m->entity_names, hash_entity(e), name);
switch (e->kind) {
case Entity_TypeName:
+2 -1
View File
@@ -732,7 +732,8 @@ void ir_print_value(irFileBuffer *f, irModule *m, irValue *value, Type *type_hin
ir_print_encoded_local(f, value->TypeName.name);
break;
case irValue_Global: {
Scope *scope = value->Global.entity->scope;
Entity *e = value->Global.entity;
Scope *scope = e->scope;
bool in_global_scope = false;
if (scope != NULL) {
// TODO(bill): Fix this rule. What should it be?
+15 -11
View File
@@ -1354,15 +1354,14 @@ ProcTypeOverloadKind are_proc_types_overload_safe(Type *x, Type *y) {
TypeProc py = base_type(y)->Proc;
if (px.is_polymorphic != py.is_polymorphic) {
return ProcOverload_Polymorphic;
}
// if (px.calling_convention != py.calling_convention) {
// return ProcOverload_CallingConvention;
// }
// if (px.is_polymorphic != py.is_polymorphic) {
// return ProcOverload_Polymorphic;
// }
if (px.param_count != py.param_count) {
return ProcOverload_ParamCount;
}
@@ -1379,6 +1378,11 @@ ProcTypeOverloadKind are_proc_types_overload_safe(Type *x, Type *y) {
return ProcOverload_ParamVariadic;
}
if (px.is_polymorphic != py.is_polymorphic) {
return ProcOverload_Polymorphic;
}
if (px.result_count != py.result_count) {
return ProcOverload_ResultCount;
}
@@ -2448,12 +2452,12 @@ gbString write_type_to_string(gbString str, Type *type) {
}
} else {
GB_ASSERT(var->kind == Entity_TypeName);
#if 0
str = gb_string_appendc(str, "type/");
str = write_type_to_string(str, var->type);
#else
str = gb_string_appendc(str, "type");
#endif
if (var->type->kind == Type_Generic) {
str = gb_string_appendc(str, "type/");
str = write_type_to_string(str, var->type);
} else {
str = gb_string_appendc(str, "type");
}
}
}
}