A union is not a missing struct either
layout searched only Tast.structs, so a declared union came back as "no struct is named X" — which reads as "that type does not exist" about a type the checker knows. Refused by kind beside the enum, and both refusals now have a test: a new enum and a new union, evaluated into the session.
This commit is contained in:
parent
404b8559c5
commit
41025fc0ac
4
BUILT.md
4
BUILT.md
@ -1042,7 +1042,9 @@ suffix would reintroduce the ambiguity the rule exists to remove, and a rule wit
|
|||||||
rely on. The refusal carries `:candidates`, so a person is one copy-paste from the answer and a client has its
|
rely on. The refusal carries `:candidates`, so a person is one copy-paste from the answer and a client has its
|
||||||
completion list — the same shape as `package_of` refusing a directory imported under two aliases rather than picking
|
completion list — the same shape as `package_of` refusing a directory imported under two aliases rather than picking
|
||||||
one. An enum is refused by *kind* (`X is an enum, not a struct`): its members are erased to `i32` before `Tast.program`
|
one. An enum is refused by *kind* (`X is an enum, not a struct`): its members are erased to `i32` before `Tast.program`
|
||||||
exists, which is the same fact that makes a `defenum` unreloadable.
|
exists, which is the same fact that makes a `defenum` unreloadable. A union is refused the same way and for its own
|
||||||
|
reason — it is declared, and union *values* are milestone 6. Both are `Types.Named` at a use site, so falling through
|
||||||
|
to "no struct is named X" would say a type does not exist about one that plainly does.
|
||||||
|
|
||||||
**`render.ml` is not reused, and that is not a second walk.** It walks a *value* and emits the code that prints it;
|
**`render.ml` is not reused, and that is not a second walk.** It walks a *value* and emits the code that prints it;
|
||||||
this describes a *type* and emits text. What is shared is the spelling: field types go through `Types.to_string`, which
|
this describes a *type* and emits text. What is shared is the spelling: field types go through `Types.to_string`, which
|
||||||
|
|||||||
12
lib/dev.ml
12
lib/dev.ml
@ -529,12 +529,18 @@ let layout t ~ty =
|
|||||||
Wire.quote (Types.to_string f.Tast.fty) ])
|
Wire.quote (Types.to_string f.Tast.fty) ])
|
||||||
s.Tast.fields) ]
|
s.Tast.fields) ]
|
||||||
| None ->
|
| None ->
|
||||||
(* An enum is a type the checker knows and this op cannot describe: its
|
(* Two types the checker knows and this op cannot describe. An enum's
|
||||||
members are erased to i32 before [Tast.program] exists, which is the
|
members are erased to i32 before [Tast.program] exists, which is the
|
||||||
same fact that makes a defenum unreloadable. Saying which kind it is
|
same fact that makes a defenum unreloadable; a union is declared and
|
||||||
beats "no such type" for a name that plainly exists. *)
|
has no values yet. Either way, saying which kind it is beats "no such
|
||||||
|
type" for a name that plainly exists. *)
|
||||||
if Hashtbl.mem t.session.Session.env.Check.enums ty then
|
if Hashtbl.mem t.session.Session.env.Check.enums ty then
|
||||||
error (ty ^ " is an enum, not a struct; its members are erased to i32")
|
error (ty ^ " is an enum, not a struct; its members are erased to i32")
|
||||||
|
else if
|
||||||
|
List.exists (fun (u : Tast.union) -> String.equal u.Tast.uname ty)
|
||||||
|
t.session.Session.program.Tast.unions
|
||||||
|
then
|
||||||
|
error (ty ^ " is a union, not a struct; union values are milestone 6")
|
||||||
else
|
else
|
||||||
let suffix = "/" ^ ty in
|
let suffix = "/" ^ ty in
|
||||||
let candidates =
|
let candidates =
|
||||||
|
|||||||
@ -174,6 +174,44 @@ let () =
|
|||||||
let r = request c "(:op \"layout\" :type \"Nonesuch\")" in
|
let r = request c "(:op \"layout\" :type \"Nonesuch\")" in
|
||||||
if status r <> "error" then fail "a type that does not exist got a layout";
|
if status r <> "error" then fail "a type that does not exist got a layout";
|
||||||
|
|
||||||
|
(* A name that plainly exists and is not a struct is refused by *kind*.
|
||||||
|
Both of these are types the checker knows and this op cannot
|
||||||
|
describe, and "no struct is named X" would read as "X does not
|
||||||
|
exist". *)
|
||||||
|
let refusal r =
|
||||||
|
Option.value ~default:(status r) (Wire.string_field r "message")
|
||||||
|
in
|
||||||
|
let contains hay needle =
|
||||||
|
let n = String.length needle in
|
||||||
|
let rec go i =
|
||||||
|
i + n <= String.length hay
|
||||||
|
&& (String.equal (String.sub hay i n) needle || go (i + 1))
|
||||||
|
in
|
||||||
|
go 0
|
||||||
|
in
|
||||||
|
let r =
|
||||||
|
request c
|
||||||
|
"(:op \"eval\" :code \"(defenum Colour [red 0 green 1])\" :file \"/tmp/buf.flan\")"
|
||||||
|
in
|
||||||
|
if status r <> "ok" then fail "a new enum: %s" (refusal r)
|
||||||
|
else begin
|
||||||
|
let r = request c "(:op \"layout\" :type \"Colour\")" in
|
||||||
|
if status r <> "error" then fail "an enum answered a struct layout"
|
||||||
|
else if not (contains (refusal r) "is an enum") then
|
||||||
|
fail "an enum is refused as: %s" (refusal r)
|
||||||
|
end;
|
||||||
|
let r =
|
||||||
|
request c
|
||||||
|
"(:op \"eval\" :code \"(defunion Shape [(Circle [r f32])])\" :file \"/tmp/buf.flan\")"
|
||||||
|
in
|
||||||
|
if status r <> "ok" then fail "a new union: %s" (refusal r)
|
||||||
|
else begin
|
||||||
|
let r = request c "(:op \"layout\" :type \"Shape\")" in
|
||||||
|
if status r <> "error" then fail "a union answered a struct layout"
|
||||||
|
else if not (contains (refusal r) "is a union") then
|
||||||
|
fail "a union is refused as: %s" (refusal r)
|
||||||
|
end;
|
||||||
|
|
||||||
(* The identity rule, and the case NEXT.md named: a second [Blob] typed
|
(* The identity rule, and the case NEXT.md named: a second [Blob] typed
|
||||||
into a package is [agent/Blob], the qualified name resolves, and the
|
into a package is [agent/Blob], the qualified name resolves, and the
|
||||||
bare one is refused with the names it could have meant rather than
|
bare one is refused with the names it could have meant rather than
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user