From 1ee54d6b56df1ac9436786b508f5a5036d723ed8 Mon Sep 17 00:00:00 2001 From: Joseph Ferano Date: Sat, 12 Sep 2026 20:27:19 +0700 Subject: [PATCH] A union is a type name, and (vec-new) did not think so The prelude's own (vec-new Form) was refused with "nothing here says what (vec-new) is a Vec of" -- a message about a missing annotation, to a program that had written one. The build went red the moment the Form declaration was checked against anything, which is why the front half landed unmeasured. The test a leading bare symbol has to pass was spelled out twice, once in vec_new_elem and once in map_new_types, and both lists were written before unions existed: primitives, structs, enums, aliases. resolve_name has known about unions since they landed, so the two halves disagreed about what a type name is. Now there is one list, read by both, so the next kind of type cannot be added to one of them. The case is in unions.flan rather than in a file of its own, because what it asserts is that a union is an element type like any other -- (vec-new Shape), (map-new string Shape) -- and that is a sentence about unions. Also drops forms.so, a build artefact the last lane committed. --- .gitignore | 1 + forms.so | Bin 10008 -> 0 bytes lib/check.ml | 25 +++++++++++++++++-------- test/programs/unions.flan | 14 ++++++++++++++ test/test_acceptance.ml | 3 ++- 5 files changed, 34 insertions(+), 9 deletions(-) delete mode 100755 forms.so diff --git a/.gitignore b/.gitignore index 59fe709..abda8df 100644 --- a/.gitignore +++ b/.gitignore @@ -68,3 +68,4 @@ test/web-files-out.txt # Python bytecode from the tools directory __pycache__/ *.pyc +/forms.so diff --git a/forms.so b/forms.so deleted file mode 100755 index bf4727d281647e706568819f70fae9ced546e1e7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10008 zcmeHNUuaup6#tT@Yr56jSQUe__HIj|OnZ}Brmkh$#J0OFsh!<$)(tPWO|nGOBqq1m zsbC@c5K3Ji=9>&3#61ZGK_-G0D)z+(5g7vo>w}W8;UC29LGXIc{l1glroH0B@Imew z_x`@~`_B3PoO}D-ozuQP5+C(?JdC7?Jk@DN!b_ZZs)_W*0RY@4^bcCPNpla9w!-odK2YxF8l!NPb>0`zJqH_!0W~u1&%NNcR-#XkPou(#KK9?bX&S zJ%&0)ueNIG1E}LtYVTV5!>HpUtF3^3QZ3&IsFmN<%4;G2QcJ}b`s|0z&i?8}=u_WZ zGg{S3lUn{faAsXyJ~j!vQtvU^+srIfnpv_qHbo3bM~4T?L&2`Io1o4RK7O@YI%?uJ-lxO z`r=E2>W1}N;8=%%nK*jO=#Ezg`_`@>=60Pp28R<#0XG8wzX)LB z*a{aWlswPHRMBT~&|n{a^U~djPI4D?P|j<&!SQzE#~k=a9r$hs{sjmAf&)M8z`qK7 z2ZJbBi6yp$q_TQWOJ#Bit(YtsdeLAOBNQ#AXR_Ow!h9*snY5luWRpd$&M33VY*r~0 z^E1f?i+rJBkS!vc*ArSM2XklnOnj7*ku1OxuZ8(K@tKLGTg0Y~Z{a5V9^rr-)f$lT z+jx8zNCGw<-w2YRjkni*WE*di5H*5Y4*4av}VKU|StO!GJ(i%NlENiKV5 zr9f2jMBFeZ$g;vhS^?3tsOfNsdZEtHU1vlLB1dfjzw! zGU!<8c=l)0#6BhkMy23*`@Wa`i|mQ}1`qd#4kGP}8v!>0ZUo#2xDjw8;6}iWfExif z0=F*$fBa?UtpYjgMsqPhg zRm?~H6`@nE6A^ZpW24Y~T>J0t^n3Eg8Q&Ml;70<#5O`JKPXccWZ1g7`yM638lXN@o z#^dwwu)X!)-;+Jo6TI;6gm?f}o(5c};4xK4v2r}Xqi}gx8>8ojeJGP~iAQhgbkiO9 zk^^6M;NN!OF9W|@J>e4v`!5~%Zyk8X^J6FpXv5P_MJL9dv>nIYXZTG>RP4)H0F_22;-E=3&23cTp1Ob70KTC^7}+ z){zvgLKdux`GjuhOi8A-R8gNxTGskpW)=p@<7jz9LBrc2<1h&ROwc)mH3}3$*xfdv zca?BI^xFODy(jDt?vX#O1M8z`Lfh@_^ae7ko*YIm-cQqjmTVE w6zi8j#cwD1(euOaC9R!%@cZfkjyLQiw8e0B7C*zg`M-0Jn=I5Vd85()Z(4)dh5!Hn diff --git a/lib/check.ml b/lib/check.ml index 9a39427..a593571 100644 --- a/lib/check.ml +++ b/lib/check.ml @@ -2073,6 +2073,21 @@ and file_guard ctx loc ~path_slot ~op mk_steps = (Tast.Let ([ (ok, mk loc Types.Bool (Tast.Bool false)) ], [ mk loc Types.Unit (Tast.While (notok (), [ body ])) ])) +(* Is this bare symbol the name of a type? Every table [resolve_name] will look + in, and the union table is one of them: a union is [Named] exactly as a + struct is, so (vec-new Form) is as ordinary as (vec-new Cell). It was left + out when unions landed, which made the prelude's own (vec-new Form) fail + with "nothing here says what (vec-new) is a Vec of" — a message about a + missing annotation for a program that had written one. One list, read by + both callers, so the next kind of type added cannot be added to one of + them. *) +and type_named ctx n = + List.mem n Types.primitive_names + || Hashtbl.mem ctx.env.structs n + || Hashtbl.mem ctx.env.unions n + || Hashtbl.mem ctx.env.enums n + || Hashtbl.mem ctx.env.aliases n + (* The element type for [vec-new]: a leading bare symbol naming a type, or the expectation at the site. A bare symbol shadowed by a local or a global is that binding — an allocator, in practice — and not a type. *) @@ -2082,10 +2097,7 @@ and vec_new_elem ctx ~want loc args = | { Ast.e = Ast.Var n; _ } :: rest when lookup ctx n = None && (not (Hashtbl.mem ctx.env.globals n)) - && (List.mem n Types.primitive_names - || Hashtbl.mem ctx.env.structs n - || Hashtbl.mem ctx.env.enums n - || Hashtbl.mem ctx.env.aliases n) -> + && type_named ctx n -> Some (resolve_name ctx.env ~seen:[] loc n, rest) | _ -> None in @@ -2114,10 +2126,7 @@ and map_new_types ctx ~want loc args = let is_type n = lookup ctx n = None && (not (Hashtbl.mem ctx.env.globals n)) - && (List.mem n Types.primitive_names - || Hashtbl.mem ctx.env.structs n - || Hashtbl.mem ctx.env.enums n - || Hashtbl.mem ctx.env.aliases n) + && type_named ctx n in match args with | { Ast.e = Ast.Var k; _ } :: { Ast.e = Ast.Var v; _ } :: rest diff --git a/test/programs/unions.flan b/test/programs/unions.flan index 56ad9fb..070687c 100644 --- a/test/programs/unions.flan +++ b/test/programs/unions.flan @@ -93,4 +93,18 @@ (print (Shape.Dot {.x 1.5 .y -2.5})) (println "") (print (Shape.Tag {.name "printed" .n 9})) (println "") (print (Cell {.id 7 .s (Shape.Rect {.w 1 .h 2})})) (println "") + + ;; A union names an element type the same way a struct does. It reads as + ;; trivia and it was not: the type-name test (vec-new) and (map-new) use to + ;; read a leading bare symbol listed structs, enums, aliases and primitives + ;; and not unions, so (vec-new Shape) was refused for not saying what it + ;; held -- by a program that had said. + (let [vs (vec-new Shape) + ms (map-new string Shape)] + (push vs (Shape.Rect {.w 2 .h 3})) + (push vs Shape.Empty) + (put ms "only" (Shape.Tag {.name "in a map" .n 1})) + (print (i64 (area (at vs 0)))) (println "") + (println (describe (at vs 1))) + (println (match (get ms "only") (Some s) (describe s) None "missing"))) 0) diff --git a/test/test_acceptance.ml b/test/test_acceptance.ml index d60033c..81cb83a 100644 --- a/test/test_acceptance.ml +++ b/test/test_acceptance.ml @@ -1696,7 +1696,8 @@ ERR@7 unexpected token: not the kind the caller was reading 32\n0\n-1\nin a cell\nempty\n30\nreassigned\n15\n\ Shape.Empty\n(Shape.Dot {.x 1.5 .y -2.5})\n\ (Shape.Tag {.name \"printed\" .n 9})\n\ - (Cell {.id 7 .s (Shape.Rect {.w 1 .h 2})})\n" + (Cell {.id 7 .s (Shape.Rect {.w 1 .h 2})})\n\ + 6\nempty\nin a map\n" in outputs "unions" "programs/unions.flan" unions_out; outputs ~opt:"-O0" "unions, -O0" "programs/unions.flan" unions_out;