ffi M5.A.next.4A.bare.1.B: bare $args lowers to []Type slice value
Step 4A final-slice fix. Bare `$<pack_name>` (no `[<int>]`)
in expression position now parses + lowers to a comptime
`[]Type` slice value carrying one `const_type(TypeId)` per
pack element.
Plumbing:
- src/ast.zig: new `ComptimePackRef { pack_name }` node +
`comptime_pack_ref` variant in Data.
- src/parser.zig: `parsePrimary`'s `$` arm makes `[` optional
after the pack name. With `[<int>]` → existing
`pack_index_type_expr` (single Type value). Without → new
`comptime_pack_ref` (whole pack as []Type).
- src/sema.zig: adds the no-op switch arms for the new node
in `analyzeNode` and `findNodeAtOffset`.
- src/ir/lower.zig: `lowerExpr` arm reads `pack_arg_types[name]`
and calls `buildPackSliceValue(arg_tys)`. The helper allocas
a `[N x Any]` array, emits one `const_type(arg_tys[i])` per
slot, then a slice `{data_ptr, len}` aggregate. No active
binding → focused diagnostic + null slice placeholder. The
IR slice element type is `Any` (matches the today's
`Type → .any` mapping in type_bridge); the interp stores
raw `.type_tag` Values directly (NOT Any-boxed) so
`args[i]` at interp time reads a Type value.
- src/ir/emit_llvm.zig: relaxed `const_type` to silently emit
undef-i64 instead of the previous stderr-noisy bail. Storage
of Type values in runtime aggregates is harmless (undef in,
undef out). Use-site misuse is caught by the bails on
type_name/type_eq/has_impl and the bitcast guard.
`examples/170-pack-bare-value.sx` flips from the parse-error
lock-in to "0/1/3/4" — four call shapes of `len_of(..$args) ->
s64 { list := $args; return list.len; }`. The slice's `.len`
field carries the per-mono pack arity.
210/210 example tests + `zig build test` green.
The remaining 4A.bare slices (4 and 5) — resolveTypeArg
silent-arm fix for index_expr + smoke test of a real builder
walking $args — are separate commits per the cadence rule.
This commit is contained in:
@@ -1668,15 +1668,19 @@ pub const LLVMEmitter = struct {
|
||||
self.mapRef(llvm_val);
|
||||
}
|
||||
},
|
||||
.const_type => |tid| {
|
||||
// Type values are comptime-only — they MUST be erased by
|
||||
// the time we emit LLVM. Reaching here means a Type leaked
|
||||
// into a runtime path (e.g. a builder returned a Type from
|
||||
// a fn the compiler didn't strip). Loud failure: emit an
|
||||
// undef placeholder so the verifier catches downstream
|
||||
// use, AND log the offending TypeId so the diagnostic is
|
||||
// actionable.
|
||||
std.debug.print("emit_llvm: Type value reached runtime (TypeId={}). Type is comptime-only; check the builder path that produced this.\n", .{@intFromEnum(tid)});
|
||||
.const_type => {
|
||||
// Type values are comptime-only. At LLVM emit they
|
||||
// become undef-i64 placeholders — Type-aware ops are
|
||||
// routed through the interp; if one slips through to
|
||||
// a runtime use site (`type_name` / `type_eq` /
|
||||
// `has_impl` / `bitcast`), the corresponding emit_llvm
|
||||
// bail or runtime use-site error fires loudly. Pure
|
||||
// STORAGE of Type values in runtime aggregates (e.g.
|
||||
// `$args` lowering builds an `[]Any` slice whose
|
||||
// elements happen to be Type values that the user's
|
||||
// code may or may not actually read) is safe — undef
|
||||
// just gets stored, undef just gets read; no use-site
|
||||
// misbehaviour follows.
|
||||
self.mapRef(c.LLVMGetUndef(self.cached_i64));
|
||||
},
|
||||
|
||||
|
||||
Reference in New Issue
Block a user