Skip to content

Commit 9a66e20

Browse files
committed
ci: fix remaining master failures
1 parent d934e4b commit 9a66e20

28 files changed

Lines changed: 483 additions & 281 deletions

.github/workflows/tccbin_source_recovery.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ jobs:
3838
env:
3939
EVENT_NAME: ${{ github.event_name }}
4040
HANDOFF_ID: ${{ inputs.resume_handoff_id || '' }}
41-
UPSTREAM_NAME: ${{ github.event.workflow_run.name || '' }}
41+
UPSTREAM_PATH: ${{ github.event.workflow_run.path || '' }}
4242
run: |
4343
set -euo pipefail
4444
case "$EVENT_NAME" in
@@ -55,8 +55,8 @@ jobs:
5555
echo 'handoff_id=' >> "$GITHUB_OUTPUT"
5656
;;
5757
workflow_run)
58-
case "$UPSTREAM_NAME" in
59-
'Update tccbin'|'TCC bundle revalidation') ;;
58+
case "$UPSTREAM_PATH" in
59+
'.github/workflows/update_tccbin.yml'|'.github/workflows/tccbin_revalidate.yml') ;;
6060
*) exit 1 ;;
6161
esac
6262
echo 'mode=workflow_run' >> "$GITHUB_OUTPUT"

vlib/net/jsonrpc/jsonrpc.v

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -56,15 +56,42 @@ pub fn error_with_code(message string, code int) ResponseError {
5656

5757
// JSON-RPC standard-ish errors :contentReference[oaicite:3]{index=3}
5858

59-
pub const parse_error = error_with_code('Invalid JSON.', -32700)
60-
pub const invalid_request = error_with_code('Invalid request.', -32600)
61-
pub const method_not_found = error_with_code('Method not found.', -32601)
62-
pub const invalid_params = error_with_code('Invalid params', -32602)
63-
pub const internal_error = error_with_code('Internal error.', -32693)
64-
pub const server_error_start = error_with_code('Error occurred when starting server.', -32099)
65-
pub const server_not_initialized = error_with_code('Server not initialized.', -32002)
66-
pub const unknown_error = error_with_code('Unknown error.', -32001)
67-
pub const server_error_end = error_with_code('Error occurred when stopping the server.', -32000)
59+
pub const parse_error = ResponseError{
60+
code: -32700
61+
message: 'Invalid JSON.'
62+
}
63+
pub const invalid_request = ResponseError{
64+
code: -32600
65+
message: 'Invalid request.'
66+
}
67+
pub const method_not_found = ResponseError{
68+
code: -32601
69+
message: 'Method not found.'
70+
}
71+
pub const invalid_params = ResponseError{
72+
code: -32602
73+
message: 'Invalid params'
74+
}
75+
pub const internal_error = ResponseError{
76+
code: -32693
77+
message: 'Internal error.'
78+
}
79+
pub const server_error_start = ResponseError{
80+
code: -32099
81+
message: 'Error occurred when starting server.'
82+
}
83+
pub const server_not_initialized = ResponseError{
84+
code: -32002
85+
message: 'Server not initialized.'
86+
}
87+
pub const unknown_error = ResponseError{
88+
code: -32001
89+
message: 'Unknown error.'
90+
}
91+
pub const server_error_end = ResponseError{
92+
code: -32000
93+
message: 'Error occurred when stopping the server.'
94+
}
6895
pub const error_codes = [
6996
parse_error.code(),
7097
invalid_request.code(),

vlib/v3/driver/driver.v

Lines changed: 61 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2497,10 +2497,47 @@ fn register_native_source_typedefs(mut tc types.TypeChecker, state &V3ModuleCach
24972497
if c_name !in tc.structs {
24982498
tc.structs[c_name] = []types.StructField{}
24992499
}
2500-
tc.c_typedef_structs[c_name] = true
2500+
if !c_typedef_is_function_pointer(source, name) {
2501+
tc.c_typedef_structs[c_name] = true
2502+
}
2503+
}
2504+
}
2505+
}
2506+
}
2507+
2508+
fn register_headerless_c_types(mut tc types.TypeChecker) {
2509+
// The C backend always supplies this platform-specific declaration in its
2510+
// headerless preamble, even when the program does not import `os`.
2511+
if 'C.stat' !in tc.structs {
2512+
tc.structs['C.stat'] = []types.StructField{}
2513+
}
2514+
}
2515+
2516+
fn c_typedef_is_function_pointer(source string, name string) bool {
2517+
mut offset := 0
2518+
for offset < source.len {
2519+
relative := source[offset..].index(name) or { return false }
2520+
start := offset + relative
2521+
end := start + name.len
2522+
if (start == 0 || (!source[start - 1].is_alnum() && source[start - 1] != `_`))
2523+
&& (end == source.len || (!source[end].is_alnum() && source[end] != `_`)) {
2524+
mut i := start - 1
2525+
for i >= 0 && source[i].is_space() {
2526+
i--
2527+
}
2528+
if i >= 0 && source[i] == `*` {
2529+
i--
2530+
for i >= 0 && source[i].is_space() {
2531+
i--
2532+
}
2533+
if i >= 0 && source[i] == `(` {
2534+
return true
2535+
}
25012536
}
25022537
}
2538+
offset = end
25032539
}
2540+
return false
25042541
}
25052542

