Skip to content

Commit da61c81

Browse files
DeusDataastandrik
andcommitted
fix(lsp): unify the two type short-name indexes that broke the main build
main does not compile. internal/cbm/lsp/type_registry.h declares type_short_buckets, type_short_entries and type_short_bucket_count twice, and cbm_registry_types_by_short_name twice with different parameter types. Two changes implemented the same feature independently: a4c0ffb perf(cs): eliminate the C# corpus-proportional scans (2026-08-16, ours) CBMTypeShortIter, cbm_type_short_iter_next 793716d perf(lsp): index C++ short-name type lookups (PR #1679, astandrik) CBMTypeNameIter, cbm_type_name_iter_next They landed in different hunks of the same struct and the same header section, so git merged them with no conflict and nothing failed until the merge commit was built. This is the failure mode where a clean merge is not evidence that two changes compose. The two iterators are structurally identical -- same five fields, byte-identical _next bodies reading the same reg->type_short_entries chain. They differ in one place, and it matters: #1679 on aux-index allocation failure, sets tail_i = 0, so the iterator degrades to a full types[] scan and the candidate set is unchanged. a4c0ffb sets tail_i = reg->type_qn_entry_count unconditionally, so on that same failure it SKIPS the first type_qn_entry_count types and silently yields an incomplete candidate set. So this keeps a4c0ffb's names -- CBMTypeShortIter reads correctly beside its type_short_* members and beside CBMTypeEmbedIter and CBMFreeFuncIter -- and #1679's body, which is the correct one. The surviving declaration carries both rationales: the C++ short-name lookup and cs_resolve_type_name's step-9 fallback are now stated as two consumers of one index, which is what they are. The merge also broke two comment/member pairings, repaired here: the duplicated members had displaced the free-function index members from under their own comment, and the CBMTypeShortIter block had been interleaved between CBMFreeFuncIter's typedef and its declarations. No behaviour change for either consumer beyond the allocation-failure path, which strictly gains coverage for C#. c_lsp.c and cs_lsp.c now call one function. #1679's tests, including the fault-injection case that NULLs the buckets and asserts the full-scan fallback, carry over unchanged apart from the type name. Local: c_lsp, cs_lsp and registry -- 881 passed, 0 failed. Co-Authored-By: astandrik <astandrik@yandex-team.ru> Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
1 parent 7808686 commit da61c81

4 files changed

Lines changed: 22 additions & 73 deletions

File tree

