Merge the cross-lane fixes from the first full Linux run

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
This commit is contained in:
Martin Vogel committed 2026-11-02 22:46:44 +01:00
commit e4f967e31f
9 files changed
+99 -69

No files matched your search

+16
View File
@@ -754,6 +754,21 @@ static bool perl_is_direct_coderef_argument(TSNode refgen) {
return !ts_node_is_null(args) && ts_node_eq(args, container);
}
/* `$f ? \&a : \&b` and `$f || \&a` hand over one of several values, so each \&name there only
* mentions its sub. Parentheses change nothing. */
static bool perl_coderef_in_composite(TSNode refgen) {
for (TSNode parent = ts_node_parent(refgen); !ts_node_is_null(parent);
parent = ts_node_parent(parent)) {
const char *kind = ts_node_type(parent);
if (strcmp(kind, "conditional_expression") == 0 || strcmp(kind, "binary_expression") == 0 ||
strcmp(kind, "lowprec_logical_expression") == 0)
return true;
if (strcmp(kind, "list_expression") != 0)
return false;
}
return false;
}
static void perl_emit_non_direct_coderef_usage(PerlLSPContext *ctx, TSNode refgen) {
if (!ctx || !ctx->usages || !ctx->enclosing_func_qn ||
perl_is_direct_coderef_argument(refgen)) {
@@ -777,6 +792,7 @@ static void perl_emit_non_direct_coderef_usage(PerlLSPContext *ctx, TSNode refge
usage.ref_name = name;
usage.enclosing_func_qn = ctx->enclosing_func_qn;
usage.kind = CBM_USAGE_VALUE;
usage.may_be_call_reference = !perl_coderef_in_composite(refgen);
usage.site_start_byte = start;
usage.site_end_byte = end;
cbm_usages_push(ctx->usages, ctx->arena, usage);
+1
View File
@@ -664,6 +664,7 @@ static void ocaml_collect_structure(cbm_source_walk_t *walk, const char *owner,
}
}
}
ts_tree_cursor_delete(&cursor);
}
/* Where this file stands among the modules of its build. */
+3 -1
View File
@@ -29,7 +29,9 @@
* has no sub import of its own, and lists the name in @EXPORT or @EXPORT_OK. What it
* lists can be a name it imported itself, which is then that module's export.
*
* `\&name` takes a reference to the sub the same lookup selects, without calling it.
* `\&name` takes a reference to the sub the same lookup selects, without calling it. Under a
* conditional or an operator the value is one of several, so the site only mentions the sub:
* the carrier from extraction says which.
*
* Literal glob assignment and lexical `my sub` replace a name, so that name
* abstains. A glob assigned from a computed name can touch any package anywhere
+1
View File
@@ -4811,6 +4811,7 @@ static void resolve_worker_impl(int worker_id, void *ctx_ptr) {
cbm_pxc_set_rust_manifest(NULL);
cbm_destroy_thread_parser();
cbm_slab_destroy_thread();
cbm_kind_in_set_free_cache(); /* a damaged source file's scan fills it here too */
cbm_service_pattern_cache_end();
cbm_pxc_thread_scratch_end();
file_node_cache_clear();
+1 -2
View File
@@ -4702,8 +4702,7 @@ static bool resolve_usages(file_resolver_t *resolver, CBMArena *arena) {
/* Source binding can establish a direct callable argument without a
* hybrid row. Composite expressions remain USAGE: the extraction
* carrier deliberately leaves may_be_call_reference false for them. */
if (!site && (usage->may_be_call_reference || resolver->file->language == CBM_LANG_PERL) &&
cbm_resolve_admit(&outcome) &&
if (!site && usage->may_be_call_reference && cbm_resolve_admit(&outcome) &&
callable_node(cbm_gbuf_find_by_qn(resolver->file->graph, outcome.target)))
relation = "CALL_REFERENCE";
/* Reading a property hands over its result, not the function. */
+18 -43
View File
@@ -315,27 +315,17 @@ static const RP_QualityGolden rp_quality_goldens[] = {
.label = "Function",
.declaration_line = 1,
.declaration_text = "sub handler {}"},
.mode = RQ_KNOWN_GAP,
.gap_id = "perl_exact_coderef_is_call_reference-1",
.why = "Delegate or coderef argument values and callable-parameter applicability require an "
"audited proof bridge.",
.tried = "Original full-MCP fixture retained; exact source occurrence and target declaration "
"reviewed; raw and forbidden assertions retained."}},
.mode = RQ_REQUIRED}},
{"repro_perl_exact_coderef_is_call_reference",
{.case_id = "perl_exact_coderef_is_call_reference-2",
.site = {.file = "refs.pl", .caller = "argument", .start_byte = 66, .end_byte = 83},
.relation = "CALLS",
.target = {.file = "refs.pl",
.suffix = "refs.accept",
.suffix = "refs.submit",
.label = "Function",
.declaration_line = 2,
.declaration_text = "sub accept { my ($callback) = @_; }"},
.mode = RQ_KNOWN_GAP,
.gap_id = "perl_exact_coderef_is_call_reference-2",
.why = "Delegate or coderef argument values and callable-parameter applicability require an "
"audited proof bridge.",
.tried = "Original full-MCP fixture retained; exact source occurrence and target declaration "
"reviewed; raw and forbidden assertions retained."}},
.declaration_text = "sub submit { my ($callback) = @_; }"},
.mode = RQ_REQUIRED}},
{"repro_rust_direct_scoped_function_value_is_exact_reference",
{.case_id = "rust_direct_scoped_function_value_is_exact_reference-1",
.site = {.file = "main.rs", .caller = "scoped_argument", .start_byte = 83, .end_byte = 98},
@@ -890,49 +880,31 @@ static const RP_QualityGolden rp_quality_goldens[] = {
.site = {.file = "complex.pl", .caller = "complex", .start_byte = 99, .end_byte = 138},
.relation = "CALLS",
.target = {.file = "complex.pl",
.suffix = "complex.accept",
.suffix = "complex.submit",
.label = "Function",
.declaration_line = 3,
.declaration_text = "sub accept { my ($callback) = @_; }"},
.mode = RQ_KNOWN_GAP,
.gap_id = "perl_conditional_coderefs_stay_usage-1",
.why = "Conditional callable values retain genuine target mentions, but complete source "
"binding, callable-argument applicability and value-reference proof are not yet "
"audited for this language/form.",
.tried = "Original full-MCP fixture retained; exact source occurrence and target declaration "
"reviewed; raw and forbidden assertions retained."}},
.declaration_text = "sub submit { my ($callback) = @_; }"},
.mode = RQ_REQUIRED}},
{"repro_perl_conditional_coderefs_stay_usage",
{.case_id = "perl_conditional_coderefs_stay_usage-2",
.site = {.file = "complex.pl", .caller = "complex", .start_byte = 116, .end_byte = 123},
.site = {.file = "complex.pl", .caller = "complex", .start_byte = 114, .end_byte = 123},
.relation = "USAGE",
.target = {.file = "complex.pl",
.suffix = "complex.handler",
.label = "Function",
.declaration_line = 1,
.declaration_text = "sub handler {}"},
.mode = RQ_KNOWN_GAP,
.gap_id = "perl_conditional_coderefs_stay_usage-2",
.why = "Conditional callable values retain genuine target mentions, but complete source "
"binding, callable-argument applicability and value-reference proof are not yet "
"audited for this language/form.",
.tried = "Original full-MCP fixture retained; exact source occurrence and target declaration "
"reviewed; raw and forbidden assertions retained."}},
.mode = RQ_REQUIRED}},
{"repro_perl_conditional_coderefs_stay_usage",
{.case_id = "perl_conditional_coderefs_stay_usage-3",
.site = {.file = "complex.pl", .caller = "complex", .start_byte = 128, .end_byte = 137},
.site = {.file = "complex.pl", .caller = "complex", .start_byte = 126, .end_byte = 137},
.relation = "USAGE",
.target = {.file = "complex.pl",
.suffix = "complex.alternate",
.label = "Function",
.declaration_line = 2,
.declaration_text = "sub alternate {}"},
.mode = RQ_KNOWN_GAP,
.gap_id = "perl_conditional_coderefs_stay_usage-3",
.why = "Conditional callable values retain genuine target mentions, but complete source "
"binding, callable-argument applicability and value-reference proof are not yet "
"audited for this language/form.",
.tried = "Original full-MCP fixture retained; exact source occurrence and target declaration "
"reviewed; raw and forbidden assertions retained."}},
.mode = RQ_REQUIRED}},
{"repro_python_local_function_shadows_imported_callable",
{.case_id = "repro_python_local_function_shadows_imported_callable-reference",
.site = {.file = "use.py", .caller = "crossArgument", .start_byte = 121, .end_byte = 129},
@@ -2302,10 +2274,12 @@ TEST(repro_tsx_exact_bound_method_is_call_reference) {
PASS();
}
/* The registrar is not called `accept`: that is a Perl builtin, only an import overrides it
* (perlsub), and `perl -c` rejects `accept(\&handler)` as too few arguments to the builtin. */
TEST(repro_perl_exact_coderef_is_call_reference) {
static const char source[] = "sub handler {}\n"
"sub accept { my ($callback) = @_; }\n"
"sub argument { accept(\\&handler); }\n";
"sub submit { my ($callback) = @_; }\n"
"sub argument { submit(\\&handler); }\n";
int rc = rp_assert_exact_function_value_reference_quality(
"refs.pl", source, CBM_LANG_PERL, "Function", "repro_perl_exact_coderef_is_call_reference");
if (rc != 0)
@@ -3564,12 +3538,13 @@ TEST(repro_php_complex_first_class_callable_stays_usage) {
PASS();
}
/* The registrar is not called `accept`: see repro_perl_exact_coderef_is_call_reference. */
TEST(repro_perl_conditional_coderefs_stay_usage) {
static const char source[] = "sub handler {}\n"
"sub alternate {}\n"
"sub accept { my ($callback) = @_; }\n"
"sub submit { my ($callback) = @_; }\n"
"sub complex { my ($flag) = @_; "
"accept($flag ? \\&handler : \\&alternate); }\n";
"submit($flag ? \\&handler : \\&alternate); }\n";
int rc = rp_assert_complex_function_values_stay_usage_quality(
"complex.pl", source, CBM_LANG_PERL, "Function",
"repro_perl_conditional_coderefs_stay_usage");
+3 -3
View File
@@ -184,9 +184,9 @@ static const MKC_Golden mkc_goldens[] = {
{"mkc_c2_csharp_operator_plus", "operator+", "new Vec2(a.X + b.X, a.Y + b.Y)", "Vec2",
" public Vec2(float x, float y) { X = x; Y = y; }", "Method", 4, 0, true},
{"mkc_c2_scala_symbolic_method", "run", "a + b", "+",
" def +(other: Vec2): Vec2 = Vec2(x + other.x, y + other.y)", "Method", 2, 0, false},
" def +(other: Vec2): Vec2 = Vec2(x + other.x, y + other.y)", "Method", 2, 0, true},
{"mkc_c2_scala_symbolic_method", "run", "(a + b).dot(b)", "dot",
" def dot(other: Vec2): Double = x * other.x + y * other.y", "Method", 3, 0, false},
" def dot(other: Vec2): Double = x * other.x + y * other.y", "Method", 3, 0, true},
{"mkc_c2_ruby_operator_plus", "+", "Vec2.new(@x + other.x, @y + other.y)", "initialize",
" def initialize(x, y)", "Method", 3, 0, true},
{"mkc_c4_typescript_async_await", "getData", "fetch(url)", "fetch",
@@ -211,7 +211,7 @@ static const MKC_Golden mkc_goldens[] = {
{"mkc_c4_swift_async_await", "run", "getData(url: url)", "getData",
"func getData(url: String) async -> String {", "Function", 5, 0, true},
{"mkc_c5_scala_generic_call", "run", "first(ns)", "first",
"def first[T](xs: List[T]): Option[T] =", "Function", 1, 0, false},
"def first[T](xs: List[T]): Option[T] =", "Function", 1, 0, true},
{"mkc_c5_swift_generic_call", "run", "maxOf(a, b)", "maxOf",
"func maxOf<T: Comparable>(_ a: T, _ b: T) -> T {", "Function", 1, 0, true},
{"mkc_c5_ruby_duck_typed_call", "run", "first(items)", "first", "def first(collection)",
+33 -20
View File
@@ -4305,12 +4305,7 @@ TEST(pipeline_call_reference_sequential_parallel_edge_set_parity) {
.label = "Function",
.declaration_line = 1,
.declaration_text = "sub perlReferenceTarget {}"},
.mode = RQ_KNOWN_GAP,
.gap_id = "callback-perl-coderef",
.why = "Package/subroutine declaration identity and typeglob/redefinition barriers lack a "
"proof adapter.",
.tried = "Focused pipeline probe: direct coderef has a legacy carrier only; no legacy "
"confidence is admitted."},
.mode = RQ_REQUIRED},
{.case_id = "javascript-script-shadow-control",
.site = {.file = "shadow.js",
.caller = "shadow.javascriptShadowSite",
@@ -4691,9 +4686,9 @@ TEST(pipeline_call_reference_sequential_parallel_edge_set_parity) {
parallel_reference[i]);
}
for (int i = 0; i < pair_count; i++) {
/* These six independent expectations are counted above as source-audited
/* These five independent expectations are counted above as source-audited
* quality gaps; recovery must promote them to required in the oracle. */
if (i != 4 && i != 5 && i != 7 && i != 10 && i != 12 && i != 13)
if (i != 4 && i != 5 && i != 7 && i != 10 && i != 12)
ASSERT_GT(sequential_reference[i], 0);
ASSERT_EQ(parallel_reference[i], sequential_reference[i]);
ASSERT_EQ(sequential_usage[i], 0);
@@ -15477,26 +15472,44 @@ static bool rust_std_receiver_quality(cbm_store_t *store, const char *project, c
.site = {.file = "src/lib.rs", .caller = "lib.real_caller", .needle = "EvidenceTier(1)"},
.relation = "CALLS",
.target = {.file = "src/lib.rs",
.suffix = "lib.EvidenceTier",
.label = "Struct",
.declaration_line = 4,
.declaration_text = "pub struct EvidenceTier(pub u8);"},
.mode = RQ_KNOWN_GAP,
.gap_id = "RUST-TUPLE-STRUCT-CONSTRUCTOR-IDENTITY",
.why = "The tuple-struct constructor is genuine but has no independent callable "
"declaration identity in the current graph.",
.tried = "Retained the exact source invocation and struct anchor; no synthesized method "
"or legacy confidence substitutes for a constructor proof."},
.mode = RQ_REQUIRED},
{.case_id = "rust.tuple-constructor.argument",
.site = {.file = "src/lib.rs", .caller = "lib.real_caller", .needle = "EvidenceTier(2)"},
.relation = "CALLS",
.target = {.file = "src/lib.rs",
.suffix = "lib.EvidenceTier",
.label = "Struct",
.declaration_line = 4,
.declaration_text = "pub struct EvidenceTier(pub u8);"},
.mode = RQ_KNOWN_GAP,
.gap_id = "RUST-TUPLE-STRUCT-CONSTRUCTOR-IDENTITY",
.why = "The argument independently invokes the tuple-struct constructor; its callable "
"identity is not represented.",
.tried = "Kept the second raw call site in the denominator rather than merging it with "
"the receiver constructor."},
.mode = RQ_REQUIRED},
{.case_id = "rust.return-type.usage",
.site = {.file = "src/lib.rs",
.caller = "lib.real_caller",
.needle = "EvidenceTier",
.occurrence_index = 5},
.relation = "USAGE",
.target = {.file = "src/lib.rs",
.suffix = "lib.EvidenceTier",
.label = "Struct",
.declaration_line = 4,
.declaration_text = "pub struct EvidenceTier(pub u8);"},
.mode = RQ_REQUIRED},
{.case_id = "rust.return-type.uses-type",
.site = {.file = "src/lib.rs",
.caller = "lib.real_caller",
.needle = "EvidenceTier",
.occurrence_index = 5},
.relation = "USES_TYPE",
.target = {.file = "src/lib.rs",
.suffix = "lib.EvidenceTier",
.label = "Struct",
.declaration_line = 4,
.declaration_text = "pub struct EvidenceTier(pub u8);"},
.mode = RQ_REQUIRED},
{.case_id = "rust.iterator-closure.receiver",
.site = {.file = "src/lib.rs",
.caller = "lib.untyped_receiver",
+23
View File
@@ -1941,6 +1941,12 @@ static const char PL2_THING[] =
"sub takes_ref { my $r = \\&own; $r }\n"
"sub takes_qualified_ref { keep(\\&My::Root::root_m) }\n"
"sub no_absent_ref { my $r = \\&absent; $r }\n"
"sub also { return 5; }\n"
"sub picks_one { my $f = shift; keep($f ? \\&own : \\&also) }\n"
"sub falls_back { my $f = shift; my $r = $f || \\&also; $r }\n"
"sub low_or { my $f = shift; my $r = ($f or \\&also); $r }\n"
"sub in_parens { my $f = shift; my $r = $f ? (\\&own) : 0; $r }\n"
"sub table_entry { my %t = (a => \\&own); $t{a} }\n"
"1;\n";
static const char PL3_THING[] =
@@ -2011,6 +2017,18 @@ TEST(resolver_source_perl_invocant_reexports_and_code_references) {
"sub own { return 4; }"),
SL_REF_AT("code-reference-with-its-package", "lib/My/Thing.pm", "Thing.takes_qualified_ref", "\\&My::Root::root_m", 0, "lib/My/Root.pm", "Root.root_m", "Function", 2,
"sub root_m { return 3; }"),
SL_USE_AT("conditional-branch-mentions-its-sub", "lib/My/Thing.pm", "Thing.picks_one", "\\&own", 1, "lib/My/Thing.pm", "Thing.own", "Function", 5,
"sub own { return 4; }"),
SL_USE_AT("other-conditional-branch-mentions-its-sub", "lib/My/Thing.pm", "Thing.picks_one", "\\&also", 0, "lib/My/Thing.pm", "Thing.also", "Function", 19,
"sub also { return 5; }"),
SL_USE_AT("logical-operand-mentions-its-sub", "lib/My/Thing.pm", "Thing.falls_back", "\\&also", 1, "lib/My/Thing.pm", "Thing.also", "Function", 19,
"sub also { return 5; }"),
SL_USE_AT("low-precedence-operand-mentions-its-sub", "lib/My/Thing.pm", "Thing.low_or", "\\&also", 2, "lib/My/Thing.pm", "Thing.also", "Function", 19,
"sub also { return 5; }"),
SL_USE_AT("parentheses-change-nothing", "lib/My/Thing.pm", "Thing.in_parens", "\\&own", 2, "lib/My/Thing.pm", "Thing.own", "Function", 5,
"sub own { return 4; }"),
SL_REF_AT("table-entry-names-one-sub", "lib/My/Thing.pm", "Thing.table_entry", "\\&own", 3, "lib/My/Thing.pm", "Thing.own", "Function", 5,
"sub own { return 4; }"),
};
static const RQ_Forbidden forbidden[] = {
SL_DENY_AT("plain-function-takes-whatever-it-is-given", "lib/My/Thing.pm", "Thing._select", "$_[0]->own", 0),
@@ -2018,6 +2036,11 @@ TEST(resolver_source_perl_invocant_reexports_and_code_references) {
SL_DENY_AT("second-shift-is-the-second-argument", "lib/My/Thing.pm", "Thing.second_shift", "shift->own", 1),
SL_DENY_AT("anonymous-sub-has-its-own-arguments", "lib/My/Thing.pm", "Thing.anon_has_its_own_args", "shift->own", 2),
SL_NO_REF_AT("code-reference-to-nothing", "lib/My/Thing.pm", "Thing.no_absent_ref", "\\&absent", 0),
SL_NO_REF_AT("conditional-branch-is-no-reference", "lib/My/Thing.pm", "Thing.picks_one", "\\&own", 1),
SL_NO_REF_AT("other-conditional-branch-is-no-reference", "lib/My/Thing.pm", "Thing.picks_one", "\\&also", 0),
SL_NO_REF_AT("logical-operand-is-no-reference", "lib/My/Thing.pm", "Thing.falls_back", "\\&also", 1),
SL_NO_REF_AT("low-precedence-operand-is-no-reference", "lib/My/Thing.pm", "Thing.low_or", "\\&also", 2),
SL_NO_REF_AT("parentheses-are-no-reference", "lib/My/Thing.pm", "Thing.in_parens", "\\&own", 2),
};
ASSERT(sl_check("perl-invocant", ".pm", "package Filler;\nsub f { return 1; }\n1;\n", sources,
sizeof(sources) / sizeof(sources[0]), expected,