An error says which macro it is really about
The provenance rides on the location, not on the form, because the location is the thing that already travels: Expand.unmarshal stamps the call site onto every node a macro answers with, and that stamp goes on through the AST and the typed IR untouched. Tagging it there means an error raised anywhere downstream can name the macro with no field added to Form, to Ast or to Tast. Outermost wins. The macro the author wrote is the one worth naming, not whatever it expanded into on the way down. The honest limit, since it would otherwise read as a claim: a macro's expansion has no source of its own to point at, so the note lands on the call site along with the error. What it buys is the reader knowing the code being refused is not the code they wrote.
This commit is contained in:
parent
2efed1630f
commit
e8aeb89282
27
lib/loc.ml
27
lib/loc.ml
@ -20,11 +20,28 @@ type t = {
|
||||
col : int; (* 1-based *)
|
||||
eline : int; (* 1-based, exclusive end *)
|
||||
ecol : int;
|
||||
(* The macro whose expansion produced whatever is at this position, if one
|
||||
did. It rides on the location rather than on the form because the location
|
||||
is the thing that already travels: [Expand.unmarshal] stamps the call
|
||||
site onto every node a macro answers with, and that stamp goes on through
|
||||
the AST and the typed IR untouched. Tagging it here means an error raised
|
||||
anywhere downstream can say which macro it is really about, with no field
|
||||
added to Form, to Ast or to Tast. *)
|
||||
macro : string option;
|
||||
}
|
||||
|
||||
let make file line col = { file; line; col; eline = line; ecol = col }
|
||||
let make file line col =
|
||||
{ file; line; col; eline = line; ecol = col; macro = None }
|
||||
|
||||
let unknown = make "<unknown>" 0 0
|
||||
|
||||
(** Tag a location as coming out of [name]'s expansion, unless it already names
|
||||
a macro. Already-tagged wins because the tag is applied outermost-last: the
|
||||
macro the author actually wrote is the one worth naming, not whatever it
|
||||
expanded into on the way. *)
|
||||
let from_macro name (t : t) =
|
||||
match t.macro with None -> { t with macro = Some name } | Some _ -> t
|
||||
|
||||
(** [upto start stop] is [start] widened to end where [stop] begins. A [stop]
|
||||
that is not after [start], or is in another file, leaves it alone: a span
|
||||
that runs backwards would draw nonsense. *)
|
||||
@ -124,6 +141,14 @@ let sort_notes (d : diag) =
|
||||
let note ?(sev = Info) loc msg = { nmsg = msg; nloc = loc; nsev = sev }
|
||||
|
||||
let diag ?(kind = "error") ?(notes = []) ?expansion loc msg =
|
||||
(* The location already knows whether it came out of a macro, so an error
|
||||
does not have to be raised anywhere special to say so. An explicit
|
||||
[expansion] still wins, for the one caller that knows better. *)
|
||||
let expansion =
|
||||
match expansion with
|
||||
| Some _ as e -> e
|
||||
| None -> (match loc.macro with Some m -> Some (m, loc) | None -> None)
|
||||
in
|
||||
sort_notes { kind; dloc = loc; dmsg = msg; notes; expansion }
|
||||
|
||||
let raise_diag d = raise (Error (sort_notes d))
|
||||
|
||||
11
lib/macro.ml
11
lib/macro.ml
@ -176,7 +176,12 @@ let rec expand_form (l : loaded) (f : Form.t) : Form.t =
|
||||
match f.Form.v with
|
||||
| Form.List ({ Form.v = Form.Sym n; _ } :: args) when List.mem_assoc n l.fns ->
|
||||
let args = List.map (expand_form l) args in
|
||||
settle l n loc (Expand.call ~loc (List.assoc n l.fns) args) fuel
|
||||
(* The call site, tagged with the macro it is a call to. [Expand.unmarshal]
|
||||
stamps this onto every node the macro answers with, so from here down
|
||||
every form it produced knows where it came from and an error on one of
|
||||
them can say so. *)
|
||||
let from = Loc.from_macro n loc in
|
||||
settle l n loc (Expand.call ~loc:from (List.assoc n l.fns) args) fuel
|
||||
| Form.List xs -> Form.make (Form.List (List.map (expand_form l) xs)) loc
|
||||
| Form.Vec xs -> Form.make (Form.Vec (List.map (expand_form l) xs)) loc
|
||||
| Form.Map xs -> Form.make (Form.Map (List.map (expand_form l) xs)) loc
|
||||
@ -193,7 +198,9 @@ and settle l first loc (f : Form.t) left =
|
||||
first fuel
|
||||
else begin
|
||||
let args = List.map (expand_form l) args in
|
||||
settle l first loc (Expand.call ~loc (List.assoc m l.fns) args) (left - 1)
|
||||
let from = Loc.from_macro m loc in
|
||||
settle l first loc (Expand.call ~loc:from (List.assoc m l.fns) args)
|
||||
(left - 1)
|
||||
end
|
||||
(* Settled at the head. The rest of it may still hold macro calls — a cond
|
||||
expands to an if whose else-branch is another cond — so the ordinary walk
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user