additive: complete resolver traversal gaps

This commit is contained in:
agra
2026-06-09 13:05:23 +03:00
parent b46ad8b7a7
commit 1fb65e9e75
2 changed files with 101 additions and 4 deletions

View File

@@ -392,6 +392,7 @@ const ResolvePass = struct {
.fn_decl => |*fd| {
var frame = Frame{ .params = fd.type_params, .owner = node, .parent = here.scope };
const inner = Ctx{ .source = here.source, .scope = &frame };
self.visitTypeParamConstraints(fd.type_params, inner);
for (fd.params) |p| {
self.visit(p.type_expr, inner);
if (p.default_expr) |d| self.visit(d, inner);
@@ -402,6 +403,7 @@ const ResolvePass = struct {
.lambda => |*l| {
var frame = Frame{ .params = l.type_params, .owner = node, .parent = here.scope };
const inner = Ctx{ .source = here.source, .scope = &frame };
self.visitTypeParamConstraints(l.type_params, inner);
for (l.params) |p| {
self.visit(p.type_expr, inner);
if (p.default_expr) |d| self.visit(d, inner);
@@ -412,6 +414,7 @@ const ResolvePass = struct {
.struct_decl => |*sd| {
var frame = Frame{ .params = sd.type_params, .owner = node, .parent = here.scope };
const inner = Ctx{ .source = here.source, .scope = &frame };
self.visitTypeParamConstraints(sd.type_params, inner);
self.visitAll(sd.field_types, inner);
self.visitAllOpt(sd.field_defaults, inner);
self.visitAll(sd.methods, inner);
@@ -420,6 +423,7 @@ const ResolvePass = struct {
.protocol_decl => |*pd| {
var frame = Frame{ .params = pd.type_params, .owner = node, .parent = here.scope };
const inner = Ctx{ .source = here.source, .scope = &frame };
self.visitTypeParamConstraints(pd.type_params, inner);
for (pd.methods) |m| {
self.visitAll(m.params, inner);
if (m.return_type) |rt| self.visit(rt, inner);
@@ -429,6 +433,7 @@ const ResolvePass = struct {
.impl_block => |*ib| {
var frame = Frame{ .params = ib.target_type_params, .owner = node, .parent = here.scope };
const inner = Ctx{ .source = here.source, .scope = &frame };
self.visitTypeParamConstraints(ib.target_type_params, inner);
if (ib.target_type_expr) |tt| self.visit(tt, inner);
self.visitAll(ib.protocol_type_args, inner);
self.visitAll(ib.methods, inner);
@@ -466,6 +471,9 @@ const ResolvePass = struct {
},
.pack_index_type_expr => |*p| self.recordPack(&self.out.type_refs, node, p.pack_name, p.index, here.scope),
.comptime_pack_ref => |*p| self.recordPack(&self.out.value_refs, node, p.pack_name, null, here.scope),
.error_type_expr => |*e| {
if (e.name) |name| self.recordAuthors(&self.out.type_refs, node, name, here.source);
},
.parameterized_type_expr => |*p| {
// the head (generic-struct / type-fn / protocol) is S2.1b; the
// type args are ordinary references, collected now.
@@ -625,7 +633,6 @@ const ResolvePass = struct {
.import_decl,
.namespace_decl,
.error_set_decl,
.error_type_expr,
.foreign_expr,
.library_decl,
.framework_decl,
@@ -643,6 +650,10 @@ const ResolvePass = struct {
for (nodes) |n| if (n) |nn| self.visit(nn, ctx);
}
fn visitTypeParamConstraints(self: *ResolvePass, params: []const ast.StructTypeParam, ctx: Ctx) void {
for (params) |p| self.visit(p.constraint, ctx);
}
/// A type-position reference: a generic param in scope → symbolic template ref;
/// otherwise a user type, collected RAW. Builtins / undeclared names collect to
/// an empty set and are simply not recorded.
@@ -676,16 +687,29 @@ const ResolvePass = struct {
fn recordAuthors(self: *ResolvePass, table: *NodeRefTable, node: *const ast.Node, name: []const u8, from: []const u8) void {
const set = self.res.collectVisibleAuthors(name, from, .user_bare_flat);
if (set.distinctCount() == 0) return;
table.put(node, .{ .authors = set }) catch @panic("resolve: OOM");
self.replaceRef(table, node, .{ .authors = set });
}
fn recordTemplate(self: *ResolvePass, table: *NodeRefTable, node: *const ast.Node, m: GenericMatch) void {
table.put(node, .{ .template = self.internTemplate(m) }) catch @panic("resolve: OOM");
self.replaceRef(table, node, .{ .template = self.internTemplate(m) });
}
fn recordPack(self: *ResolvePass, table: *NodeRefTable, node: *const ast.Node, name: []const u8, index: ?u32, scope: ?*const Frame) void {
const m = lookupGeneric(scope, name) orelse return;
table.put(node, .{ .pack = .{ .id = self.internPack(m), .index = index } }) catch @panic("resolve: OOM");
self.replaceRef(table, node, .{ .pack = .{ .id = self.internPack(m), .index = index } });
}
fn replaceRef(self: *ResolvePass, table: *NodeRefTable, node: *const ast.Node, ref: ResolvedRef) void {
const entry = table.getOrPut(node) catch @panic("resolve: OOM");
if (entry.found_existing) self.releaseRef(entry.value_ptr.*);
entry.value_ptr.* = ref;
}
fn releaseRef(self: *ResolvePass, ref: ResolvedRef) void {
switch (ref) {
.authors => |a| if (a.flat.len > 0) self.out.alloc.free(a.flat),
.template, .pack => {},
}
}
fn internTemplate(self: *ResolvePass, m: GenericMatch) TemplateParamId {