code cleanup in cloner and checker. proper cycle detection again
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Thu, 26 Aug 2021 14:50:11 +0000 (09:50 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Thu, 26 Aug 2021 14:50:11 +0000 (09:50 -0500)
14 files changed:
bin/onyx
core/alloc/heap.onyx
core/container/array.onyx
core/container/iter.onyx
core/io/reader.onyx
core/math.onyx
core/string.onyx
core/string/reader.onyx
docs/bugs
src/onyx.c
src/onyxchecker.c
src/onyxclone.c
src/onyxparser.c
src/onyxsymres.c

index 4c0e4e12d2606c9c3ad36d494ee7a2153cedf581..daf84b19fb9b26b1f329d2d04049e4d887bcd0ab 100755 (executable)
Binary files a/bin/onyx and b/bin/onyx differ
index e76ad66bb5d77529572f2774c24c7987b8ed49ed..33722d0b4be7abba2eaf465d1b1aff26550e14b0 100644 (file)
@@ -232,3 +232,5 @@ init :: () {
     heap_allocator.data = ^heap_state;
     heap_allocator.func = heap_alloc_proc;
 }
+
+get_watermark :: () => cast(u32) heap_state.next_alloc;
\ No newline at end of file
index 16eb82ed4262f6a5f901b5c9a7e145c9c5336c6f..88e5180de88e4f1ded62b04c0b142bd2102c252c 100644 (file)
@@ -389,15 +389,19 @@ first :: #match {
 }
 
 count_where :: #match {
-    (arr: ^[..] $T, predicate: (T) -> bool) -> u32 {
+    (arr: ^[..] $T, predicate: $Pred) -> u32 {
+        return count_where((#type [] T).{ arr.data, arr.count }, predicate);
+    },
+
+    (arr: [] $T, predicate: (T) -> bool) -> u32 {
         count: u32 = 0;
-        for ^it: *arr do if predicate(*it) do count += 1;
+        for ^it: arr do if predicate(*it) do count += 1;
         return count;
     },
 
-    (arr: ^[..] $T, predicate: (^T) -> bool) -> u32 {
+    (arr: [] $T, predicate: (^T) -> bool) -> u32 {
         count: u32 = 0;
-        for ^it: *arr do if predicate(it) do count += 1;
+        for ^it: arr do if predicate(it) do count += 1;
         return count;
     },
 }
index 8f4c8e699738fded0afe5d65bd43833e67a87034..97217cb28ce297914eb2d7f3baab0addca19d7a9 100644 (file)
@@ -67,6 +67,12 @@ map :: (it: Iterator($T), transform: (T) -> $R) -> Iterator(R) {
     };
 }
 
+take_one :: (it: Iterator($T)) -> (T, bool) {
+    ret, cont := it.next(it.data);
+    if !cont do it.close(it.data);
+    return ret, cont;
+}
+
 take :: (it: Iterator($T), count: u32) -> Iterator(T) {
     TakeIterator :: struct (T: type_expr) {
         iterator:  Iterator(T);
index bfacd02f647adeefb3db0229caddfe84ee51640e..bbb13f43254d7017b8c0361c2a81e8d7d7bd1b57 100644 (file)
@@ -22,6 +22,10 @@ reader_from_string :: (s: str) -> (Reader, ^StringStream) {
     return Reader.{ stream_ptr }, stream_ptr;
 }
 
+reader_empty :: (use reader: ^Reader) -> bool {
+    return stream_end_of_file(stream);
+}
+
 read_byte :: (use reader: ^Reader) -> u8 {
     err, byte := stream_read_byte(stream);
     return byte;
@@ -40,6 +44,60 @@ read_bytes :: #match {
     }
 }
 
+read_i32 :: (use reader: ^Reader) -> i32 {
+    n: i32 = 0;
+
+    skip_whitespace(reader);
+
+    is_negative := false;
+    err, curr := stream_peek_byte(stream);
+    if curr == #char "-" {
+        is_negative = true;
+        err, curr = stream_read_byte(stream);
+        err, curr = stream_peek_byte(stream);
+    }
+
+    while curr >= #char "0" && curr <= #char "9" {
+        err, curr = stream_read_byte(stream);
+
+        n *= 10;
+        n += cast(u32) (curr - #char "0"); 
+
+        err, curr = stream_peek_byte(stream);
+        if err == Error.EOF do break;
+    }
+
+    if is_negative do n = -n;
+    return n;
+}
+
+read_i64 :: (use reader: ^Reader) -> i64 {
+    n: i64 = 0;
+
+    skip_whitespace(reader);
+
+    is_negative := false;
+    err, curr := stream_peek_byte(stream);
+    if curr == #char "-" {
+        is_negative = true;
+        err, curr = stream_read_byte(stream);
+        err, curr = stream_peek_byte(stream);
+    }
+
+    while curr >= #char "0" && curr <= #char "9" {
+        err, curr = stream_read_byte(stream);
+
+        n *= 10;
+        n += cast(u64) (curr - #char "0"); 
+
+        err, curr = stream_peek_byte(stream);
+        if err == Error.EOF do break;
+    }
+
+    if is_negative do n = -n;
+    return n;
+}
+
 read_u32 :: (use reader: ^Reader) -> u32 {
     n: u32 = 0;
 
index 2886c730f0b6ad5f773dc55855d7149289da3284..5396f70dfd8ba5a35d2e2b880a245cfdb4fd8d8b 100644 (file)
@@ -197,6 +197,22 @@ pow :: #match {
     }
 }
 
