From ef74414b9618aa246a1b5d626ecbdbce3c056a74 Mon Sep 17 00:00:00 2001 From: Brendan Hansen Date: Mon, 8 Nov 2021 21:22:20 -0600 Subject: [PATCH] Added more yielding and remove ugly code --- include/astnodes.h | 17 +++++--- src/astnodes.c | 73 +++++++++++++++++--------------- src/checker.c | 58 +++++++++++++++++--------- src/polymorph.c | 48 +++++++++------------ src/symres.c | 5 +++ src/utils.c | 102 ++++++++++++++++----------------------------- 6 files changed, 149 insertions(+), 154 deletions(-) diff --git a/include/astnodes.h b/include/astnodes.h index bdcac1b7..1c5b0525 100644 --- a/include/astnodes.h +++ b/include/astnodes.h @@ -1009,9 +1009,8 @@ struct AstPolySolution { }; struct AstSolidifiedFunction { - AstFunction* func; - - b32 header_complete: 1; + AstFunction *func; + struct Entity *func_header_entity; }; struct AstPolyProc { @@ -1145,6 +1144,7 @@ typedef enum EntityType { Entity_Type_Polymorphic_Proc, Entity_Type_Macro, Entity_Type_Foreign_Function_Header, + Entity_Type_Temp_Function_Header, // Same as a Function_Header, except it disappears after it checks completely. Entity_Type_Function_Header, Entity_Type_Global_Header, Entity_Type_Process_Directive, @@ -1219,7 +1219,6 @@ void entity_heap_remove_top(EntityHeap* entities); // If target_arr is null, the entities will be placed directly in the heap. void add_entities_for_node(bh_arr(Entity *)* target_arr, AstNode* node, Scope* scope, Package* package); -b32 entity_bring_to_state(Entity* ent, EntityState state); void symres_entity(Entity* ent); void check_entity(Entity* ent); void emit_entity(Entity* ent); @@ -1385,8 +1384,13 @@ void clone_function_body(bh_allocator a, AstFunction* dest, AstFunction* source) void promote_numlit_to_larger(AstNumLit* num); b32 convert_numlit_to_type(AstNumLit* num, Type* type); +typedef enum TypeMatch { + TYPE_MATCH_SUCCESS, + TYPE_MATCH_FAILED, + TYPE_MATCH_YIELD, +} TypeMatch; #define unify_node_and_type(node, type) (unify_node_and_type_((node), (type), 1)) -b32 unify_node_and_type_(AstTyped** pnode, Type* type, b32 permanent); +TypeMatch unify_node_and_type_(AstTyped** pnode, Type* type, b32 permanent); Type* resolve_expression_type(AstTyped* node); i64 get_expression_integer_value(AstTyped* node); @@ -1414,7 +1418,7 @@ void arguments_copy(Arguments* dest, Arguments* src); void arguments_clone(Arguments* dest, Arguments* src); void arguments_deep_clone(bh_allocator a, Arguments* dest, Arguments* src); void arguments_remove_baked(Arguments* args); -b32 check_arguments_against_type(Arguments* args, TypeFunction* func_type, VarArgKind* va_kind, +TypeMatch check_arguments_against_type(Arguments* args, TypeFunction* func_type, VarArgKind* va_kind, OnyxToken* location, char* func_name, struct OnyxError* error); i32 get_argument_buffer_size(TypeFunction* type, Arguments* args); @@ -1431,6 +1435,7 @@ AstFunction* polymorphic_proc_lookup(AstPolyProc* pp, PolyProcLookupMethod pp_lo AstFunction* polymorphic_proc_solidify(AstPolyProc* pp, bh_arr(AstPolySolution) slns, OnyxToken* tkn); AstNode* polymorphic_proc_try_solidify(AstPolyProc* pp, bh_arr(AstPolySolution) slns, OnyxToken* tkn); AstFunction* polymorphic_proc_build_only_header(AstPolyProc* pp, PolyProcLookupMethod pp_lookup, ptr actual); +AstFunction* polymorphic_proc_build_only_header_with_slns(AstPolyProc* pp, bh_arr(AstPolySolution) slns); void add_overload_option(bh_arr(OverloadOption)* poverloads, u64 precedence, AstTyped* overload); AstTyped* find_matching_overload_by_arguments(bh_arr(OverloadOption) overloads, Arguments* args, b32* should_yield); diff --git a/src/astnodes.c b/src/astnodes.c index 0b246471..5a5d6dc6 100644 --- a/src/astnodes.c +++ b/src/astnodes.c @@ -503,36 +503,35 @@ b32 convert_numlit_to_type(AstNumLit* num, Type* type) { return 0; } -// NOTE: Returns 0 if it was not possible to make the types compatible. // TODO: This function should be able return a "yield" condition. There // are a couple cases that need to yield in order to be correct, like // polymorphic functions with a typeof for the return type. -b32 unify_node_and_type_(AstTyped** pnode, Type* type, b32 permanent) { +TypeMatch unify_node_and_type_(AstTyped** pnode, Type* type, b32 permanent) { AstTyped* node = *pnode; - if (type == NULL) return 0; - if (node == NULL) return 0; + if (type == NULL) return TYPE_MATCH_FAILED; + if (node == NULL) return TYPE_MATCH_FAILED; if (node->kind == Ast_Kind_Struct_Literal && node->type_node == NULL) { - if (node->entity != NULL) return 1; + if (node->entity != NULL) return TYPE_MATCH_SUCCESS; if (type->kind == Type_Kind_VarArgs) type = type->VarArgs.elem; - if (!type_is_sl_constructable(type)) return 0; + if (!type_is_sl_constructable(type)) return TYPE_MATCH_FAILED; // If this shouldn't make permanent changes and submit entities, // just assume that it works and don't submit the entities. - if (!permanent) return 1; + if (!permanent) return TYPE_MATCH_SUCCESS; node->type = type; add_entities_for_node(NULL, (AstNode *) node, NULL, NULL); - return 1; + return TYPE_MATCH_SUCCESS; } if (node->kind == Ast_Kind_Array_Literal && node->type == NULL) { - if (node->entity != NULL) return 1; + if (node->entity != NULL) return TYPE_MATCH_SUCCESS; // If this shouldn't make permanent changes and submit entities, // just assume that it works and don't submit the entities. - if (!permanent) return 1; + if (!permanent) return TYPE_MATCH_SUCCESS; Type* array_type=NULL; switch (type->kind) { @@ -554,21 +553,21 @@ b32 unify_node_and_type_(AstTyped** pnode, Type* type, b32 permanent) { node->flags |= Ast_Flag_Array_Literal_Typed; add_entities_for_node(NULL, (AstNode *) node, NULL, NULL); - return 1; + return TYPE_MATCH_SUCCESS; } if (node->kind == Ast_Kind_Unary_Field_Access) { AstType* ast_type = type->ast_type; AstNode* resolved = try_symbol_resolve_from_node((AstNode *) ast_type, node->token); - if (resolved == NULL) return 0; + if (resolved == NULL) return TYPE_MATCH_FAILED; if (permanent) *pnode = (AstTyped *) resolved; - return 1; + return TYPE_MATCH_SUCCESS; } if (node->kind == Ast_Kind_Overloaded_Function) { AstTyped* func = find_matching_overload_by_type(((AstOverloadedFunction *) node)->overloads, type); - if (func == NULL) return 0; + if (func == NULL) return TYPE_MATCH_FAILED; // HACK: It feels like there should be a better place to flag that a procedure was definitely used. if (func->kind == Ast_Kind_Function) @@ -580,10 +579,10 @@ b32 unify_node_and_type_(AstTyped** pnode, Type* type, b32 permanent) { if (node->kind == Ast_Kind_Polymorphic_Proc) { AstFunction* func = polymorphic_proc_lookup((AstPolyProc *) node, PPLM_By_Function_Type, type, node->token); - if (func == NULL) return 0; + if (func == NULL) return TYPE_MATCH_FAILED; // FIXME: This is incorrect. It should actually yield and not return a failure. - if (func == (AstFunction *) &node_that_signals_a_yield) return 0; + if (func == (AstFunction *) &node_that_signals_a_yield) return TYPE_MATCH_YIELD; *pnode = (AstTyped *) func; node = *pnode; @@ -592,14 +591,14 @@ b32 unify_node_and_type_(AstTyped** pnode, Type* type, b32 permanent) { // HACK: NullProcHack // The null_proc matches any procedure, and because of that, will cause a runtime error if you // try to call it. - if (type->kind == Type_Kind_Function && (node->flags & Ast_Flag_Proc_Is_Null) != 0) return 1; + if (type->kind == Type_Kind_Function && (node->flags & Ast_Flag_Proc_Is_Null) != 0) return TYPE_MATCH_SUCCESS; // The normal case where everything works perfectly. Type* node_type = get_expression_type(node); - if (types_are_compatible(node_type, type)) return 1; + if (types_are_compatible(node_type, type)) return TYPE_MATCH_SUCCESS; i64 any_id = type_build_from_ast(context.ast_alloc, builtin_any_type)->id; - if (node_type && node_type->id != any_id && type->id == any_id) return 1; + if (node_type && node_type->id != any_id && type->id == any_id) return TYPE_MATCH_SUCCESS; // Here are some of the ways you can unify a node with a type if the type of the // node does not match the given type: @@ -612,7 +611,7 @@ b32 unify_node_and_type_(AstTyped** pnode, Type* type, b32 permanent) { && type->kind == Type_Kind_Function) { node_type->Function.return_type = type->Function.return_type; - return 1; + return TYPE_MATCH_SUCCESS; } // If the node is an auto cast (~~) node, then check to see if the cast is legal @@ -621,11 +620,11 @@ b32 unify_node_and_type_(AstTyped** pnode, Type* type, b32 permanent) { char* dummy; Type* from_type = get_expression_type(((AstUnaryOp *) node)->expr); if (!from_type || !cast_is_legal(from_type, type, &dummy)) { - return 0; + return TYPE_MATCH_FAILED; } else { if (permanent) ((AstUnaryOp *) node)->type = type; - return 1; + return TYPE_MATCH_SUCCESS; } } @@ -643,47 +642,53 @@ b32 unify_node_and_type_(AstTyped** pnode, Type* type, b32 permanent) { *pnode = (AstTyped *) make_cast(context.ast_alloc, node, type); } - return legal; + return legal ? TYPE_MATCH_SUCCESS : TYPE_MATCH_FAILED; } } // If the node is a numeric literal, try to convert it to the destination type. else if (node->kind == Ast_Kind_NumLit) { - if (convert_numlit_to_type((AstNumLit *) node, type)) return 1; + if (convert_numlit_to_type((AstNumLit *) node, type)) return TYPE_MATCH_SUCCESS; } // If the node is a compound expression, and it doesn't have a type created, // recursive call this function with the individual components of the compound // expression. else if (node->kind == Ast_Kind_Compound) { - if (type->kind != Type_Kind_Compound) return 0; + if (type->kind != Type_Kind_Compound) return TYPE_MATCH_FAILED; AstCompound* compound = (AstCompound *) node; u32 expr_count = bh_arr_length(compound->exprs); - if (expr_count != type->Compound.count) return 0; + if (expr_count != type->Compound.count) return TYPE_MATCH_FAILED; fori (i, 0, (i64) expr_count) { - if (!unify_node_and_type_(&compound->exprs[i], type->Compound.types[i], permanent)) return 0; + TypeMatch tm = unify_node_and_type_(&compound->exprs[i], type->Compound.types[i], permanent); + if (tm != TYPE_MATCH_SUCCESS) { + return tm; + } } compound->type = type_build_compound_type(context.ast_alloc, compound); - return 1; + return TYPE_MATCH_SUCCESS; } else if (node->kind == Ast_Kind_If_Expression) { AstIfExpression* if_expr = (AstIfExpression *) node; - b32 true_success = unify_node_and_type_(&if_expr->true_expr, type, permanent); - b32 false_success = unify_node_and_type_(&if_expr->false_expr, type, permanent); + TypeMatch true_success = unify_node_and_type_(&if_expr->true_expr, type, permanent); + TypeMatch false_success = unify_node_and_type_(&if_expr->false_expr, type, permanent); - if (true_success && false_success) { + if (true_success == TYPE_MATCH_SUCCESS && false_success == TYPE_MATCH_SUCCESS) { if (permanent) if_expr->type = type; - return 1; + return TYPE_MATCH_SUCCESS; + + } else if (true_success == TYPE_MATCH_FAILED || false_success == TYPE_MATCH_FAILED) { + return TYPE_MATCH_FAILED; } else { - return 0; + return TYPE_MATCH_YIELD; } } @@ -692,7 +697,7 @@ b32 unify_node_and_type_(AstTyped** pnode, Type* type, b32 permanent) { return unify_node_and_type_(&alias->alias, type, permanent); } - return 0; + return TYPE_MATCH_FAILED; } Type* resolve_expression_type(AstTyped* node) { diff --git a/src/checker.c b/src/checker.c index 8be7267d..cecf4f97 100644 --- a/src/checker.c +++ b/src/checker.c @@ -39,6 +39,16 @@ return Check_Error; \ } while (0) +#define TYPE_CHECK_(expr, type, type_name) \ + TypeMatch type_name; \ + type_name = unify_node_and_type(expr, type); \ + if (type_name == TYPE_MATCH_YIELD) YIELD((*expr)->token->pos, "Waiting on type checking."); \ + if (type_name == TYPE_MATCH_FAILED) + +#define CONCAT(a, b) a##_##b +#define DEFER_LINE(a, line) CONCAT(a, line) +#define TYPE_CHECK(expr, type) TYPE_CHECK_(expr, type, DEFER_LINE(tc, __LINE__)) + typedef enum CheckStatus { Check_Success, // The node was successfully checked with out errors Check_Complete, // The node is done processing @@ -77,6 +87,7 @@ CheckStatus check_global(AstGlobal* global); CheckStatus check_function(AstFunction* func); CheckStatus check_overloaded_function(AstOverloadedFunction* func); CheckStatus check_struct(AstStructType* s_node); +CheckStatus check_temp_function_header(AstFunction* func); CheckStatus check_function_header(AstFunction* func); CheckStatus check_memres_type(AstMemRes* memres); CheckStatus check_memres(AstMemRes* memres); @@ -116,7 +127,7 @@ CheckStatus check_return(AstReturn* retnode) { return Check_Success; } - if (!unify_node_and_type(&retnode->expr, *expected_return_type)) { + TYPE_CHECK(&retnode->expr, *expected_return_type) { ERROR_(retnode->token->pos, "Expected to return a value of type '%s', returning value of type '%s'.", type_get_name(*expected_return_type), @@ -334,7 +345,7 @@ CheckStatus check_switch(AstSwitch* switchnode) { continue; } - if (!unify_node_and_type(value, resolved_expr_type)) { + TYPE_CHECK(value, resolved_expr_type) { OnyxToken* tkn = sc->block->token; if ((*value)->token) tkn = (*value)->token; @@ -566,12 +577,15 @@ CheckStatus check_call(AstCall** pcall) { } OnyxError error; - if (!check_arguments_against_type(&call->args, &callee->type->Function, &call->va_kind, - call->token, get_function_name(callee), &error)) { + TypeMatch tm = check_arguments_against_type(&call->args, &callee->type->Function, &call->va_kind, + call->token, get_function_name(callee), &error); + if (tm == TYPE_MATCH_FAILED) { onyx_submit_error(error); return Check_Error; } + if (tm == TYPE_MATCH_YIELD) YIELD(call->token->pos, "Waiting on argument type checking."); + call->flags |= Ast_Flag_Has_Been_Checked; callee->flags |= Ast_Flag_Function_Used; @@ -726,7 +740,7 @@ CheckStatus check_binaryop_assignment(AstBinaryOp** pbinop) { } } - if (!unify_node_and_type(&binop->right, binop->left->type)) { + TYPE_CHECK(&binop->right, binop->left->type) { ERROR_(binop->token->pos, "Cannot assign value of type '%s' to a '%s'.", node_get_type_name(binop->right), @@ -812,8 +826,8 @@ CheckStatus check_binaryop_compare(AstBinaryOp** pbinop) { b32 right_ac = node_is_auto_cast((AstNode *) binop->right); if (left_ac && right_ac) ERROR(binop->token->pos, "Cannot have auto cast on both sides of binary operator."); - else if (unify_node_and_type(&binop->left, rtype)); - else if (unify_node_and_type(&binop->right, ltype)); + else if (unify_node_and_type(&binop->left, rtype) == TYPE_MATCH_SUCCESS); // @TODO: Should check for yield + else if (unify_node_and_type(&binop->right, ltype) == TYPE_MATCH_SUCCESS); // @TODO: Should check for yield else { ERROR_(binop->token->pos, "Cannot compare '%s' to '%s'.", @@ -903,8 +917,8 @@ CheckStatus check_binaryop(AstBinaryOp** pbinop) { // :UnaryFieldAccessIsGross if (binop->left->kind == Ast_Kind_Unary_Field_Access || binop->right->kind == Ast_Kind_Unary_Field_Access) { - if (unify_node_and_type(&binop->left, binop->right->type)); - else if (unify_node_and_type(&binop->right, binop->left->type)); + if (unify_node_and_type(&binop->left, binop->right->type) == TYPE_MATCH_SUCCESS); // @TODO: Should check for yield. + else if (unify_node_and_type(&binop->right, binop->left->type) == TYPE_MATCH_SUCCESS); // @TODO: Should check for yield. else { report_bad_binaryop(binop); return Check_Error; @@ -973,8 +987,8 @@ CheckStatus check_binaryop(AstBinaryOp** pbinop) { if (left_ac && right_ac) { ERROR(binop->token->pos, "Cannot have auto cast on both sides of binary operator."); } - else if (unify_node_and_type(&binop->left, binop->right->type)); - else if (unify_node_and_type(&binop->right, binop->left->type)); + else if (unify_node_and_type(&binop->left, binop->right->type) == TYPE_MATCH_SUCCESS); // @TODO: Should check for yield. + else if (unify_node_and_type(&binop->right, binop->left->type) == TYPE_MATCH_SUCCESS); // @TODO: Should check for yield. else { ERROR_(binop->token->pos, "Mismatched types for binary operation '%s'. left: '%s', right: '%s'.", @@ -1130,7 +1144,7 @@ CheckStatus check_struct_literal(AstStructLiteral* sl) { YIELD_((*actual)->token->pos, "Trying to resolve type of expression for member '%s'.", smem.name); } - if (!unify_node_and_type(actual, formal)) { + TYPE_CHECK(actual, formal) { ERROR_(sl->token->pos, "Mismatched types for %d%s member named '%s', expected '%s', got '%s'.", i + 1, bh_num_suffix(i + 1), @@ -1187,7 +1201,7 @@ CheckStatus check_array_literal(AstArrayLiteral* al) { al->flags &= ((*expr)->flags & Ast_Flag_Comptime) | (al->flags &~ Ast_Flag_Comptime); - if (!unify_node_and_type(expr, elem_type)) { + TYPE_CHECK(expr, elem_type) { ERROR_((*expr)->token->pos, "Mismatched types for value of in array, expected '%s', got '%s'.", type_get_name(elem_type), node_get_type_name(*expr)); @@ -1206,14 +1220,14 @@ CheckStatus check_range_literal(AstRangeLiteral** prange) { StructMember smem; type_lookup_member(expected_range_type, "low", &smem); - if (!unify_node_and_type(&range->low, smem.type)) { + TYPE_CHECK(&range->low, smem.type) { ERROR_(range->token->pos, "Expected left side of range to be a 32-bit integer, got '%s'.", node_get_type_name(range->low)); } type_lookup_member(expected_range_type, "high", &smem); - if (!unify_node_and_type(&range->high, smem.type)) { + TYPE_CHECK(&range->high, smem.type) { ERROR_(range->token->pos, "Expected right side of range to be a 32-bit integer, got '%s'.", node_get_type_name(range->high)); @@ -1244,7 +1258,7 @@ CheckStatus check_if_expression(AstIfExpression* if_expr) { CHECK(expression, &if_expr->true_expr); CHECK(expression, &if_expr->false_expr); - if (!unify_node_and_type(&if_expr->cond, &basic_types[Basic_Kind_Bool])) { + TYPE_CHECK(&if_expr->cond, &basic_types[Basic_Kind_Bool]) { ERROR_(if_expr->token->pos, "If-expression expected boolean for condition, got '%s'.", type_get_name(if_expr->cond->type)); } @@ -1746,7 +1760,7 @@ CheckStatus check_insert_directive(AstDirectiveInsert** pinsert) { Type* code_type = type_build_from_ast(context.ast_alloc, builtin_code_type); - if (!unify_node_and_type(&insert->code_expr, code_type)) { + TYPE_CHECK(&insert->code_expr, code_type) { ERROR_(insert->token->pos, "#insert expected a value of type 'Code', got '%s'.", type_get_name(insert->code_expr->type)); } @@ -1976,7 +1990,7 @@ CheckStatus check_struct_defaults(AstStructType* s_node) { if ((*smem)->initial_value && *(*smem)->initial_value) { CHECK(expression, (*smem)->initial_value); - if (!unify_node_and_type((*smem)->initial_value, (*smem)->type)) { + TYPE_CHECK((*smem)->initial_value, (*smem)->type) { ERROR_((*(*smem)->initial_value)->token->pos, "Mismatched type for initial value, expected '%s', got '%s'.", type_get_name((*smem)->type), @@ -2002,6 +2016,11 @@ CheckStatus check_struct_defaults(AstStructType* s_node) { return Check_Success; } +CheckStatus check_temp_function_header(AstFunction* func) { + CHECK(function_header, func); + return Check_Complete; +} + CheckStatus check_function_header(AstFunction* func) { //if (func->entity_body && func->entity_body->state < Entity_State_Check_Types) // YIELD(func->token->pos, "Waiting for function body to complete symbol resolution to check header."); @@ -2116,7 +2135,7 @@ CheckStatus check_memres(AstMemRes* memres) { if (memres->type != NULL) { Type* memres_type = memres->type; - if (!unify_node_and_type(&memres->initial_value, memres_type)) { + TYPE_CHECK(&memres->initial_value, memres_type) { ERROR_(memres->token->pos, "Cannot assign value of type '%s' to a '%s'.", node_get_type_name(memres->initial_value), @@ -2357,6 +2376,7 @@ void check_entity(Entity* ent) { switch (ent->type) { case Entity_Type_Foreign_Function_Header: case Entity_Type_Function_Header: cs = check_function_header(ent->function); break; + case Entity_Type_Temp_Function_Header: cs = check_temp_function_header(ent->function); break; case Entity_Type_Function: cs = check_function(ent->function); break; case Entity_Type_Overloaded_Function: cs = check_overloaded_function(ent->overloaded_function); break; case Entity_Type_Global: cs = check_global(ent->global); break; diff --git a/src/polymorph.c b/src/polymorph.c index 2390071e..f98c45be 100644 --- a/src/polymorph.c +++ b/src/polymorph.c @@ -106,9 +106,6 @@ static b32 add_solidified_function_entities(AstSolidifiedFunction solidified_fun .scope = solidified_func.func->poly_scope, }; - entity_bring_to_state(&func_header_entity, Entity_State_Code_Gen); - if (onyx_has_errors()) return 0; - Entity func_entity = { .state = Entity_State_Resolve_Symbols, .type = Entity_Type_Function, @@ -120,6 +117,7 @@ static b32 add_solidified_function_entities(AstSolidifiedFunction solidified_fun Entity* entity_header = entity_heap_insert(&context.entities, func_header_entity); Entity* entity_body = entity_heap_insert(&context.entities, func_entity); + solidified_func.func_header_entity = entity_header; solidified_func.func->entity_header = entity_header; solidified_func.func->entity_body = entity_body; @@ -137,7 +135,7 @@ static AstSolidifiedFunction generate_solidified_function( b32 header_only) { AstSolidifiedFunction solidified_func; - solidified_func.header_complete = 0; + solidified_func.func_header_entity = NULL; // NOTE: Use the position of token if one was provided, otherwise just use NULL. OnyxFilePos poly_scope_pos = { 0 }; @@ -502,7 +500,8 @@ static void solve_for_polymorphic_param_value(PolySolveResult* resolved, AstPoly value_to_use = (AstTyped *) get_function_from_node((AstNode *) value); } - if (!unify_node_and_type(&value_to_use, param->type)) { + TypeMatch tm = unify_node_and_type(&value_to_use, param->type); + if (tm == TYPE_MATCH_FAILED) { if (err_msg) *err_msg = bh_aprintf(global_scratch_allocator, "The procedure '%s' expects a value of type '%s' for baked %d%s parameter, got '%s'.", get_function_name(pp->base_func), @@ -513,6 +512,8 @@ static void solve_for_polymorphic_param_value(PolySolveResult* resolved, AstPoly return; } + if (tm == TYPE_MATCH_YIELD) flag_to_yield = 1; + *resolved = ((PolySolveResult) { PSK_Value, value }); } @@ -605,6 +606,7 @@ AstFunction* polymorphic_proc_lookup(AstPolyProc* pp, PolyProcLookupMethod pp_lo if (slns == NULL) { if (flag_to_yield) { flag_to_yield = 0; + bh_arr_free(slns); return (AstFunction *) &node_that_signals_a_yield; } @@ -647,12 +649,9 @@ AstFunction* polymorphic_proc_solidify(AstPolyProc* pp, bh_arr(AstPolySolution) // NOTE: Cache the function for later use, reducing duplicate functions. bh_table_put(AstSolidifiedFunction, pp->concrete_funcs, unique_key, solidified_func); - if (!add_solidified_function_entities(solidified_func, 0)) { - onyx_report_error(tkn->pos, "Error in polymorphic procedure header generated from this call site."); - return NULL; - } + add_solidified_function_entities(solidified_func, 0); - return solidified_func.func; + return (AstFunction *) &node_that_signals_a_yield; } // NOTE: This can return either a AstFunction or an AstPolyProc, depending if enough parameters were @@ -712,6 +711,10 @@ AstFunction* polymorphic_proc_build_only_header(AstPolyProc* pp, PolyProcLookupM ensure_polyproc_cache_is_created(pp); + return polymorphic_proc_build_only_header_with_slns(pp, slns); +} + +AstFunction* polymorphic_proc_build_only_header_with_slns(AstPolyProc* pp, bh_arr(AstPolySolution) slns) { AstSolidifiedFunction solidified_func; char* unique_key = build_poly_slns_unique_key(slns); @@ -725,36 +728,23 @@ AstFunction* polymorphic_proc_build_only_header(AstPolyProc* pp, PolyProcLookupM solidified_func = generate_solidified_function(pp, slns, NULL, 1); } - if (solidified_func.header_complete) return solidified_func.func; + if (solidified_func.func_header_entity && solidified_func.func_header_entity->state == Entity_State_Finalized) return solidified_func.func; Entity func_header_entity = { .state = Entity_State_Resolve_Symbols, - .type = Entity_Type_Function_Header, + .type = Entity_Type_Temp_Function_Header, .function = solidified_func.func, .package = NULL, .scope = solidified_func.func->poly_scope, }; - // HACK: Everything with entity_bring_to_state is a big hack... - // The idea is that instead of making the caller yield for a simple procedure header, - // do a single pass of trying to solve for the parameter types and return types. - // The big missing piece of the entity pumping system is that once an entity is - // entered into the system, it cannot be removed and it is assumed it is going to - // be used in the final binary. This is obviously not always the case, but that - // is how the system currently works. - b32 successful = entity_bring_to_state(&func_header_entity, Entity_State_Code_Gen); - if (onyx_has_errors()) { - onyx_errors_print(); - onyx_clear_errors(); - return NULL; - } - - solidified_func.header_complete = successful; + Entity* func_header_entity_ptr = entity_heap_insert(&context.entities, func_header_entity); + solidified_func.func_header_entity = func_header_entity_ptr; - // NOTE: Cache the function for later use, only if it didn't have errors in its header. + // NOTE: Cache the function for later use. bh_table_put(AstSolidifiedFunction, pp->concrete_funcs, unique_key, solidified_func); - return solidified_func.func; + return (AstFunction *) &node_that_signals_a_yield; } // diff --git a/src/symres.c b/src/symres.c index 0b2d427a..38e59376 100644 --- a/src/symres.c +++ b/src/symres.c @@ -751,6 +751,10 @@ static SymresStatus symres_directive_solidify(AstDirectiveSolidify** psolid) { } solid->resolved_proc = polymorphic_proc_try_solidify(solid->poly_proc, solid->known_polyvars, solid->token); + if (solid->resolved_proc == (AstFunction *) &node_that_signals_a_yield) { + solid->resolved_proc = NULL; + return Symres_Yield_Macro; + } // NOTE: Not a DirectiveSolidify. *psolid = (AstDirectiveSolidify *) solid->resolved_proc; @@ -1241,6 +1245,7 @@ void symres_entity(Entity* ent) { case Entity_Type_Static_If: ss = symres_static_if(ent->static_if); break; case Entity_Type_Foreign_Function_Header: + case Entity_Type_Temp_Function_Header: case Entity_Type_Function_Header: ss = symres_function_header(ent->function); break; case Entity_Type_Function: ss = symres_function(ent->function); break; diff --git a/src/utils.c b/src/utils.c index 537044b3..82a43868 100644 --- a/src/utils.c +++ b/src/utils.c @@ -364,6 +364,13 @@ AstTyped* find_matching_overload_by_arguments(bh_arr(OverloadOption) overloads, // NOTE: Overload is not something that is known to be overloadable. if (overload == NULL) continue; + if (overload == (AstFunction *) &node_that_signals_a_yield) { + // If it was not possible to create the type for this procedure, tell the + // caller that this should yield and try again later. + if (should_yield) *should_yield = 1; + + return NULL; + } if (overload->kind != Ast_Kind_Function) continue; if (overload->type == NULL) { // If it was not possible to create the type for this procedure, tell the @@ -383,10 +390,16 @@ AstTyped* find_matching_overload_by_arguments(bh_arr(OverloadOption) overloads, if (!fill_in_arguments(&args, (AstNode *) overload, NULL)) continue; VarArgKind va_kind; - if (check_arguments_against_type(&args, &overload->type->Function, &va_kind, NULL, NULL, NULL)) { + TypeMatch tm = check_arguments_against_type(&args, &overload->type->Function, &va_kind, NULL, NULL, NULL); + if (tm == TYPE_MATCH_SUCCESS) { matched_overload = node; break; } + + if (tm == TYPE_MATCH_YIELD) { + if (should_yield) *should_yield = 1; + return NULL; + } } bh_imap_free(&all_overloads); @@ -407,10 +420,15 @@ AstTyped* find_matching_overload_by_type(bh_arr(OverloadOption) overloads, Type* AstTyped* node = (AstTyped *) entry->key; if (node->kind == Ast_Kind_Overloaded_Function) continue; - if (unify_node_and_type(&node, type)) { + TypeMatch tm = unify_node_and_type(&node, type); + if (tm == TYPE_MATCH_SUCCESS) { matched_overload = node; break; } + + if (tm == TYPE_MATCH_YIELD) { + return (AstTyped *) &node_that_signals_a_yield; + } } bh_imap_free(&all_overloads); @@ -527,38 +545,7 @@ AstFunction* macro_resolve_header(AstMacro* macro, Arguments* args, OnyxToken* c } // CLEANUP Copy'n'pasted from polymorphic_proc_build_only_header - AstSolidifiedFunction solidified_func; - - char* unique_key = build_poly_slns_unique_key(slns); - if (bh_table_has(AstSolidifiedFunction, pp->concrete_funcs, unique_key)) { - solidified_func = bh_table_get(AstSolidifiedFunction, pp->concrete_funcs, unique_key); - - } else { - // NOTE: This function is only going to have the header of it correctly created. - // Nothing should happen to this function's body or else the original will be corrupted. - // - brendanfh 2021/01/10 - solidified_func = generate_solidified_function(pp, slns, callsite, 1); - } - - if (solidified_func.header_complete) return solidified_func.func; - - Entity func_header_entity = { - .state = Entity_State_Resolve_Symbols, - .type = Entity_Type_Function_Header, - .function = solidified_func.func, - .package = NULL, - .scope = solidified_func.func->poly_scope, - }; - - b32 successful = entity_bring_to_state(&func_header_entity, Entity_State_Code_Gen); - if (onyx_has_errors()) return NULL; - - solidified_func.header_complete = successful; - - bh_table_put(AstSolidifiedFunction, pp->concrete_funcs, unique_key, solidified_func); - if (!successful) return (AstFunction *) &node_that_signals_a_yield; - - return solidified_func.func; + return polymorphic_proc_build_only_header_with_slns(pp, slns); } default: assert(("Bad macro body type.", 0)); @@ -567,27 +554,6 @@ AstFunction* macro_resolve_header(AstMacro* macro, Arguments* args, OnyxToken* c return NULL; } -b32 entity_bring_to_state(Entity* ent, EntityState state) { - EntityState last_state = ent->state; - - while (ent->state != state) { - switch (ent->state) { - case Entity_State_Resolve_Symbols: symres_entity(ent); break; - case Entity_State_Check_Types: check_entity(ent); break; - case Entity_State_Code_Gen: emit_entity(ent); break; - - default: return 0; - } - - if (ent->state == last_state) return 0; - last_state = ent->state; - - if (onyx_has_errors()) return 0; - } - - return 1; -} - // // Arguments resolving @@ -788,8 +754,8 @@ typedef enum ArgState { AS_Expecting_Untyped_VA, } ArgState; -b32 check_arguments_against_type(Arguments* args, TypeFunction* func_type, VarArgKind* va_kind, - OnyxToken* location, char* func_name, OnyxError* error) { +TypeMatch check_arguments_against_type(Arguments* args, TypeFunction* func_type, VarArgKind* va_kind, + OnyxToken* location, char* func_name, OnyxError* error) { b32 permanent = location != NULL; if (func_name == NULL) func_name = "UNKNOWN FUNCTION"; @@ -821,7 +787,9 @@ b32 check_arguments_against_type(Arguments* args, TypeFunction* func_type, VarAr if (arg_pos >= (u32) bh_arr_length(arg_arr)) goto type_checking_done; assert(arg_arr[arg_pos]->kind == Ast_Kind_Argument); - if (!unify_node_and_type_(&arg_arr[arg_pos]->value, formal_params[arg_pos], permanent)) { + TypeMatch tm = unify_node_and_type_(&arg_arr[arg_pos]->value, formal_params[arg_pos], permanent); + if (tm == TYPE_MATCH_YIELD) return tm; + if (tm == TYPE_MATCH_FAILED) { if (error != NULL) { error->pos = arg_arr[arg_pos]->token->pos, error->text = bh_aprintf(global_heap_allocator, @@ -832,7 +800,7 @@ b32 check_arguments_against_type(Arguments* args, TypeFunction* func_type, VarAr bh_num_suffix(arg_pos + 1), node_get_type_name(arg_arr[arg_pos]->value)); } - return 0; + return tm; } if (arg_arr[arg_pos]->value->type && arg_arr[arg_pos]->value->type->id != any_type_id && formal_params[arg_pos]->id == any_type_id) { @@ -856,7 +824,7 @@ b32 check_arguments_against_type(Arguments* args, TypeFunction* func_type, VarAr error->pos = arg_arr[arg_pos]->token->pos; error->text = "Unable to resolve type of argument."; } - return 0; + return TYPE_MATCH_FAILED; } arg_arr[arg_pos]->va_kind = VA_Kind_Any; @@ -866,7 +834,9 @@ b32 check_arguments_against_type(Arguments* args, TypeFunction* func_type, VarAr *va_kind = VA_Kind_Typed; assert(arg_arr[arg_pos]->kind == Ast_Kind_Argument); - if (!unify_node_and_type_(&arg_arr[arg_pos]->value, variadic_type, permanent)) { + TypeMatch tm = unify_node_and_type_(&arg_arr[arg_pos]->value, variadic_type, permanent); + if (tm == TYPE_MATCH_YIELD) return tm; + if (tm == TYPE_MATCH_FAILED) { if (error != NULL) { error->pos = arg_arr[arg_pos]->token->pos, error->text = bh_aprintf(global_heap_allocator, @@ -875,7 +845,7 @@ b32 check_arguments_against_type(Arguments* args, TypeFunction* func_type, VarAr type_get_name(variadic_type), node_get_type_name(arg_arr[arg_pos]->value)); } - return 0; + return tm; } arg_arr[arg_pos]->va_kind = VA_Kind_Typed; @@ -894,7 +864,7 @@ b32 check_arguments_against_type(Arguments* args, TypeFunction* func_type, VarAr error->pos = arg_arr[arg_pos]->token->pos; error->text = "Unable to resolve type for argument."; } - return 0; + return TYPE_MATCH_FAILED; } arg_arr[arg_pos]->va_kind = VA_Kind_Untyped; @@ -911,7 +881,7 @@ type_checking_done: error->pos = location->pos; error->text = "Too few arguments to function call."; } - return 0; + return TYPE_MATCH_FAILED; } if (arg_pos < (u32) arg_count) { @@ -919,10 +889,10 @@ type_checking_done: error->pos = location->pos; error->text = bh_aprintf(global_heap_allocator, "Too many arguments to function call. %d %d", arg_pos, arg_count); } - return 0; + return TYPE_MATCH_FAILED; } - return 1; + return TYPE_MATCH_SUCCESS; } -- 2.25.1