test(ir): lock protocol/impl lookup before A4.2 extraction (A4.2 scaffolding step 1)

Test-first scaffolding ahead of extracting src/ir/protocols.zig — no code change
to the refactor targets (registerProtocolDecl / registerImplBlock /
registerParamImpl / hasImplPlain / tryUserConversion / tryPackImplMatch /
createProtocolThunk / buildProtocolValue).

Adds 4 .ir snapshots (only 0400 existed for 04xx), each captured surgically via
`sx ir | normalize_ir`, path-free, idempotent, and print-free at IR-gen time
(the 0524 contamination lesson):
- 0413-protocols-parameterized-protocol-value  parameterized protocol
                                               (registerParamImpl + tryUserConversion)
- 0414-protocols-generic-struct-protocol-erase generic-struct erasure
                                               (createProtocolThunk + buildProtocolValue)
- 0416-protocols-auto-type-erasure             auto erasure (buildProtocolValue + thunk)
- 0528-packs-protocol-pack-methods             pack-variadic impl (tryPackImplMatch)

With existing 0400 (impl-for-builtin) they pin erasure (auto/generic/builtin) +
parameterized + pack-variadic + dispatch; the 0410/0411/0412 runtime anchors
already pin cross-module visibility + duplicate-impl rejections.

Adds 1 unit test via the public surface (no new exposure, mirroring A4.1
sub-step 1): registerProtocolDecl -> getProtocolInfo builds the dispatch method
table (method names, param_types with self excluded, concrete vs Self return
with ret_is_self + *void encoding). The impl-lookup / conversion plan-object
tests (hasImplPlain, tryUserConversion, tryPackImplMatch — private today) land
with the registry in sub-step 2.

zig build, zig build test, tests/run_examples.sh (357/0) all green.
This commit is contained in:
agra
2026-06-02 21:44:01 +03:00
parent 7ab5d7bee9
commit df386a422e
5 changed files with 17395 additions and 0 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -828,3 +828,54 @@ test "E1.4c noreturn typing: divergence shapes + if-else unification + block pro
defer alloc.destroy(both_div);
try std.testing.expectEqual(TypeId.noreturn, lowering.inferExprType(both_div));
}
// ── A4.2 test-first scaffolding: protocol-decl registration ──────────
// Lock `registerProtocolDecl`'s method-table output (consumed by protocol
// dispatch + impl planning) before the protocol/impl lookup moves to
// `src/ir/protocols.zig`. Public surface only (registerProtocolDecl +
// getProtocolInfo are pub) — the impl-lookup / conversion plan tests land
// with the registry in sub-step 2 (as A4.1's internal tests landed with
// GenericResolver). Arena: a non-parameterized protocol dupes its method
// infos via the module allocator and never frees them.
test "protocols: registerProtocolDecl builds the dispatch method table" {
var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
defer arena.deinit();
const alloc = arena.allocator();
var module = ir_mod.Module.init(alloc);
defer module.deinit();
var lowering = Lowering.init(&module);
// Shape :: protocol { area :: () -> f64; scaled :: (factor: f64) -> Self; }
const methods = [_]ast.ProtocolMethodDecl{
.{ .name = "area", .params = &.{}, .param_names = &.{}, .return_type = typeKeyword(alloc, "f64"), .default_body = null },
.{
.name = "scaled",
.params = &[_]*Node{typeKeyword(alloc, "f64")},
.param_names = &[_][]const u8{"factor"},
.return_type = typeKeyword(alloc, "Self"),
.default_body = null,
},
};
const pd = ast.ProtocolDecl{ .name = "Shape", .methods = &methods };
lowering.registerProtocolDecl(&pd);
// getProtocolInfo resolves the registered protocol struct by type.
const shape_ty = module.types.findByName(module.types.internString("Shape")).?;
const info = lowering.getProtocolInfo(shape_ty).?;
try std.testing.expectEqual(@as(usize, 2), info.methods.len);
// area :: () -> f64 — no params (self excluded), concrete f64 return.
try std.testing.expectEqualStrings("area", info.methods[0].name);
try std.testing.expectEqual(@as(usize, 0), info.methods[0].param_types.len);
try std.testing.expectEqual(TypeId.f64, info.methods[0].ret_type);
try std.testing.expect(!info.methods[0].ret_is_self);
// scaled :: (factor: f64) -> Self — one f64 param; `Self` return is
// flagged and encoded as `*void` (the dispatcher auto-unboxes it).
try std.testing.expectEqualStrings("scaled", info.methods[1].name);
try std.testing.expectEqual(@as(usize, 1), info.methods[1].param_types.len);
try std.testing.expectEqual(TypeId.f64, info.methods[1].param_types[0]);
try std.testing.expect(info.methods[1].ret_is_self);
try std.testing.expectEqual(module.types.ptrTo(.void), info.methods[1].ret_type);
}