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" ->
|
||||
(match args with
|
||||
| [ 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 as_string () = mk loc Types.String (Tast.Str data) in
|
||||
(* 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
|
||||
| [ _; { Ast.e = Ast.Var "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
|
||||
| Some Types.String -> as_string ()
|
||||
|
||||
@ -360,6 +360,25 @@ let () =
|
||||
"(defn main [] i32 (restart-case 0 (use-value [v i32] v))\n\
|
||||
\ (invoke-restart 'use-value (println \"\")) 0)"
|
||||
"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
|
||||
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
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user