A .fln file's common mistakes are answered in .fln terms, a bare () in a body slot does nothing, and the syntax gaps found writing by hand are listed in TODO.org
This commit is contained in:
parent
7e48f1eaf5
commit
dca29a5605
46
TODO.org
46
TODO.org
@ -628,6 +628,52 @@ awaiting confirmation, and the build order. Rules out Parinfer, wisp and
|
||||
sweet-expressions, and a simplified in-paren syntax — all thin the parens
|
||||
without removing them.
|
||||
|
||||
** TODO A one-line if cannot take its else on the next line
|
||||
=if c then a= then =else b= under it is refused. Proposal: an =else=/=elif= at
|
||||
the if's column continues a one-line if, as F#'s does.
|
||||
|
||||
** TODO A lambda with a block cannot be a call's argument
|
||||
=sort-by(xs, fn(a, b)= plus a block is refused; the lambda has to be bound first,
|
||||
with its type written. Proposal: a call ending in =fn(...)= and a trailing =:=
|
||||
hands the block to that lambda: =sort-by(xs, fn(a, b)):=.
|
||||
|
||||
** TODO A lambda's parameters cannot be typed
|
||||
=fn(a, b)= takes bare names, so a lambda bound by =let= needs
|
||||
=let f: Fn(C, C) -> bool = fn(a, b)=. Proposal: =fn(a: C, b: C)= as in a
|
||||
=fn= definition.
|
||||
|
||||
** TODO A condition struct with a parent has no sugar
|
||||
=defstruct(DiskFull, :parent, IoError, [free i64])= is the fallback, with a
|
||||
paren field vector. Proposal: =struct DiskFull :parent IoError= plus field lines.
|
||||
|
||||
** TODO defmacro has no sugar
|
||||
=defmacro(repeat, [i n & body]):= with a space-separated parameter vector.
|
||||
Proposal: =macro repeat(i, n, & body)= plus a block.
|
||||
|
||||
** TODO loop/recur has no sugar
|
||||
=loop([x a y b]):=. Proposal: =loop x = a, y = b= plus a block; =recur(...)=
|
||||
stays a call.
|
||||
|
||||
** TODO A restart's report string is a body line
|
||||
=:report= and its string sit as two statements under =restart name()=.
|
||||
Proposal: =restart name() "report text"= on the header line.
|
||||
|
||||
** TODO An enum member has only a keyword spelling
|
||||
=:north= works, =Dir.north= is an unknown name, while a data case is
|
||||
=Shape.Rect=. Proposal: accept =Dir.north= as the member.
|
||||
|
||||
** TODO Checker and runtime messages print types and fixes in parens
|
||||
In a .fln file, =(Fn [A] R)=, =(Option i32)=, =(get 0 :body)=, =(/ x 0)= and most
|
||||
usage hints still print paren syntax; a handful now print .fln spellings.
|
||||
Proposal: =Types.to_string= and the hints take the syntax of the location's file.
|
||||
|
||||
** TODO flan convert separates adjacent one-line globals with blank lines
|
||||
=once a: i32= on consecutive lines come back one blank line apart.
|
||||
|
||||
** TODO A bad map key type is followed by unknown-name errors for its parts
|
||||
=map-new([const u8], i32)= reports the key, then "unknown name const" and
|
||||
"unknown name i32" — in both syntaxes.
|
||||
|
||||
** TODO The shims in sand.flan can go
|
||||
=sand.flan= defines =dyn->f64= and =dyn->u32=, one-line functions whose only job
|
||||
is that their parameter slot unboxes. Every call site can write =(f64 d)= and
|
||||
|
||||
13
lib/check.ml
13
lib/check.ml
@ -9036,6 +9036,19 @@ and unknown_name : 'a. ?setting:bool -> ctx -> Loc.t -> string -> 'a =
|
||||
name head field head
|
||||
end
|
||||
else
|
||||
(* [x++]: a name may end in +, so the increment of another language
|
||||
reads as one unknown name. *)
|
||||
let n = String.length name in
|
||||
let stem = if n > 2 then String.sub name 0 (n - 2) else "" in
|
||||
let suffix = if n > 2 then String.sub name (n - 2) 2 else "" in
|
||||
if (suffix = "++" || suffix = "--") && lookup ctx stem <> None then
|
||||
Loc.failk "check/unknown-name" loc
|
||||
"unknown name %s — to %s %s, write %s"
|
||||
name (if suffix = "++" then "add one to" else "take one from") stem
|
||||
(if Source.indented_at loc then
|
||||
Printf.sprintf "%s(%s) or %s %s= 1" suffix stem stem (String.make 1 suffix.[0])
|
||||
else Printf.sprintf "(%s %s)" suffix stem)
|
||||
else
|
||||
match nearest (value_candidates ctx) name with
|
||||
| Some m ->
|
||||
Loc.failk "check/unknown-name" loc "unknown name %s — did you mean %s?" name m
|
||||
|
||||
@ -380,7 +380,16 @@ and list _f h args =
|
||||
| _ -> false
|
||||
in
|
||||
let ft = if fl < lvl || (fl = lvl && same) then paren ft else ft in
|
||||
(String.concat (" " ^ op ^ " ") (ft :: List.map (at (lvl + 1)) rest), lvl)
|
||||
(* [(a and b) or c]: the parentheses precedence makes optional are
|
||||
written, as most readers expect them. *)
|
||||
let and_in_or (x : Form.t) t =
|
||||
match x.v with
|
||||
| Form.List ({ v = Form.Sym "and"; _ } :: _ :: _ :: _) when s = "or" && t.[0] <> '(' -> paren t
|
||||
| _ -> t
|
||||
in
|
||||
let ft = and_in_or first ft in
|
||||
(String.concat (" " ^ op ^ " ")
|
||||
(ft :: List.map (fun x -> and_in_or x (at (lvl + 1) x)) rest), lvl)
|
||||
| Form.Sym "-", [ x ] ->
|
||||
let t, l = expr x in
|
||||
if l >= 9 && t <> "" && R.is_neg_char t.[0] then ("-" ^ t, 8)
|
||||
@ -410,7 +419,7 @@ and list _f h args =
|
||||
| Form.Sym s, [ ({ v = Form.Map _; _ } as m) ] when name_ok s && R.capitalised s ->
|
||||
(s ^ fst (expr m), 9)
|
||||
| Form.Sym "fn", [ { v = Form.Vec ps; _ }; body ] when List.for_all sym_param ps ->
|
||||
("fn(" ^ commas ps ^ ") = " ^ at 0 body, 0)
|
||||
("fn(" ^ commas ps ^ ") = " ^ unit_text body, 0)
|
||||
| Form.Sym "if", [ c; a; b ] ->
|
||||
("if " ^ at 1 c ^ " then " ^ inline_text ~lvl:1 a ^ " else " ^ inline_text b, 0)
|
||||
| _ -> call ()
|
||||
@ -420,6 +429,10 @@ and list _f h args =
|
||||
everything else as a value. [lvl] is what a value in the slot needs. *)
|
||||
and inline_text ?(lvl = 0) (f : Form.t) =
|
||||
match f.v with
|
||||
(* In a one-line slot a bare [()] reads as [(do)]; the value [()] is
|
||||
written [(())]. *)
|
||||
| Form.List [] -> "(())"
|
||||
| Form.List [ { v = Form.Sym "do"; _ } ] -> "()"
|
||||
| Form.List [ { v = Form.Sym (("break" | "continue" | "return") as w); _ } ] -> w
|
||||
| Form.List [ { v = Form.Sym (("break" | "continue") as w); _ }; { v = Form.Kw k; _ } ]
|
||||
when kw_ok k ->
|
||||
@ -431,6 +444,13 @@ and inline_text ?(lvl = 0) (f : Form.t) =
|
||||
at 9 t ^ " " ^ op ^ "= " ^ at (max lvl 1) w
|
||||
| _ -> at lvl f
|
||||
|
||||
(* A body after [=]: [()] there reads as [(do)]. *)
|
||||
and unit_text (f : Form.t) =
|
||||
match f.v with
|
||||
| Form.List [] -> "(())"
|
||||
| Form.List [ { v = Form.Sym "do"; _ } ] -> "()"
|
||||
| _ -> at 0 f
|
||||
|
||||
(* [t = v], or [t += w] when [v] is [(+ t w)]. *)
|
||||
and assign_text ?(lvl = 0) t v =
|
||||
let tt = at 9 t in
|
||||
@ -653,6 +673,9 @@ and plain n (f : Form.t) : string list =
|
||||
(* No arguments before the block: [comment:] rather than
|
||||
[comment():], the author's decision 85. *)
|
||||
| Form.Sym s, [] when name_ok s && not (List.mem s reserved) -> s ^ ":"
|
||||
(* A header word glued to its parenthesis is the fallback call,
|
||||
[if(c):], so it needs no parentheses of its own. *)
|
||||
| Form.Sym s, _ :: _ when List.mem s reserved -> s ^ "(" ^ commas fixed ^ "):"
|
||||
| _ -> head_text h ^ "(" ^ commas fixed ^ "):"
|
||||
in
|
||||
[ ind n ^ guard opener ] @ block ~seq (n + 2) rest
|
||||
@ -916,7 +939,7 @@ and sugar n (f : Form.t) : string list option =
|
||||
| _ -> true)
|
||||
&& String.length head + 3 + String.length (at 0 x) <= width
|
||||
&& not (!inside f) ->
|
||||
Some [ head ^ " = " ^ at 0 x ]
|
||||
Some [ head ^ " = " ^ unit_text x ]
|
||||
| _ -> Some (head :: block (n + 2) body)))
|
||||
| Form.List ({ v = Form.Sym (("def" | "defonce" | "defconst") as d); _ }
|
||||
:: { v = Form.Sym name; _ } :: rest)
|
||||
|
||||
@ -208,9 +208,22 @@ let lex ?(line = 1) ?(col = 1) ~file src : token list =
|
||||
Reader.advance st;
|
||||
emit COLON (piece l0.Loc.line (l0.Loc.col + n) 1)
|
||||
end
|
||||
else
|
||||
else begin
|
||||
(* [0..10]: a range from another language. *)
|
||||
let text = String.sub src st.Reader.pos (stop - st.Reader.pos) in
|
||||
(match String.index_opt text '.' with
|
||||
| Some i when i + 1 < String.length text && text.[i + 1] = '.' ->
|
||||
failk "dot-range" (piece l0.Loc.line l0.Loc.col (String.length text))
|
||||
"%s is not a number. A range of numbers is written range(%s, %s), \
|
||||
as in for i in range(%s, %s)"
|
||||
text (String.sub text 0 i)
|
||||
(String.sub text (i + 2) (String.length text - i - 2))
|
||||
(String.sub text 0 i)
|
||||
(String.sub text (i + 2) (String.length text - i - 2))
|
||||
| _ -> ());
|
||||
let f = Reader.read_number st in
|
||||
emit (ATOM f.v) f.loc
|
||||
end
|
||||
| _ -> name_run ()
|
||||
in
|
||||
let rec go () =
|
||||
@ -477,9 +490,13 @@ let expect_eol p ~after =
|
||||
if (peek p).tok = INDENT then
|
||||
failk "stray-indent" (peek_at p 1).loc
|
||||
"this line is indented under %s, which takes no block. A call takes \
|
||||
an indented block only with a trailing colon, as in \
|
||||
rl/with-drawing():"
|
||||
an indented block only with a trailing colon, as in %s:"
|
||||
after
|
||||
(* The call itself when [after] is one, [f(a, b)]; else an example. *)
|
||||
(match String.index_opt after '(', String.index_opt after ' ' with
|
||||
| Some i, Some j when i < j -> after
|
||||
| Some _, None when after.[String.length after - 1] = ')' -> after
|
||||
| _ -> "rl/with-drawing()")
|
||||
| EOF -> ()
|
||||
| _ -> stray p ~after
|
||||
|
||||
@ -725,6 +742,14 @@ and if_expr p =
|
||||
(* What a one-line slot takes — a match arm's value, a then or an else, the
|
||||
thing after defer: a value, or one of the statements that fit on a line,
|
||||
break, continue, return and an assignment. *)
|
||||
(* A bare [()] written where a body goes — a one-line slot, a function's
|
||||
[= ()] — is the empty statement, [(do)], as it is on a line of its own:
|
||||
"do nothing" is what it says there. [(())] stays a value. *)
|
||||
and unit_slot p i0 (t0 : token) (e : Form.t) =
|
||||
if p.i - i0 = 2 && t0.tok = LP && e.v = Form.List [] then
|
||||
Form.make (Form.List [ sym t0.loc "do" ]) e.loc
|
||||
else e
|
||||
|
||||
and inline_stmt p : Form.t =
|
||||
let t = peek p in
|
||||
let glued = let n = peek_at p 1 in n.tok = LP && not n.sp in
|
||||
@ -744,6 +769,7 @@ and inline_stmt p : Form.t =
|
||||
mk p t.loc (Form.List [ sym t.loc "return"; v ])
|
||||
else mk p t.loc (Form.List [ sym t.loc "return" ])
|
||||
| _ ->
|
||||
let i0 = p.i in
|
||||
let e, _ = expr p in
|
||||
match (peek p).tok with
|
||||
| NAME "=" ->
|
||||
@ -754,7 +780,7 @@ and inline_stmt p : Form.t =
|
||||
let eq = advance p in
|
||||
let v, _ = expr p in
|
||||
mk p t.loc (compound eq.loc (List.assoc op assign_ops) e v (span p e.loc))
|
||||
| _ -> e
|
||||
| _ -> unit_slot p i0 t e
|
||||
|
||||
(* [fn(a, b) = body] is a lambda; [fn(...)] followed by anything else is the
|
||||
fallback call spelling of [(fn ...)]. *)
|
||||
@ -766,7 +792,9 @@ and fn_expr p =
|
||||
| NAME "=" ->
|
||||
ignore (advance p);
|
||||
let ps = lambda_params args in
|
||||
let i0 = p.i and t0 = peek p in
|
||||
let body, _ = expr p in
|
||||
let body = unit_slot p i0 t0 body in
|
||||
(mk p t.loc
|
||||
(Form.List
|
||||
[ sym t.loc "fn"; Form.make (Form.Vec ps) (span_of_list lp.loc args); body ]),
|
||||
@ -826,6 +854,15 @@ and items p closer open_loc ~what =
|
||||
\ let f = %s\n ...\n\n\
|
||||
and pass f, or write it on one line: %s = value"
|
||||
(text_of e) (text_of e)
|
||||
else if starts_value n.tok && n.sp && not (negative_literal n.tok)
|
||||
&& n.loc.Loc.line > e.loc.Loc.eline then
|
||||
(* Most often the bracket was never closed: the next statement
|
||||
has been read as one more argument. *)
|
||||
failk "missing-comma" n.loc
|
||||
"%s on a new line follows %s with no comma between them. If the \
|
||||
%c on line %d was meant to close before this line, close it; \
|
||||
otherwise separate %s with commas"
|
||||
(show n.tok) (text_of e) opener open_loc.Loc.line what
|
||||
else if starts_value n.tok && n.sp && not (negative_literal n.tok) then
|
||||
failk "missing-comma" n.loc
|
||||
"%s follows %s with no comma between them. Separate %s with \
|
||||
@ -883,6 +920,14 @@ and map_items p open_loc =
|
||||
| COMMA -> ignore (advance p); go (e :: acc)
|
||||
| RC -> ignore (advance p); List.rev (e :: acc)
|
||||
| EOF -> unclosed p '{' open_loc
|
||||
(* [P{x = 1}] or [P{x: 1}]: another language's field syntax. *)
|
||||
| (NAME "=" | COLON) as tk
|
||||
when (match e.v with Form.Sym n -> n <> "" && n.[0] <> '.' | _ -> false) ->
|
||||
let n = text_of e in
|
||||
failk "brace-field" (peek p).loc
|
||||
"a field in braces is written {.%s value}: a dot before the name, \
|
||||
and no %s between it and the value"
|
||||
n (if tk = COLON then "colon" else "= sign")
|
||||
| tk when starts_value tk && (peek p).sp ->
|
||||
if lvl < 8 then refuse_ws ~brace:true t.loc e;
|
||||
go (e :: acc)
|
||||
@ -1294,7 +1339,15 @@ and header (s : st) w : Form.t =
|
||||
ignore (advance p);
|
||||
block s ~after:"fn"
|
||||
end
|
||||
else [ value_line s ~after:"=" ]
|
||||
else begin
|
||||
let i0 = p.i and t0 = peek p in
|
||||
let v = value_line s ~after:"=" in
|
||||
let bare =
|
||||
t0.tok = LP && p.toks.(i0 + 1).tok = RP && v.v = Form.List []
|
||||
&& (match p.toks.(i0 + 2).tok with NEWLINE | EOF | DEDENT -> true | _ -> false)
|
||||
in
|
||||
[ (if bare then Form.make (Form.List [ sym t0.loc "do" ]) v.loc else v) ]
|
||||
end
|
||||
| NEWLINE ->
|
||||
ignore (advance p);
|
||||
if (peek p).tok = INDENT then block s ~after:"fn" else []
|
||||
|
||||
@ -206,7 +206,8 @@ Each item: the proposal, then the reason in one line.
|
||||
- **`for i in range(n)`**, `range(a, b)`, `range(a, b, step)` read as
|
||||
`dotimes`. `range` here is syntax, not a function. `..` is avoided because
|
||||
`a..b` would lex as one name. **Built** (a label goes first here too:
|
||||
`for :outer i in range(n)`).
|
||||
`for :outer i in range(n)`; in a macro template the variable may be an
|
||||
unquote, `for ~i in range(~n)`).
|
||||
- **`return v`, `break`, `break :outer`, `continue`, `defer expr`** (or `defer`
|
||||
plus a block). **Built**; `defer` plus a block reads `(defer a b …)`.
|
||||
`break`, `continue`, `return v` and `x = v`/`x += v` also fit the one-line
|
||||
@ -255,7 +256,8 @@ Each item: the proposal, then the reason in one line.
|
||||
the body, where the form wants them. **Built.**
|
||||
- **Unit:** `()` as a statement reads `(do)`; in a type it is `()`. **Built**;
|
||||
inside an expression `()` stays `()`, and the printer writes a lone `()`
|
||||
statement as `(())`.
|
||||
statement as `(())`. A bare `()` in a one-line body slot (`fn f() -> () = ()`,
|
||||
`_ -> ()`, `fn() = ()`, `then ()`) is a statement too, and reads `(do)`.
|
||||
- **Lambda:** `fn(i, j) = i * 10 + j`, or `fn(i, j)` plus a block. **Built**;
|
||||
its parameters are bare names, as `(fn [i j] …)` wants, with no `dyn`.
|
||||
`fn(…)` followed by anything else is the fallback call.
|
||||
|
||||
@ -582,6 +582,25 @@ let () =
|
||||
reads "typed let" "let x: i32 = 5\nx" "(let [x (the i32 5)] x)";
|
||||
refuses "a let takes no block" "fn f() -> ()\n let x = 1\n g(x)\n h(x)"
|
||||
"indent/let-block" "go at the let's column";
|
||||
(* Mistakes carried over from other languages, answered in this one. *)
|
||||
refuses "a block without the colon names the call" "with-allocator(a, b)\n g()"
|
||||
"indent/stray-indent" "as in with-allocator(a, b):";
|
||||
refuses "field with =" "p = P{x = 1}" "indent/brace-field" "{.x value}";
|
||||
refuses "field with a colon" "p = P{x: 1}" "indent/brace-field" "no colon";
|
||||
refuses "a dotted range" "for i in 0..10\n g(i)" "indent/dot-range" "range(0, 10)";
|
||||
refuses "a block lambda inside a call" "sort-by(xs, fn(a, b)\n a < b)"
|
||||
"indent/lambda-block-in-brackets" "let f = fn(a, b)";
|
||||
refuses "an unclosed call swallows the next line" "fn f() -> ()\n push(v, 1\n g()"
|
||||
"indent/missing-comma" "If the ( on line 2 was meant to close";
|
||||
refuses "else under a one-line if" "if a then b\nelse c"
|
||||
"indent/orphan-else" "one-line if";
|
||||
reads "a bare () in a body slot does nothing"
|
||||
"fn f() -> () = ()\nfn g(x) -> ()\n match x\n 1 -> h()\n _ -> ()\n k = fn() = ()"
|
||||
"(defn f [] () (do))\n(defn g [x dyn] () (match x 1 (h) _ (do)) (set k (fn [] (do))))";
|
||||
reads "a parenthesised () stays a value" "x = (())" "(set x ())";
|
||||
reads "a template's for takes an unquoted variable"
|
||||
"quote\n for ~i in range(~n)\n g(~i)"
|
||||
"(quasiquote (dotimes [(unquote i) (unquote n)] (g (unquote i))))";
|
||||
(* And back: the printer writes the idioms. *)
|
||||
let prints name src want =
|
||||
match Reader.read_all ~file:"<p>" src with
|
||||
@ -718,7 +737,40 @@ let () =
|
||||
"(defn f [] i32\n (let [a 1 ; first\n b 2] ; second\n (+ a b)))"
|
||||
" let a = 1 ; first\n let b = 2 ; second";
|
||||
back "comments to parens" "; head\n\nfn main() -> i32\n ; why\n g() ; note\n 0"
|
||||
"; head\n\n(defn main [] i32\n ; why\n (g) ; note\n 0)"
|
||||
"; head\n\n(defn main [] i32\n ; why\n (g) ; note\n 0)";
|
||||
(* Written the way the corpus writes them. *)
|
||||
back "quasiquote as its reader sugar"
|
||||
"defmacro(m, [x & body]):\n quote\n g(~x)\n ~@body"
|
||||
"`(do (g ~x) ~@body)";
|
||||
back "arms a pair to a line"
|
||||
("fn f(s) -> dyn\n match s\n 1 -> \"one, a long string to break the line\"\n"
|
||||
^ " _ -> \"another long string to push it over\"")
|
||||
" (match s\n 1 \"one, a long string to break the line\"\n _ \"another";
|
||||
back "a let's bindings hang after their names"
|
||||
("fn f() -> dyn\n let a = compute-something-long(1, 2, 3, 4, 5)\n"
|
||||
^ " let b = compute-something-long(5, 6, 7, 8, 9)\n a")
|
||||
"(let [a (compute-something-long 1 2 3 4 5)\n b (compute-something-long 5 6 7 8 9)]";
|
||||
back "a label stays with its test"
|
||||
"fn f() -> ()\n while :outer some-long-condition?(1, 2, 3) and another-long-one?(4, 5, 6)\n g()"
|
||||
"(while :outer";
|
||||
back "a call's arguments fill the line"
|
||||
"fn f() -> ()\n println(\"alpha\", \"beta\", \"gamma\", \"delta\", \"epsilon\", \"zeta\", \"eta\", \"theta\", \"iota\", g(1))"
|
||||
"\"eta\" \"theta\" \"iota\"\n (g 1))";
|
||||
back "a comment between a cond's test and its branch stays there"
|
||||
"fn f(x) -> dyn\n if x\n ; why\n 1\n elif y\n 2\n else\n 3"
|
||||
"; why";
|
||||
prints "an if with no else keeps its test in the parentheses"
|
||||
"(defn f [] () (if (> a 1) (let [k 2] (g k))))" " if(a > 1):\n let k = 2";
|
||||
prints "and inside or keeps its parentheses"
|
||||
"(defn f [a bool b bool c bool] bool (or (and a b) c))" "= (a and b) or c";
|
||||
prints "a field of a field chains" "(defn f [] () (g (.count (.x w))))" "g(w.x.count)";
|
||||
prints "an else-if chain on one line"
|
||||
"(defn f [r] dyn (if (> r 7) :rich (if (> r 4) :fair :poor)))"
|
||||
"if r > 7 then :rich else if r > 4 then :fair else :poor";
|
||||
prints "a long vector wraps" ("(defn f [] () (let [v [" ^ String.concat " " (List.init 30 string_of_int) ^ "]] (g v)))")
|
||||
" let v = [0 1 2 3";
|
||||
prints "a template's for keeps its unquotes"
|
||||
"(defmacro m [i n & body] `(dotimes [~i ~n] ~@body))" "for ~i in range(~n)"
|
||||
|
||||
(* ── Spans, for pause marks and error overlays ──────────────────────── *)
|
||||
|
||||
@ -914,7 +966,21 @@ let () =
|
||||
(* A unit argument deeper in the last form is about that argument. *)
|
||||
refused "unit-arg.flan"
|
||||
"(defn g [x dyn] dyn x)\n(defn f [coll] dyn (g (println 1)))\n(defn main [] () (f 1))\n"
|
||||
[ "() does not box into dyn" ]
|
||||
[ "() does not box into dyn" ];
|
||||
(* Checker messages about a .fln file are in its spelling. *)
|
||||
refused "enum-none.fln" "fn main() -> i32\n let n = None\n 0\n" [ "the(Option(i32), None)" ];
|
||||
checks "enum-annotated.fln"
|
||||
"enum Dir\n north\n south\n\nfn main() -> i32\n let d: Dir = :north\n i32(d)\n";
|
||||
refused "annotation-dyn.fln" "fn main() -> i32\n let d = the(dyn, 3)\n let x: i32 = d\n x\n"
|
||||
[ "a type annotation checks a value as i32"; "write i32(d)" ];
|
||||
refused "narrowing.fln" "fn f() -> i64 = 1\n\nfn main() -> i32\n let x: i32 = 0\n x = f()\n x\n"
|
||||
[ "it has to be written: i32(x)" ];
|
||||
refused "unknown-type.fln" "fn f(p: Keyword) -> i32 = 0\n\nfn main() -> i32 = 0\n"
|
||||
[ "unknown type Keyword" ];
|
||||
refused "untyped-lambda.fln" "fn main() -> i32\n let f = fn(a)\n a\n 0\n"
|
||||
[ "let f: Fn(T, ...) -> R = fn(...)" ];
|
||||
refused "plusplus.fln" "fn main() -> i32\n let x = 1\n x++\n x\n"
|
||||
[ "write ++(x) or x += 1" ]
|
||||
|
||||
(* ── Both directions of an import, on both backends ────────────────── *)
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user