wcc: reject transitive nested-tagged widen at type_assignable (#199 α)
cgen has no wrapped-slot layout — the tagged-union slot is universally [tag:8B][payload:up_to_24B], single level. The recursive walk admitted let r: (size|io.eof|io.error) = u for u: io.underread (transitively in io.error.params); cg_tag_for_variant + taggedvariantindext don't recurse, returned -1, defaulted to tag=0, and the slot read back as variant 0 = size at runtime. Restores SSoT inside the checker pair: is / as / match variant lookup is already non-recursive (#198 sibling), and the LET-init / return / assign arms now agree. Aligns DOWN to the leaner side (rule-10 stage symmetry). ww-stricter than Hare; harec keeps the drill at ref/harec/src/types.c:702-739 (#199b is the deferred wrapped-slot layout port). Pre-flight audit (drew mandate): zero transitive-widen sites in lib/ + selfhost/ + cmd/ + examples/. No wrapper-tagged variant (io.error, strconv.error, fmt.field) is used as a variant of a wider union anywhere in bootstrap. Mechanical fix. Escape hatch for callers: spread (...wrapper) inlines the wrapper's flat variants into the parent set at parse time. Wwstage's gate additionally preserves the recursive drill on op == TK_ELLIPSIS because wwstage stays AST-keyed (cstage flattens at resolve_type). 771_widen_transitive: 5 rows (reject_transitive_widen, spread_alt_widen, direct_flat_variant, branched_callee_widen, wrapper_typed_widen). Row 2 is CS-only — wwstage's is / match on spread-expanded variants is open-bug #190/#198.
This commit is contained in:
@@ -304,8 +304,24 @@ type_assignable(Type *dst, Type *src)
|
||||
Type *su = (src->kind == TY_NAMED) ? src->under : src;
|
||||
if (du && du->kind == TY_TAGGED &&
|
||||
!(su && su->kind == TY_TAGGED)) {
|
||||
for (Tparam *p = du->params; p; p = p->next)
|
||||
/* #199(α): direct variant only — no transitive drill into
|
||||
* a NAMED-tagged wrapper variant. Cgen has no wrapped-slot
|
||||
* layout (single-level [tag][payload]), so admitting a
|
||||
* nested widen silently miscompiled to tag=0 (#199 repro
|
||||
* io.underread → (size|io.eof|io.error)). ww-stricter than
|
||||
* Hare; harec types.c:702-739 keeps the drill (#199b is
|
||||
* the deferred wrapped-slot port). Restores SSoT with
|
||||
* `is`/`as`'s non-recursive variant lookup. Callers compose
|
||||
* `let inner: Wrapper = sub; let r: parent = inner;`. */
|
||||
for (Tparam *p = du->params; p; p = p->next) {
|
||||
Type *pu = (p->type && p->type->kind == TY_NAMED)
|
||||
? p->type->under : p->type;
|
||||
if (pu && pu->kind == TY_TAGGED) {
|
||||
if (type_eq(p->type, src)) return 1;
|
||||
continue;
|
||||
}
|
||||
if (type_assignable(p->type, src)) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if (du && du->kind == TY_TAGGED &&
|
||||
|
||||
Reference in New Issue
Block a user