A short-circuit temp stops calling itself a destructuring one
fresh_temp takes the purpose, so and/or mint and~N and or~N where they used to mint destructure~N. The names are shown -- the inspector lists a frame locals by name -- and nothing pinned the old spelling; destructure~nth is an unrelated compiler builtin. Confirmed in a --debug build DWARF. The caret wart on and last operand in a want-free position is documented at the site and in FIX.org rather than fixed: every candidate fix reads worse than what is there, and the real fix is check_if choosing which arm to blame.
This commit is contained in:
parent
9eed4cbd8c
commit
2daf7e9164
43
lib/parse.ml
43
lib/parse.ml
@ -14,15 +14,21 @@ let sym (f : Form.t) =
|
||||
| Sym s -> s
|
||||
| _ -> fail f "expected a name, found %s" (Form.to_string f)
|
||||
|
||||
(* Names for the temporaries a destructuring binding needs — the value is bound
|
||||
once and every name in the pattern reads *that*, so a pattern over a call
|
||||
calls it once. [~] is a delimiter in the reader, so no symbol anyone can
|
||||
write contains one: these cannot collide with a source name and a source
|
||||
name cannot shadow one. Reset per program so the names, and therefore the
|
||||
slot numbering downstream, are the same every run. *)
|
||||
(* Names for the temporaries this file mints — the value is bound once and
|
||||
everything that needs it reads *that*, so a destructuring pattern over a
|
||||
call calls it once and a short-circuit operand is evaluated once. [~] is a
|
||||
delimiter in the reader, so no symbol anyone can write contains one: these
|
||||
cannot collide with a source name and a source name cannot shadow one.
|
||||
Reset per program so the names, and therefore the slot numbering
|
||||
downstream, are the same every run.
|
||||
|
||||
The purpose is part of the name because these names are shown: the
|
||||
inspector lists a frame's locals by name, and a short-circuit temp called
|
||||
[destructure~3] is a plain lie about where it came from. One counter across
|
||||
all purposes, so a name is still unique whatever minted it. *)
|
||||
let temps = ref 0
|
||||
|
||||
let fresh_temp () = incr temps; Printf.sprintf "destructure~%d" !temps
|
||||
let fresh_temp what = incr temps; Printf.sprintf "%s~%d" what !temps
|
||||
|
||||
(* Destructuring binds in [let] and nowhere else. Every other binding position —
|
||||
a [defn] parameter, a [defstruct] field, an [fn] parameter, a [dotimes]
|
||||
@ -673,7 +679,7 @@ and bindings f (items : Form.t list) : Ast.binding list =
|
||||
the reference as well as the binding is what makes the two impossible to
|
||||
separate by accident. *)
|
||||
and temp (p : Form.t) (v : Ast.expr) : Ast.expr * Ast.binding =
|
||||
let t = fresh_temp () in
|
||||
let t = fresh_temp "destructure" in
|
||||
({ Ast.e = Ast.Var t; loc = p.loc },
|
||||
{ Ast.bname = t; bty = None; bval = v; bloc = p.loc })
|
||||
|
||||
@ -915,7 +921,24 @@ and cond f (args : Form.t list) : Ast.expr =
|
||||
because the sentinel it answered was a bool literal that boxed to fit
|
||||
whatever the real branch was; neither is now, and they are at least
|
||||
symmetric about it. Making bool and dyn arms join as dyn is a check_if
|
||||
question, noted in FIX.org under item 7 and not decided here. *)
|
||||
question, noted in FIX.org under item 7 and not decided here.
|
||||
|
||||
One known wart, measured rather than guessed, and left alone deliberately.
|
||||
In a want-free position — [(println (and true true (vec-new i32)))] — the
|
||||
caret lands on the *second* [true] and not on the vec: the last operand is
|
||||
the then arm, check_if types the then arm first, and the mismatch is
|
||||
therefore reported against the else arm, which is the previous operand's
|
||||
temp. An operand anywhere but last is a condition instead, so check_truthy
|
||||
blames it at its own loc and the caret is right; [or] is right everywhere,
|
||||
because there the chain and not the sentinel sits in the else arm. Giving
|
||||
the else arm's [Var] node the *last* operand's loc moves the caret onto the
|
||||
vec and makes the sentence read backwards — "expected (Vec i32), found
|
||||
bool" under a caret on the thing that is the (Vec i32) — so it is not an
|
||||
improvement; answering a bool literal again would revert the paragraph
|
||||
above; and inverting the condition to move the last operand into the else
|
||||
arm buys a [not] per operand and worse locs than it fixes. What would
|
||||
actually fix it is check_if preferring the arm that is not a compiler temp
|
||||
when it reports, which is check.ml's call. Written up in FIX.org. *)
|
||||
and shortcircuit f (args : Form.t list) ~is_and : Ast.expr =
|
||||
let mk e = { Ast.e; loc = f.loc } in
|
||||
let rec go = function
|
||||
@ -923,7 +946,7 @@ and shortcircuit f (args : Form.t list) ~is_and : Ast.expr =
|
||||
| [ last ] -> expr last
|
||||
| x :: rest ->
|
||||
let ex = expr x in
|
||||
let t = fresh_temp () in
|
||||
let t = fresh_temp (if is_and then "and" else "or") in
|
||||
let tvar = { Ast.e = Ast.Var t; loc = ex.Ast.loc } in
|
||||
let bind = { Ast.bname = t; bty = None; bval = ex; bloc = ex.Ast.loc } in
|
||||
let rest = go rest in
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user