check: widen const def-ref to declared int type in def init (#113)
A def initializer whose rhs references another def -- `def INT_MIN: int = I32_MIN;`, `def SIZE_MAX: size = U64_MAX;` -- failed to compile: an N_IDENT->SK_DEF types as the referent's DECLARED type (i32, u64), so the def-init assignability check (type_assignable) rejected i32 -> int / u64 -> size, even though the value is a compile-time constant that fits. This blocked faithful types/types::c limit defs (no cast in the Hare source). In a def initializer the rhs is a flexible constant. When it folds to a compile-time integer (the #88 eval_def_const path: sibling/imported def refs, casts, arithmetic) and the value fits the declared integer target, re-flexibilize it to UNTYPED_INT so the existing untyped-int->typed assignability path accepts it. This emulates Hare's flexible-constant promotion (ICONST -> promote_flexible/lower_flexible, ref/harec/src/types.c:860); def_cast_fits is the range check that keeps a genuine out-of-range narrowing a loud "not assignable" error, never a silent truncation (rule 7). It is strictly the const subset: the general CONCRETE (non-const) integer widening Hare does at types.c:1021-1037 is intentionally stricter in ww -- #115. cstage-only: the wwstage checker (selfhost/cmd/wcc/check.ww, "let init / return assignability") intentionally never checks def-init assignability (it stays quiet, leaving full inference to the C side), so it never rejected the widening -- the #88 stamp already laid the correct DATA row. Relaxing the cstage aligns the richer side DOWN to the leaner side (rule 10); both stages stamp the identical folded value, so emitted asm is byte-identical. The bootstrap corpus has zero cross-prim-width def-ref defs, so the new path is dead there and 990-997 are unperturbed. Coverage: test/wcc/760_def_widen_const (i32->int neg, u64->size, byte-id on each, cstage-only out-of-range narrowing fail-loud).
This commit is contained in:
@@ -2160,21 +2160,48 @@ check_file(Checker *c, Node *file)
|
||||
case N_DEF: {
|
||||
if (d->rhs) {
|
||||
Type *rt = cexpr(c, d->rhs);
|
||||
/* #88: fold sibling/imported def refs, casts, and
|
||||
* arithmetic to a constant. litfold (plain literal
|
||||
* leaf) is already typed UNTYPED_INT by cexpr;
|
||||
* constfold (#88, gated on litfold missing) covers
|
||||
* the richer shapes and is the one we stamp, so
|
||||
* existing literal/unary defs keep their rhs node
|
||||
* and the emitted bytes stay byte-identical. */
|
||||
u64 dv;
|
||||
int litfold = rt != ty_err
|
||||
&& fold_int_literal(d->rhs, &dv);
|
||||
int constfold = rt != ty_err && !litfold
|
||||
&& eval_def_const(c, d->rhs, &dv, 0);
|
||||
/* #113: a def-ref that folds to a compile-time
|
||||
* constant (a def ref like `def INT_MIN: int =
|
||||
* I32_MIN`) carries its referent's concrete declared
|
||||
* type (i32), not UNTYPED_INT, so the assignability
|
||||
* check below rejected i32 -> int. In a def
|
||||
* initializer the rhs is a flexible constant, so
|
||||
* re-flexibilize the folded value to UNTYPED_INT here
|
||||
* when it fits the declared integer target — emulating
|
||||
* Hare's flexible-constant promotion (ICONST ->
|
||||
* promote_flexible/lower_flexible, range-checked:
|
||||
* ref/harec/src/types.c:860, reached via the
|
||||
* STORAGE_ICONST assignability case at :1012/:1019).
|
||||
* ww has no ICONST flexible-range type; def_cast_fits
|
||||
* is the range check that keeps a genuine out-of-range
|
||||
* value a loud "not assignable" error, never a silent
|
||||
* truncation (rule 7). This is strictly the const
|
||||
* subset: the general CONCRETE (non-const) integer
|
||||
* widening Hare does at ref/harec/src/types.c:1021-1037
|
||||
* is intentionally stricter in ww, see #115. */
|
||||
Type *art = rt;
|
||||
if (constfold && d->type && type_isint(d->type)
|
||||
&& type_isint(rt) && !type_isuntyped(rt)
|
||||
&& def_cast_fits(d->type, dv))
|
||||
art = ty_untyped_int;
|
||||
if (d->type && rt != ty_err && d->type != ty_err
|
||||
&& !type_assignable(d->type, rt))
|
||||
&& !type_assignable(d->type, art))
|
||||
err(c, d->pos, "def %s init %s not assignable to %s",
|
||||
d->str, type_name(c->a, rt),
|
||||
type_name(c->a, d->type));
|
||||
/* #88: const-fold sibling/imported def refs,
|
||||
* casts, and arithmetic so cgen's literal-only
|
||||
* emit can lay down the DATA row. GATED on the
|
||||
* plain literal fold missing first, so existing
|
||||
* literal/unary defs keep their rhs node and the
|
||||
* emitted bytes stay byte-identical. */
|
||||
u64 dv;
|
||||
if (rt != ty_err
|
||||
&& !fold_int_literal(d->rhs, &dv)
|
||||
&& eval_def_const(c, d->rhs, &dv, 0))
|
||||
if (constfold)
|
||||
stamp_intlit(c, d->rhs, dv);
|
||||
}
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user