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:
4077
examples/expected/0413-protocols-parameterized-protocol-value.ir
Normal file
4077
examples/expected/0413-protocols-parameterized-protocol-value.ir
Normal file
File diff suppressed because it is too large
Load Diff
4092
examples/expected/0414-protocols-generic-struct-protocol-erase.ir
Normal file
4092
examples/expected/0414-protocols-generic-struct-protocol-erase.ir
Normal file
File diff suppressed because it is too large
Load Diff
5142
examples/expected/0416-protocols-auto-type-erasure.ir
Normal file
5142
examples/expected/0416-protocols-auto-type-erasure.ir
Normal file
File diff suppressed because it is too large
Load Diff
4033
examples/expected/0528-packs-protocol-pack-methods.ir
Normal file
4033
examples/expected/0528-packs-protocol-pack-methods.ir
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user