The three ways an embed is written wrong, each said at the right moment
A computed path, a file that is not there, and a second argument that is not `string`. The type argument is now settled before the file is opened: a program asking for a type embed cannot read a file as was otherwise told the file was missing, and got the real complaint only after fixing the wrong thing. A missing asset is a compile error naming it rather than an empty embed, because an asset silently absent is the class of quiet wrongness the whole feature exists to remove. An empty *directory* is not that: it embeds cleanly as [0 EmbedFile] and len answers 0.
This commit is contained in:
parent
fff4f5d985
commit
fe85ecd246
15
lib/check.ml
15
lib/check.ml
@ -2038,6 +2038,17 @@ and named_call ctx ~want loc name args =
|
|||||||
| "embed" ->
|
| "embed" ->
|
||||||
(match args with
|
(match args with
|
||||||
| [ p ] | [ p; _ ] ->
|
| [ p ] | [ p; _ ] ->
|
||||||
|
(* The spelling is settled before the file is opened, so a program that
|
||||||
|
asks for a type embed cannot read a file as is told that, rather than
|
||||||
|
being told the file is missing and left to discover the other half
|
||||||
|
after fixing it. *)
|
||||||
|
(match args with
|
||||||
|
| [ _; { Ast.e = Ast.Var "string"; _ } ] | [ _ ] -> ()
|
||||||
|
| [ _; t ] ->
|
||||||
|
fail t.Ast.loc
|
||||||
|
"embed's second argument is the type to read the file as, and \
|
||||||
|
`string` is the only one — (embed \"p\") is the [u8]"
|
||||||
|
| _ -> ());
|
||||||
let data = read_embed_file (embed_path loc p) p.Ast.loc in
|
let data = read_embed_file (embed_path loc p) p.Ast.loc in
|
||||||
let as_string () = mk loc Types.String (Tast.Str data) in
|
let as_string () = mk loc Types.String (Tast.Str data) in
|
||||||
(* A [Str] node typed [u8] rather than a [Bytes] prim over one. [Bytes]
|
(* A [Str] node typed [u8] rather than a [Bytes] prim over one. [Bytes]
|
||||||
@ -2055,10 +2066,6 @@ and named_call ctx ~want loc name args =
|
|||||||
(match args with
|
(match args with
|
||||||
| [ _; { Ast.e = Ast.Var "string"; _ } ] ->
|
| [ _; { Ast.e = Ast.Var "string"; _ } ] ->
|
||||||
expect loc ~want (as_string ())
|
expect loc ~want (as_string ())
|
||||||
| [ _; t ] ->
|
|
||||||
fail t.Ast.loc
|
|
||||||
"embed's second argument is the type to read the file as, and \
|
|
||||||
`string` is the only one — (embed \"p\") is the [u8]"
|
|
||||||
| _ ->
|
| _ ->
|
||||||
(match want with
|
(match want with
|
||||||
| Some Types.String -> as_string ()
|
| Some Types.String -> as_string ()
|
||||||
|
|||||||
@ -360,6 +360,25 @@ let () =
|
|||||||
"(defn main [] i32 (restart-case 0 (use-value [v i32] v))\n\
|
"(defn main [] i32 (restart-case 0 (use-value [v i32] v))\n\
|
||||||
\ (invoke-restart 'use-value (println \"\")) 0)"
|
\ (invoke-restart 'use-value (println \"\")) 0)"
|
||||||
"a restart argument must be a value";
|
"a restart argument must be a value";
|
||||||
|
(* An embed reads the bytes before any value exists, so the path has to be
|
||||||
|
a literal - Odin's rule and for Odin's reason (check_load_directive
|
||||||
|
refuses anything that is not Addressing_Constant). This is the refusal
|
||||||
|
that keeps the result genuinely free at run time. *)
|
||||||
|
refuses_src "an embedded path that is computed"
|
||||||
|
"(defn main [] i32 (let [p \"x\"] (len (embed p))))"
|
||||||
|
"must be a literal string";
|
||||||
|
(* A file that is not there is a compile error naming it, not an empty
|
||||||
|
embed: an asset silently missing is the class of quiet wrongness this
|
||||||
|
whole feature exists to remove. *)
|
||||||
|
refuses_src "an embedded file that does not exist"
|
||||||
|
"(defn main [] i32 (len (embed \"no-such-asset.bin\")))"
|
||||||
|
"cannot embed";
|
||||||
|
(* One extra argument, and `string` is the only thing it can be. Two
|
||||||
|
spellings, not one form that changes type with its context. *)
|
||||||
|
refuses_src "embed asked for a type it cannot read a file as"
|
||||||
|
"(defn main [] i32 (len (embed \"no-such-asset.bin\" i32)))"
|
||||||
|
"`string` is the only one";
|
||||||
|
|
||||||
(* Allocators, spec-memory.md. The tier on its own, with no container
|
(* Allocators, spec-memory.md. The tier on its own, with no container
|
||||||
above it, so that a failure here is not read as a Vec bug. What is
|
above it, so that a failure here is not read as a Vec bug. What is
|
||||||
asserted is the capability set differing per allocator, the context
|
asserted is the capability set differing per allocator, the context
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user