Running ./build.sh produces the following compiler error:
src/name_canonicalization.cpp(194): Assertion Failure: `!are_types_identical_unique_tuples(key->type, pair.type)`
This is a compiler error. Please report this.
Tried with a locally built (default debug configuration)
Odin: dev-2026-05:f03ec366c
OS: macOS Tahoe 26.3.1 (build 25D2128, kernel 25.3.0)
CPU: Apple M3 Pro
RAM: 18432 MiB
Backend: LLVM 22.1.4
Also tried with a build from Homebrew:
Odin: dev-2026-05:ea5175d86
- Entry point:
graphics_api/examples/bindings/main.odin - Depends on local packages:
graphics_api,webgl(via collectionsharedthat just points to workspace root) - Output:
public/graphics_api/examples/bindings/main.wasm
I tried removing stuff to get the minimal repro, but it looks like it's extremely sensitive to any changes. I tried my best to only include the essential parts of my workspace, but cutting further is very difficult because touching seemingly random things "fixes" the bug.
For example, simply adding a print statement at graphics_api/examples/bindings/main.odin:62
makes the compilation succeed.
It looks like the bug is most directly related to this type:
// graphics_api/graphics_api.odin:172
TypedUniformBuffer :: struct($T: typeid) {
buffer: UniformBuffer,
shape: [0]T,
}Especially the shape field, which I admit, is hacky. I use [0]T as a phantom
type, that allows me to extract T via reflection, but the value of the field
does not serve any purpose at runtime.
Nevertheless, I don't see how that little hack should contribute to the observed bug. I experimented with other variants. These are also bugged:
[1]T,^T,proc() -> T,
But these compile fine:
[^]T[dynamic]T
Maybe there is some insight in it, or maybe it's just another fragile equilibrium.
This type is used in one place. Removing this usage fixes the bug, which further ties the bug to it:
// graphics_api/examples/bindings/shaders.gen.odin:18
shaders_BindGroup0 :: struct #all_or_none {
// The single usage of the seemingly offending type (removing this line fixes the bug):
uniforms: gapi.TypedUniformBuffer(shaders_Uniforms) `@binding(0) @stages(vert)`,
texture: gapi.Texture `@binding(1) @stages(frag)`,
textureSampler: gapi.Sampler `@binding(2) @stages(frag)`,
}One more place that seems important is the invocation of the function that actually does the reflection stuff with the phantom type:
// graphics_api/examples/bindings/main.odin:58
groupLayout0_desc: gapi.BindGroupLayoutDescriptor
// This line seems important. Removing the call to inferBindGroupLayoutDescriptor stops the bug
groupLayout0_desc = gapi.inferBindGroupLayoutDescriptor(shaders_BindGroup0) or_else {}Because it's so fragile, my only hope was to try to debug through the compilation. I managed to catch the failing assertion while stepping through the compiler, but I don't know what I was looking at exactly:
> -exec bt
* thread #11, stop reason = EXC_BREAKPOINT (code=1, subcode=0x1001bf8e8)
* frame #0: 0x00000001001bf8e8 odin`type_set_update_with_mutex(s=0x0000000106b08878, pair=TypeInfoPair @ 0x0000000170371fa8, m=0x0000000106b08870) at name_canonicalization.cpp:194:3
frame #1: 0x00000001001bf498 odin`type_set_update_with_mutex(s=0x0000000106b08878, ptr=0x00000001071c91c0, m=0x0000000106b08870) at name_canonicalization.cpp:209:9
frame #2: 0x00000001001bea44 odin`add_min_dep_type_info(c=0x0000000106b087b8, t=0x00000001071c91c0) at checker.cpp:2548:6
frame #3: 0x00000001001bea74 odin`add_min_dep_type_info(c=0x0000000106b087b8, t=0x000000010716abb8) at checker.cpp:2555:3
frame #4: 0x00000001001bec78 odin`add_min_dep_type_info(c=0x0000000106b087b8, t=0x0000000107173020) at checker.cpp:2609:3
frame #5: 0x00000001001bf07c odin`add_min_dep_type_info(c=0x0000000106b087b8, t=0x0000000107172798) at checker.cpp:2672:6
frame #6: 0x00000001001bea74 odin`add_min_dep_type_info(c=0x0000000106b087b8, t=0x00000001071726f0) at checker.cpp:2555:3
frame #7: 0x00000001001bec50 odin`add_min_dep_type_info(c=0x0000000106b087b8, t=0x00000001071730f8) at checker.cpp:2601:3
frame #8: 0x00000001001bf07c odin`add_min_dep_type_info(c=0x0000000106b087b8, t=0x0000000107170a00) at checker.cpp:2672:6
frame #9: 0x00000001001bea74 odin`add_min_dep_type_info(c=0x0000000106b087b8, t=0x0000000107170958) at checker.cpp:2555:3
frame #10: 0x00000001001bec50 odin`add_min_dep_type_info(c=0x0000000106b087b8, t=0x0000000107176d28) at checker.cpp:2601:3
frame #11: 0x00000001001c0324 odin`add_dependency_to_set_worker(data=0x00000001098d2388) at checker.cpp:2813:3
frame #12: 0x000000010017e148 odin`thread_pool_thread_proc(thread=0x00000001062bc860) at thread_pool.cpp:239:6
frame #13: 0x000000010017de9c odin`internal_thread_proc(arg=0x00000001062bc860) at threading.cpp:609:2
frame #14: 0x0000000195d33c08 libsystem_pthread.dylib`_pthread_start + 136
> -exec f
frame #0: 0x00000001001bf8e8 odin`type_set_update_with_mutex(s=0x0000000106b08878, pair=TypeInfoPair @ 0x0000000170371fa8, m=0x0000000106b08870) at name_canonicalization.cpp:194:3
191 GB_ASSERT(hash_index < s->capacity);
192 for (usize i = 0; i < s->capacity; i++) {
193 TypeInfoPair *key = &s->keys[hash_index];
-> 194 GB_ASSERT(!are_types_identical_unique_tuples(key->type, pair.type));
^
195 if (key->hash == TYPE_SET_TOMBSTONE || key->hash == 0) {
196 *key = pair;
197 s->count++;
> -exec frame var
(TypeSet *) s = 0x0000000106b08878
(TypeInfoPair) pair = {
type = 0x00000001071c91c0
hash = 12732292366340213554
}
(RWSpinLock *) m = 0x0000000106b08870
(gbprivDefer<(unnamed class)>) _defer_233 = {
f = {
m = 0x0000000170371f98
}
}
(usize) mask = 63
(usize) hash = 12732292366340213554
(usize) hash_index = 5
(usize) i = 19
(TypeInfoPair *) key = 0x00000007cd0c2450
> key->type->Named->base
0x00000001071c91c0
> pair.type
0x00000001071c91c0
> key->type->Named->name->text
0x000000015571897a "BindGroupLayout :: ^_BindGroupLayout\nBuffer :: be_Buffer\nFragmentShader :: distinct Shader\nFramebuffer :: be_Framebuffer\nIndexBuffer :: distinct Buffer\nPipeline :: be_Pipeline\nPipelineLayout :: be_PipelineLayout\nProgram :: be_Program\nSampler :: be_Sampler\nShader :: be_Shader\nShaderLibrary :: be_ShaderLibrary\nTexture :: be_Texture\nTextureLoader :: be_TextureLoader\nTextureSource :: be_TextureSource\nUniformBuffer :: distinct Buffer\nVertexArray :: be_VertexArray\nVertexBuffer :: distinct Buffer\nVertexShader :: distinct Shader\n\nError :: enum {\n\tNone,\n Unknown,\n\tNotFound,\n\tMalformed,\n OutOfMemory,\n\tInvalidValue,\n InvalidType,\n InvalidOperation,\n NilValue,\n}\n\nErrorOrAllocatorError :: union #shared_nil { Error, runtime.Allocator_Error }\n\nAsyncResourceStatus :: enum { Empty, Pending, Ready, Error }\n\nBufferDescriptor :: struct {\n size: int,\n}\n\nBufferType :: enum u8 { Vertex, Index, Uniform }\n\nShaderType :: enum u8 { Vertex, Fragment }\n\nStepMode :: enum u8 { Vertex = 0, Instance }\n\nTopology :: enum u8 { PointList, "...