fix(ir): const evaluators' field-access arm is raw value-shadow aware [F0.11]
A backtick raw value-shadow receiver (`` `f64 := … `` then `` `f64.epsilon ``, `` `s8.max ``) was misclassified as the builtin numeric-limit accessor by the shared compile-time evaluators. The sibling `isFloatValuedExpr` already guards this with an `is_raw` check, but `evalConstFloatExpr` / `evalConstIntExpr` did not — so once a raw value-shadow's field read flowed into the unified float→int narrowing rule or an array-dim count, the float folder returned the BUILTIN `f64.epsilon` (2.22e-16) and wrongly errored, and the integer folder turned `` `s8.max `` into the builtin `127` (a fabricated 127-element array). Both evaluators' field-access arms now mirror `isFloatValuedExpr`'s `is_raw` guard: a raw receiver yields `obj_name = null`, so it is never a numeric-limit/pack leaf and falls through to the ordinary runtime field read. A raw value-shadow is a mutable-local field (an observable later reassignment), so it is genuinely runtime and must not be const-folded — it now behaves exactly like a plainly-named field read: `` `f64.epsilon `` narrowing into `s64` truncates its field value (11.5 → 11, identical to `b.epsilon`), and `` `s8.max `` as an array dimension is rejected as a non-constant count (identical to `b.max`). The bare builtin path is unchanged. Regression (issue 0095 / F0.11-7): - examples/0169-types-value-shadow-field-narrowing.sx (positive — raw float-field read narrows/truncates, mutation proves runtime, bare limit still folds) - examples/1148-diagnostics-value-shadow-field-dim-not-const.sx (negative — raw int-field dim rejected as non-const) - program_index.test.zig "a backtick raw-shadow receiver is a field read, not a numeric-limit fold (F0.11-7)" specs.md + readme.md note the value-shadow rule extends into the narrowing/count contexts.
This commit is contained in:
58
examples/0169-types-value-shadow-field-narrowing.sx
Normal file
58
examples/0169-types-value-shadow-field-narrowing.sx
Normal file
@@ -0,0 +1,58 @@
|
||||
// A raw value binding whose spelling shadows a builtin FLOAT type name
|
||||
// (`` `f64 ``) and whose FLOAT field is read into an INTEGER binding. Field
|
||||
// access on such a value is an ORDINARY runtime field read — the unified
|
||||
// float→int narrowing rule (F0.11) must treat it EXACTLY like a non-shadowed
|
||||
// struct's field read, never as the builtin numeric-limit accessor. So
|
||||
// `` `f64.epsilon `` reads the value's `epsilon` field (a runtime f64) and a
|
||||
// float→int narrowing TRUNCATES it, identical to a plainly-named `b.epsilon` —
|
||||
// it does NOT fold the builtin `f64.epsilon` (= 2.22e-16) into the binding.
|
||||
//
|
||||
// The receiver is a mutable `:=` local, so its field is a RUNTIME value, not a
|
||||
// compile-time constant: reading it after a reassignment yields the new value,
|
||||
// proving it can never be const-folded from the initializer literal.
|
||||
//
|
||||
// Companion to 0161 (value-shadow field reads in NON-narrowing, s64-field
|
||||
// contexts). This file exercises the narrowing path 0161 does not: a FLOAT
|
||||
// field flowing into an integer binding.
|
||||
//
|
||||
// Regression (issue 0095 / F0.11-7): the compile-time float evaluator's
|
||||
// field-access arm misclassified a raw value-shadow receiver as the builtin
|
||||
// numeric-limit accessor, so `` `f64.epsilon `` newly errored under the
|
||||
// narrowing rule with the BUILTIN value (2.22e-16) instead of reading the
|
||||
// field. The fix mirrors the `is_raw` guard the sibling `isFloatValuedExpr`
|
||||
// already applies, so the const-folding cluster agrees: a raw receiver is a
|
||||
// field read, only a bare type receiver folds a limit.
|
||||
#import "modules/std.sx";
|
||||
|
||||
FBox :: struct { epsilon: f64; }
|
||||
|
||||
main :: () {
|
||||
// Raw value-shadow of the builtin `f64`, FLOAT field → narrow into s64.
|
||||
// Ordinary field read + runtime float→int truncation: 11.0 → 11.
|
||||
`f64 := FBox.{ epsilon = 11.0 };
|
||||
x : s64 = `f64.epsilon;
|
||||
|
||||
// A NON-integral field value truncates exactly the same way — a runtime
|
||||
// f64 has no compile-time value to fold, so 11.5 → 11 (NOT a non-integral
|
||||
// narrowing error, which would only fire on a compile-time-constant float).
|
||||
`f64b := FBox.{ epsilon = 11.5 };
|
||||
y : s64 = `f64b.epsilon;
|
||||
|
||||
// The value-shadowed read is identical to a plainly-named one: `b.epsilon`
|
||||
// narrows the same way, so the backtick spelling changes nothing.
|
||||
b := FBox.{ epsilon = 11.5 };
|
||||
yb : s64 = b.epsilon;
|
||||
|
||||
print("x={} y={} yb={}\n", x, y, yb); // 11 11 11
|
||||
|
||||
// The field is a RUNTIME value: reassign, then read → the new value, not
|
||||
// the initializer literal (so const-folding it would be unsound).
|
||||
`f64.epsilon = 4.0;
|
||||
xm : s64 = `f64.epsilon;
|
||||
print("xm={}\n", xm); // 4
|
||||
|
||||
// The bare builtin receiver (not raw-escaped) is UNAFFECTED — it still
|
||||
// folds the numeric limit. `f64.max - f64.max` = 0.0 is integral → 0.
|
||||
lim : s64 = f64.max - f64.max;
|
||||
print("lim={}\n", lim); // 0
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
// A raw value binding whose spelling shadows a builtin INTEGER type name
|
||||
// (`` `s8 ``) used as an array DIMENSION through one of its fields. Field
|
||||
// access on a raw value is an ORDINARY runtime field read, so `` `s8.max `` is
|
||||
// a runtime value — NOT the builtin `s8.max` (= 127) and NOT a compile-time
|
||||
// constant. An array dimension demands a compile-time integer constant, so the
|
||||
// dimension is rejected with the same diagnostic a plainly-named runtime field
|
||||
// read (`b.max`) earns — the backtick spelling changes nothing.
|
||||
//
|
||||
// Sibling (integer) half of the F0.11-7 fix: the compile-time INTEGER evaluator
|
||||
// (`evalConstIntExpr`) misclassified a raw value-shadow receiver as the builtin
|
||||
// `<IntType>.min`/`.max` accessor, silently folding 127 and fabricating a
|
||||
// 127-element array. The `is_raw` guard now defers it to an ordinary field
|
||||
// read, so it surfaces as a non-constant dimension instead of a silent wrong
|
||||
// length.
|
||||
//
|
||||
// Negative companion to 0169 (the FLOAT-field narrowing half, exit 0).
|
||||
//
|
||||
// Regression (issue 0095 / F0.11-7).
|
||||
#import "modules/std.sx";
|
||||
|
||||
DimBox :: struct { max: s64; }
|
||||
|
||||
main :: () {
|
||||
`s8 := DimBox.{ max = 3 };
|
||||
// Raw value-shadow field read → a runtime value, not the builtin `s8.max`
|
||||
// (127) and not a compile-time constant → rejected as a non-const dim.
|
||||
arr : [`s8.max]f32 = ---;
|
||||
print("len={}\n", arr.len);
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
x=11 y=11 yb=11
|
||||
xm=4
|
||||
lim=0
|
||||
@@ -0,0 +1 @@
|
||||
1
|
||||
@@ -0,0 +1,5 @@
|
||||
error: array dimension must be a compile-time integer constant
|
||||
--> examples/1148-diagnostics-value-shadow-field-dim-not-const.sx:27:13
|
||||
|
|
||||
27 | arr : [`s8.max]f32 = ---;
|
||||
| ^^^^^^
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
Reference in New Issue
Block a user