refactor(ir): converge structural type-shape resolution onto resolveCompound (A2.3b)

Codex corrective step before the A2 merge gate: A2.3 left type_bridge with a
parallel structural type-resolution algorithm and an inline tuple-literal-spread
shape in lower.zig with a `.void` fallback.

Finding 1 — single owner for structural shapes:
- TypeResolver.resolveCompound is now the sole structural type-shape
  constructor. Namespaced on `table` (so the stateless type_bridge can call it)
  and extended to own function types, plain `Closure(P...) -> R`, and plain
  positional/named tuples (it already owned *T/[*]T/[]T/?T/[N]T). It returns
  null only for the pack-shaped forms that need caller state (`Closure(..p)`,
  spread tuples); OOM yields `.unresolved`.
- type_bridge: deleted its 8 independent structural resolvers
  (resolveArray/Slice/Pointer/ManyPointer/Optional/Function/Closure/TupleType).
  resolveAstType delegates those node kinds to resolveCompound via a binding-free
  StatelessInner adapter. The only residual stateless shape code is two tiny
  fallbacks for the pack-shaped forms resolveCompound defers
  (resolveClosurePackShape — used by Into(Block) at registration time —
  and resolveTupleSpreadShape) plus resolveParameterizedType (kept:
  generic-instantiation convergence is A4.1 per PLAN-ARCH).
- lower.zig: stateful resolveTypeWithBindings uses resolveCompound; the
  `.function_type_expr` switch arm is gone. PackResolver.resolveFunctionTypeWithBindings
  deleted (subsumed). Plain closures/tuples now resolve via resolveCompound in
  both paths; only pack closures / spread tuples reach PackResolver.

Finding 2 — no `.void` failure fallback in lower.zig pack handling:
- the inline tuple_literal-with-spread type assembly moved into
  PackResolver.resolveTupleLiteralType (returns ?TypeId; OOM `catch return .void`
  became `catch return .unresolved`).

Alias result preserved: TypeTable.aliases stays gone; no table.aliases reads;
ProgramIndex.type_alias_map threaded explicitly.

type_resolver.test.zig: resolveCompound test rewritten (namespaced + new
function/closure/tuple/pack-shape arms, arena-backed). Gate green: zig build,
zig build test, run_examples 350/0.
This commit is contained in:
agra
2026-06-02 15:20:31 +03:00
parent 3ed1b3a7a0
commit 9b50aacbe4
5 changed files with 199 additions and 136 deletions

View File

@@ -97,24 +97,36 @@ pub const PackResolver = struct {
} });
}
/// Resolve a `(Params...) -> Ret` function type expression with the
/// active type/pack bindings applied. Mirrors
/// `resolveClosureTypeWithBindings` but for `function_type_expr`.
/// Unlocks `$args[$i]` in fn-pointer type literals like
/// `fp : (*void, $args[0]) -> $args[1] = ...` — used in step 5's
/// generic trampoline body.
pub fn resolveFunctionTypeWithBindings(self: PackResolver, ft: *const ast.FunctionTypeExpr) TypeId {
var param_ids = std.ArrayList(TypeId).empty;
defer param_ids.deinit(self.l.alloc);
for (ft.param_types) |pt| {
param_ids.append(self.l.alloc, self.l.resolveTypeWithBindings(pt)) catch return .unresolved;
/// Resolve a tuple LITERAL used in a type position whose elements include a
/// pack spread (`(..$Ts)` / `(..xs.T)` — these parse as a tuple literal, not
/// a `tuple_type_expr`). Returns null when no element is a spread, so the
/// caller falls through to ordinary name/type resolution. A failed
/// allocation yields `.unresolved` (never a real `.void`).
pub fn resolveTupleLiteralType(self: PackResolver, tl: *const ast.TupleLiteral) ?TypeId {
var any_spread = false;
for (tl.elements) |el| {
if (el.value.data == .spread_expr) {
any_spread = true;
break;
}
}
const ret_ty = if (ft.return_type) |rt| self.l.resolveTypeWithBindings(rt) else .void;
const cc: types.TypeInfo.CallConv = switch (ft.call_conv) {
.default => .default,
.c => .c,
};
return self.l.module.types.functionTypeCC(param_ids.items, ret_ty, cc);
if (!any_spread) return null;
var field_ids = std.ArrayList(TypeId).empty;
defer field_ids.deinit(self.l.alloc);
for (tl.elements) |el| {
if (el.value.data == .spread_expr) {
if (self.packTypeElems(el.value.data.spread_expr.operand)) |elems| {
defer self.l.alloc.free(elems);
for (elems) |e| field_ids.append(self.l.alloc, e) catch return .unresolved;
continue;
}
}
field_ids.append(self.l.alloc, self.l.resolveTypeWithBindings(el.value)) catch return .unresolved;
}
return self.l.module.types.intern(.{ .tuple = .{
.fields = self.l.alloc.dupe(TypeId, field_ids.items) catch return .unresolved,
.names = null,
} });
}
/// TYPE-position pack expansion: given a spread operand, return the