‎internal/cbm/lsp/c_lsp.c‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2818,10 +2818,10 @@ static const CBMRegisteredFunc *c_lookup_member_depth(CLSPContext *ctx, const ch
28182818
const char *shortn = dot ? dot + 1 : type_qn;
28192819
size_t slen = strlen(shortn);
28202820
const char *best_qn = NULL;
2821-
CBMTypeNameIter it;
2821+
CBMTypeShortIter it;
28222822
cbm_registry_types_by_short_name(ctx->registry, shortn, &it);
28232823
int i;
2824-
while ((i = cbm_type_name_iter_next(&it)) >= 0) {
2824+
while ((i = cbm_type_short_iter_next(&it)) >= 0) {
28252825
const char *q = ctx->registry->types[i].qualified_name;
28262826
if (!q) {
28272827
continue;

‎internal/cbm/lsp/type_registry.c‎

Lines changed: 2 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,7 @@ static void build_ffunc_short_index(CBMTypeRegistry *reg, CBMArena *idx_arena) {
299299
}
300300

301301
void cbm_registry_types_by_short_name(const CBMTypeRegistry *reg, const char *short_name,
302-
CBMTypeNameIter *out) {
302+
CBMTypeShortIter *out) {
303303
out->reg = reg;
304304
out->hash = fnv1a(short_name);
305305
if (reg->type_qn_buckets && reg->type_qn_bucket_count > 0) {
@@ -319,7 +319,7 @@ void cbm_registry_types_by_short_name(const CBMTypeRegistry *reg, const char *sh
319319
}
320320
}
321321

322-
int cbm_type_name_iter_next(CBMTypeNameIter *it) {
322+
int cbm_type_short_iter_next(CBMTypeShortIter *it) {
323323
const CBMTypeRegistry *reg = it->reg;
324324
while (it->chain_idx >= 0) {
325325
const CBMRegistryHashEntry *e = &reg->type_short_entries[it->chain_idx];
@@ -413,42 +413,6 @@ int cbm_free_func_iter_next(CBMFreeFuncIter *it) {
413413
return -1;
414414
}
415415

416-
void cbm_registry_types_by_short_name(const CBMTypeRegistry *reg, const char *short_name,
417-
CBMTypeShortIter *out) {
418-
out->reg = reg;
419-
out->hash = fnv1a(short_name);
420-
if (reg->type_qn_buckets && reg->type_qn_bucket_count > 0) {
421-
if (reg->type_short_buckets && reg->type_short_bucket_count > 0) {
422-
int slot = (int)(out->hash & (uint64_t)(reg->type_short_bucket_count - 1));
423-
out->chain_idx = reg->type_short_buckets[slot];
424-
} else {
425-
out->chain_idx = -1;
426-
}
427-
out->tail_i = reg->type_qn_entry_count;
428-
out->tail_end = reg->type_count;
429-
} else {
430-
out->chain_idx = -1;
431-
out->tail_i = 0;
432-
out->tail_end = reg->type_count;
433-
}
434-
}
435-
436-
int cbm_type_short_iter_next(CBMTypeShortIter *it) {
437-
const CBMTypeRegistry *reg = it->reg;
438-
while (it->chain_idx >= 0) {
439-
const CBMRegistryHashEntry *e = &reg->type_short_entries[it->chain_idx];
440-
int p = e->payload_index;
441-
uint64_t h = e->hash;
442-
it->chain_idx = e->next_index;
443-
if (h != it->hash)
444-
continue;
445-
return p;
446-
}
447-
if (it->tail_i < it->tail_end)
448-
return it->tail_i++;
449-
return -1;
450-
}
451-
452416
void cbm_registry_methods(const CBMTypeRegistry *reg, const char *receiver_qn,
453417
const char *method_name, CBMMethodIter *out) {
454418
memset(out, 0, sizeof(*out));

‎internal/cbm/lsp/type_registry.h‎

Lines changed: 7 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ typedef struct CBMTypeRegistry {
119119
int *type_short_buckets;
120120
CBMRegistryHashEntry *type_short_entries;
121121
int type_short_bucket_count;
122+
int type_short_entry_count;
122123
// Embedded-type index: fnv1a(bare last-'.'-segment of each embedded_type) -> chain
123124
// of TYPE indices declaring it. payload_index = type index (a type may appear once
124125
// per embedded entry; consumers dedup adjacent same-type via the iterator).
@@ -128,10 +129,6 @@ typedef struct CBMTypeRegistry {
128129
int type_embed_entry_count;
129130
// Free-function short-name index: fnv1a(short_name) -> chain of FREE-function
130131
// (receiver_type==NULL) indices. payload_index = func index.
131-
int *type_short_buckets;
132-
CBMRegistryHashEntry *type_short_entries;
133-
int type_short_bucket_count;
134-
int type_short_entry_count;
135132
int *ffunc_short_buckets;
136133
CBMRegistryHashEntry *ffunc_short_entries;
137134
int ffunc_short_bucket_count;
@@ -236,16 +233,19 @@ const CBMRegisteredFunc *cbm_registry_lookup_symbol_by_types(const CBMTypeRegist
236233
// any post-finalize tail; otherwise it degrades to the original full scan. Results
237234
// preserve ascending registry order. The index is a hash prefilter; callers must
238235
// re-check their exact predicate, including tail entries.
236+
// Built by finalize into type_short_buckets. Shared by the C++ short-name lookup
237+
// and by cs_resolve_type_name's step-9 fallback, which scanned type_count per
238+
// unresolved name — quadratic against the shared Tier-2 registry.
239239
typedef struct {
240240
const CBMTypeRegistry *reg;
241241
uint64_t hash;
242242
int chain_idx;
243243
int tail_i;
244244
int tail_end;
245-
} CBMTypeNameIter;
245+
} CBMTypeShortIter;
246246
void cbm_registry_types_by_short_name(const CBMTypeRegistry *reg, const char *short_name,
247-
CBMTypeNameIter *out);
248-
int cbm_type_name_iter_next(CBMTypeNameIter *it);
247+
CBMTypeShortIter *out);
248+
int cbm_type_short_iter_next(CBMTypeShortIter *it);
249249

250250
// Iterate registry TYPE indices whose embedded_types contain an entry whose BARE
251251
// name (last '.'-segment) equals `bare`. On a finalized registry this walks the
@@ -278,21 +278,6 @@ typedef struct {
278278
int tail_i;
279279
int tail_end;
280280
} CBMFreeFuncIter;
281-
/* Iterate TYPE indices sharing a short name — the type-side twin of the free-
282-
* function iterator. Built by finalize into type_short_buckets; degrades to a
283-
* full types[] scan on an unfinalized registry (same correctness, old cost).
284-
* Added for cs_resolve_type_name's step-9 fallback, which scanned type_count
285-
* per unresolved name — quadratic against the shared Tier-2 registry. */
286-
typedef struct {
287-
const CBMTypeRegistry *reg;
288-
uint64_t hash;
289-
int chain_idx;
290-
int tail_i;
291-
int tail_end;
292-
} CBMTypeShortIter;
293-
void cbm_registry_types_by_short_name(const CBMTypeRegistry *reg, const char *short_name,
294-
CBMTypeShortIter *out);
295-
int cbm_type_short_iter_next(CBMTypeShortIter *it);
296281

297282
void cbm_registry_free_funcs_by_short_name(const CBMTypeRegistry *reg, const char *short_name,
298283
CBMFreeFuncIter *out);

‎tests/test_c_lsp.c‎

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15331,13 +15331,13 @@ TEST(registry_short_name_indexes) {
1533115331
/* Qualified-name bare segment "Trait": types 0, 4, then the bare-QN type
1533215332
* 5. The iterator is a hash prefilter, so apply the exact predicate before
1533315333
* asserting its order just like production consumers do. */
15334-
CBMTypeNameIter nit;
15334+
CBMTypeShortIter nit;
1533515335
cbm_registry_types_by_short_name(&reg, "Trait", &nit);
1533615336
{
1533715337
int expected[] = {0, 4, 5};
1533815338
int exact_count = 0;
1533915339
int candidate;
15340-
while ((candidate = cbm_type_name_iter_next(&nit)) >= 0) {
15340+
while ((candidate = cbm_type_short_iter_next(&nit)) >= 0) {
1534115341
const char *qn = reg.types[candidate].qualified_name;
1534215342
const char *last_dot = qn ? strrchr(qn, '.') : NULL;
1534315343
const char *candidate_short = last_dot ? last_dot + 1 : qn;
@@ -15352,7 +15352,7 @@ TEST(registry_short_name_indexes) {
1535215352
{
1535315353
int exact_count = 0;
1535415354
int candidate;
15355-
while ((candidate = cbm_type_name_iter_next(&nit)) >= 0) {
15355+
while ((candidate = cbm_type_short_iter_next(&nit)) >= 0) {
1535615356
const char *qn = reg.types[candidate].qualified_name;
1535715357
const char *last_dot = qn ? strrchr(qn, '.') : NULL;
1535815358
const char *candidate_short = last_dot ? last_dot + 1 : qn;
@@ -15382,7 +15382,7 @@ TEST(registry_short_name_indexes) {
1538215382

1538315383
int actual;
1538415384
for (;;) {
15385-
actual = cbm_type_name_iter_next(&nit);
15385+
actual = cbm_type_short_iter_next(&nit);
1538615386
if (actual < 0)
1538715387
break;
1538815388
const char *qn = reg.types[actual].qualified_name;
@@ -15437,19 +15437,19 @@ TEST(registry_short_name_indexes) {
1543715437
t.short_name = "Trait";
1543815438
cbm_registry_add_type(&reg, t);
1543915439
cbm_registry_types_by_short_name(&reg, "Trait", &nit);
15440-
ASSERT_EQ(cbm_type_name_iter_next(&nit), 0);
15441-
ASSERT_EQ(cbm_type_name_iter_next(&nit), 4);
15442-
ASSERT_EQ(cbm_type_name_iter_next(&nit), 5);
15443-
ASSERT_EQ(cbm_type_name_iter_next(&nit), tail_type_i);
15444-
ASSERT_EQ(cbm_type_name_iter_next(&nit), -1);
15440+
ASSERT_EQ(cbm_type_short_iter_next(&nit), 0);
15441+
ASSERT_EQ(cbm_type_short_iter_next(&nit), 4);
15442+
ASSERT_EQ(cbm_type_short_iter_next(&nit), 5);
15443+
ASSERT_EQ(cbm_type_short_iter_next(&nit), tail_type_i);
15444+
ASSERT_EQ(cbm_type_short_iter_next(&nit), -1);
1544515445

1544615446
int *saved_type_short_buckets = reg.type_short_buckets;
1544715447
reg.type_short_buckets = NULL;
1544815448
cbm_registry_types_by_short_name(&reg, "Trait", &nit);
1544915449
int fallback_expected[] = {0, 4, 5, tail_type_i};
1545015450
int fallback_count = 0;
1545115451
int candidate;
15452-
while ((candidate = cbm_type_name_iter_next(&nit)) >= 0) {
15452+
while ((candidate = cbm_type_short_iter_next(&nit)) >= 0) {
1545315453
const char *qn = reg.types[candidate].qualified_name;
1545415454
const char *last_dot = qn ? strrchr(qn, '.') : NULL;
1545515455
const char *candidate_short = last_dot ? last_dot + 1 : qn;
@@ -15479,7 +15479,7 @@ TEST(registry_short_name_indexes) {
1547915479

1548015480
cbm_registry_types_by_short_name(&reg, "Trait", &nit);
1548115481
fallback_count = 0;
15482-
while ((candidate = cbm_type_name_iter_next(&nit)) >= 0) {
15482+
while ((candidate = cbm_type_short_iter_next(&nit)) >= 0) {
1548315483
const char *qn = reg.types[candidate].qualified_name;
1548415484
const char *last_dot = qn ? strrchr(qn, '.') : NULL;
1548515485
const char *candidate_short = last_dot ? last_dot + 1 : qn;

0 commit comments

Comments
 (0)