feat(resolver): route plain bare-call author through Phase B collector via SelectedFunc [stdlib C]
Phase C of the unified resolver (R5 §C, §#3). Re-base the plain bare-name
call author onto the Phase B collector behind one shared SelectedFunc, so
every call-path consumer reads ONE author and they can no longer disagree
(fix-0102 F2). Behavior-preserving: 0722-0735 byte-identical, run_examples
stays at 475.
- SelectedFunc {decl, source, materialized?} replaces ResolvedAuthor in
BareCallee.func; CallPlan.Target gains a `selected` arm (calls.zig).
- selectPlainCallableAuthor: resolveBareCallee's body verbatim over
resolver.collectVisibleAuthors (.user_bare_flat) — the ONE graph-walk.
fnDeclOfRaw mirrors imports.fnDeclOf so the collector's all-domain authors
reproduce module_fns' fn-only view; every byte of the negative space is
preserved (own==winner → .none; non-plain-free → .none; filter-before-count;
≥2 distinct → .ambiguous). No eager materialization.
- selectedFuncId materializes the FuncId on demand (shadow-only), caching into
materialized — null until a site needs it (0102d: a shadow taken as a value
never lowers the winner).
- Six consumers route through the one selector: lowerCall variadic packing,
free-fn UFCS, fn-value, closure(fn), resolveCallParamTypes, and
expandCallDefaults (decl-only, no materialization). plan() produces the
SelectedFunc as `.selected`. Generic/comptime/foreign/builtin stay legacy.
- lower.test.zig: wire module_decls; selectPlainCallableAuthor verdicts
(own-winner → .none; ≥2 flat → .ambiguous; own-shadow → decl+source, fid
round-trips, materialized null).
Gate: zig build + zig build test (412 ok) + run_examples (475, byte-identical)
+ m3te ios-sim build exit 0.
This commit is contained in:
@@ -72,6 +72,13 @@ pub const CallPlan = struct {
|
||||
/// A callee carried by name — reflection builtin, generic / lazy fn,
|
||||
/// closure / fn-pointer binding, or a not-yet-lowered namespace fn.
|
||||
named: []const u8,
|
||||
/// The single bare-call author `selectPlainCallableAuthor` selected for a
|
||||
/// genuine flat same-name collision (R5 §#3). Carries the resolved
|
||||
/// `*FnDecl` + source so `plan` and the lowering call-path read ONE
|
||||
/// author and can no longer disagree (fix-0102 F2); the FuncId is
|
||||
/// materialized on demand. Only set when the bare name reroutes away from
|
||||
/// the first-wins winner; the common path still uses `func` / `named`.
|
||||
selected: Lowering.SelectedFunc,
|
||||
/// Protocol method, by index in the protocol's method table.
|
||||
protocol_method: u32,
|
||||
/// Foreign-class method (Obj-C / JNI), with its static-ness.
|
||||
@@ -149,6 +156,28 @@ pub const CallResolver = struct {
|
||||
if (std.mem.eql(u8, bare_name, "type_is_unsigned")) return refl(bare_name, .bool);
|
||||
if (std.mem.eql(u8, bare_name, "type_of")) return refl(bare_name, .any);
|
||||
if (std.mem.eql(u8, bare_name, "field_value")) return refl(bare_name, .any);
|
||||
// Plain bare same-name flat collision (R5 §C): route through the ONE
|
||||
// selector so `plan` reads the SAME author the lowering call-path
|
||||
// binds — they can no longer disagree (fix-0102 F2). The gate mirrors
|
||||
// `lowerCall`'s: a plain top-level identifier with no scope-mangle /
|
||||
// local shadow. A generic / foreign / builtin author is not plain-free
|
||||
// so the selector returns `.none`; `.ambiguous` / `.none` fall through
|
||||
// to the first-wins path below, byte-for-byte.
|
||||
if (std.mem.eql(u8, name, bare_name) and
|
||||
(if (self.l.scope) |scope| scope.lookup(bare_name) == null else true))
|
||||
{
|
||||
if (self.l.current_source_file) |caller_file| {
|
||||
switch (self.l.selectPlainCallableAuthor(bare_name, caller_file)) {
|
||||
.func => |sf| return .{
|
||||
.kind = .direct_fn,
|
||||
.return_type = if (sf.decl.return_type) |rt| self.l.resolveType(rt) else .void,
|
||||
.target = .{ .selected = sf },
|
||||
.expands_defaults = defaultsFor(sf.decl, c.args.len),
|
||||
},
|
||||
.ambiguous, .none => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
// Generic function — infer return type via type bindings.
|
||||
if (self.l.program_index.fn_ast_map.get(name)) |fd| {
|
||||
if (fd.type_params.len > 0) {
|
||||
|
||||
Reference in New Issue
Block a user