additive: complete resolver traversal gaps
This commit is contained in:
@@ -342,6 +342,26 @@ fn findFn(root: *const ast.Node, name: []const u8) ?*const ast.Node {
|
||||
return null;
|
||||
}
|
||||
|
||||
fn findDecl(root: *const ast.Node, name: []const u8, comptime kind: std.meta.Tag(ast.Node.Data)) ?*const ast.Node {
|
||||
for (root.data.root.decls) |d| {
|
||||
if (std.meta.activeTag(d.data) != kind) continue;
|
||||
const dn = d.data.declName() orelse continue;
|
||||
if (std.mem.eql(u8, dn, name)) return d;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
fn expectTypeRefOwnTag(
|
||||
rp: *const resolver.ResolvedProgram,
|
||||
node: *const ast.Node,
|
||||
expected: std.meta.Tag(resolver.RawDeclRef),
|
||||
) !void {
|
||||
const ref = rp.type_refs.get(node) orelse return error.MissingTypeRef;
|
||||
try std.testing.expect(ref == .authors);
|
||||
try std.testing.expect(ref.authors.own != null);
|
||||
try std.testing.expectEqual(expected, std.meta.activeTag(ref.authors.own.?.raw));
|
||||
}
|
||||
|
||||
// The pass populates the three bare-name domains over REAL Phase A facts: a type
|
||||
// reference (own struct author), a value/const reference (own const), and a
|
||||
// callable head (flat-imported author). It keys every entry by NODE IDENTITY, and
|
||||
@@ -462,3 +482,56 @@ test "resolver: resolve — bare-name domains populated, keyed by node, symbolic
|
||||
try std.testing.expectEqual(@as(u32, 0), rp.struct_const_refs.count());
|
||||
try std.testing.expectEqual(@as(u32, 0), rp.ufcs_refs.count());
|
||||
}
|
||||
|
||||
test "resolver: resolve — generic constraints and named error sets are type refs" {
|
||||
var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
|
||||
defer arena.deinit();
|
||||
const alloc = arena.allocator();
|
||||
const io = testIo();
|
||||
|
||||
var tmp = std.testing.tmpDir(.{});
|
||||
defer tmp.cleanup();
|
||||
|
||||
try tmp.dir.writeFile(io, .{ .sub_path = "main.sx", .data =
|
||||
\\Alias :: struct { x: s64 }
|
||||
\\ParseErr :: error { Bad }
|
||||
\\Box :: struct($N: Alias) { value: Alias }
|
||||
\\Constrained :: protocol(T: Alias) { get :: () -> T; }
|
||||
\\take :: ($N: Alias) -> s64 { return 0; }
|
||||
\\fail :: () -> !ParseErr { raise error.Bad; }
|
||||
\\main :: () -> s32 { return 0; }
|
||||
\\
|
||||
});
|
||||
|
||||
var dirbuf: [4096]u8 = undefined;
|
||||
const absdir = dirbuf[0..try tmp.dir.realPath(io, &dirbuf)];
|
||||
const main_path = try std.fmt.allocPrint(alloc, "{s}/main.sx", .{absdir});
|
||||
|
||||
var prog = try buildResolved(alloc, io, absdir, main_path);
|
||||
|
||||
var idx = ProgramIndex.init(alloc);
|
||||
defer idx.deinit();
|
||||
idx.module_decls = &prog.decls;
|
||||
idx.flat_import_graph = &prog.flat_import_graph;
|
||||
idx.import_graph = &prog.import_graph;
|
||||
|
||||
var rp = resolver.resolve(prog.root, &idx, main_path, alloc);
|
||||
defer rp.deinit();
|
||||
|
||||
const alias_tag = std.meta.Tag(resolver.RawDeclRef).struct_decl;
|
||||
const error_tag = std.meta.Tag(resolver.RawDeclRef).error_set_decl;
|
||||
|
||||
const box = findDecl(prog.root, "Box", .struct_decl) orelse return error.MissingStruct;
|
||||
try expectTypeRefOwnTag(&rp, box.data.struct_decl.type_params[0].constraint, alias_tag);
|
||||
|
||||
const constrained = findDecl(prog.root, "Constrained", .protocol_decl) orelse return error.MissingProtocol;
|
||||
try expectTypeRefOwnTag(&rp, constrained.data.protocol_decl.type_params[0].constraint, alias_tag);
|
||||
|
||||
const take = findFn(prog.root, "take") orelse return error.MissingFn;
|
||||
try expectTypeRefOwnTag(&rp, take.data.fn_decl.type_params[0].constraint, alias_tag);
|
||||
|
||||
const fail = findFn(prog.root, "fail") orelse return error.MissingFn;
|
||||
const err_ty = fail.data.fn_decl.return_type orelse return error.NoReturnType;
|
||||
try std.testing.expect(err_ty.data == .error_type_expr);
|
||||
try expectTypeRefOwnTag(&rp, err_ty, error_tag);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user