diff --git a/runtime/flan_dyn.c b/runtime/flan_dyn.c index 9208a601..41899587 100644 --- a/runtime/flan_dyn.c +++ b/runtime/flan_dyn.c @@ -3733,6 +3733,12 @@ flan_dyn flan_dyn_get(flan_dyn m, flan_dyn k, const uint8_t *loc, int64_t loclen) { class_entry *e; if (!is_map(m)) trap2(loc, loclen, TYPE_TRAP, "get", "only a map answers it", m, k); + /* A struct's view: its field, or a trap at this site naming the fields. */ + if (dyn_obj(m)->kind == OBJ_VIEW) { + const uint8_t *fty; + uint8_t *p = view_field(loc, loclen, "get", dyn_obj(m), k, &fty); + return view_read(loc, loclen, "get", dyn_obj(m), fty, p); + } e = class_sync(dyn_obj(m)); if (e != NULL && class_slot(e, k) < 0) trap_no_slot(loc, loclen, "get", dyn_obj(m), e, k); diff --git a/test/programs/dyn-view-any.flan b/test/programs/dyn-view-any.flan index e533bdf1..a05512b0 100644 --- a/test/programs/dyn-view-any.flan +++ b/test/programs/dyn-view-any.flan @@ -160,6 +160,19 @@ (let [p (Point {.x 1.0 .y 2}) q (Point {.x 1.0 .y 2})] (println (= (keep p) (keep q)))) + ;; .field and [:k] on a struct's view: a read is get, a set is put, + ;; and the typed struct sees every write. + (let [p (Point {.x 1.0 .y 2}) + m (Mix {.a 1 .b 2 .c 0.5 .d false .e [1 2 3] .f 4}) + dp (keep p) + dm (keep m)] + (set (.y dp) 5) + (update (.y dp) + 10) + (set (at dp :x) 2.5) + (set (.d dm) true) + (set (at (.e dm) 1) 20) + (println (.y dp) (at dp :x) (.a dm) (.d dm) (at (.e dm) 1)) + (println (.y p) (.x p) (.d m) (at (.e m) 1))) 0) ;; A value an element's width cannot hold. (= n 1) @@ -215,4 +228,9 @@ (let [fs [(f32 0.5)]] (set (at (keep fs) 0) 16777217) 0) + ;; A field a struct does not have, through .field. + (= n 10) + (let [p (Point {.x 1.0 .y 2})] + (set (.z (keep p)) 3) + 0) :else (do (println "?") 1)))) diff --git a/test/test_acceptance.ml b/test/test_acceptance.ml index ea8e0e58..7071fdab 100644 --- a/test/test_acceptance.ml +++ b/test/test_acceptance.ml @@ -5925,7 +5925,8 @@ level "1" grid [[1 2 3] [4 5 60]]\n60\n\ points [#Point{:x 1 :y 1} #Point{:x 2 :y 20}]\n20\n\ vec [1 2 3]\n3\n6\n5\n4\n3\n\ - temp #Point{:x 1.5 :y 2}\n4\n3\ntrue\n" + temp #Point{:x 1.5 :y 2}\n4\n3\ntrue\n\ + 15 2.5 1 true 20\n15 2.5 true 20\n" in let any_traps = [ ("1", "300 does not fit a u8 element, which holds 0 to 255"); @@ -5933,7 +5934,8 @@ level "1" 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"); - ("9", "16777217 has no exact f32") ] + ("9", "16777217 has no exact f32"); + ("10", "dyn put: a Point has no field :z. Its fields are :x :y") ] and any_stale = [ ("4", "this view points into a local of leak-local, and that call \ has returned");