wcc: add the opaque abstract type (kind + UNDEFINED sentinel + name-binding) (#108)

#108 sub-fold (a): TY_OPAQUE exists, is name-bindable, and carries an
UNDEFINED size sentinel. Mirrors the #85 `size` fold pattern at every
site, both stages (rule-10).

opaque is abstract + UNSIZED: prim()'d with size=align=SIZE_UNDEFINED
(NOT 0 — a 0 would let a bare `let x: opaque` fabricate a 0-byte local),
mirroring harec builtin_type_opaque (ref/harec/src/types.c:1446). ww had
no incomplete-size sentinel, so this fold ADDS one: cstage
`#define SIZE_UNDEFINED ((u64)-1)` (== harec types.h:58 (size_t)-1) and
wwstage `def SIZE_UNDEFINED: u64 = 18446744073709551615`.

Legal only behind indirection: `*opaque` (8B ptr) and `[]opaque` (24B
slice header) construct correctly because type_ptr/type_slice (and the
wwstage typeptr/typeslice) size themselves independent of the element.
opaque is deliberately absent from is-int/unsigned/num/float and from
the size-classification switches (let_emit_size / tupleelemslot /
fieldslotsize) on both stages — it only reaches those as TY_PTR/TY_SLICE.

The use-restriction GUARDS (reject bare opaque / size(opaque) / opaque
field / [N]opaque / []opaque-indexing), assignability, and cgen-verify
are the separate sub-folds (b)/(c)/(d) — NOT here.

opaque is unused by the bootstrap, so 990-997 stay byte-identical
(inert, like #85). Regenerates the w6c/wwdump combined.ww (typ.ww +
check.ww embedded). New probe 960_opaque_decl_run exercises `*opaque`
and `[]opaque` (.len/.ptr) behind indirection.
This commit is contained in:
2026-05-26 09:02:08 +09:00
parent d9cfb91cb9
commit 3a18d2cfe6
9 changed files with 209 additions and 1 deletions

View File

@@ -17,6 +17,7 @@ Type *ty_f32, *ty_f64, *ty_str;
Type *ty_err;
Type *ty_never;
Type *ty_nomem;
Type *ty_opaque;
Type *ty_untyped_int, *ty_untyped_float, *ty_untyped_str;
Type *ty_untyped_rune, *ty_untyped_bool, *ty_untyped_nil;
@@ -78,6 +79,10 @@ typesinit(Arena *a)
ty_nomem->size = ty_void->size;
ty_nomem->align = ty_void->align;
ty_nomem->iserror = 1;
/* #108(a): abstract + unsized. SIZE_UNDEFINED (not 0) so a bare
* `let x: opaque` can't fabricate a 0-byte local; legal only behind
* indirection. Mirrors harec builtin_type_opaque (types.c:1446). */
ty_opaque = prim(a, TY_OPAQUE, "opaque", SIZE_UNDEFINED, SIZE_UNDEFINED);
ty_untyped_int = prim(a, TY_UNTYPED_INT, "untyped_int", 0, 1);
ty_untyped_float = prim(a, TY_UNTYPED_FLOAT, "untyped_float", 0, 1);
@@ -375,6 +380,7 @@ type_name(Arena *a, Type *t)
case TY_UINT: return "uint";
case TY_UINTPTR: return "uintptr";
case TY_SIZE: return "size";
case TY_OPAQUE: return "opaque";
case TY_F32: return "f32";
case TY_F64: return "f64";
case TY_STR: return "str";