GCC Code Coverage Report


src/
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
32 / 32
100.0%
Branches:
10 / 10, 2 excl
100.0%
Functions:
7 / 8
87.5%

global/type-name-disambiguator.spice
Line Branch Exec Source
1 // Copyright (c) 2021-2026 ChilliBits. All rights reserved.
2
3 // Std imports
4 import "std/data/vector";
5 import "std/data/unordered-map";
6 import "std/type/type-conversion";
7 import "std/os/recursive-mutex";
8
9 // Own imports
10 import "@/util/concurrency";
11
12 /**
13 * Two structs or interfaces that share a simple name but stem from independent declarations (e.g. a package-private
14 * `Node<T>` declared separately in two source files, see issue #1253) are distinct types, but render to the same
15 * name. That collision surfaces both as a type-checker conflation (same manifestation signature) and as a linker/codegen
16 * clash (same mangled name). To keep them apart without affecting the common, non-colliding case, this registry hands
17 * out a deterministic disambiguation suffix for the second and any further distinct type sharing a given name. The
18 * first type to claim a name keeps it unchanged, so nothing changes unless a name is actually reused.
19 *
20 * Spice only supports globals of primitive type, so like the TypeRegistry, the disambiguator is a normal struct owned by the GlobalResourceManager, which registers it as the active one.
21 * Since the GlobalResourceManager is created per compilation, the state is automatically cleared between compilations.
22 */
23 1821 public type TypeNameDisambiguator struct {
24 // Maps a simple type name to the list of distinct type ids claiming it, in first-seen order
25 UnorderedMap<String, Vector<unsigned long>> claimedTypeIds
26 // Name mangling claims names while the back end runs in parallel
27 RecursiveMutex claimedTypeIdsMutex
28 }
29
30 // Active type name disambiguator. It is owned by the global resource manager.
31 TypeNameDisambiguator* ACTIVE_TYPE_NAME_DISAMBIGUATOR;
32
33 /**
34 * Make the given type name disambiguator the active one. getDisambiguationSuffix() operates on it.
35 *
36 * @param disambiguator Type name disambiguator
37 */
38 1055 public p setActiveTypeNameDisambiguator(TypeNameDisambiguator* disambiguator) {
39 1055 ACTIVE_TYPE_NAME_DISAMBIGUATOR = disambiguator;
40 1055 }
41
42 /**
43 * Get the active type name disambiguator
44 *
45 * @return Active type name disambiguator
46 */
47 569534 f<TypeNameDisambiguator*> getActiveTypeNameDisambiguator() {
48 569534 assert ACTIVE_TYPE_NAME_DISAMBIGUATOR != nil<TypeNameDisambiguator*>;
49 569534 return ACTIVE_TYPE_NAME_DISAMBIGUATOR;
50 }
51
52 /**
53 * Get the disambiguation suffix for a struct/interface type with the given name and type id.
54 * The first type id to claim a name keeps it unchanged (empty suffix); every further distinct type id sharing the name
55 * receives a deterministic, dot-separated suffix (e.g. ".1", ".2"). A dot is used on purpose: it is not a valid Spice
56 * identifier character, so the disambiguated name can never collide with a genuine, user-declared type name.
57 *
58 * @param name Simple type name
59 * @param typeId Custom type id of the type
60 * @return Disambiguation suffix (empty for the first claimer of the name)
61 */
62 569534 public f<String> TypeNameDisambiguator.getDisambiguationSuffix(const String& name, unsigned long typeId) {
63 569534 ConditionalLock _lock = ConditionalLock(&this.claimedTypeIdsMutex);
64
65
2/2
✓ Branch 0 taken 566133 times.
✓ Branch 1 taken 3401 times.
569534 if !this.claimedTypeIds.contains(name) {
66 3401 this.claimedTypeIds.upsert(name, Vector<unsigned long>());
67 3401 }
68 569534 Vector<unsigned long>& ids = this.claimedTypeIds.get(name);
69
70 // Find the index of the type id among the ones already claiming this name
71 569534 unsigned long index = ids.getSize();
72
2/2
✓ Branch 0 taken 3493 times.
✓ Branch 1 taken 571897 times.
575390 for unsigned long i = 0l; i < ids.getSize(); i++ {
73
2/2
✓ Branch 0 taken 566041 times.
✓ Branch 1 taken 5856 times.
571897 if ids.get(i) == typeId {
74 566041 index = i;
75 566041 break;
76 }
77 5856 }
78 // If not seen yet, claim the name
79
2/2
✓ Branch 0 taken 566041 times.
✓ Branch 1 taken 3493 times.
569534 if index == ids.getSize() {
80 3493 ids.pushBack(typeId);
81 3493 }
82
83 // The first claimer keeps the plain name to avoid churn for the common, non-colliding case
84
2/2
✓ Branch 0 taken 3596 times.
✓ Branch 1 taken 565938 times.
569534 if index == 0l {
85 1131876 return String();
86 }
87 7192 return String(".") + toString(index);
88 569534 }
89
90 /**
91 * Get the disambiguation suffix for a struct/interface type with the given name and type id from the active type name
92 * disambiguator.
93 *
94 * @param name Simple type name
95 * @param typeId Custom type id of the type
96 * @return Disambiguation suffix (empty for the first claimer of the name)
97 */
98 569534 public f<String> getDisambiguationSuffix(const String& name, unsigned long typeId) {
99 569534 TypeNameDisambiguator* disambiguator = getActiveTypeNameDisambiguator();
100 569534 return disambiguator.getDisambiguationSuffix(name, typeId);
101 }
102
103 /**
104 * Clear the disambiguation registry
105 */
106 766 public p TypeNameDisambiguator.clear() {
107 766 this.claimedTypeIds.clear();
108 766 }
109