Emit interface values from source rather than only from hand-written fixtures:
store and copy all four bytes of an object/table pair in locals, parameters,
fields and array elements; convert a class reference or null at a use site;
and call an interface method through if_call with the compile-time slot. The
emitted code reuses the E06-S02 trampoline, the E06-S04 conversions, and
iface_slot, so no new runtime entry point or layout is introduced (D153).
src/compiler/emit.s: four-byte value paths for a slot, a field and a call
site; interface-aware em_target/em_store_targetsrc/compiler/members.s: four-byte member load/store between a field and
if_dst/if_srcsrc/compiler/parser.s: pass-2 hooks for conversion assignment and interface
call sitessrc/compiler/iftables.s: the table lookup the conversion emission needs
(it_find, already present)src/common/emit.inc: new emitter error codes for an unsupported interface
shapetests/compiler/iface.n8, tests/compiler/iface-test.sscripts/build-iface-test.ps1, scripts/verify-iface-test.ps1tests/semantic/*.n8 for the misuse diagnosticsdocs/decisions.md (D153), docs/architecture.md, docs/memory-map.mdplanning/claims/E06-S07.mdbuild/iface-test/null in an interface context produces the canonical null value and a
call through it takes the fault path.if_call with the value pointer in
A/X and the slot in Y, with arguments and one-/two-byte returns.Exact failed criteria. The argument, return and call criteria (1, 3, 4 and 5) cannot be met. The emitter has no calling-convention layer at all, so there is nothing for an interface value to travel through:
parse_args (parser.s, around line 2107) parses and type-checks each
argument but emits no code; the only emitter hooks in the call path are
em_member_receiver and em_call before the argument list.em_call (emit.s) refuses C_MEM_PCOUNT != 0 with EM_ERR_CALL, so no
emitted call takes arguments.em_return emits a bare RTS; em_begin_func emits no prologue and
fl_prologue/fl_ret/fl_ret_byte/fl_ret_word are never called by the
parser, so parameters and returns have no emitted frame.em_target, em_store_target, em_expr_name, em_push_left and em_bin
reject every width but one byte, so interface locals/fields cannot even be
loaded or stored yet.it_class builds the per-class tables only in the output stage, after the
code section's length and addresses exist. A conversion emits the table
address as an immediate, so the table has to be placed (or its address fixed)
before pass 2 can emit the conversion.Evidence collected. src/compiler/emit.s (whole file), parser.s
call/assignment/argument paths, flow.s, codegen.s, iftables.s,
members.s, interfaces.s, and runtime/interfaces.s were read. No emitter
hook for arguments, prologue or value returns exists in any of them; the
calls-test.s fixture passes self in A/X and runs a method body directly,
which is why the gap has not surfaced before.
Smallest decision or fact needed. A calling-convention emission story must
land first (argument push in source order, argument byte count for the discard,
frame_enter prologue sizing, return with 0/1/2-byte and interface results),
together with a decision placing interface tables at a layout-time-known address
so a conversion can embed the table pointer. That work is larger than this
story and changes the generated ABI/section layout, so it needs its own story
and a Dxxx record rather than being folded in here.
Safe work that remains possible. The storage half can be implemented and
proven without the calling convention: four-byte em_expr_name/em_target/
em_store_target for locals and fields, four-byte member load/store in
members.s, null as the canonical zero value, and copy-mode if_assign
between two interface slots. It cannot satisfy the story's call and argument
criteria on its own, so the claim stays blocked until the calling-convention
story exists.
types.s classifies class and interface
references by name and ty_assign accepts a class for an interface it
implements (tests/semantic/refs.n8).if_assign takes the destination in A/X and the mode in Y (0 copies
if_src, any other value converts if_obj with if_tab); if_call takes
the value pointer in A/X and the slot in Y. Both are already proven by
tests/runtime/convert-test.s and tests/runtime/ifcall-test.s.$FB-$FE is FRAME_SP/FRAME_FP, $F5-$F8 is
EM_LP/EM_TMP, $F9 is MB_SELF, $C0-$C5 are the print vectors and
$C6+ is IF_RESULT. A second value pointer must live in BSS and be copied
to if_src/if_dst with absolute stores.if_assign, if_call, if_ret_*, if_arg_push, if_elem_*) and the
pass-3 table builder; nothing emits calls to them.blocked rather than done because
four acceptance criteria cannot be verified without the calling-convention
layer.Powered by TurnKey Linux.