25062543
fn cache_c_compiler_predefined_macros(flags []string, ccompiler string, target pref.Target, native_inputs_language string) (map[string]string, bool) {
@@ -4858,7 +4895,7 @@ fn incremental_changed_functions(snapshot V3IncrementalSnapshot, old map[string]
48584895
return keys, names
48594896
}
48604897

4861-
fn incremental_changed_functions_require_reachability_rebuild(a &flat.FlatAst, tc &types.TypeChecker, changed_names map[string]bool, cached map[string]bool, user_files []string) bool {
4898+
fn incremental_changed_functions_require_reachability_rebuild(a &flat.FlatAst, tc &types.TypeChecker, mut changed_names map[string]bool, mut used map[string]bool, user_files []string) bool {
48624899
if changed_names.len == 0 {
48634900
return false
48644901
}
@@ -4891,7 +4928,17 @@ fn incremental_changed_functions_require_reachability_rebuild(a &flat.FlatAst, t
48914928
if !aliases.any(current[it]) {
48924929
continue
48934930
}
4894-
if !aliases.any(cached[it]) {
4931+
if !aliases.any(used[it]) {
4932+
// A newly reached stringifier can be added to the incremental body without
4933+
// invalidating unchanged functions or the cached support prefix.
4934+
if name.ends_with('.str') {
4935+
changed_names[node.value] = true
4936+
changed_names[name] = true
4937+
for alias in aliases {
4938+
used[alias] = true
4939+
}
4940+
continue
4941+
}
48954942
return true
48964943
}
48974944
}
@@ -7967,6 +8014,7 @@ pub fn run(args []string) {
79678014
}
79688015
mut cvsw := time.new_stopwatch()
79698016
pre_tc.collect(a)
8017+
register_headerless_c_types(mut pre_tc)
79708018
register_native_source_typedefs(mut pre_tc, &cache_state)
79718019
if translated_mode {
79728020
for file in user_files {
@@ -8204,7 +8252,7 @@ pub fn run(args []string) {
82048252
used_fns = clone_string_bool_map(cached_program_used_fns)
82058253
uses_generics = true
82068254
if incremental_cache_hit
8207-
&& incremental_changed_functions_require_reachability_rebuild(a, markused_tc, incremental_changed_names, cached_program_used_fns, user_files) {
8255+
&& incremental_changed_functions_require_reachability_rebuild(a, markused_tc, mut incremental_changed_names, mut used_fns, user_files) {
82088256
os.setenv('V3_CACHE_DISABLE_INCREMENTAL', '1', true)
82098257
restart_v3_after_cache_invalidation()
82108258
}
@@ -8757,8 +8805,8 @@ pub fn run(args []string) {
87578805
base_specialized_fns := a.specialized_fn_nodes.len
87588806
monomorph_scope := prealloc_scope_begin_for_v3()
87598807
monomorph_used_fns, monomorph_errors, generated_monomorph_specs = transform.monomorphize_with_used_checked_config_scoped_cached(mut a,
8760-
&pre_tc, monomorph_input_used, should_parallel_monomorphize(), monomorph_scope,
8761-
cached_monomorph_specs)
8808+
&pre_tc, monomorph_input_used, !current_no_parallel
8809+
&& should_parallel_monomorphize(), monomorph_scope, cached_monomorph_specs)
87628810
parse_cache_enabled := pre_tc.type_cache_parse_enabled()
87638811
prealloc_scope_leave_for_v3(monomorph_scope)
87648812
// Specialization can rewrite payload text on pre-existing nodes as
@@ -8798,8 +8846,9 @@ pub fn run(args []string) {
87988846
prealloc_scope_free_for_v3(monomorph_scope)
87998847
} else {
88008848
monomorph_used_fns, monomorph_errors, generated_monomorph_specs = transform.monomorphize_with_used_checked_config_scoped_cached(mut a,
8801-
&pre_tc, monomorph_input_used, should_parallel_monomorphize()
8802-
&& !incremental_cache_hit, unsafe { nil }, cached_monomorph_specs)
8849+
&pre_tc, monomorph_input_used, !current_no_parallel
8850+
&& should_parallel_monomorphize() && !incremental_cache_hit, unsafe { nil },
8851+
cached_monomorph_specs)
88038852
}
88048853
// Monomorphization publishes every synthesized or rewritten AST string
88058854
// after its final worker merge, including the serial/no-worker path.
@@ -11630,7 +11679,9 @@ fn vmod_subdirs(dir string) ![]string {
1163011679
if os.read_file(vmod_path)!.trim_space().len == 0 {
1163111680
return []string{}
1163211681
}
11633-
manifest := vmod.from_file(vmod_path)!
11682+
// An invalid v.mod does not make the source directory invalid. This matches
11683+
// the legacy builder, while still honoring `subdirs` in valid manifests.
11684+
manifest := vmod.from_file(vmod_path) or { return []string{} }
1163411685
return manifest.unknown['subdirs'] or { []string{} }
1163511686
}
1163611687

@@ -11747,8 +11798,7 @@ fn same_dir_module_source_files(test_file string, module_name string, prefs &pre
1174711798
if module_name.len > 0 {
1174811799
for file in all_files {
1174911800
declared_module := declared_module_in_file(file)
11750-
if declared_module != module_name && !(declared_module in ['', 'main']
11751-
&& module_name in ['', 'main']) {
11801+
if declared_module != module_name {
1175211802
continue
1175311803
}
1175411804
files << file

vlib/v3/gen/c/cleanc.v

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1371,13 +1371,13 @@ pub fn cache_external_input_files_with_resolved_flags(a &flat.FlatAst, vroot str
13711371
mut cur_file_is_program := false
13721372
mut context_directives := map[string][]string{}
13731373
mut conditional_context_mutations := map[string]bool{}
1374-
mut conditional_depth := 0
1374+
mut conditionals := []CCacheConditional{}
13751375
for node in a.nodes {
13761376
if node.kind == .file {
13771377
cur_file = node.value
13781378
cur_file_is_program = program_files[cur_file] || program_files[os.real_path(cur_file)]
13791379
cur_module = ''
1380-
conditional_depth = 0
1380+
conditionals.clear()
13811381
continue
13821382
}
13831383
if node.kind == .module_decl {
@@ -1396,20 +1396,46 @@ pub fn cache_external_input_files_with_resolved_flags(a &flat.FlatAst, vroot str
13961396
}
13971397
if node.kind == .directive {
13981398
if node.value in ['if', 'ifdef', 'ifndef'] {
1399-
conditional_depth++
1400-
} else if node.value == 'endif' && conditional_depth > 0 {
1401-
conditional_depth--
1399+
parent_inactive := conditionals.any(it.inactive)
1400+
parent_ambiguous := conditionals.any(it.ambiguous)
1401+
condition := c_cache_known_condition(c_preprocessor_directive_line(node.value,
1402+
node.typ), include_macros, dynamic_include_macros,
1403+
compiler_macro_environment_complete)
1404+
conditionals << CCacheConditional{
1405+
parent_inactive: parent_inactive
1406+
condition: condition
1407+
inactive: parent_inactive || condition < 0
1408+
ambiguous: parent_ambiguous || condition == 0
1409+
}
1410+
} else if node.value in ['else', 'elif'] && conditionals.len > 0 {
1411+
conditional_idx := conditionals.len - 1
1412+
mut conditional := conditionals[conditional_idx]
1413+
if node.value == 'else' {
1414+
conditional.inactive = conditional.parent_inactive || conditional.condition > 0
1415+
} else if conditional.condition > 0 {
1416+
conditional.inactive = true
1417+
} else {
1418+
next_condition := c_cache_known_condition(c_preprocessor_directive_line(node.value,
1419+
node.typ), include_macros, dynamic_include_macros,
1420+
compiler_macro_environment_complete)
1421+
conditional.condition = next_condition
1422+
conditional.ambiguous = conditional.ambiguous || next_condition == 0
1423+
conditional.inactive = conditional.parent_inactive || next_condition < 0
1424+
}
1425+
conditionals[conditional_idx] = conditional
1426+
} else if node.value == 'endif' && conditionals.len > 0 {
1427+
conditionals.delete_last()
14021428
}
14031429
}
14041430
if node.kind == .directive && node.value in ['define', 'undef'] {
14051431
directive := c_preprocessor_directive_line(node.value, node.typ)
1406-
is_conditional := conditional_depth > 0
1407-
c_record_include_macro_definition(directive, is_conditional, mut include_macros, mut
1432+
is_ambiguous := conditionals.any(it.inactive || it.ambiguous)
1433+
c_record_include_macro_definition(directive, is_ambiguous, mut include_macros, mut
14081434
dynamic_include_macros)
14091435
mut module_context := context_directives[owner_module]
14101436
module_context << directive
14111437
context_directives[owner_module] = module_context
1412-
if is_conditional {
1438+
if is_ambiguous {
14131439
conditional_context_mutations[owner_module] = true
14141440
}
14151441
continue
@@ -1430,7 +1456,7 @@ pub fn cache_external_input_files_with_resolved_flags(a &flat.FlatAst, vroot str
14301456
has_untracked_include = true
14311457
continue
14321458
}
1433-
context_is_replayable := conditional_depth == 0
1459+
context_is_replayable := !conditionals.any(it.inactive || it.ambiguous)
14341460
&& !conditional_context_mutations[owner_module]
14351461
for path in c_include_file_paths(include_arg, vroot, cur_file, include_dirs) {
14361462
c_record_cache_resolution_path(path, mut resolution_dirs, mut

vlib/v3/gen/c/fn.v

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -772,14 +772,17 @@ fn (mut g FlatGen) should_emit_fn_node_in_module_known(node flat.Node, module_na
772772
if g.should_emit_ierror_method(node.value, qfn) {
773773
return true
774774
}
775-
// Every specialization materialized from the combined program/module-cache
776-
// graph is a concrete body needed by either main or one of the cached objects.
777-
if is_program_specialization {
778-
return true
779-
}
780775
if g.fn_node_is_open_generic_template(node, module_name) {
781776
return false
782777
}
778+
// Every concrete specialization materialized from the combined
779+
// program/module-cache graph is needed by either main or a cached object.
780+
// Check for an open template first: cache-wide reachability can retain a raw
781+
// generic receiver declaration in `specialized_generic_fns`, but it still has
782+
// no valid C ABI until monomorphization replaces its type parameters.
783+
if is_program_specialization {
784+
return true
785+
}
783786
if g.has_used_fn_filter() {
784787
if g.used_fn_contains_in_module(node.value, module_name) {
785788
return true
@@ -799,10 +802,23 @@ fn (g &FlatGen) fn_node_is_open_generic_template(node flat.Node, module_name str
799802
return false
800803
}
801804
receiver := node.value.all_before_last('.')
802-
base, args, ok := g.shared_generic_app_parts(receiver)
805+
// This declaration gate must inspect the source spelling authoritatively. The
806+
// shared expression cache can already contain a negative result for the same
807+
// string from a different resolution context during cache-wide generation.
808+
base, args, ok := parse_shared_generic_app_parts(receiver)
803809
if !ok || args.len == 0 {
804810
return false
805811
}
812+
// Receiver declarations encode their own generic parameters in the receiver
813+
// text. During cache-wide self-host generation the declaration can outlive
814+
// the short-name generic-struct index, so recognize the canonical V generic
815+
// parameter spelling directly as well.
816+
for arg in args {
817+
clean := arg.trim_space()
818+
if clean.len == 1 && clean[0] >= `A` && clean[0] <= `Z` {
819+
return true
820+
}
821+
}
806822
mut candidates := [base]
807823
if !base.contains('.') && module_name.len > 0 && module_name !in ['main', 'builtin'] {
808824
candidates << '${module_name}.${base}'
@@ -10188,6 +10204,10 @@ fn (g &FlatGen) call_key(id flat.NodeId, name string) string {
1018810204
}
1018910205
}
1019010206
if resolved := g.tc.resolved_call_name(id) {
10207+
if resolved == name && !name.contains('.')
10208+
&& (name in g.tc.fn_param_types || name in g.tc.fn_ret_types) {
10209+
return name
10210+
}
1019110211
if resolved_call_matches_target(resolved, name) {
1019210212
return g.normalize_call_key(resolved)
1019310213
}
@@ -10239,10 +10259,13 @@ fn (g &FlatGen) normalize_call_key_uncached(name string) string {
1023910259
return local
1024010260
}
1024110261
}
10262+
if !name.contains('.') && g.non_generic_fn_decl_exists_in_module(name, g.tc.cur_module)
10263+
&& (name in g.tc.fn_param_types || name in g.tc.fn_ret_types) {
10264+
return name
10265+
}
1024210266
// A selected import belongs to the current source file and must win over a
10243-
// same-spelled short signature retained from an imported module. The checker
10244-
// can omit per-node resolution data when the program unit is emitted from the
10245-
// module cache, so recover the file-local declaration before accepting `name`.
10267+
// same-spelled short signature retained from another imported module. A real
10268+
// declaration in the current module still has normal lexical priority.
1024610269
if imported := g.selective_import_call_key_in_file(name, g.tc.cur_file) {
1024710270
return imported
1024810271
}

vlib/v3/gen/c/parallel_worker_test.v

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,19 @@ fn test_parallel_generic_app_cache_uses_frozen_base_and_private_overlays() {
278278
assert 'Shared[string]' !in frozen.entries
279279
}
280280

281+
fn test_open_generic_receiver_template_bypasses_stale_generic_app_cache() {
282+
mut g, _ := parallel_worker_test_gen(true)
283+
mut cache := g.generic_app_cache
284+
cache.entries['AtomicVal[T]'] = GenericAppInfo{}
285+
node := flat.Node{
286+
kind: .fn_decl
287+
value: 'AtomicVal[T].load'
288+
}
289+
assert g.fn_node_is_open_generic_template(node, 'stdatomic')
290+
assert !g.should_emit_fn_node_in_module_known(node, 'stdatomic', 'atomic.v',
291+
'stdatomic__AtomicVal_T__load', true)
292+
}
293+
281294
fn test_parallel_type_declarations_include_body_discovered_fn_ptr_types() {
282295
mut g, _ := parallel_worker_test_gen(true)
283296
g.parallel_type_decls = '/* precomputed type declarations */\n'.clone()

0 commit comments

Comments
 (0)