+power_mod :: (base: u32, exp: u32, mod: u32) -> u32 {
+    t: u64 = 1;
+    e: u64 = ~~exp;
+    b: u64 = ~~base;
+    m: u64 = ~~mod;
+
+    while e > 0 {
+        if e % 2 != 0 do t = (t * b) % m;
+
+        b = (b * b) % m;
+        e /= 2;
+    }
+
+    return ~~(t % m);
+}
+
 ln :: (a: f32) -> f32 {
     // FIX: This is probably not the most numerically stable solution.
     if a < 1 {
index 4cafb683fce804a9a61f200fe59e8da5ee0de8df..b5d011bc6d39b4b3fb4f11344ac1fa29cd4d4ddc 100644 (file)
@@ -169,6 +169,11 @@ ends_with :: (s: str, suffix: str) -> bool {
     return true;
 }
 
+strip_whitespace :: #match {
+    (s: ^str) { strip_leading_whitespace(s); strip_trailing_whitespace(s); },
+    (s:  str) { strip_leading_whitespace(s); strip_trailing_whitespace(s); },
+}
+
 strip_leading_whitespace :: #match {
     (s: ^str) {
         while true do switch s.data[0] {
index 0cea068a18370f6769e8a5330e93dd7188372ba5..503c9d60ce661597bba9f890803bbecd2ca5e5d1 100644 (file)
@@ -71,6 +71,8 @@ read_byte :: (use reader: ^String_Reader) -> u8 {
     return data[0];
 }
 
+peek_byte :: (use reader: ^String_Reader) -> u8 do return data[0];
+
 read_bytes :: (use reader: ^String_Reader, byte_count := 1) -> str {
     bc := byte_count;
     if count < bc do bc = count;
@@ -131,13 +133,14 @@ read_until :: (use reader: ^String_Reader, skip: u32, uptos: ..u8) -> str {
 }
 
 // Reads a continuous string of alphabetic chars along with underscores '_'
-read_word :: (use reader: ^String_Reader) -> str {
+read_word :: (use reader: ^String_Reader, numeric_allowed := false) -> str {
     if count == 0 do return str.{ null, 0 };
 
     out := str.{ data, 0 };
     for ch: *(cast(^str) reader) {
         if     (ch >= #char "a" && ch <= #char "z")
             || (ch >= #char "A" && ch <= #char "Z")
+            || (numeric_allowed && (ch >= #char "0" && ch <= #char "9"))
             || ch == #char "_" {
             out.count += 1;            
         }
index d3d19cde48b94fe80050c57e61c068f96559e8e6..d78b982472fe77b1b38593708359720457b2ca5e 100644 (file)
--- a/docs/bugs
+++ b/docs/bugs
@@ -1,5 +1,13 @@
 List of known bugs:
 
+[ ] macros are not allowed at the expression level. This is not necessarily a bug, but does
+    bring many complications to the table about how resolve this.
+
+[ ] recursive quick-procedures / procedures that use #auto have trouble if the first lexical
+    return statement is a recursive call.
+
+[X] There is not proper cycle detection in the compiler. Infinite should not be possible.
+
 [ ] Compound assignment operators such as += evaluate the location of their left-value twice.
     Not only is this bad for efficiency, if the value requires calling a function, that
     function will be called twice instead of once. This is a simple code generation fix,
index ec2d87fa758475c38ad16eb2b05e1cc35d61c62b..75d7797baa566c381319aa96ad660a14f822d1ce 100644 (file)
@@ -403,6 +403,23 @@ static void output_dummy_progress_bar() {
 }
 #endif
 
+static void dump_cycles() {
+    context.cycle_detected = 1;
+    Entity* ent;
+
+    onyx_report_error((OnyxFilePos) { 0 }, "Cycle detected. Dumping all stuck processing units.");
+
+    while (1) {
+        ent = entity_heap_top(&context.entities);
+        entity_heap_remove_top(&context.entities);
+        if (ent->state < Entity_State_Code_Gen) process_entity(ent);
+
+        if (bh_arr_length(context.entities.entities) == 0) {
+            break;
+        }
+    }
+}
+
 static i32 onyx_compile() {
     u64 start_time = bh_time_curr();
 
@@ -440,12 +457,20 @@ static i32 onyx_compile() {
         // before the "key" node that will unblock the progress. This means a more sophisticated
         // cycle detection algorithm must be used.
         //
-        static Entity* first_no_change = NULL;
+        static Entity* watermarked_node = NULL;
         if (!changed) {
-            if (!first_no_change) first_no_change = ent;
-            else if (first_no_change == ent) context.cycle_detected = 1;
+            if (!watermarked_node) {
+                watermarked_node = ent;
+            }
+            else if (watermarked_node == ent) {
+                entity_heap_insert_existing(&context.entities, ent);
+                dump_cycles();
+            }
+            else if (watermarked_node->macro_attempts < ent->macro_attempts) {
+                watermarked_node = ent;
+            }
         } else {
-            first_no_change = NULL;
+            watermarked_node = NULL;
         }
 
         if (onyx_has_errors()) return ONYX_COMPILER_PROGRESS_ERROR;
index 945d25b90ef8fa1ad520da05f3c93bb5576a0c53..e4c99dd38c0d0fa5062e507385cae1067ef768ad 100644 (file)
     if (cs > Check_Errors_Start) return cs; \
     } while (0)
 
+#define YIELD(loc, msg) do { \
+    if (context.cycle_detected) { \
+        onyx_report_error(loc, msg); \
+        return Check_Error; \
+    } else { \
+        return Check_Yield_Macro; \
+    } \
+    } while (0)
+
+#define YIELD_(loc, msg, ...) do { \
+    if (context.cycle_detected) { \
+        onyx_report_error(loc, msg, __VA_ARGS__); \
+        return Check_Error; \
+    } else { \
+        return Check_Yield_Macro; \
+    } \
+    } while (0)
+
 typedef enum CheckStatus {
     Check_Success,  // The node was successfully checked with out errors
     Check_Complete, // The node is done processing
@@ -116,7 +134,8 @@ CheckStatus check_return(AstReturn* retnode) {
 
         if (*expected_return_type == &type_auto_return) {
             resolve_expression_type(retnode->expr);
-            if (retnode->expr->type == NULL) return Check_Yield_Macro;
+            if (retnode->expr->type == NULL)
+                YIELD(retnode->token->pos, "Trying to determine automatic return type.");
 
             *expected_return_type = retnode->expr->type;
             return Check_Success;
@@ -152,7 +171,7 @@ CheckStatus check_if(AstIfWhile* ifnode) {
 
     if (ifnode->kind == Ast_Kind_Static_If) {
         if ((ifnode->flags & Ast_Flag_Static_If_Resolved) == 0) {
-            return Check_Yield_Macro;
+            YIELD(ifnode->token->pos, "Waiting for static if to be resolved.");
         }
 
         if (static_if_resolution(ifnode)) {
@@ -442,7 +461,7 @@ static CheckStatus check_resolve_callee(AstCall* call, AstTyped** effective_call
                 return Check_Error;
 
             } else {
-                return Check_Yield_Macro;
+                YIELD(call->token->pos, "Waiting for overloaded function option to pass type-checking.");
             }
         }
 
@@ -459,16 +478,20 @@ static CheckStatus check_resolve_callee(AstCall* call, AstTyped** effective_call
         call->callee = callee;
 
         AstTyped* new_callee = (AstTyped *) macro_resolve_header((AstMacro *) callee, &call->args, call->token);
-        if (new_callee == (AstTyped *) &node_that_signals_a_yield) return Check_Yield_Macro;
         if (new_callee == NULL) return Check_Error;
+        if (new_callee == (AstTyped *) &node_that_signals_a_yield) {
+            YIELD(call->token->pos, "Waiting for macro header to pass type-checking.");
+        }
 
         arguments_remove_baked(&call->args);
         callee = new_callee;
 
     } else if (callee->kind == Ast_Kind_Polymorphic_Proc) {
         AstTyped* new_callee = (AstTyped *) polymorphic_proc_lookup((AstPolyProc *) callee, PPLM_By_Arguments, &call->args, call->token);
-        if (new_callee == (AstTyped *) &node_that_signals_a_yield) return Check_Yield_Macro;
         if (new_callee == NULL) return Check_Error;
+        if (new_callee == (AstTyped *) &node_that_signals_a_yield) {
+            YIELD(call->token->pos, "Waiting for polymorphic procedure header to pass type-checking.");
+        }
 
         arguments_remove_baked(&call->args);
         callee = new_callee;
@@ -478,7 +501,9 @@ static CheckStatus check_resolve_callee(AstCall* call, AstTyped** effective_call
 
     // NOTE: Build callee's type
     fill_in_type((AstTyped *) callee);
-    if (callee->type == NULL) return Check_Yield_Macro;
+    if (callee->type == NULL) {
+        YIELD(call->token->pos, "Trying to resolve function type for callee.");
+    }
 
     if (callee->type->kind != Type_Kind_Function) {
         onyx_report_error(call->token->pos,
@@ -608,7 +633,9 @@ CheckStatus check_call(AstCall** pcall) {
 
     call->va_kind = VA_Kind_Not_VA;
     call->type = callee->type->Function.return_type;
-    if (call->type == &type_auto_return) return Check_Yield_Macro;
+    if (call->type == &type_auto_return) {
+        YIELD(call->token->pos, "Waiting for auto-return type to be solved.");
+    }
 
     Type **formal_params = callee->type->Function.params;
 
@@ -766,7 +793,7 @@ CheckStatus check_binaryop_assignment(AstBinaryOp* binop) {
                     return Check_Error;
 
                 } else {
-                    return Check_Yield_Macro;
+                    YIELD(binop->token->pos, "Trying to resolve try of right hand side.");
                 }
             }
 
@@ -824,7 +851,7 @@ CheckStatus check_binaryop_assignment(AstBinaryOp* binop) {
 
     if (binop->right->type == NULL) {
         if (binop->right->entity != NULL && binop->right->entity->state <= Entity_State_Check_Types) {
-            return Check_Yield_Macro;
+            YIELD(binop->token->pos, "Trying to resolve type of right hand side.");
         }
     }
 
@@ -1026,7 +1053,7 @@ CheckStatus check_binaryop(AstBinaryOp** pbinop) {
         AstCall *implicit_call = binaryop_try_operator_overload(binop);
 
         if (implicit_call == (AstCall *) &node_that_signals_a_yield)
-            return Check_Yield_Macro;
+            YIELD(binop->token->pos, "Trying to resolve operator overload.");
 
         if (implicit_call != NULL) {
             // NOTE: Not a binary op
@@ -1125,7 +1152,8 @@ CheckStatus check_unaryop(AstUnaryOp** punop) {
 
     if (unaryop->operation == Unary_Op_Cast) {
         char* err;
-        if (unaryop->type == NULL) return Check_Yield_Macro;
+        if (unaryop->type == NULL)
+            YIELD(unaryop->token->pos, "Trying to resolve destination type for cast.");
 
         if (!cast_is_legal(unaryop->expr->type, unaryop->type, &err)) {
             onyx_report_error(unaryop->token->pos, "Cast Error: %s", err);
@@ -1176,7 +1204,8 @@ CheckStatus check_struct_literal(AstStructLiteral* sl) {
         }
 
         fill_in_type((AstTyped *) sl);
-        if (sl->type == NULL) return Check_Yield_Macro;
+        if (sl->type == NULL)
+            YIELD(sl->token->pos, "Trying to resolve type of struct literal.");
     }
 
     if (!type_is_structlike_strict(sl->type)) {
@@ -1222,21 +1251,21 @@ CheckStatus check_struct_literal(AstStructLiteral* sl) {
     sl->flags |= Ast_Flag_Comptime;
 
     fori (i, 0, mem_count) {
+        // NOTE: Not checking the return on this function because
+        // this for loop is bounded by the number of members in the
+        // type.
+        type_lookup_member_by_idx(sl->type, i, &smem);
+        Type* formal = smem.type;
+
         CHECK(expression, actual);
 
         // HACK HACK HACK
         if ((*actual)->type == NULL &&
             (*actual)->entity != NULL &&
             (*actual)->entity->state <= Entity_State_Check_Types) {
-            return Check_Yield_Macro;
+            YIELD_((*actual)->token->pos, "Trying to resolve type of expression for member '%s'.", smem.name);
         }
 
-        // NOTE: Not checking the return on this function because
-        // this for loop is bounded by the number of members in the
-        // type.
-        type_lookup_member_by_idx(sl->type, i, &smem);
-        Type* formal = smem.type;
-
         if (!type_check_or_auto_cast(actual, formal)) {
             onyx_report_error(sl->token->pos,
                     "Mismatched types for %d%s member named '%s', expected '%s', got '%s'.",
@@ -1265,7 +1294,8 @@ CheckStatus check_array_literal(AstArrayLiteral* al) {
         }
 
         fill_in_type((AstTyped *) al);
-        if (al->type == NULL) return Check_Yield_Macro;
+        if (al->type == NULL)
+            YIELD(al->token->pos, "Trying to resolve type of array literal.");
 
         al->type = type_make_array(context.ast_alloc, al->type, bh_arr_length(al->values));
         if (al->type == NULL || al->type->kind != Type_Kind_Array) {
@@ -1292,7 +1322,7 @@ CheckStatus check_array_literal(AstArrayLiteral* al) {
         if ((*expr)->type == NULL &&
             (*expr)->entity != NULL &&
             (*expr)->entity->state <= Entity_State_Check_Types) {
-            return Check_Yield_Macro;
+            YIELD_(al->token->pos, "Trying to resolve type of %d%s element of array literal.", expr - al->values, bh_num_suffix(expr - al->values));
         }
 
         al->flags &= ((*expr)->flags & Ast_Flag_Comptime) | (al->flags &~ Ast_Flag_Comptime);
@@ -1377,7 +1407,7 @@ CheckStatus check_if_expression(AstIfExpression* if_expr) {
 CheckStatus check_address_of(AstAddressOf* aof) {
     CHECK(expression, &aof->expr);
     if (aof->expr->type == NULL) {
-        return Check_Yield_Macro;
+        YIELD(aof->token->pos, "Trying to resolve type of expression to take a reference.");
     }
 
     if ((aof->expr->kind != Ast_Kind_Subscript
@@ -1428,7 +1458,7 @@ CheckStatus check_subscript(AstSubscript** psub) {
         AstCall *implicit_call = binaryop_try_operator_overload(binop);
 
         if (implicit_call == (AstCall *) &node_that_signals_a_yield)
-            return Check_Yield_Macro;
+            YIELD(sub->token->pos, "Trying to resolve operator overload.");
 
         if (implicit_call != NULL) {
             // NOTE: Not an array access
@@ -1510,7 +1540,7 @@ CheckStatus check_field_access(AstFieldAccess** pfield) {
     CHECK(expression, &field->expr);
     if (field->expr->type == NULL) {
         // onyx_report_error(field->token->pos, "Unable to deduce type of expression for accessing field.");
-        return Check_Yield_Macro;
+        YIELD(field->token->pos, "Trying to resolve type of source expression.");
     }
 
     if (!type_is_structlike(field->expr->type)) {
@@ -1562,7 +1592,7 @@ CheckStatus check_field_access(AstFieldAccess** pfield) {
 CheckStatus check_method_call(AstBinaryOp** mcall) {
     CHECK(expression, &(*mcall)->left);
     if ((*mcall)->left->type == NULL) {
-        return Check_Yield_Macro;
+        YIELD((*mcall)->token->pos, "Trying to resolve type of left hand side.");
     }
 
     AstTyped* implicit_argument = (*mcall)->left;
@@ -1598,7 +1628,8 @@ CheckStatus check_size_of(AstSizeOf* so) {
     CHECK(type, so->so_ast_type);
 
     so->so_type = type_build_from_ast(context.ast_alloc, so->so_ast_type);
-    if (so->so_type == NULL) return Check_Yield_Macro;
+    if (so->so_type == NULL)
+        YIELD(so->token->pos, "Trying to resolve type to take the size of.");
 
     so->size = type_size_of(so->so_type);
 
@@ -1610,7 +1641,8 @@ CheckStatus check_align_of(AstAlignOf* ao) {
     CHECK(type, ao->ao_ast_type);
 
     ao->ao_type = type_build_from_ast(context.ast_alloc, ao->ao_ast_type);
-    if (ao->ao_type == NULL) return Check_Yield_Macro;
+    if (ao->ao_type == NULL)
+        YIELD(ao->token->pos, "Trying to resolve type to take the alignment of.");
 
     ao->alignment = type_alignment_of(ao->ao_type);
 
@@ -1628,7 +1660,7 @@ CheckStatus check_expression(AstTyped** pexpr) {
         }
 
         if (type_build_from_ast(context.ast_alloc, (AstType*) expr) == NULL) {
-            return Check_Yield_Macro;
+            YIELD(expr->token->pos, "Trying to construct type.");
         }
 
         expr->type = &basic_types[Basic_Kind_Type_Index];
@@ -1714,7 +1746,8 @@ CheckStatus check_expression(AstTyped** pexpr) {
             //         break;
             //     }
             // }
-            if (expr->type == NULL) return Check_Yield_Macro;
+            if (expr->type == NULL)
+                YIELD(expr->token->pos, "Waiting for function type to be resolved.");
 
             expr->flags |= Ast_Flag_Function_Used;
             break;
@@ -1804,7 +1837,8 @@ CheckStatus check_insert_directive(AstDirectiveInsert** pinsert) {
             return Check_Error;
         }
 
-        return Check_Yield_Macro;
+        // Bad wording for the message.
+        YIELD(insert->token->pos, "Waiting for resolution to code expression type.");
     }
 
     Type* code_type = type_build_from_ast(context.ast_alloc, builtin_code_type);
@@ -1874,8 +1908,8 @@ CheckStatus check_statement(AstNode** pstmt) {
                     onyx_report_error(stmt->token->pos, "Local's type is not a type.");
                     return Check_Error;
                 }
-                
-                return Check_Yield_Macro;
+
+                YIELD(typed_stmt->token->pos, "Waiting for local variable's type.");
             }
             return Check_Success;
         }
@@ -1926,7 +1960,8 @@ CheckStatus check_block(AstBlock* block) {
 
 CheckStatus check_function(AstFunction* func) {
     if (func->flags & Ast_Flag_Already_Checked) return Check_Success;
-    if (func->entity_header && func->entity_header->state < Entity_State_Code_Gen) return Check_Yield_Macro;
+    if (func->entity_header && func->entity_header->state < Entity_State_Code_Gen)
+        YIELD(func->token->pos, "Waiting for procedure header to pass type-checking");
     
     expected_return_type = &func->type->Function.return_type;
     if (func->body) {
@@ -1978,11 +2013,12 @@ CheckStatus check_overloaded_function(AstOverloadedFunction* func) {
     bh_imap_free(&all_overloads);
 
     if (done) return Check_Success;
-    else      return Check_Yield_Macro;
+    else      YIELD(func->token->pos, "Waiting for all options to pass type-checking.");
 }
 
 CheckStatus check_struct(AstStructType* s_node) {
-    if (s_node->entity_defaults && s_node->entity_defaults->state < Entity_State_Check_Types) return Check_Yield_Macro;
+    if (s_node->entity_defaults && s_node->entity_defaults->state < Entity_State_Check_Types)
+        YIELD(s_node->token->pos, "Waiting for struct member definitions to pass symbol resolution.");
 
     bh_arr_each(AstStructMember *, smem, s_node->members) {
         if ((*smem)->type_node != NULL) {
@@ -1993,7 +2029,8 @@ CheckStatus check_struct(AstStructType* s_node) {
             CHECK(expression, &(*smem)->initial_value);
 
             fill_in_type((*smem)->initial_value);
-            if ((*smem)->initial_value->type == NULL) return Check_Yield_Macro;
+            if ((*smem)->initial_value->type == NULL)
+                YIELD((*smem)->initial_value->token->pos, "Trying to resolve type for initial value for member.");
 
             resolve_expression_type((*smem)->initial_value);
             if ((*smem)->type == NULL) (*smem)->type = (*smem)->initial_value->type;
@@ -2007,7 +2044,8 @@ CheckStatus check_struct(AstStructType* s_node) {
 
     // NOTE: fills in the stcache
     type_build_from_ast(context.ast_alloc, (AstType *) s_node);
-    if (s_node->stcache == NULL || !s_node->stcache_is_valid) return Check_Yield_Macro;
+    if (s_node->stcache == NULL || !s_node->stcache_is_valid)
+        YIELD(s_node->token->pos, "Waiting for type to be constructed.");
 
     bh_arr_each(StructMember *, smem, s_node->stcache->Struct.memarr) {
         if ((*smem)->type->kind == Type_Kind_Compound) {
@@ -2020,7 +2058,8 @@ CheckStatus check_struct(AstStructType* s_node) {
 }
 
 CheckStatus check_struct_defaults(AstStructType* s_node) {
-    if (s_node->entity_type && s_node->entity_type->state < Entity_State_Code_Gen) return Check_Yield_Macro;
+    if (s_node->entity_type && s_node->entity_type->state < Entity_State_Code_Gen)
+        YIELD(s_node->token->pos, "Waiting for struct type to be constructed before checking defaulted members.");
 
     bh_arr_each(StructMember *, smem, s_node->stcache->Struct.memarr) {
         if ((*smem)->initial_value && *(*smem)->initial_value) {
@@ -2042,7 +2081,8 @@ CheckStatus check_struct_defaults(AstStructType* s_node) {
 }
 
 CheckStatus check_function_header(AstFunction* func) {
-    if (func->entity_body && func->entity_body->state < Entity_State_Check_Types) return Check_Yield_Macro;
+    if (func->entity_body && func->entity_body->state < Entity_State_Check_Types)
+        YIELD(func->token->pos, "Waiting for function header to complete symbol resolution");
 
     b32 expect_default_param = 0;
     b32 has_had_varargs = 0;
@@ -2105,7 +2145,7 @@ CheckStatus check_function_header(AstFunction* func) {
             //         "Unable to resolve type for parameter, '%b'",
             //         local->token->text,
             //         local->token->length);
-            return Check_Yield_Macro;
+            YIELD(local->token->pos, "Waiting for parameter type to be known.");
         }
 
         if (local->type->kind == Type_Kind_Compound) {
@@ -2139,7 +2179,7 @@ CheckStatus check_function_header(AstFunction* func) {
     if (func->return_type != NULL) CHECK(type, func->return_type);
 
     func->type = type_build_function_type(context.ast_alloc, func);
-    if (func->type == NULL) return Check_Yield_Macro;
+    if (func->type == NULL) YIELD(func->token->pos, "Waiting for function type to be constructed");
 
     return Check_Success;
 }
@@ -2147,7 +2187,7 @@ CheckStatus check_function_header(AstFunction* func) {
 CheckStatus check_memres_type(AstMemRes* memres) {
     CHECK(type, memres->type_node);
     fill_in_type((AstTyped *) memres);
-    if (memres->type_node && !memres->type) return Check_Yield_Macro;
+    if (memres->type_node && !memres->type) YIELD(memres->token->pos, "Waiting for global type to be constructed.");
     return Check_Success;
 }
 
@@ -2173,7 +2213,7 @@ CheckStatus check_memres(AstMemRes* memres) {
 
         } else {
             if (memres->initial_value->type == NULL && memres->initial_value->entity != NULL && memres->initial_value->entity->state <= Entity_State_Check_Types) {
-                return Check_Yield_Macro;
+                YIELD(memres->token->pos, "Waiting for global type to be constructed.");
             }
             memres->type = memres->initial_value->type;
         }
@@ -2208,7 +2248,7 @@ CheckStatus check_type(AstType* type) {
             resolve_expression_type(type_of->expr);
 
             if (type_of->expr->type == NULL) {
-                return Check_Yield_Macro;
+                YIELD(type_of->token->pos, "Trying to check type for type-of expression.");
             }
 
             type_of->resolved_type = type_of->expr->type;
@@ -2288,7 +2328,8 @@ CheckStatus check_static_if(AstIf* static_if) {
 CheckStatus check_process_directive(AstNode* directive) {
     if (directive->kind == Ast_Kind_Directive_Export) {
         AstTyped* export = ((AstDirectiveExport *) directive)->export;
-        if (export->entity && export->entity->state <= Entity_State_Check_Types) return Check_Yield_Macro;
+        if (export->entity && export->entity->state <= Entity_State_Check_Types)
+            YIELD(directive->token->pos, "Waiting for export type to be known.");
     }
 
     return Check_Success;
index dbc3677350921b03a898ed9cbf5f27c7650b53cb..425a2dca8efda262b1c5af87de35421e141e342b 100644 (file)
@@ -122,6 +122,8 @@ AstNode* ast_clone_list(bh_allocator a, void* n) {
        return root;
 }
 
+#define C(nt, mname) ((nt *) nn)->mname = (void *) ast_clone(a, ((nt *) node)->mname);
+
 // NOTE: Using void* to avoid a lot of unnecessary casting
 AstNode* ast_clone(bh_allocator a, void* n) {
        AstNode* node = (AstNode *) n;
@@ -142,18 +144,18 @@ AstNode* ast_clone(bh_allocator a, void* n) {
                case Ast_Kind_Binary_Op:
         case Ast_Kind_Pipe:
         case Ast_Kind_Method_Call:
-                       ((AstBinaryOp *) nn)->left  = (AstTyped *) ast_clone(a, ((AstBinaryOp *) node)->left);
-                       ((AstBinaryOp *) nn)->right = (AstTyped *) ast_clone(a, ((AstBinaryOp *) node)->right);
+               C(AstBinaryOp, left);
+               C(AstBinaryOp, right);
                        break;
 
                case Ast_Kind_Unary_Op:
-                       ((AstUnaryOp *) nn)->expr = (AstTyped *) ast_clone(a, ((AstUnaryOp *) node)->expr);
-                       ((AstUnaryOp *) nn)->type_node = (AstType *) ast_clone(a, ((AstUnaryOp *) node)->type_node);
+                       C(AstUnaryOp, expr);
+                       C(AstUnaryOp, type_node);
                        break;
 
                case Ast_Kind_Param:
                case Ast_Kind_Local:
-                       ((AstLocal *) nn)->type_node = (AstType *) ast_clone(a, ((AstLocal *) node)->type_node);
+                       C(AstLocal, type_node);
                        break;
 
                case Ast_Kind_Call:
@@ -161,33 +163,33 @@ AstNode* ast_clone(bh_allocator a, void* n) {
                        break;
 
                case Ast_Kind_Argument:
-                       ((AstArgument *) nn)->value = (AstTyped *) ast_clone(a, ((AstArgument *) node)->value);
+                       C(AstArgument, value);
                        break;
 
                case Ast_Kind_Address_Of:
-                       ((AstAddressOf *) nn)->expr = (AstTyped *) ast_clone(a, ((AstAddressOf *) node)->expr);
+                       C(AstAddressOf, expr);
                        break;
 
                case Ast_Kind_Dereference:
-                       ((AstDereference *) nn)->expr = (AstTyped *) ast_clone(a, ((AstDereference *) node)->expr);
+                       C(AstDereference, expr);
                        break;
 
                case Ast_Kind_Slice:
                case Ast_Kind_Subscript:
-                       ((AstSubscript *) nn)->addr = (AstTyped *) ast_clone(a, ((AstSubscript *) node)->addr);
-                       ((AstSubscript *) nn)->expr = (AstTyped *) ast_clone(a, ((AstSubscript *) node)->expr);
+                       C(AstSubscript, addr);
+                       C(AstSubscript, expr);
                        break;
 
                case Ast_Kind_Field_Access:
-                       ((AstFieldAccess *) nn)->expr = (AstTyped *) ast_clone(a, ((AstFieldAccess *) node)->expr);
+                       C(AstFieldAccess, expr);
                        break;
 
                case Ast_Kind_Size_Of:
-                       ((AstSizeOf *) nn)->so_ast_type = (AstType *) ast_clone(a, ((AstSizeOf *) node)->so_ast_type);
+                       C(AstSizeOf, so_ast_type);
                        break;
 
                case Ast_Kind_Align_Of:
-                       ((AstAlignOf *) nn)->ao_ast_type = (AstType *) ast_clone(a, ((AstAlignOf *) node)->ao_ast_type);
+                       C(AstAlignOf, ao_ast_type);
                        break;
 
                case Ast_Kind_Struct_Literal: {
@@ -215,13 +217,13 @@ AstNode* ast_clone(bh_allocator a, void* n) {
                }
 
         case Ast_Kind_Range_Literal:
-                       ((AstRangeLiteral *) nn)->low  = (AstTyped *) ast_clone(a, ((AstRangeLiteral *) node)->low); 
-                       ((AstRangeLiteral *) nn)->high = (AstTyped *) ast_clone(a, ((AstRangeLiteral *) node)->high); 
-                       ((AstRangeLiteral *) nn)->step = (AstTyped *) ast_clone(a, ((AstRangeLiteral *) node)->step); 
+               C(AstRangeLiteral, low);
+               C(AstRangeLiteral, high);
+               C(AstRangeLiteral, step);
                break;
 
                case Ast_Kind_Return:
-                       ((AstReturn *) nn)->expr = (AstTyped *) ast_clone(a, ((AstReturn *) node)->expr);
+                       C(AstReturn, expr);
                        break;
 
                case Ast_Kind_Block:
@@ -229,29 +231,29 @@ AstNode* ast_clone(bh_allocator a, void* n) {
                        break;
 
                case Ast_Kind_Defer:
-                       ((AstDefer *) nn)->stmt = ast_clone(a, ((AstDefer *) node)->stmt);
+                       C(AstDefer, stmt);
                        break;
 
                case Ast_Kind_For:
-                       ((AstFor *) nn)->var = (AstLocal *) ast_clone(a, ((AstFor *) node)->var);
-                       ((AstFor *) nn)->iter = (AstTyped *) ast_clone(a, ((AstFor *) node)->iter);
-                       ((AstFor *) nn)->stmt = (AstBlock *) ast_clone(a, ((AstFor *) node)->stmt);
+                       C(AstFor, var);
+                       C(AstFor, iter);
+                       C(AstFor, stmt);
                        break;
 
                case Ast_Kind_If:
                case Ast_Kind_While:
-                       ((AstIfWhile *) nn)->local = (AstLocal *) ast_clone(a, ((AstIfWhile *) node)->local);
-                       ((AstIfWhile *) nn)->assignment = (AstBinaryOp *) ast_clone(a, ((AstIfWhile *) node)->assignment);
+                       C(AstIfWhile, local);
+                       C(AstIfWhile, assignment);
 
                        if (((AstIfWhile *) nn)->assignment)
                                ((AstIfWhile *) nn)->assignment->left = (AstTyped *) ((AstIfWhile *) nn)->local;
 
-                       ((AstIfWhile *) nn)->cond = (AstTyped *) ast_clone(a, ((AstIfWhile *) node)->cond);
+                       C(AstIfWhile, cond);
                        //fallthrough
 
                case Ast_Kind_Static_If:
-                       ((AstIfWhile *) nn)->true_stmt = (AstBlock *) ast_clone(a, ((AstIfWhile *) node)->true_stmt);
-                       ((AstIfWhile *) nn)->false_stmt = (AstBlock *) ast_clone(a, ((AstIfWhile *) node)->false_stmt);
+                       C(AstIfWhile, true_stmt);
+                       C(AstIfWhile, false_stmt);
                        break;
 
                case Ast_Kind_Switch: {
@@ -284,28 +286,28 @@ AstNode* ast_clone(bh_allocator a, void* n) {
                }
 
                case Ast_Kind_Pointer_Type:
-                       ((AstPointerType *) nn)->elem = (AstType *) ast_clone(a, ((AstPointerType *) node)->elem);
+                       C(AstPointerType, elem);
                        break;
 
                case Ast_Kind_Array_Type:
-                       ((AstArrayType *) nn)->count_expr = (AstTyped *) ast_clone(a, ((AstArrayType *) node)->count_expr);
-                       ((AstArrayType *) nn)->elem = (AstType *) ast_clone(a, ((AstArrayType *) node)->elem);
+                       C(AstArrayType, count_expr);
+                       C(AstArrayType, elem);
                        break;
 
                case Ast_Kind_Slice_Type:
-                       ((AstSliceType *) nn)->elem = (AstType *) ast_clone(a, ((AstSliceType *) node)->elem);
+                       C(AstSliceType, elem);
                        break;
 
                case Ast_Kind_DynArr_Type:
-                       ((AstDynArrType *) nn)->elem = (AstType *) ast_clone(a, ((AstDynArrType *) node)->elem);
+                       C(AstDynArrType, elem);
                        break;
 
                case Ast_Kind_VarArg_Type:
-                       ((AstVarArgType *) nn)->elem = (AstType *) ast_clone(a, ((AstVarArgType *) node)->elem);
+                       C(AstVarArgType, elem);
                        break;
 
                case Ast_Kind_Type_Alias:
-                       ((AstTypeAlias *) nn)->to = (AstType *) ast_clone(a, ((AstTypeAlias *) node)->to);
+                       C(AstTypeAlias, to);
                        break;
 
         case Ast_Kind_Struct_Type: {
@@ -324,8 +326,8 @@ AstNode* ast_clone(bh_allocator a, void* n) {
         }
 
         case Ast_Kind_Struct_Member:
-                       ((AstStructMember *) nn)->type_node = (AstType *) ast_clone(a, ((AstStructMember *) node)->type_node);
-            ((AstStructMember *) nn)->initial_value = (AstTyped *) ast_clone(a, ((AstStructMember *) node)->initial_value);
+               C(AstStructMember, type_node);
+               C(AstStructMember, initial_value);
             break;
 
         case Ast_Kind_Poly_Call_Type: {
@@ -357,7 +359,7 @@ AstNode* ast_clone(bh_allocator a, void* n) {
         }
 
                case Ast_Kind_Function_Type:
-                       ((AstFunctionType *) nn)->return_type = (AstType *) ast_clone(a, ((AstFunctionType *) node)->return_type);
+                       C(AstFunctionType, return_type);
                        ((AstFunctionType *) nn)->param_count = ((AstFunctionType *) node)->param_count;
                        fori (i, 0, (i64) ((AstFunctionType *) nn)->param_count) {
                                ((AstFunctionType *) nn)->params[i] = (AstType *) ast_clone(a, ((AstFunctionType *) node)->params[i]);
@@ -366,8 +368,8 @@ AstNode* ast_clone(bh_allocator a, void* n) {
 
                case Ast_Kind_Binding:
                        bh_printf("Cloning binding: %b\n", node->token->text, node->token->length);
-                       ((AstTyped *) nn)->type_node = (AstType *) ast_clone(a, ((AstTyped *) node)->type_node);
-                       ((AstBinding *) nn)->node = ast_clone(a, ((AstBinding *) node)->node);
+                       C(AstTyped, type_node);
+                       C(AstBinding, node);
                        break;
 
                case Ast_Kind_Function: {
@@ -398,10 +400,9 @@ AstNode* ast_clone(bh_allocator a, void* n) {
                        break;
                }
 
-               case Ast_Kind_Use: {
-                       ((AstUse *) nn)->expr = (AstTyped *) ast_clone(a, ((AstUse *) node)->expr);
+               case Ast_Kind_Use:
+                       C(AstUse, expr);
                        break;
-               }
 
                case Ast_Kind_Directive_Solidify: {
                        AstDirectiveSolidify* dd = (AstDirectiveSolidify *) nn;
@@ -437,34 +438,32 @@ AstNode* ast_clone(bh_allocator a, void* n) {
             break;
         }
 
-        case Ast_Kind_Named_Value: {
-            ((AstNamedValue *) nn)->value = (AstTyped *) ast_clone(a, ((AstNamedValue *) node)->value);
+        case Ast_Kind_Named_Value:
+               C(AstNamedValue, value);
             break;
-        }
 
-        case Ast_Kind_If_Expression: {
-            ((AstIfExpression *) nn)->cond = (AstTyped *) ast_clone(a, ((AstIfExpression *) node)->cond);
-            ((AstIfExpression *) nn)->true_expr = (AstTyped *) ast_clone(a, ((AstIfExpression *) node)->true_expr);
-            ((AstIfExpression *) nn)->false_expr = (AstTyped *) ast_clone(a, ((AstIfExpression *) node)->false_expr);
+        case Ast_Kind_If_Expression:
+               C(AstIfExpression, cond);
+               C(AstIfExpression, true_expr);
+               C(AstIfExpression, false_expr);
             break;
-        }
 
-               case Ast_Kind_Directive_Insert: {
-                       ((AstDirectiveInsert *) nn)->code_expr = (AstTyped *) ast_clone(a, ((AstDirectiveInsert *) node)->code_expr);
+               case Ast_Kind_Directive_Insert:
+                       C(AstDirectiveInsert, code_expr);
                        break;
-               }
 
-               case Ast_Kind_Typeof: {
-                       ((AstTypeOf *) nn)->expr = (AstTyped *) ast_clone(a, ((AstTypeOf *) node)->expr);
+               case Ast_Kind_Typeof:
+                       C(AstTypeOf, expr);
                        ((AstTypeOf *) nn)->resolved_type = NULL;
                        break;
-               }
        }
 
        clone_depth--;
        return nn;
 }
 
+#undef C
+
 AstFunction* clone_function_header(bh_allocator a, AstFunction* func) {
     if (func->kind != Ast_Kind_Function) return NULL;
 
index 0892a6cd103749fd33225976a6493f8e3574e714..391ac9c83a524f6059fd35354ccf9eb2cbe14086 100644 (file)
@@ -2066,8 +2066,13 @@ static AstFunction* parse_function_definition(OnyxParser* parser, OnyxToken* tok
     parser->polymorph_context.poly_params = NULL;
 
     func_def->return_type = (AstType *) &basic_type_void;
-    if (consume_token_if_next(parser, Token_Type_Right_Arrow))
-        func_def->return_type = parse_type(parser);
+    if (consume_token_if_next(parser, Token_Type_Right_Arrow)) {
+        if (parse_possible_directive(parser, "auto")) {
+            func_def->return_type = (AstType *) &basic_type_auto_return;
+        } else {
+            func_def->return_type = parse_type(parser);
+        }
+    }
 
     while (parser->curr->type == '#') {
         if (parse_possible_directive(parser, "intrinsic")) {
index 27a28f7176ab70ba9c60bb1fe6c93d2d859e605d..d58cd4fcec3d88596e8839991aaa9317230e3c3f 100644 (file)
@@ -1195,8 +1195,8 @@ void symres_entity(Entity* ent) {
     }
 
     report_unresolved_symbols = (context.entities.type_count[Entity_Type_Static_If] == 0 &&
-                                 context.entities.type_count[Entity_Type_Use_Package] == 0);
-                                // || context.cycle_detected;
+                                 context.entities.type_count[Entity_Type_Use_Package] == 0)
+                                || context.cycle_detected;
 
     SymresStatus ss = Symres_Success;
     EntityState next_state = Entity_State_Check_Types;