polymorphism is even more powerful now!
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Mon, 15 Nov 2021 02:04:57 +0000 (20:04 -0600)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Mon, 15 Nov 2021 02:04:57 +0000 (20:04 -0600)
include/astnodes.h
src/checker.c
src/polymorph.c
src/symres.c
tests/lazy_iterators
tests/lazy_iterators.onyx

index 097c97400016031289f9a8d66ea94dd8d7f19f84..277a01866b7f20217398355953cf855cd4a93a85 100644 (file)
@@ -809,11 +809,21 @@ struct AstType { AstType_base; };
 
 struct AstBasicType     { AstType_base; Type* basic_type; };
 struct AstPointerType   { AstType_base; AstType* elem; };
-struct AstFunctionType  { AstType_base; AstType* return_type; u64 param_count; AstType* params[]; };
 struct AstArrayType     { AstType_base; AstType* elem; AstTyped *count_expr; };
 struct AstSliceType     { AstType_base; AstType* elem; };
 struct AstDynArrType    { AstType_base; AstType* elem; };
 struct AstVarArgType    { AstType_base; AstType* elem; };
+struct AstFunctionType  {
+    AstType_base;
+
+    // Used in a rare case in solve_for_polymorphic_param_type.
+    Type *partial_function_type;
+
+    AstType* return_type;
+
+    u64 param_count;
+    AstType* params[];
+};
 struct AstStructType {
     AstType_base;
     char *name;
@@ -1512,6 +1522,7 @@ typedef enum TypeMatch {
     TYPE_MATCH_SUCCESS,
     TYPE_MATCH_FAILED,
     TYPE_MATCH_YIELD,
+    TYPE_MATCH_SPECIAL, // Only used for nest polymorph function lookups
 } TypeMatch;
 #define unify_node_and_type(node, type) (unify_node_and_type_((node), (type), 1))
 TypeMatch unify_node_and_type_(AstTyped** pnode, Type* type, b32 permanent);
index 8225cba526823c8e3f9f7aacd89edd8196910183..bb586666f7b93a457c7b9df2456b7b3bc46f465a 100644 (file)
@@ -2609,9 +2609,12 @@ CheckStatus check_polyquery(AstPolyQuery *query) {
             case TYPE_MATCH_SUCCESS:
                 goto poly_var_solved;
 
+            case TYPE_MATCH_SPECIAL:
+                return Check_Yield_Macro;
+
             case TYPE_MATCH_YIELD:
             case TYPE_MATCH_FAILED: {
-                if (query->successful_symres) continue;
+                if (query->successful_symres || solved_something) continue;
 
                 if (query->error_on_fail || context.cycle_detected) {
                     onyx_report_error(query->token->pos, "Error solving for polymorphic variable '%b'.", param->poly_sym->token->text, param->poly_sym->token->length);
@@ -2699,12 +2702,14 @@ void check_entity(Entity* ent) {
         default: break;
     }
 
-    if (cs == Check_Success)          ent->state = Entity_State_Code_Gen;
-    if (cs == Check_Complete)         ent->state = Entity_State_Finalized;
-    if (cs == Check_Return_To_Symres) ent->state = Entity_State_Resolve_Symbols;
-    if (cs == Check_Failed)           ent->state = Entity_State_Failed;
-    if (cs == Check_Yield_Macro)      ent->macro_attempts++;
-    else {
+    switch (cs) {
+        case Check_Yield_Macro:      ent->macro_attempts++; break;
+        case Check_Success:          ent->state = Entity_State_Code_Gen;        goto clear_attempts;
+        case Check_Complete:         ent->state = Entity_State_Finalized;       goto clear_attempts;
+        case Check_Return_To_Symres: ent->state = Entity_State_Resolve_Symbols; goto clear_attempts;
+        case Check_Failed:           ent->state = Entity_State_Failed;          goto clear_attempts;
+
+    clear_attempts:
         ent->macro_attempts = 0;
         ent->micro_attempts = 0;
     }
index eaa38e6c58118ed06c0e9174ce1c75341fbce99e..51f6da592f0f7b87195d133a2ab208503e649513 100644 (file)
@@ -9,6 +9,11 @@
 // checker ever gets multi-threaded, this would have to become a threadlocal variable.
 static b32 flag_to_yield = 0;
 
+// This flag is used in the very special case that you are passing a polymorphic procedure
+// to a polymorphic procedure, and you have enough information to instantiate said procedure
+// in order to resolve the type of one of the return values.
+static b32 doing_nested_polymorph_lookup = 0;
+
 // The name is pretty self-descriptive, but this is a node that is returned from things
 // like polymorphic_proc_lookup when it is determined that everything works so far, but
 // the caller must yield in order to finish checking this polymorphic procedure.
@@ -413,6 +418,28 @@ static AstTyped* lookup_param_in_arguments(AstFunction* func, AstPolyParam* para
     return NULL;
 }
 
+static AstTyped* try_lookup_based_on_partial_function_type(AstPolyProc *pp, AstFunctionType *ft) {
+    if (ft->partial_function_type == NULL) {
+        AstType *old_return_type = ft->return_type;
+        ft->return_type = (AstType *) &basic_type_void;
+        ft->partial_function_type = type_build_from_ast(context.ast_alloc, (AstType *) ft);
+        assert(ft->partial_function_type);
+        ft->return_type = old_return_type;
+    }
+
+    AstTyped *result = (AstTyped *) polymorphic_proc_lookup(pp, PPLM_By_Function_Type, ft->partial_function_type, pp->token);
+    if (result && result->type == NULL) {
+        doing_nested_polymorph_lookup = 1;
+        result = NULL;
+    }
+    if (result == &node_that_signals_a_yield) {
+        doing_nested_polymorph_lookup = 1;
+        result = NULL;
+    }
+
+    return result;
+}
+
 // NOTE: The job of this function is to solve for type of AstPolySolution using the provided
 // information. It is asssumed that the "param" is of kind PPK_Poly_Type. This function uses
 // either the arguments provided, or a function type to compare against to pattern match for
@@ -427,6 +454,30 @@ static void solve_for_polymorphic_param_type(PolySolveResult* resolved, AstFunct
             AstTyped* typed_param = lookup_param_in_arguments(func, param, args, err_msg);
             if (typed_param == NULL) return;
 
+            // CLEANUP FIXME HACK TODO GROSS
+            if (typed_param->kind == Ast_Kind_Argument) {
+                AstTyped* potential = ((AstArgument *) typed_param)->value;
+                if (potential->kind == Ast_Kind_Polymorphic_Proc) {
+                    if (param->idx < (u32) bh_arr_length(func->params)) {
+                        AstType *param_type = func->params[param->idx].local->type_node;
+                        if (param_type->kind == Ast_Kind_Function_Type) {
+                            AstFunctionType *ft = (AstFunctionType *) param_type;
+                            b32 all_types = 1;
+                            fori (i, 0, (i32) ft->param_count) {
+                                if (!node_is_type((AstNode *) ft->params[i])) {
+                                    all_types = 0;
+                                    break;
+                                }
+                            }
+
+                            if (all_types) {
+                                typed_param = try_lookup_based_on_partial_function_type((AstPolyProc *) potential, ft);
+                            }
+                        }
+                    }
+                }
+            }
+
             actual_type = resolve_expression_type(typed_param);
             if (actual_type == NULL) return;
 
@@ -475,6 +526,7 @@ static void solve_for_polymorphic_param_value(PolySolveResult* resolved, AstFunc
         value = ((AstArgument *) value)->value;
     }
 
+    Type*    param_type = NULL;
     AstType *param_type_expr = func->params[param->idx].local->type_node;
     if (param_type_expr == (AstType *) &basic_type_type_expr) {
         if (!node_is_type((AstNode *) value)) {
@@ -495,10 +547,8 @@ static void solve_for_polymorphic_param_value(PolySolveResult* resolved, AstFunc
             return;
         }
 
-        if (param->type == NULL)
-            param->type = type_build_from_ast(context.ast_alloc, param_type_expr);
-
-        if (param->type == NULL) {
+        param_type = type_build_from_ast(context.ast_alloc, param_type_expr);
+        if (param_type == NULL) {
             flag_to_yield = 1;
             *err_msg = "Waiting to know type for polymorphic value.";
             return;
@@ -509,12 +559,12 @@ static void solve_for_polymorphic_param_value(PolySolveResult* resolved, AstFunc
             value_to_use = (AstTyped *) get_function_from_node((AstNode *) value);
         }
 
-        TypeMatch tm = 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(func),
-                    type_get_name(param->type),
+                    type_get_name(param_type),
                     param->idx + 1,
                     bh_num_suffix(param->idx + 1),
                     node_get_type_name(value_to_use));
@@ -541,6 +591,11 @@ TypeMatch find_polymorphic_sln(AstPolySolution *out, AstPolyParam *param, AstFun
         default: if (err_msg) *err_msg = "Invalid polymorphic parameter kind. This is a compiler bug.";
     }
 
+    if (doing_nested_polymorph_lookup) {
+        doing_nested_polymorph_lookup = 0;
+        return TYPE_MATCH_SPECIAL;
+    }
+
     if (flag_to_yield) {
         flag_to_yield = 0;
         return TYPE_MATCH_YIELD;
@@ -627,7 +682,6 @@ 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;
         }
 
index a96a0237bb1a66795af295d22ccdf763adcfe26a..85690d2e829ac7479f9c3a64ac2b3cecd323be38 100644 (file)
@@ -181,13 +181,13 @@ static SymresStatus symres_type(AstType** type) {
         case Ast_Kind_Function_Type: {
             AstFunctionType* ftype = (AstFunctionType *) *type;
 
-            SYMRES(type, &ftype->return_type);
-
             if (ftype->param_count > 0) {
                 fori (i, 0, (i64) ftype->param_count) {
                     SYMRES(type, &ftype->params[i]);
                 }
             }
+
+            SYMRES(type, &ftype->return_type);
             break;
         }
 
index 47af0b1f14d77762a67229b029b2b0eb2887d97d..2c7ab48d001adb3abcb124139d15df6892071d52 100644 (file)
@@ -1,3 +1,9 @@
+Closing the count iterator...
+54
+56
+58
+60
+62
 Starting the iteration...
 54
 56
index 98d08cc3920078c55f086fc8bb4257c07e544be7..700bf1b5a9e84a571edb6153f558bce876add716 100644 (file)
@@ -36,7 +36,6 @@ count_iterator :: (lo: i32, hi: i32, step := 1) -> Iterator(i32) {
 
 main :: (args: [] cstr) {
     // Hopefully soon, the following will be possible.
-/*
     quick_iterator :=
                 count_iterator(1, 10)
                 |> iter.map((x) => x * 2)
@@ -48,7 +47,6 @@ main :: (args: [] cstr) {
     for v: quick_iterator {
         println(v);
     }
-*/
 
     iterator := count_iterator(1, 10)
                 |> iter.map((x: i32) -> i32     { return x * 2; })