diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 06b832311..438992f53 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -2219,16 +2219,13 @@ gb_internal void check_entity_decl(CheckerContext *ctx, Entity *e, DeclInfo *d, } CheckerContext c = *ctx; - ProcInfo *prev_instantiation = global_error_instantiation; - ErrorRecordInstantiation *prev_record_instantiation = global_error_record_instantiation; - defer (global_error_instantiation = prev_instantiation); - defer (global_error_record_instantiation = prev_record_instantiation); + ErrorInstantiations prev_instantiations = global_error_context.instantiations; + defer (global_error_context.instantiations = prev_instantiations); if (d->scope->flags & ScopeFlag_File) { // NOTE(bill): a global is checked in a context of its own file, never in that of whatever needed it first, // which may be in another file or package, or a procedure body (nor is it part of its instantiation). // Only the cycle detection carries over. - global_error_instantiation = nullptr; - global_error_record_instantiation = nullptr; + global_error_context.instantiations = {}; CheckerTypePath *type_path = c.type_path; UntypedExprInfoMap *untyped = c.untyped; gb_zero_size(&c.pkg, gb_size_of(CheckerContext) - gb_offset_of(CheckerContext, pkg)); diff --git a/src/check_expr.cpp b/src/check_expr.cpp index d71c98d3b..6cbf41ef6 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -860,7 +860,7 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E proc_info->tags = tags; proc_info->generated_from_polymorphic = true; proc_info->poly_def_node = poly_def_node; - proc_info->poly_parent = global_error_instantiation; + proc_info->poly_parent = global_error_context.instantiations.proc; // Before it can be found by another thread which could use it first d->gen_proc_info.store(proc_info); @@ -9173,8 +9173,8 @@ gb_internal CallArgumentError check_polymorphic_record_type(CheckerContext *c, O String generated_name = make_string_c(expr_to_string(call)); Type *named_type = alloc_type_named(generated_name, nullptr, nullptr); - ErrorRecordInstantiation instantiation = {global_error_record_instantiation, call, named_type}; - global_error_record_instantiation = &instantiation; + ErrorRecordInstantiation instantiation = {global_error_context.instantiations.records, call, named_type}; + global_error_context.instantiations.records = &instantiation; if (bt->kind == Type_Struct) { Ast *node = clone_ast(bt->Struct.node); Type *struct_type = alloc_type_struct(); @@ -9202,7 +9202,7 @@ gb_internal CallArgumentError check_polymorphic_record_type(CheckerContext *c, O } else { GB_PANIC("Unsupported parametric polymorphic record type"); } - global_error_record_instantiation = instantiation.prev; + global_error_context.instantiations.records = instantiation.prev; add_declaration_dependency(c, named_type->Named.type_name); operand->mode = Addressing_Type; diff --git a/src/checker.cpp b/src/checker.cpp index 435431847..51fc773fc 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -2719,7 +2719,7 @@ gb_internal void check_procedure_later(Checker *c, AstFile *file, Token token, D info->type = type; info->body = body; info->tags = tags; - info->poly_parent = global_error_instantiation; + info->poly_parent = global_error_context.instantiations.proc; check_procedure_later(c, info); } @@ -6265,9 +6265,9 @@ gb_internal WORKER_TASK_PROC(check_collect_entities_worker_proc) { AstFile *f = cast(AstFile *)data; reset_checker_context(ctx, f, untyped); - global_error_hold = true; + global_error_context.hold = true; check_collect_entities(ctx, f->decls); - global_error_hold = false; + global_error_context.hold = false; add_untyped_expressions(&c->info, ctx->untyped); @@ -6702,12 +6702,12 @@ gb_internal WORKER_TASK_PROC(calculate_global_init_order_worker) { gb_internal void error_out_instantiations(void) { isize const max_shown = 8; isize count = 0; - for (ErrorRecordInstantiation *r = global_error_record_instantiation; r != nullptr; r = r->prev) { + for (ErrorRecordInstantiation *r = global_error_context.instantiations.records; r != nullptr; r = r->prev) { if (count++ < max_shown) { error_out("\t%s instantiated as '%.*s'\n", token_pos_to_string(ast_token(r->site).pos), LIT(r->named_type->Named.name)); } } - for (ProcInfo *pi = global_error_instantiation; pi != nullptr; pi = pi->poly_parent) { + for (ProcInfo *pi = global_error_context.instantiations.proc; pi != nullptr; pi = pi->poly_parent) { if (count++ >= max_shown) { continue; } @@ -6839,10 +6839,10 @@ gb_internal bool check_proc_info(Checker *c, ProcInfo *pi, UntypedExprInfoMap *u ctx.state_flags &= ~StateFlag_type_assert; } - ProcInfo *prev_instantiation = global_error_instantiation; - global_error_instantiation = pi->generated_from_polymorphic ? pi : pi->poly_parent; + ErrorInstantiations prev_instantiations = global_error_context.instantiations; + global_error_context.instantiations = {pi->generated_from_polymorphic ? pi : pi->poly_parent, nullptr}; bool body_was_checked = check_proc_body(&ctx, pi->token, pi->decl, pi->type, pi->body); - global_error_instantiation = prev_instantiation; + global_error_context.instantiations = prev_instantiations; if (body_was_checked) { pi->decl->proc_checked_state.store(ProcCheckedState_Checked); diff --git a/src/checker_global.cpp b/src/checker_global.cpp index fea0ee8b8..866c205a2 100644 --- a/src/checker_global.cpp +++ b/src/checker_global.cpp @@ -519,12 +519,12 @@ gb_internal void resolve_global_decl_source(GlobalDeclSource *src, InternedStrin return; } GlobalWhenTrial *trial = global_when_trial; - i32 mute_depth = global_error_mute_depth; + i32 mute_depth = global_error_context.mute_depth; global_when_trial = nullptr; - global_error_mute_depth = 0; + global_error_context.mute_depth = 0; resolve_global_decl_source_internal(src, needed); global_when_trial = trial; - global_error_mute_depth = mute_depth; + global_error_context.mute_depth = mute_depth; } gb_internal Entity *force_scope_placeholders(Scope *s, InternedString name, u32 hash) { @@ -2027,8 +2027,8 @@ gb_internal bool global_when_trial_begin_entity(Entity *e, GlobalWhenTrialEntity return true; } scope->trial = t; - scope->mute_depth = global_error_mute_depth; - global_error_mute_depth = 0; + scope->mute_depth = global_error_context.mute_depth; + global_error_context.mute_depth = 0; t->real_depth += 1; return true; } @@ -2036,7 +2036,7 @@ gb_internal bool global_when_trial_begin_entity(Entity *e, GlobalWhenTrialEntity gb_internal void global_when_trial_end_entity(GlobalWhenTrialEntityScope *scope) { if (scope->trial != nullptr) { scope->trial->real_depth -= 1; - global_error_mute_depth = scope->mute_depth; + global_error_context.mute_depth = scope->mute_depth; } } diff --git a/src/error.cpp b/src/error.cpp index 0ea8ab77f..edd000693 100644 --- a/src/error.cpp +++ b/src/error.cpp @@ -32,7 +32,21 @@ struct ErrorCollector { gb_global ErrorCollector global_error_collector; -gb_thread_local bool global_error_hold = false; +// Optional annotations for the next errored source line, `show_error_on_line` snapshots and clears them. +// +// primary label, inline: primary label, vertical: secondary span (always vertical): +// append(&x, true) append(x, {1,2,3}) append(&x, true) +// ^~~^ expected '…', found '…' ^ ^^ ^~~^ expected '…', found '…' +// | | +// expected '^…', pass '&x' '[dynamic][3]int', elements are '[3]int' +struct ErrorCaret { + char label[512]; // primary label text + bool label_vertical; // render primary label as | + text below, not inline + bool sec_present; // a secondary span (to the left) is set + TokenPos sec_pos; + TokenPos sec_end; + char sec_label[512]; +}; struct ErrorRecordInstantiation { ErrorRecordInstantiation *prev; @@ -40,65 +54,63 @@ struct ErrorRecordInstantiation { struct Type * named_type; }; -// The polymorphic procedure instantiation whose body is being checked on this thread, -// and the polymorphic records being instantiated within it, see `error_out_instantiations` -gb_thread_local struct ProcInfo * global_error_instantiation = nullptr; -gb_thread_local ErrorRecordInstantiation *global_error_record_instantiation = nullptr; +// The polymorphic instantiations the code being checked is within, see `error_out_instantiations` +struct ErrorInstantiations { + struct ProcInfo * proc; // whose body is being checked + ErrorRecordInstantiation *records; // being instantiated within it +}; + +// Per-thread, so nothing leaks between concurrently-checked files +struct ErrorContext { + bool hold; // see `release_held_errors` + + // Scoped error muting. While muted, error/warning emission is suppressed but still *counted*, so a + // caller can trial-check something (e.g. one branch of a procedure group) and learn whether it would + // have failed without printing anything. Muting nests. + i32 mute_depth; + i64 mute_count; + + ErrorInstantiations instantiations; + ErrorCaret caret; +}; + +gb_global gb_thread_local ErrorContext global_error_context; + gb_internal void error_out_instantiations(void); // defined in checker.cpp -// Scoped, per-thread error muting. While muted, error/warning emission is suppressed but still -// *counted*, so a caller can trial-check something (e.g. one branch of a procedure group) and learn -// whether it would have failed without printing anything. Muting nests. -gb_thread_local i32 global_error_mute_depth = 0; -gb_thread_local i64 global_error_mute_count = 0; - gb_internal void begin_error_mute(void) { - global_error_mute_depth += 1; + global_error_context.mute_depth += 1; } gb_internal void end_error_mute(void) { - GB_ASSERT(global_error_mute_depth > 0); - global_error_mute_depth -= 1; + GB_ASSERT(global_error_context.mute_depth > 0); + global_error_context.mute_depth -= 1; } gb_internal i64 error_mute_count(void) { - return global_error_mute_count; + return global_error_context.mute_count; } gb_internal bool is_error_muted(void) { - return global_error_mute_depth > 0; + return global_error_context.mute_depth > 0; } -// Optional annotations for the next errored source line. -// All per-thread, so nothing leaks between concurrently-checked files. -// `show_error_on_line` snapshots and clears them. -// -// primary label, inline: primary label, vertical: secondary span (always vertical): -// append(&x, true) append(x, {1,2,3}) append(&x, true) -// ^~~^ expected '…', found '…' ^ ^^ ^~~^ expected '…', found '…' -// | | -// expected '^…', pass '&x' '[dynamic][3]int', elements are '[3]int' -gb_thread_local char global_caret_label_buf[512]; // primary label text -gb_thread_local bool global_caret_label_vertical; // render primary label as | + text below, not inline -gb_thread_local bool global_caret_sec_present; // a secondary span (to the left) is set -gb_thread_local TokenPos global_caret_sec_pos; -gb_thread_local TokenPos global_caret_sec_end; -gb_thread_local char global_caret_sec_label[512]; - gb_internal void set_caret_label(char const *text) { - global_caret_label_vertical = false; + ErrorCaret *caret = &global_error_context.caret; + caret->label_vertical = false; if (text == nullptr) { - global_caret_label_buf[0] = 0; + caret->label[0] = 0; } else { - gb_snprintf(global_caret_label_buf, gb_size_of(global_caret_label_buf), "%s", text); + gb_snprintf(caret->label, gb_size_of(caret->label), "%s", text); } } gb_internal void set_caret_label_vertical(char const *text) { set_caret_label(text); - global_caret_label_vertical = true; + global_error_context.caret.label_vertical = true; } gb_internal void set_caret_secondary(TokenPos pos, TokenPos end, char const *text) { - global_caret_sec_present = text != nullptr; - global_caret_sec_pos = pos; - global_caret_sec_end = end; - gb_snprintf(global_caret_sec_label, gb_size_of(global_caret_sec_label), "%s", text ? text : ""); + ErrorCaret *caret = &global_error_context.caret; + caret->sec_present = text != nullptr; + caret->sec_pos = pos; + caret->sec_end = end; + gb_snprintf(caret->sec_label, gb_size_of(caret->sec_label), "%s", text ? text : ""); } @@ -114,11 +126,11 @@ gb_internal void push_error_value(TokenPos const &pos, ErrorValueKind kind = Err gb_internal void pop_error_value(void) { mutex_lock(&global_error_collector.mutex); if (global_error_collector.curr_error_value_set.load()) { - if ((global_error_instantiation != nullptr || global_error_record_instantiation != nullptr) && - global_error_collector.curr_error_value.kind == ErrorValue_Error) { + ErrorInstantiations const &insts = global_error_context.instantiations; + if ((insts.proc != nullptr || insts.records != nullptr) && global_error_collector.curr_error_value.kind == ErrorValue_Error) { error_out_instantiations(); } - array_add(global_error_hold ? &global_error_collector.held_error_values : &global_error_collector.error_values, global_error_collector.curr_error_value); + array_add(global_error_context.hold ? &global_error_collector.held_error_values : &global_error_collector.error_values, global_error_collector.curr_error_value); global_error_collector.curr_error_value = {}; global_error_collector.curr_error_value_set.store(false); @@ -275,7 +287,7 @@ gb_internal void print_all_errors(void); typedef ERROR_OUT_PROC(ErrorOutProc); gb_internal ERROR_OUT_PROC(default_error_out_va) { - if (global_error_mute_depth > 0) { + if (global_error_context.mute_depth > 0) { // NOTE(bill): the error this would continue was muted, so there is no current error value return; } @@ -374,18 +386,8 @@ gb_internal isize show_error_on_line(TokenPos const &pos, TokenPos end) { // Consume the caret annotations now, so they are cleared even on an early return and can never leak // onto a later error's line. - char caret_label[512]; - gb_snprintf(caret_label, gb_size_of(caret_label), "%s", global_caret_label_buf); - bool caret_label_vertical = global_caret_label_vertical; - bool sec_present = global_caret_sec_present; - TokenPos sec_pos = global_caret_sec_pos; - TokenPos sec_end = global_caret_sec_end; - char sec_label[512]; - gb_snprintf(sec_label, gb_size_of(sec_label), "%s", global_caret_sec_label); - global_caret_label_buf[0] = 0; - global_caret_label_vertical = false; - global_caret_sec_present = false; - global_caret_sec_label[0] = 0; + ErrorCaret caret = global_error_context.caret; + global_error_context.caret = {}; if (!show_error_line()) { return -1; @@ -595,10 +597,10 @@ gb_internal isize show_error_on_line(TokenPos const &pos, TokenPos end) { // same way as the primary's, and only draw it if it sits fully to the left within the window. i32 sec_pad = 0; i32 sec_len = 0; - bool draw_sec = sec_present && sec_pos.line == pos.line && sec_end.line == pos.line; + bool draw_sec = caret.sec_present && caret.sec_pos.line == pos.line && caret.sec_end.line == pos.line; if (draw_sec) { - i32 sec_start_byte = error_start_index_bytes + (sec_pos.column - pos.column); - i32 sec_end_byte = error_start_index_bytes + (sec_end.column - pos.column); + i32 sec_start_byte = error_start_index_bytes + (caret.sec_pos.column - pos.column); + i32 sec_end_byte = error_start_index_bytes + (caret.sec_end.column - pos.column); if (window_open_bytes > 0) { sec_pad += 4; } @@ -658,9 +660,9 @@ gb_internal isize show_error_on_line(TokenPos const &pos, TokenPos end) { } } - if (caret_label[0] != 0 && !caret_label_vertical) { + if (caret.label[0] != 0 && !caret.label_vertical) { terminal_set_colours(TerminalStyle_Normal, TerminalColour_Grey); - error_out(" %s", caret_label); + error_out(" %s", caret.label); } // NOTE(Feoramund): Specifically print a newline, then reset colours, @@ -673,12 +675,12 @@ gb_internal isize show_error_on_line(TokenPos const &pos, TokenPos end) { // secondary span takes priority (its label explains the primary); otherwise a vertical primary label. i32 vpad = -1; char const *vtext = nullptr; - if (draw_sec && sec_label[0] != 0) { + if (draw_sec && caret.sec_label[0] != 0) { vpad = sec_pad; - vtext = sec_label; - } else if (caret_label_vertical && caret_label[0] != 0) { + vtext = caret.sec_label; + } else if (caret.label_vertical && caret.label[0] != 0) { vpad = squiggle_padding; - vtext = caret_label; + vtext = caret.label; } if (vpad >= 0 && vtext != nullptr && vtext[0] != 0) { error_out("\t"); @@ -719,11 +721,11 @@ gb_internal void error_out_coloured(char const *str, TerminalStyle style, Termin gb_internal void error_va(TokenPos const &pos, TokenPos end, char const *fmt, va_list va) { - if (global_error_mute_depth > 0) { - global_error_mute_count += 1; + if (global_error_context.mute_depth > 0) { + global_error_context.mute_count += 1; return; } - (global_error_hold ? global_error_collector.held_count : global_error_collector.count).fetch_add(1); + (global_error_context.hold ? global_error_collector.held_count : global_error_collector.count).fetch_add(1); mutex_lock(&global_error_collector.mutex); if (global_error_collector.count > MAX_ERROR_COLLECTOR_COUNT()) { print_all_errors(); @@ -760,12 +762,12 @@ gb_internal void warning_va(TokenPos const &pos, TokenPos end, char const *fmt, if (global_ignore_warnings()) { return; } - if (global_error_mute_depth > 0) { - global_error_mute_count += 1; + if (global_error_context.mute_depth > 0) { + global_error_context.mute_count += 1; return; } - (global_error_hold ? global_error_collector.held_warning_count : global_error_collector.warning_count).fetch_add(1); + (global_error_context.hold ? global_error_collector.held_warning_count : global_error_collector.warning_count).fetch_add(1); mutex_lock(&global_error_collector.mutex); push_error_value(pos, ErrorValue_Warning); @@ -793,18 +795,18 @@ gb_internal void warning_va(TokenPos const &pos, TokenPos end, char const *fmt, gb_internal void error_line_va(char const *fmt, va_list va) { - if (global_error_mute_depth > 0) { + if (global_error_context.mute_depth > 0) { return; } error_out_va(fmt, va); } gb_internal void error_no_newline_va(TokenPos const &pos, char const *fmt, va_list va) { - if (global_error_mute_depth > 0) { - global_error_mute_count += 1; + if (global_error_context.mute_depth > 0) { + global_error_context.mute_count += 1; return; } - (global_error_hold ? global_error_collector.held_count : global_error_collector.count).fetch_add(1); + (global_error_context.hold ? global_error_collector.held_count : global_error_collector.count).fetch_add(1); mutex_lock(&global_error_collector.mutex); if (global_error_collector.count.load() > MAX_ERROR_COLLECTOR_COUNT()) { print_all_errors(); @@ -836,8 +838,8 @@ gb_internal void error_no_newline_va(TokenPos const &pos, char const *fmt, va_li gb_internal void syntax_error_va(TokenPos const &pos, TokenPos end, char const *fmt, va_list va) { - if (global_error_mute_depth > 0) { - global_error_mute_count += 1; + if (global_error_context.mute_depth > 0) { + global_error_context.mute_count += 1; return; } global_error_collector.count.fetch_add(1); @@ -872,8 +874,8 @@ gb_internal void syntax_error_va(TokenPos const &pos, TokenPos end, char const * } gb_internal void syntax_error_with_verbose_va(TokenPos const &pos, TokenPos end, char const *fmt, va_list va) { - if (global_error_mute_depth > 0) { - global_error_mute_count += 1; + if (global_error_context.mute_depth > 0) { + global_error_context.mute_count += 1; return; } global_error_collector.count.fetch_add(1);