The dot advice says assign where the form is an assignment
(set p.x 1) was being told that a field is read with an accessor, which is a sentence that does not apply to the form it is printed under. The place spelling is (set (.x p) 1), checked to be a real form.
This commit is contained in:
parent
859e3aa7f4
commit
16f90a7ef5
31
lib/check.ml
31
lib/check.ml
@ -4413,8 +4413,8 @@ and value_candidates ctx =
|
||||
dot-infix habit.
|
||||
|
||||
The second is the near miss, over values only — see [value_candidates]. *)
|
||||
and unknown_name : 'a. ctx -> Loc.t -> string -> 'a =
|
||||
fun ctx loc name ->
|
||||
and unknown_name : 'a. ?setting:bool -> ctx -> Loc.t -> string -> 'a =
|
||||
fun ?(setting = false) ctx loc name ->
|
||||
let dot = String.index_opt name '.' in
|
||||
let head, field =
|
||||
match dot with
|
||||
@ -4440,25 +4440,32 @@ and unknown_name : 'a. ctx -> Loc.t -> string -> 'a =
|
||||
| Some sn, _ ->
|
||||
let s = Option.get (fields_named ctx.env sn) in
|
||||
let notes = declared_note ctx.env sn in
|
||||
(* In a [set] the accessor is the *place*, so the spelling to give is
|
||||
[(set (.x p) 1)] and not [(.x p)] on its own. Saying "read" at an
|
||||
assignment would be a sentence that does not apply to the form it is
|
||||
printed under. *)
|
||||
let how =
|
||||
if setting then Printf.sprintf "a field is assigned through an \
|
||||
accessor, so write (set (.%s %s) ...)"
|
||||
field head
|
||||
else Printf.sprintf "a field is read with an accessor, so write (.%s %s)"
|
||||
field head
|
||||
in
|
||||
if Tast.field_index s field <> None then
|
||||
Loc.failk "check/dot-access" loc ~notes
|
||||
"unknown name %s — a field is read with an accessor, so write (.%s %s)"
|
||||
name field head
|
||||
Loc.failk "check/dot-access" loc ~notes "unknown name %s — %s" name how
|
||||
else
|
||||
Loc.failk "check/dot-access" loc ~notes
|
||||
"unknown name %s — a field is read with an accessor, (.%s %s), and \
|
||||
%s has no field %s"
|
||||
name field head sn field
|
||||
"unknown name %s — %s, and %s has no field %s" name how sn field
|
||||
| None, Some t ->
|
||||
Loc.failk "check/dot-access" loc
|
||||
"unknown name %s — a dot is part of the name here, not field access. \
|
||||
Fields are read with an accessor, (.%s %s), and %s is %s, which has \
|
||||
no fields"
|
||||
A field is reached through an accessor, (.%s %s), and %s is %s, \
|
||||
which has no fields"
|
||||
name field head head (Types.to_string t)
|
||||
| None, None ->
|
||||
Loc.failk "check/unknown-name" loc
|
||||
"unknown name %s — nothing named %s is in scope either. A field is \
|
||||
read with an accessor, (.%s %s), not with a dot"
|
||||
reached through an accessor, (.%s %s), not with a dot"
|
||||
name head field head
|
||||
end
|
||||
else
|
||||
@ -4578,7 +4585,7 @@ and check_place ctx loc (p : Ast.place) : Tast.place * Types.t =
|
||||
into the image and there is nothing to assign to. Declare it with \
|
||||
defvar if it has to change" name
|
||||
| Some (ty, false) -> Tast.Pglobal name, ty
|
||||
| None -> captured ctx loc name; unknown_name ctx loc name)
|
||||
| None -> captured ctx loc name; unknown_name ~setting:true ctx loc name)
|
||||
| Ast.Pfield (target, name) ->
|
||||
let target, sname = struct_target ctx target in
|
||||
let s = Option.get (fields_named ctx.env sname) in
|
||||
|
||||
@ -1739,6 +1739,11 @@ let () =
|
||||
rejects_check "and says so when the field is not there either"
|
||||
"(defstruct P [x i32]) (defn f [] i32 (let [p (P {.x 1})] p.z))"
|
||||
~needle:"(.z p), and P has no field z";
|
||||
rejects_check "and in a set it is the place that is spelled"
|
||||
"(defstruct P [x i32]) (defn f [] i32 (let [p (P {.x 1})] (set p.x 2) 0))"
|
||||
~needle:"a field is assigned through an accessor, so write (set (.x p) ...)";
|
||||
accepts "which is a real form"
|
||||
"(defstruct P [x i32]) (defn f [] i32 (let [p (P {.x 1})] (set (.x p) 2) (.x p)))";
|
||||
rejects_check "a dotted head that is not a struct says what it is"
|
||||
"(defn f [] i32 (let [n 1] n.x))" ~needle:"n is i32, which has no fields";
|
||||
(* A capitalised head keeps the case spelling it always had: [Shape.Circle]
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user