A float element of a dyn view takes an int it holds exactly and traps on one it does not.
This commit is contained in:
parent
e79d9c0d07
commit
749b4aeb84
7
TODO.org
7
TODO.org
@ -23,9 +23,10 @@ str. Waits on the dyn-unless-annotated design.
|
||||
** DONE Any typed container crosses into dyn as a view
|
||||
CLOSED: [2026-09-26]
|
||||
A str element reads as a copy and is never written, an aggregate element is written
|
||||
through its own view, and an int is refused by a float element. A view of storage its
|
||||
own dyn global's initialiser built is refused. Rules out copying at the crossing, and
|
||||
any check in a release build.
|
||||
through its own view, a float element takes an int only when it holds it exactly (a
|
||||
class's float slot's rule), and a u64 above the largest i64 traps when read. A view of
|
||||
storage its own dyn global's initialiser built is refused. Rules out copying at the
|
||||
crossing, a dyn big int for u64, and any check in a release build.
|
||||
|
||||
** NEXT Dyn unless annotated
|
||||
Decided 2026-09-26, replacing the plain rule: number, bool and char literals are typed,
|
||||
|
||||
@ -3306,10 +3306,10 @@ static int int_range(uint8_t c, int64_t *lo, int64_t *hi) {
|
||||
/* One element, unboxed on the way in. The dyn value's tag must be the one
|
||||
* the element's type wants, or this traps by name and never coerces a
|
||||
* mismatched value into the slot; an int the element's width cannot hold
|
||||
* traps too, naming both. An int is not a float here: it is refused, not
|
||||
* converted, as every write through a view has been. A float into an f32
|
||||
* narrows, as (f32 x) does. [v] is the view and [x] the value, for the
|
||||
* sentence. */
|
||||
* traps too, naming both. An int goes into a float element when the float
|
||||
* holds it exactly, the rule a class's typed float slot follows, and traps
|
||||
* when it does not. A float into an f32 narrows, as (f32 x) does. [v] is the
|
||||
* view and [x] the value, for the sentence. */
|
||||
static void view_write(const uint8_t *loc, int64_t loclen, const char *op,
|
||||
flan_dyn v, const uint8_t *d, flan_dyn x, uint8_t *p) {
|
||||
char ty[128];
|
||||
@ -3341,9 +3341,24 @@ static void view_write(const uint8_t *loc, int64_t loclen, const char *op,
|
||||
switch (*d) {
|
||||
case 'f': case 'd': {
|
||||
double f;
|
||||
if (flan_dyn_tag(x) != FLAN_DYN_TAG_FLOAT)
|
||||
if (flan_dyn_tag(x) == FLAN_DYN_TAG_INT) {
|
||||
/* [slot_admit]'s rule for a class's float slot: exact is a round
|
||||
trip, and the range test keeps the cast back defined. */
|
||||
int64_t n = dyn_int_value(x);
|
||||
f = *d == 'f' ? (double)(float)n : (double)n;
|
||||
if (!(f >= -9223372036854775808.0 && f < 9223372036854775808.0)
|
||||
|| (int64_t)f != n) {
|
||||
desc_spell(d, ty, sizeof ty);
|
||||
flan_say(loc, loclen,
|
||||
"dyn %s: %lld has no exact %s, so it does not go into this "
|
||||
"element. Write it as a float, as in %lld.0",
|
||||
op, (long long)n, ty, (long long)n);
|
||||
flan_trap((const uint8_t *)"DynRange", 8);
|
||||
}
|
||||
} else if (flan_dyn_tag(x) == FLAN_DYN_TAG_FLOAT)
|
||||
f = dyn_num_value(x);
|
||||
else
|
||||
trap2(loc, loclen, TYPE_TRAP, op, "this view's elements are float", v, x);
|
||||
f = dyn_num_value(x);
|
||||
if (*d == 'f') { float g = (float)f; memcpy(p, &g, 4); }
|
||||
else memcpy(p, &f, 8);
|
||||
return;
|
||||
|
||||
@ -539,7 +539,16 @@ static void refuse_view(const char *what) {
|
||||
} else if (strcmp(what, "wrongfloat") == 0) {
|
||||
static double ff[1];
|
||||
v = flan_dyn_view_flat(ff, 1, FLAN_VIEW_F64);
|
||||
FDYN_set_at(v, flan_dyn_from_i64(0), text("nope"));
|
||||
} else if (strcmp(what, "inexactfloat") == 0) {
|
||||
/* An int goes into a float element only when the float holds it
|
||||
exactly; 2^53 + 1 is the first an f64 does not. */
|
||||
static double ff[1];
|
||||
v = flan_dyn_view_flat(ff, 1, FLAN_VIEW_F64);
|
||||
FDYN_set_at(v, flan_dyn_from_i64(0), flan_dyn_from_i64(1));
|
||||
if (ff[0] != 1.0) { printf("an exact int did not land: %g\n", ff[0]); exit(1); }
|
||||
FDYN_set_at(v, flan_dyn_from_i64(0),
|
||||
flan_dyn_from_i64(((int64_t)1 << 53) + 1));
|
||||
} else if (strcmp(what, "flatpush") == 0) {
|
||||
v = flan_dyn_view_flat(buf, 2, FLAN_VIEW_I64);
|
||||
FDYN_push(v, flan_dyn_from_i64(9));
|
||||
|
||||
@ -63,12 +63,14 @@
|
||||
(show "i8" a) (show "u8" b) (show "i16" c) (show "u16" d)
|
||||
(show "i32" e) (show "u32" f) (show "i64" g) (show "u64" h)
|
||||
(println (at b 2)))
|
||||
;; f32: read widens, write narrows.
|
||||
;; f32: read widens, write narrows, and an int goes in when the f32
|
||||
;; holds it exactly.
|
||||
(let [fs [(f32 0.5) 1.25]
|
||||
dv (keep fs)]
|
||||
(set (at dv 0) 2.75)
|
||||
(set (at dv 1) 3.1)
|
||||
(show "f32" dv)
|
||||
(set (at dv 0) 4)
|
||||
(println (at fs 0)))
|
||||
;; bool, through a slice cut from a local array.
|
||||
(let [bs [true false true]]
|
||||
@ -208,4 +210,9 @@
|
||||
(let [nm (Named {.name "ada" .id 7})]
|
||||
(put (keep nm) :name "bob")
|
||||
0)
|
||||
;; An int an f32 does not hold exactly: 2^24 + 1.
|
||||
(= n 9)
|
||||
(let [fs [(f32 0.5)]]
|
||||
(set (at (keep fs) 0) 16777217)
|
||||
0)
|
||||
:else (do (println "?") 1))))
|
||||
|
||||
@ -5851,7 +5851,7 @@ level "1"
|
||||
"i8 [0 -1 -2]\nu8 [251 252 253]\ni16 [-299 301]\nu16 [60001 2]\n\
|
||||
i32 [-69999 70001]\nu32 [4000000001 2]\ni64 [-4 6]\n\
|
||||
u64 [9000000000000000001 2]\n253\n\
|
||||
f32 [2.75 3.1]\n2.75\n\
|
||||
f32 [2.75 3.1]\n4\n\
|
||||
bool [true true true]\ntrue\n\
|
||||
EIINNOORRSSTT\n\
|
||||
point #Point{:x 0.5 :y 3}\n40\n9.5\n9.5\n2\ntrue\n\
|
||||
@ -5867,7 +5867,8 @@ level "1"
|
||||
("2", "this u64 element is 18000000000000000000, above the largest \
|
||||
dyn int");
|
||||
("3", "a Point has no field :z. Its fields are :x :y");
|
||||
("8", "a str element is read-only through a dyn view") ]
|
||||
("8", "a str element is read-only through a dyn view");
|
||||
("9", "16777217 has no exact f32") ]
|
||||
and any_stale =
|
||||
[ ("4", "this view points into a local of leak-local, and that call \
|
||||
has returned");
|
||||
|
||||
@ -258,6 +258,7 @@ let () =
|
||||
("wrongwrite", "this view's elements are int");
|
||||
("wrongbool", "this view's elements are bool");
|
||||
("wrongfloat", "this view's elements are float");
|
||||
("inexactfloat", "9007199254740993 has no exact f64");
|
||||
("flatpush", "this view is a slice or an array and cannot grow");
|
||||
(* And the operator's own name in that sentence. [flan_dyn_len] hands
|
||||
a string down twice — once to its type trap and once to the view
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user