From 8fc24fd6f2c13c8fb591dfb35a47053ad5d5e694 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 13 Jan 2019 19:34:08 +0000 Subject: [PATCH] Replace `deferred` with `deferred_none`, `deferred_in`, `deferred_out` --- examples/demo/demo.odin | 2 +- src/check_decl.cpp | 2 +- src/checker.cpp | 172 ++++++++++++++++++++++++++++++++-------- src/checker.hpp | 13 ++- src/entity.cpp | 5 +- src/ir.cpp | 16 +++- 6 files changed, 169 insertions(+), 41 deletions(-) diff --git a/examples/demo/demo.odin b/examples/demo/demo.odin index 21b6904c4..6ba8aea76 100644 --- a/examples/demo/demo.odin +++ b/examples/demo/demo.odin @@ -872,7 +872,7 @@ diverging_procedures :: proc() { } deferred_procedure_associations :: proc() { - @(deferred=closure) + @(deferred_out=closure) open :: proc(s: string) -> bool { fmt.println(s); return true; diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 6723b6754..91fd0ff01 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -633,7 +633,7 @@ void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) { e->Procedure.link_name = ac.link_name; } - if (ac.deferred_procedure != nullptr) { + if (ac.deferred_procedure.entity != nullptr) { e->Procedure.deferred_procedure = ac.deferred_procedure; array_add(&ctx->checker->procs_with_deferred_to_check, e); } diff --git a/src/checker.cpp b/src/checker.cpp index 6eb14e556..94006510a 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1038,7 +1038,7 @@ void add_entity_use(CheckerContext *c, Ast *identifier, Entity *entity) { entity->flags |= EntityFlag_Used; add_declaration_dependency(c, entity); if (entity_has_deferred_procedure(entity)) { - Entity *deferred = entity->Procedure.deferred_procedure; + Entity *deferred = entity->Procedure.deferred_procedure.entity; add_entity_use(c, nullptr, deferred); } } @@ -1933,24 +1933,71 @@ DECL_ATTRIBUTE_PROC(foreign_block_decl_attribute) { } DECL_ATTRIBUTE_PROC(proc_decl_attribute) { - ExactValue ev = {}; - if (name != "deferred") { - ev = check_decl_attribute_value(c, value); - } - if (name == "deferred") { if (value != nullptr) { Operand o = {}; check_expr(c, &o, value); Entity *e = entity_of_ident(o.expr); if (e != nullptr && e->kind == Entity_Procedure) { - ac->deferred_procedure = e; + warning(elem, "'%.*s' is deprecated, please use one of the following instead: 'deferred_none', 'deferred_in', 'deferred_out'", LIT(name)); + if (ac->deferred_procedure.entity != nullptr) { + error(elem, "Previous usage of a 'deferred_*' attribute"); + } + ac->deferred_procedure.kind = DeferredProcedure_out; + ac->deferred_procedure.entity = e; + return true; + } + } + error(elem, "Expected a procedure entity for '%.*s'", LIT(name)); + return false; + } else if (name == "deferred_none") { + if (value != nullptr) { + Operand o = {}; + check_expr(c, &o, value); + Entity *e = entity_of_ident(o.expr); + if (e != nullptr && e->kind == Entity_Procedure) { + ac->deferred_procedure.kind = DeferredProcedure_none; + ac->deferred_procedure.entity = e; + return true; + } + } + error(elem, "Expected a procedure entity for '%.*s'", LIT(name)); + return false; + } else if (name == "deferred_in") { + if (value != nullptr) { + Operand o = {}; + check_expr(c, &o, value); + Entity *e = entity_of_ident(o.expr); + if (e != nullptr && e->kind == Entity_Procedure) { + if (ac->deferred_procedure.entity != nullptr) { + error(elem, "Previous usage of a 'deferred_*' attribute"); + } + ac->deferred_procedure.kind = DeferredProcedure_in; + ac->deferred_procedure.entity = e; + return true; + } + } + error(elem, "Expected a procedure entity for '%.*s'", LIT(name)); + return false; + } else if (name == "deferred_out") { + if (value != nullptr) { + Operand o = {}; + check_expr(c, &o, value); + Entity *e = entity_of_ident(o.expr); + if (e != nullptr && e->kind == Entity_Procedure) { + if (ac->deferred_procedure.entity != nullptr) { + error(elem, "Previous usage of a 'deferred_*' attribute"); + } + ac->deferred_procedure.kind = DeferredProcedure_out; + ac->deferred_procedure.entity = e; return true; } } error(elem, "Expected a procedure entity for '%.*s'", LIT(name)); return false; } else if (name == "link_name") { + ExactValue ev = check_decl_attribute_value(c, value); + if (ev.kind == ExactValue_String) { ac->link_name = ev.value_string; if (!is_foreign_name_valid(ac->link_name)) { @@ -1961,6 +2008,8 @@ DECL_ATTRIBUTE_PROC(proc_decl_attribute) { } return true; } else if (name == "link_prefix") { + ExactValue ev = check_decl_attribute_value(c, value); + if (ev.kind == ExactValue_String) { ac->link_prefix = ev.value_string; if (!is_foreign_name_valid(ac->link_prefix)) { @@ -1971,6 +2020,8 @@ DECL_ATTRIBUTE_PROC(proc_decl_attribute) { } return true; } else if (name == "deprecated") { + ExactValue ev = check_decl_attribute_value(c, value); + if (ev.kind == ExactValue_String) { String msg = ev.value_string; if (msg.len == 0) { @@ -3617,47 +3668,100 @@ void check_parsed_files(Checker *c) { Entity *src = c->procs_with_deferred_to_check[i]; GB_ASSERT(src->kind == Entity_Procedure); - Entity *dst = src->Procedure.deferred_procedure; + DeferredProcedureKind dst_kind = src->Procedure.deferred_procedure.kind; + Entity *dst = src->Procedure.deferred_procedure.entity; GB_ASSERT(dst != nullptr); GB_ASSERT(dst->kind == Entity_Procedure); if (is_type_polymorphic(src->type) || is_type_polymorphic(dst->type)) { - error(src->token, "'deferred' cannot be used with a polymorphic procedure"); + switch (dst_kind) { + case DeferredProcedure_none: + error(src->token, "'deferred_none' cannot be used with a polymorphic procedure"); + break; + case DeferredProcedure_in: + error(src->token, "'deferred_in' cannot be used with a polymorphic procedure"); + break; + case DeferredProcedure_out: + error(src->token, "'deferred_out' cannot be used with a polymorphic procedure"); + break; + } continue; } GB_ASSERT(is_type_proc(src->type)); GB_ASSERT(is_type_proc(dst->type)); + Type *src_params = base_type(src->type)->Proc.params; Type *src_results = base_type(src->type)->Proc.results; Type *dst_params = base_type(dst->type)->Proc.params; - if (src_results == nullptr && dst_params == nullptr) { - // Okay - continue; - } - if ((src_results == nullptr && dst_params != nullptr) || - (src_results != nullptr && dst_params == nullptr)) { - error(src->token, "Deferred procedure '%.*s' parameters do not match the results of initial procedure '%.*s'", LIT(src->token.string), LIT(dst->token.string)); - continue; - } - GB_ASSERT(src_results->kind == Type_Tuple); - GB_ASSERT(dst_params->kind == Type_Tuple); + if (dst_kind == DeferredProcedure_none) { + if (dst_params == nullptr) { + // Okay + continue; + } - auto const &sv = src_results->Tuple.variables; - auto const &dv = dst_params->Tuple.variables; + error(src->token, "Deferred procedure '%.*s' must have no input parameters", LIT(dst->token.string)); + } else if (dst_kind == DeferredProcedure_in) { + if (src_params == nullptr && dst_params == nullptr) { + // Okay + continue; + } + if ((src_params == nullptr && dst_params != nullptr) || + (src_params != nullptr && dst_params == nullptr)) { + error(src->token, "Deferred procedure '%.*s' parameters do not match the inputs of initial procedure '%.*s'", LIT(src->token.string), LIT(dst->token.string)); + continue; + } - if (are_types_identical(src_results, dst_params)) { - // Okay! - } else { - gbString s = type_to_string(src_results); - gbString d = type_to_string(dst_params); - error(src->token, "Deferred procedure '%.*s' parameters do not match the results of initial procedure '%.*s':\n\t(%s) =/= (%s)", - LIT(src->token.string), LIT(dst->token.string), - s, d - ); - gb_string_free(d); - gb_string_free(s); - continue; + GB_ASSERT(src_params->kind == Type_Tuple); + GB_ASSERT(dst_params->kind == Type_Tuple); + + auto const &sv = src_params->Tuple.variables; + auto const &dv = dst_params->Tuple.variables; + + if (are_types_identical(src_params, dst_params)) { + // Okay! + } else { + gbString s = type_to_string(src_params); + gbString d = type_to_string(dst_params); + error(src->token, "Deferred procedure '%.*s' parameters do not match the inputs of initial procedure '%.*s':\n\t(%s) =/= (%s)", + LIT(src->token.string), LIT(dst->token.string), + s, d + ); + gb_string_free(d); + gb_string_free(s); + continue; + } + + } else if (dst_kind == DeferredProcedure_out) { + if (src_results == nullptr && dst_params == nullptr) { + // Okay + continue; + } + if ((src_results == nullptr && dst_params != nullptr) || + (src_results != nullptr && dst_params == nullptr)) { + error(src->token, "Deferred procedure '%.*s' parameters do not match the results of initial procedure '%.*s'", LIT(src->token.string), LIT(dst->token.string)); + continue; + } + + GB_ASSERT(src_results->kind == Type_Tuple); + GB_ASSERT(dst_params->kind == Type_Tuple); + + auto const &sv = src_results->Tuple.variables; + auto const &dv = dst_params->Tuple.variables; + + if (are_types_identical(src_results, dst_params)) { + // Okay! + } else { + gbString s = type_to_string(src_results); + gbString d = type_to_string(dst_params); + error(src->token, "Deferred procedure '%.*s' parameters do not match the results of initial procedure '%.*s':\n\t(%s) =/= (%s)", + LIT(src->token.string), LIT(dst->token.string), + s, d + ); + gb_string_free(d); + gb_string_free(s); + continue; + } } } diff --git a/src/checker.hpp b/src/checker.hpp index e5a4dd0aa..abc349129 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -288,13 +288,24 @@ struct BlockLabel { Ast *label; // Ast_Label; }; +enum DeferredProcedureKind { + DeferredProcedure_none, + DeferredProcedure_in, + DeferredProcedure_out, +}; +struct DeferredProcedure { + DeferredProcedureKind kind; + Entity *entity; +}; + + struct AttributeContext { String link_name; String link_prefix; isize init_expr_list_count; String thread_local_model; String deprecated_message; - Entity *deferred_procedure; + DeferredProcedure deferred_procedure; }; AttributeContext make_attribute_context(String link_prefix) { diff --git a/src/entity.cpp b/src/entity.cpp index c9dc966ec..da627cb7c 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -77,6 +77,7 @@ struct ParameterValue { }; + // An Entity is a named "thing" in the language struct Entity { EntityKind kind; @@ -128,7 +129,7 @@ struct Entity { Ast * foreign_library_ident; String link_name; String link_prefix; - Entity *deferred_procedure; + DeferredProcedure deferred_procedure; bool is_foreign; bool is_export; } Procedure; @@ -189,7 +190,7 @@ bool is_entity_exported(Entity *e, bool allow_builtin = false) { bool entity_has_deferred_procedure(Entity *e) { GB_ASSERT(e != nullptr); if (e->kind == Entity_Procedure) { - return e->Procedure.deferred_procedure != nullptr; + return e->Procedure.deferred_procedure.entity != nullptr; } return false; } diff --git a/src/ir.cpp b/src/ir.cpp index 12dc3d278..c6c50182b 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -2905,12 +2905,24 @@ irValue *ir_emit_call(irProcedure *p, irValue *value, Array args, Pro irProcedure *the_proc = &value->Proc; Entity *e = the_proc->entity; if (entity_has_deferred_procedure(e)) { - Entity *deferred_entity = e->Procedure.deferred_procedure; + DeferredProcedureKind kind = e->Procedure.deferred_procedure.kind; + Entity *deferred_entity = e->Procedure.deferred_procedure.entity; irValue **deferred_found = map_get(&p->module->values, hash_entity(deferred_entity)); GB_ASSERT(deferred_found != nullptr); irValue *deferred = *deferred_found; - Array result_as_args = ir_value_to_array(p, result); + + auto in_args = args; + Array result_as_args = {}; + switch (kind) { + case DeferredProcedure_none: + break; + case DeferredProcedure_in: + result_as_args = in_args; + case DeferredProcedure_out: + result_as_args = ir_value_to_array(p, result); + break; + } irValue *deferred_call = ir_de_emit(p, ir_emit_call(p, deferred, result_as_args)); ir_add_defer_instr(p, p->scope_index, deferred_call);