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 bf4727d..0000000 Binary files a/forms.so and /dev/null differ 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;