2 * Copyright (c) 2015, Facebook, Inc.
5 * This source code is licensed under the MIT license found in the
6 * LICENSE file in the "hack" directory of this source tree.
12 open Reordered_argument_collections
16 (* We use `Pos.t message` on the server and convert to `Pos.absolute message`
17 * before sending it to the client *)
18 type 'a message
= 'a
* string
20 type phase
= Init
| Parsing
| Naming
| Decl
| Typing
21 type severity
= Warning
| Error
22 type format
= Context
| Raw
24 (* The file and phase of analysis being currently performed *)
25 let current_context : (Relative_path.t
* phase
) ref = ref (Relative_path.default
, Typing
)
27 let allow_errors_in_default_path = ref true
29 module PhaseMap
= Reordered_argument_map
(MyMap.Make
(struct
39 let compare x y
= (rank x
) - (rank y
)
42 (* Results of single file analysis. *)
43 type 'a file_t
= 'a list
PhaseMap.t
44 (* Results of multi-file analysis. *)
45 type 'a files_t
= ('a file_t
) Relative_path.Map.t
47 let files_t_fold v ~f ~init
=
48 Relative_path.Map.fold v ~init ~f
:begin fun path v acc
->
49 PhaseMap.fold v ~init
:acc ~f
:begin fun phase v acc
->
54 let files_t_map v ~f
=
55 Relative_path.Map.map v ~f
:begin fun v
->
59 let files_t_merge ~f x y
=
60 (* Using fold instead of merge to make the runtime proportional to the size
61 * of first argument (like List.rev_append ) *)
62 Relative_path.Map.fold x ~init
:y ~f
:begin fun k x acc
->
63 let y = Option.value (Relative_path.Map.get
y k
) ~default
:PhaseMap.empty
in
64 Relative_path.Map.add acc k
(
65 PhaseMap.merge x
y ~f
:(fun phase x
y -> f phase k x
y)
69 let files_t_to_list x
=
70 files_t_fold x ~f
:(fun _ _ x acc
-> List.rev_append x acc
) ~init
:[] |>
73 let list_to_files_t = function
74 | [] -> Relative_path.Map.empty
76 (* Values constructed here should not be used with incremental mode.
77 * See assert in incremental_update. *)
78 Relative_path.Map.singleton
Relative_path.default
79 (PhaseMap.singleton Typing x
)
81 let get_code_severity code
=
82 if code
= Error_codes.Init.err_code
Error_codes.Init.ForwardCompatibilityNotCurrent
86 (* Get most recently-ish added error. *)
87 let get_last error_map
=
88 (* If this map has more than one element, we pick an arbitrary file. Because
89 * of that, we might not end up with the most recent error and generate a
90 * less-specific error message. This should be rare. *)
91 match Relative_path.Map.max_binding error_map
with
93 | Some
(_
, phase_map
) -> begin
94 let error_list = PhaseMap.max_binding phase_map
95 |> Option.value_map ~f
:snd ~default
:[]
97 match List.rev
error_list with
102 type 'a error_
= error_code
* 'a message list
103 type error
= Pos.t error_
104 type applied_fixme
= Pos.t
* int
106 let applied_fixmes : applied_fixme files_t
ref = ref Relative_path.Map.empty
108 let (error_map
: error files_t
ref) = ref Relative_path.Map.empty
110 let accumulate_errors = ref false
111 (* Some filename when declaring *)
112 let in_lazy_decl = ref None
113 let badpos_sentinel = "PRIMARY ERROR POSITION IS NOT IN CURRENT FILE: please fix"
115 let try_with_result f1 f2
=
116 let error_map_copy = !error_map
in
117 let accumulate_errors_copy = !accumulate_errors in
118 error_map
:= Relative_path.Map.empty
;
119 accumulate_errors := true;
120 let result, errors
= Utils.try_finally
122 let result = f1
() in
125 ~finally
:begin fun () ->
126 error_map
:= error_map_copy;
127 accumulate_errors := accumulate_errors_copy;
130 match get_last errors
with
133 (* Remove bad position sentinel if present: we might be about to add a new primary
135 let l = match l with (_
, msg
) :: l when msg
= badpos_sentinel -> l | _
-> l in
139 let error_map_copy = !error_map
in
140 let accumulate_errors_copy = !accumulate_errors in
141 let applied_fixmes_copy = !applied_fixmes in
142 error_map
:= Relative_path.Map.empty
;
143 applied_fixmes := Relative_path.Map.empty
;
144 accumulate_errors := true;
145 let result, out_errors
, out_applied_fixmes
= Utils.try_finally
148 result, !error_map
, !applied_fixmes
150 ~finally
:begin fun () ->
151 error_map
:= error_map_copy;
152 applied_fixmes := applied_fixmes_copy;
153 accumulate_errors := accumulate_errors_copy;
156 let out_errors = files_t_map ~f
:(List.rev
) out_errors in
157 (out_errors, out_applied_fixmes
), result
159 let run_in_context path phase f
=
160 let context_copy = !current_context in
161 current_context := (path
, phase
);
162 Utils.try_finally ~f ~finally
:begin fun () ->
163 current_context := context_copy;
166 (* Log important data if lazy_decl triggers a crash *)
167 let lazy_decl_error_logging error error_map to_absolute to_string
=
168 let error_list = files_t_to_list !error_map
in
169 (* Print the current error list, which should be empty *)
170 Printf.eprintf
"%s" "Error list(should be empty):\n";
171 List.iter
error_list ~f
:(fun err
->
172 let msg = err
|> to_absolute
|> to_string
in Printf.eprintf
"%s\n" msg);
173 Printf.eprintf
"%s" "Offending error:\n";
174 Printf.eprintf
"%s" error
;
176 (* Print out a larger stack trace *)
177 Printf.eprintf
"%s" "Callstack:\n";
178 Printf.eprintf
"%s" (Caml.Printexc.raw_backtrace_to_string
179 (Caml.Printexc.get_callstack
500));
180 (* Exit with special error code so we can see the log after *)
181 Exit_status.exit
Exit_status.Lazy_decl_bug
183 (*****************************************************************************)
184 (* Error code printing. *)
185 (*****************************************************************************)
187 let error_kind error_code
=
188 match error_code
/ 1000 with
197 let error_code_to_string error_code
=
198 let error_kind = error_kind error_code
in
199 let error_number = Printf.sprintf
"%04d" error_code
in
200 error_kind^
"["^
error_number^
"]"
202 let phase_to_string (phase
: phase
) : string =
205 | Parsing
-> "Parsing"
210 let rec get_pos (error
: error
) = fst
(List.hd_exn
(snd error
))
213 List.sort ~
compare:begin fun x
y ->
214 Pos.compare (get_pos x
) (get_pos y)
216 |> List.remove_consecutive_duplicates ~equal
:(=)
218 and get_sorted_error_list
(err
,_
) =
219 sort
(files_t_to_list err
)
221 (* Getters and setter for passed-in map, based on current context *)
222 let get_current_file_t file_t_map
=
223 let current_file = fst
!current_context in
224 Relative_path.Map.get file_t_map
current_file |>
225 Option.value ~default
:PhaseMap.empty
227 let get_current_list file_t_map
=
228 let current_phase = snd
!current_context in
229 get_current_file_t file_t_map
|> fun x
->
230 PhaseMap.get x
current_phase |>
231 Option.value ~default
:[]
233 let set_current_list file_t_map new_list
=
234 let current_file, current_phase = !current_context in
235 file_t_map
:= Relative_path.Map.add
239 (get_current_file_t !file_t_map
)
244 let do_with_context path phase f
= run_in_context path phase
(fun () -> do_ f
)
246 (* Turn on lazy decl mode for the duration of the closure.
247 This runs without returning the original state,
248 since we collect it later in do_with_lazy_decls_
250 let run_in_decl_mode filename f
=
251 let old_in_lazy_decl = !in_lazy_decl in
252 in_lazy_decl := Some filename
;
253 Utils.try_finally ~f ~finally
:begin fun () ->
254 in_lazy_decl := old_in_lazy_decl;
257 and make_error code
(x
: (Pos.t
* string) list
) : error
= (code
, x
)
259 (*****************************************************************************)
261 (*****************************************************************************)
263 and get_code
(error
: 'a error_
) = ((fst error
): error_code
)
265 let get_severity (error
: 'a error_
) = get_code_severity (get_code error
)
267 let to_list (error
: 'a error_
) = snd error
268 let to_absolute error
=
269 let code, msg_l
= (get_code error
), (to_list error
) in
270 let msg_l = List.map
msg_l (fun (p
, s
) -> Pos.to_absolute p
, s
) in
273 let read_lines path
= In_channel.read_lines path
275 let line_margin (line_num
: int option) col_width
: string =
276 let padded_num = match line_num
with
277 | Some line_num
-> Printf.sprintf
"%*d" col_width line_num
278 | None
-> String.make col_width ' '
280 Tty.apply_color
(Tty.Normal
Tty.Cyan
) (padded_num ^
" |")
282 (* Get the lines of source code associated with this position. *)
283 let load_context_lines (pos
: Pos.absolute
): string list
=
284 let path = Pos.filename pos
in
285 let line = Pos.line pos
in
286 let end_line = Pos.end_line pos
in
289 with (Sys_error _
) -> []
291 (* Line numbers are 1-indexed. *)
292 List.filteri
lines ~f
:(fun i _
-> (i
+ 1 >= line) && (i
+ 1 <= end_line))
294 let format_context_lines (pos
: Pos.absolute
) (lines : string list
) col_width
: string =
295 let lines = (match lines with
296 | [] -> [Tty.apply_color
(Tty.Dim
Tty.White
) "No source found"]
298 let line_num = Pos.line pos
in
299 let format_line i
(line : string) =
300 Printf.sprintf
"%s %s" (line_margin (Some
(line_num + i
)) col_width
) line in
301 let formatted_lines = List.mapi ~f
:format_line lines in
302 (* TODO: display all the lines, showing the underline on all of them. *)
303 List.hd_exn
formatted_lines
305 (* Format this message as " ^^^ You did something wrong here". *)
306 let format_substring_underline (pos
: Pos.absolute
) (msg: string) (first_context_line
: string option) is_first col_width
: string =
307 let start_line, start_column
= Pos.line_column pos
in
308 let end_line, end_column
= Pos.end_line_column pos
in
309 let underline_width = match first_context_line
with
310 | None
-> 4 (* Arbitrary choice when source isn't available. *)
311 | Some first_context_line
->
312 if start_line = end_line then
313 end_column
- start_column
315 (String.length first_context_line
) - start_column
317 let underline = String.make
underline_width '^'
in
318 let underline_padding = if Option.is_some first_context_line
then
319 (String.make start_column ' '
)
323 let color = if is_first
then Tty.Bold
Tty.Red
else Tty.Dim
Tty.Default
in
324 Printf.sprintf
"%s %s%s"
325 (line_margin None col_width
)
327 (Tty.apply_color
color
328 (if is_first
then underline else (underline ^
" " ^
msg)))
330 let format_filename (pos
: Pos.absolute
): string =
331 let relative_path path =
332 let cwd = Filename.concat
(Sys.getcwd
()) "" in
335 let filename = relative_path (Pos.filename pos
) in
336 Printf.sprintf
" %s %s"
337 (Tty.apply_color
(Tty.Normal
Tty.Cyan
) "-->")
338 (Tty.apply_color
(Tty.Normal
Tty.Green
) filename)
340 let column_width line_number
=
341 let num_digits x
= int_of_float
(Float.log10
(float_of_int x
)) + 1 in
342 (max
3 (num_digits line_number
))
344 (* Format the line of code associated with this message, and the message itself. *)
345 let format_message (msg: string) (pos
: Pos.absolute
) ~is_first ~col_width
: string * string =
346 let col_width = Option.value col_width ~default
:(column_width (Pos.line pos
)) in
348 let context_lines = load_context_lines pos
in
349 let pretty_ctx = format_context_lines pos
context_lines col_width in
350 let pretty_msg = format_substring_underline pos
msg (List.hd
context_lines) is_first
col_width in
351 (pretty_ctx, pretty_msg)
353 (** Sort messages such that messages in the same file are together.
354 Do not reorder the files or messages within a file.
356 let group_by_file (msgs
: Pos.absolute message list
): Pos.absolute message list
=
357 let rec build_map msgs grouped filenames
=
360 (let filename = (Pos.filename (fst
msg)) in
361 match String.Map.find grouped
filename with
363 let grouped = String.Map.set
grouped ~key
:filename ~data
:(file_msgs
@ [msg]) in
364 build_map msgs
grouped filenames
366 let grouped = String.Map.set
grouped ~key
:filename ~data
:[msg] in
367 build_map msgs
grouped (filename::filenames
))
368 | [] -> (grouped, filenames
)
370 let grouped, filenames
= build_map msgs
String.Map.empty
[] in
371 List.concat_map
(List.rev filenames
) ~f
:(fun fn
-> String.Map.find_exn
grouped fn
)
373 (* Work out the column width needed for each file. Files with many
374 lines need a wider column due to the higher line numbers. *)
375 let col_widths (msgs
: Pos.absolute message list
): int Core_kernel.String.Map.t
=
376 (* Find the longest line number for every file in msgs. *)
378 List.fold msgs ~init
:String.Map.empty
380 let filename = Pos.filename (fst
msg) in
381 let current_max = Option.value (String.Map.find acc
filename) ~default
:0 in
382 String.Map.set acc ~key
:filename ~data
:(max
current_max (Pos.line (fst
msg))))
384 String.Map.map
longest_lines ~f
:column_width
386 (** Given a list of error messages, format them with context.
387 The list may not be ordered, and multiple messages may occur on one line.
389 let format_messages (msgs
: Pos.absolute message list
): string =
390 let msgs = group_by_file msgs in
391 (* The first message is the 'primary' message, so add a boolean to distinguish it. *)
392 let rec label_first msgs is_first
=
394 | msg::msgs -> (msg, is_first
)::label_first msgs false
397 let labelled_msgs = label_first msgs true in
399 (* Sort messages by line number, so we can display with context. *)
400 let cmp (m1
, _
) (m2
, _
) =
401 match compare (Pos.filename (fst m1
)) (Pos.filename (fst m2
)) with
402 | 0 -> compare (Pos.line (fst m1
)) (Pos.line (fst m2
))
404 let sorted_msgs = List.stable_sort
cmp labelled_msgs in
406 (* For every message, show it alongside the relevant line. If there
407 are multiple messages associated with the line, only show it once. *)
408 let col_widths = col_widths msgs in
409 let rec aux msgs prev
: string list
=
411 | (msg, is_first
)::msgs ->
412 let (pos
, err_msg
) = msg in
413 let filename = Pos.filename pos
in
414 let line = Pos.line pos
in
415 let col_width = String.Map.find
col_widths filename in
416 let pretty_ctx, pretty_msg = format_message err_msg pos ~is_first ~
col_width in
417 let formatted : string list
= (match prev
with
418 | Some
(prev_filename
, prev_line
) when prev_filename
= filename && prev_line
= line ->
419 (* Previous message was on this line too, just show the message itself*)
421 | Some
(prev_filename
, _
) when prev_filename
= filename ->
422 (* Previous message was this file, but an earlier line. *)
423 [pretty_ctx; pretty_msg]
425 [format_filename pos
; pretty_ctx; pretty_msg])
427 formatted @ aux msgs (Some
(filename, line))
430 String.concat ~sep
:"\n" (aux sorted_msgs None
) ^
"\n"
432 (* E.g. "10 errors found." *)
433 let format_summary format errors max_errors
: string option =
436 let total = List.length errors
in
437 let formatted_total =
438 Printf.sprintf
"%d error%s found"
440 (if total = 1 then "" else "s")
442 let truncated = match max_errors
with
443 | Some max_errors
when total > max_errors
->
444 Printf.sprintf
" (only showing first %d).\n" max_errors
447 Some
(formatted_total ^
truncated)
450 let to_contextual_string (error
: Pos.absolute error_
) : string =
451 let error_code = get_code error
in
452 let msgl = to_list error
in
453 let buf = Buffer.create
50 in
455 | [] -> failwith
"Impossible: an error always has non-empty list of messages"
457 Buffer.add_string
buf begin
458 Printf.sprintf
"%s %s\n"
459 (Tty.apply_color
(Tty.Bold
Tty.Red
) (error_code_to_string error_code))
460 (Tty.apply_color
(Tty.Bold
Tty.White
) msg)
462 (try Buffer.add_string
buf (format_messages msgl)
463 with _
-> Buffer.add_string
buf "Error could not be pretty-printed. Please file a bug.");
464 Buffer.add_string
buf "\n";
467 let to_absolute_for_test error
=
468 let code, msg_l = (get_code error
), (to_list error
) in
469 let msg_l = List.map
msg_l (fun (p
, s
) ->
470 let path = Pos.filename p
in
471 let path_without_prefix = Relative_path.suffix
path in
473 (Relative_path.create
Relative_path.Dummy
path_without_prefix)
475 Pos.to_absolute p, s
) in
478 let to_string ?
(indent
=false) (error
: Pos.absolute error_
) : string =
479 let error_code, msgl = (get_code error
), (to_list error
) in
480 let buf = Buffer.create
50 in
483 | (pos1
, msg1
) :: rest_of_error
->
484 Buffer.add_string
buf begin
485 let error_code = error_code_to_string error_code in
486 Printf.sprintf
"%s\n%s (%s)\n"
487 (Pos.string pos1
) msg1
error_code
489 let indentstr = if indent
then " " else "" in
490 List.iter rest_of_error
begin fun (p, w
) ->
491 let msg = Printf.sprintf
"%s%s\n%s%s\n"
492 indentstr (Pos.string p) indentstr w
in
493 Buffer.add_string
buf msg
498 let add_error error
=
499 if !accumulate_errors then
500 let () = match !current_context with
501 | (path, _
) when path = Relative_path.default
&&
502 (not
!allow_errors_in_default_path) ->
503 Hh_logger.log
"WARNING: adding an error in default path\n%s\n"
504 (Caml.Printexc.raw_backtrace_to_string
(Caml.Printexc.get_callstack
100))
507 (* Cheap test to avoid duplicating most recent error *)
508 let error_list = get_current_list !error_map
in
509 match error_list with
510 | old_error
:: _
when error
= old_error
-> ()
511 | _
-> set_current_list error_map
(error
:: error_list)
513 (* We have an error, but haven't handled it in any way *)
514 let msg = error
|> to_absolute |> to_string in
515 match !in_lazy_decl with
517 lazy_decl_error_logging msg error_map
to_absolute to_string
518 | None
-> assert_false_log_backtrace
(Some
msg)
520 (* Whether we've found at least one error *)
521 let currently_has_errors () = get_current_list !error_map
<> []
523 module Temporary
= Error_codes.Temporary
524 module Parsing
= Error_codes.Parsing
525 module Naming
= Error_codes.Naming
526 module NastCheck
= Error_codes.NastCheck
527 module Typing
= Error_codes.Typing
529 (*****************************************************************************)
531 (*****************************************************************************)
533 type t
= error files_t
* applied_fixme files_t
535 module type Error_category
= sig
539 val of_enum
: int -> t
option
540 val show
: t
-> string
541 val err_code
: t
-> int
543 (*****************************************************************************)
545 (*****************************************************************************)
547 let error_codes_treated_strictly = ref (ISet.of_list
[])
548 let is_strict_code code = ISet.mem
code !error_codes_treated_strictly
550 let default_ignored_fixme_codes = ISet.of_list
[
551 Typing.err_code
Typing.InvalidIsAsExpressionHint
;
552 Typing.err_code
Typing.InvalidEnforceableTypeArgument
;
553 Typing.err_code
Typing.RequireArgsReify
;
554 Typing.err_code
Typing.InvalidReifiedArgument
;
555 Typing.err_code
Typing.GenericsNotAllowed
;
556 Typing.err_code
Typing.InvalidNewableTypeArgument
;
557 Typing.err_code
Typing.InvalidNewableTypeParamConstraints
;
558 Typing.err_code
Typing.NewWithoutNewable
;
559 Typing.err_code
Typing.NewStaticClassReified
;
560 Typing.err_code
Typing.MemoizeReified
;
561 Typing.err_code
Typing.ReifiedTparamVariadic
;
563 let ignored_fixme_codes = ref default_ignored_fixme_codes
565 let set_allow_errors_in_default_path x
= allow_errors_in_default_path := x
567 let is_ignored_code code = ISet.mem
code !ignored_fixme_codes
569 let is_ignored_fixme code = is_ignored_code code
571 let (is_hh_fixme
: (Pos.t
-> error_code -> bool) ref) = ref (fun _ _
-> false)
572 let (get_hh_fixme_pos
: (Pos.t
-> error_code -> Pos.t
option) ref) =
573 ref (fun _ _
-> None
)
575 let add_ignored_fixme_code_error pos
code =
576 if !is_hh_fixme pos
code && is_ignored_code code then
577 let pos = Option.value (!get_hh_fixme_pos
pos code) ~default
:pos in
578 add_error (make_error
code
580 Printf.sprintf
"You cannot use HH_FIXME or HH_IGNORE_ERROR comments to suppress error %d" code])
582 (*****************************************************************************)
583 (* Errors accumulator. *)
584 (*****************************************************************************)
586 (* If primary position in error list isn't in current file, wrap with a sentinel error *)
587 let check_pos_msg pos_msg_l
=
588 let pos = fst
(List.hd_exn pos_msg_l
) in
589 let current_file = fst
!current_context in
590 if current_file <> Relative_path.default
&& Pos.filename pos <> current_file
591 then (pos, badpos_sentinel) :: pos_msg_l
594 let rec add_applied_fixme code pos =
595 if ServerLoadFlag.get_no_load
() then
596 let applied_fixmes_list = get_current_list !applied_fixmes in
597 set_current_list applied_fixmes ((pos, code) :: applied_fixmes_list)
600 and add
code pos msg =
601 let pos_msg_l = check_pos_msg [pos, msg] in
602 if not
(is_ignored_fixme code) && !is_hh_fixme
pos code
603 then add_applied_fixme code pos
604 else add_error (make_error
code pos_msg_l);
605 add_ignored_fixme_code_error pos code
607 and add_list
code pos_msg_l =
608 let pos = fst
(List.hd_exn
pos_msg_l) in
609 let pos_msg_l = check_pos_msg pos_msg_l in
610 if not
(is_ignored_fixme code) && !is_hh_fixme
pos code
611 then add_applied_fixme code pos
612 else add_error (make_error
code pos_msg_l);
613 add_ignored_fixme_code_error pos code;
615 and merge
(err'
,fixmes'
) (err
,fixmes
) =
616 let append = fun _ _ x
y ->
617 let x = Option.value x ~default
: [] in
618 let y = Option.value y ~default
: [] in
619 Some
(List.rev_append
x y)
621 files_t_merge ~f
:append err' err
,
622 files_t_merge ~f
:append fixmes' fixmes
624 and merge_into_current errors
=
625 let merged = merge errors
(!error_map
, !applied_fixmes) in
626 error_map
:= fst
merged;
627 applied_fixmes := snd
merged
629 and incremental_update
:
630 (* Need to write out the entire ugly type to convince OCaml it's polymorphic
631 * and can update both error_map as well as applied_fixmes map *)
635 (* function folding over paths of rechecked files *)
636 (a files_t
-> (Relative_path.t
-> a files_t
-> a files_t
) -> a files_t
) ->
639 = fun old new_ fold phase
->
640 (* Helper to remove acc[path][phase]. If acc[path] becomes empty afterwards,
641 * remove it too (i.e do not store empty maps or lists ever). *)
642 let remove path phase acc
=
643 let new_phase_map = match Relative_path.Map.get acc
path with
646 let new_phase_map = PhaseMap.remove phase_map phase
in
647 if PhaseMap.is_empty
new_phase_map then None
else Some
new_phase_map
649 match new_phase_map with
650 | None
-> Relative_path.Map.remove acc
path
651 | Some
x -> Relative_path.Map.add acc
path x
653 (* Replace old errors with new *)
654 let res = files_t_merge new_ old ~f
:begin fun phase
path new_ old
->
655 if path = Relative_path.default
then begin
656 let phase = match phase with
658 | Parsing
-> "Parsing"
663 Utils.assert_false_log_backtrace
(Some
(
664 "Default (untracked) error sources should not get into incremental " ^
665 "mode. There might be a missing call to Errors.do_with_context/" ^
666 "run_in_context somwhere or incorrectly used Errors.from_error_list." ^
671 | Some new_
-> Some
(List.rev new_
)
674 (* For files that were rechecked, but had no errors - remove them from maps *)
675 fold
res begin fun path acc
->
677 match Relative_path.Map.get new_
path with
679 | Some phase_map
-> PhaseMap.mem phase_map
phase
681 if has_errors then acc
682 else remove path phase acc
685 and incremental_update_set ~old ~new_ ~rechecked
phase =
686 let fold = fun init g
-> Relative_path.Set.fold ~f
:begin fun path acc
->
688 end ~init rechecked
in
689 (incremental_update
(fst old
) (fst new_
) fold phase),
690 (incremental_update
(snd old
) (snd new_
) fold phase)
692 and incremental_update_map ~old ~new_ ~rechecked
phase =
693 let fold = fun init g
-> Relative_path.Map.fold ~f
:begin fun path _ acc
->
695 end ~init rechecked
in
696 (incremental_update
(fst old
) (fst new_
) fold phase),
697 (incremental_update
(snd old
) (snd new_
) fold phase)
699 and empty
= (Relative_path.Map.empty
, Relative_path.Map.empty
)
700 and is_empty
(err
, _fixmes
) = Relative_path.Map.is_empty err
702 and count
(err
, _fixmes
) = files_t_fold err ~f
:(fun _ _
x acc
-> acc
+ List.length
x) ~init
:0
703 and get_error_list
(err
, _fixmes
) = files_t_to_list err
704 and get_applied_fixmes
(_err
, fixmes
) = files_t_to_list fixmes
705 and from_error_list err
= (list_to_files_t err
, Relative_path.Map.empty
)
707 (*****************************************************************************)
708 (* Accessors. (All methods delegated to the parameterized module.) *)
709 (*****************************************************************************)
711 let iter_error_list f err
= List.iter ~f
:f
(get_sorted_error_list err
)
713 let fold_errors ?
phase err ~init ~f
=
716 files_t_fold (fst err
)
718 ~f
:begin fun source _ errors acc
->
719 List.fold_right errors ~init
:acc ~f
:(f source
)
722 Relative_path.Map.fold (fst err
) ~init ~f
:begin fun source phases acc
->
723 match PhaseMap.get phases
phase with
725 | Some errors
-> List.fold_right errors ~init
:acc ~f
:(f source
)
728 let fold_errors_in ?
phase err ~source ~init ~f
=
729 Relative_path.Map.get
(fst err
) source
|>
730 Option.value ~default
:PhaseMap.empty
|>
731 PhaseMap.fold ~init ~f
:begin fun p errors acc
->
732 if phase <> None
&& phase <> Some
p then acc
733 else List.fold_right errors ~init
:acc ~f
736 let get_failed_files err
phase =
737 files_t_fold (fst err
)
738 ~init
:Relative_path.Set.empty
739 ~f
:begin fun source
p _ acc
->
740 if phase <> p then acc
else Relative_path.Set.add acc source
743 (*****************************************************************************)
744 (* Error code printing. *)
745 (*****************************************************************************)
747 let internal_error pos msg =
748 add
0 pos ("Internal error: "^
msg)
750 let unimplemented_feature pos msg =
751 add
0 pos ("Feature not implemented: " ^
msg)
753 let experimental_feature pos msg =
754 add
0 pos ("Cannot use experimental feature: " ^
msg)
756 (*****************************************************************************)
757 (* Temporary errors. *)
758 (*****************************************************************************)
760 let darray_not_supported pos =
761 add
Temporary.darray_not_supported pos "darray is not supported."
763 let varray_not_supported pos =
764 add
Temporary.varray_not_supported pos "varray is not supported."
766 let varray_or_darray_not_supported pos =
768 Temporary.varray_or_darray_not_supported
770 "varray_or_darray is not supported."
772 let nonnull_not_supported pos =
773 add
Temporary.nonnull_not_supported pos "nonnull is not supported."
775 (*****************************************************************************)
776 (* Parsing errors. *)
777 (*****************************************************************************)
779 let fixme_format pos =
780 add
(Parsing.err_code
Parsing.FixmeFormat
) pos
781 "HH_FIXME wrong format, expected '/* HH_FIXME[ERROR_NUMBER] */'"
783 let unexpected_eof pos =
784 add
(Parsing.err_code
Parsing.UnexpectedEof
) pos "Unexpected end of file"
786 let unterminated_comment pos =
787 add
(Parsing.err_code
Parsing.UnterminatedComment
) pos "unterminated comment"
789 let unterminated_xhp_comment pos =
790 add
(Parsing.err_code
Parsing.UnterminatedXhpComment
) pos "unterminated xhp comment"
792 let parsing_error (p, msg) =
793 add
(Parsing.err_code
Parsing.ParsingError
) p msg
795 (*****************************************************************************)
796 (* Legacy AST / AAST errors *)
797 (*****************************************************************************)
799 let unsupported_trait_use_as pos =
800 add
(Naming.err_code
Naming.UnsupportedTraitUseAs
) pos
801 "Trait use as is a PHP feature that is unsupported in Hack"
803 let unsupported_instead_of pos =
804 add
(Naming.err_code
Naming.UnsupportedInsteadOf
) pos
805 "insteadof is a PHP feature that is unsupported in Hack"
807 let invalid_trait_use_as_visibility pos =
808 add
(Naming.err_code
Naming.InvalidTraitUseAsVisibility
) pos
809 "Cannot redeclare trait method's visibility in this manner"
811 (*****************************************************************************)
813 (*****************************************************************************)
816 let unexpected_arrow pos cname
=
817 add
(Naming.err_code
Naming.UnexpectedArrow
) pos (
818 "Keys may not be specified for "^cname^
" initialization"
821 let missing_arrow pos cname
=
822 add
(Naming.err_code
Naming.MissingArrow
) pos (
823 "Keys must be specified for "^cname^
" initialization"
826 let disallowed_xhp_type pos name
=
827 add
(Naming.err_code
Naming.DisallowedXhpType
) pos (
828 name^
" is not a valid type. Use :xhp or XHPChild."
831 let name_already_bound name pos1 pos2
=
832 let name = Utils.strip_ns
name in
833 add_list
(Naming.err_code
Naming.NameAlreadyBound
) [
834 pos1
, "Name already bound: "^
name;
835 pos2
, "Previous definition is here"
838 let name_is_reserved name pos =
839 let name = Utils.strip_all_ns
name in
840 add
(Naming.err_code
Naming.NameIsReserved
) pos (
841 name^
" cannot be used as it is reserved."
844 let dollardollar_unused pos =
845 add
(Naming.err_code
Naming.DollardollarUnused
) pos ("This expression does not contain a "^
846 "usage of the special pipe variable. Did you forget to use the ($$) "^
849 let method_name_already_bound pos name =
850 add
(Naming.err_code
Naming.MethodNameAlreadyBound
) pos (
851 "Method name already bound: "^
name
854 let reference_in_rx pos =
855 add
(Naming.err_code
Naming.ReferenceInRx
) pos (
856 "References are not allowed in reactive code."
858 let error_name_already_bound name name_prev
p p_prev
=
859 let name = Utils.strip_ns
name in
860 let name_prev = Utils.strip_ns
name_prev in
862 p, "Name already bound: "^
name;
863 p_prev
, (if String.compare name name_prev = 0
864 then "Previous definition is here"
865 else "Previous definition "^
name_prev^
" differs only in capitalization ")
868 "This appears to be defined in an hhi file included in your project "^
869 "root. The hhi files for the standard library are now a part of the "^
870 "typechecker and must be removed from your project. Typically, you can "^
871 "do this by deleting the \"hhi\" directory you copied into your "^
872 "project when first starting with Hack." in
874 if (Relative_path.prefix
(Pos.filename p)) = Relative_path.Hhi
875 then errs @ [p_prev
, hhi_msg]
876 else if (Relative_path.prefix
(Pos.filename p_prev
)) = Relative_path.Hhi
877 then errs @ [p, hhi_msg]
879 add_list
(Naming.err_code
Naming.ErrorNameAlreadyBound
) errs
881 let error_class_attribute_already_bound name name_prev p p_prev
=
882 let name = Utils.strip_ns
name in
883 let name_prev = Utils.strip_ns
name_prev in
885 p, "A class and an attribute class cannot share the same name. Conflicting class: "^
name;
886 p_prev
, "Previous definition: "^
name_prev
888 add_list
(Naming.err_code
Naming.AttributeClassNameConflict
) errs
890 let unbound_name pos name kind
=
891 let kind_str = match kind
with
892 | `cls
-> "an object type"
893 | `func
-> "a global function"
894 | `const
-> "a global constant"
896 add
(Naming.err_code
Naming.UnboundName
) pos
897 ("Unbound name: "^
(strip_ns
name)^
" ("^
kind_str^
")")
899 let different_scope pos var_name
pos'
=
900 add_list
(Naming.err_code
Naming.DifferentScope
) [
901 pos, ("The variable "^ var_name ^
" is defined");
902 pos'
, ("But in a different scope")
905 let rx_move_invalid_location pos =
906 add
(Naming.err_code
Naming.RxMoveInvalidLocation
) pos
907 "Rx\\move is only allowed in argument position or as right hand side of the assignment."
909 let undefined ~in_rx_scope
pos var_name
=
910 let rx_scope_clarification =
911 if in_rx_scope
then "or unsets "
913 add
(Naming.err_code
Naming.Undefined
) pos ("Variable "^var_name^
915 "or there exists at least one control flow path reaching this point which "^
916 "does not define " ^
rx_scope_clarification ^ var_name ^
".")
918 let this_reserved pos =
919 add
(Naming.err_code
Naming.ThisReserved
) pos
920 "The type parameter \"this\" is reserved"
922 let start_with_T pos =
923 add
(Naming.err_code
Naming.StartWith_T
) pos
924 "Please make your type parameter start with the letter T (capital)"
926 let already_bound pos name =
927 add
(Naming.err_code
Naming.NameAlreadyBound
) pos ("Argument already bound: "^
name)
929 let unexpected_typedef pos def_pos
=
930 add_list
(Naming.err_code
Naming.UnexpectedTypedef
) [
931 pos, "Unexpected typedef";
932 def_pos
, "Definition is here";
935 let fd_name_already_bound pos =
936 add
(Naming.err_code
Naming.FdNameAlreadyBound
) pos
937 "Field name already bound"
939 let primitive_toplevel pos =
940 add
(Naming.err_code
Naming.PrimitiveToplevel
) pos (
941 "Primitive type annotations are always available and may no \
942 longer be referred to in the toplevel namespace."
945 let primitive_invalid_alias pos used valid
=
946 add
(Naming.err_code
Naming.PrimitiveInvalidAlias
) pos
947 ("Invalid Hack type. Using '"^used^
"' in Hack is considered \
948 an error. Use '"^valid^
"' instead, to keep the codebase \
951 let dynamic_new_in_strict_mode pos =
952 add
(Naming.err_code
Naming.DynamicNewInStrictMode
) pos
953 "Cannot use dynamic new in strict mode"
955 let invalid_type_access_root (pos, id
) =
956 add
(Naming.err_code
Naming.InvalidTypeAccessRoot
) pos
957 (id^
" must be an identifier for a class, \"self\", or \"this\"")
959 let duplicate_user_attribute (pos, name) existing_attr_pos
=
960 add_list
(Naming.err_code
Naming.DuplicateUserAttribute
) [
961 pos, "You cannot reuse the attribute "^
name;
962 existing_attr_pos
, name^
" was already used here";
965 let misplaced_rx_of_scope pos =
966 add
(Naming.err_code
Naming.MisplacedRxOfScope
) pos (
967 "<<__RxOfScope>> attribute is only allowed on lambdas."
969 let rx_of_scope_and_explicit_rx pos =
970 add
(Naming.err_code
Naming.RxOfScopeAndExplicitRx
) pos (
971 "<<__RxOfScope>> attribute cannot be used with explicit reactivity annotations."
973 let unbound_attribute_name pos name =
974 let reason = if (string_starts_with
name "__")
975 then "starts with __ but is not a standard attribute"
976 else "does not have a class. Please declare a class for the attribute."
977 in add
(Naming.err_code
Naming.UnboundName
) pos
978 ("Unrecognized user attribute: "^
(Utils.strip_ns
name)^
" "^
reason)
980 let this_no_argument pos =
981 add
(Naming.err_code
Naming.ThisNoArgument
) pos "\"this\" expects no arguments"
984 add
(Naming.err_code
Naming.VoidCast
) pos "Cannot cast to void."
987 add
(Naming.err_code
Naming.UnsetCast
) pos "Don't use (unset), just assign null!"
989 let object_cast pos cls_opt
=
990 let msg1 = "Object casts are unsupported." in
994 " Try 'if ($var instanceof "^c^
")' or 'invariant($var instanceof "^c^
", ...)'."
997 add
(Naming.err_code
Naming.ObjectCast
) pos (msg1 ^
msg2)
999 let this_hint_outside_class pos =
1000 add
(Naming.err_code
Naming.ThisHintOutsideClass
) pos
1001 "Cannot use \"this\" outside of a class"
1003 let this_type_forbidden pos =
1004 add
(Naming.err_code
Naming.ThisMustBeReturn
) pos
1005 "The type \"this\" cannot be used as a constraint on a class' generic, \
1006 or as the type of a static member variable"
1008 let nonstatic_property_with_lsb pos =
1009 add
(Naming.err_code
Naming.NonstaticPropertyWithLSB
) pos
1010 "__LSB attribute may only be used on static properties"
1012 let lowercase_this pos type_
=
1013 add
(Naming.err_code
Naming.LowercaseThis
) pos (
1014 "Invalid Hack type \""^type_^
"\". Use \"this\" instead"
1017 let classname_param pos =
1018 add
(Naming.err_code
Naming.ClassnameParam
) pos
1019 ("Missing type parameter to classname; classname is entirely"
1020 ^
" meaningless without one")
1022 let invalid_instanceof pos =
1023 add
(Naming.err_code
Naming.InvalidInstanceof
) pos
1024 "This instanceof has an invalid right operand. Only class identifiers, \
1025 local variables, accesses of objects / classes / arrays, and function / \
1026 method calls are allowed."
1028 let tparam_with_tparam pos x =
1029 add
(Naming.err_code
Naming.TparamWithTparam
) pos (
1030 Printf.sprintf
"%s is a type parameter. Type parameters cannot \
1031 themselves take type parameters (e.g. %s<int> doesn't make sense)" x x
1034 let shadowed_type_param p pos name =
1035 add_list
(Naming.err_code
Naming.ShadowedTypeParam
) [
1036 p, Printf.sprintf
"You cannot re-bind the type parameter %s" name;
1037 pos, Printf.sprintf
"%s is already bound here" name
1040 let missing_typehint pos =
1041 add
(Naming.err_code
Naming.MissingTypehint
) pos
1042 "Please add a type hint"
1044 let expected_variable pos =
1045 add
(Naming.err_code
Naming.ExpectedVariable
) pos
1046 "Was expecting a variable name"
1048 let clone_too_many_arguments pos =
1049 add
(Naming.err_code
Naming.NamingTooManyArguments
) pos
1050 "__clone method cannot take arguments"
1052 let naming_too_few_arguments pos =
1053 add
(Naming.err_code
Naming.NamingTooFewArguments
) pos
1056 let naming_too_many_arguments pos =
1057 add
(Naming.err_code
Naming.NamingTooManyArguments
) pos
1058 "Too many arguments"
1060 let expected_collection pos cn
=
1061 add
(Naming.err_code
Naming.ExpectedCollection
) pos (
1062 "Unexpected collection type " ^
(Utils.strip_ns cn
)
1065 let illegal_CLASS pos =
1066 add
(Naming.err_code
Naming.IllegalClass
) pos
1067 "Using __CLASS__ outside a class or trait"
1069 let illegal_TRAIT pos =
1070 add
(Naming.err_code
Naming.IllegalTrait
) pos
1071 "Using __TRAIT__ outside a trait"
1073 let lvar_in_obj_get pos =
1074 add
(Naming.err_code
Naming.LvarInObjGet
) pos
1075 "Dynamic method or attribute access is not allowed on a non-dynamic value."
1077 let nullsafe_property_write_context pos =
1078 add
(Typing.err_code
Typing.NullsafePropertyWriteContext
) pos
1079 "?-> syntax not supported here, this function effectively does a write"
1081 let illegal_fun pos =
1082 let msg = "The argument to fun() must be a single-quoted, constant "^
1083 "literal string representing a valid function name." in
1084 add
(Naming.err_code
Naming.IllegalFun
) pos msg
1086 let illegal_member_variable_class pos =
1087 let msg = "Cannot declare a constant named 'class'. \
1088 The name 'class' is reserved for the class \
1089 constant that represents the name of the class" in
1090 add
(Naming.err_code
Naming.IllegalMemberVariableClass
) pos msg
1092 let illegal_meth_fun pos =
1093 let msg = "String argument to fun() contains ':';"^
1094 " for static class methods, use"^
1095 " class_meth(Cls::class, 'method_name'), not fun('Cls::method_name')" in
1096 add
(Naming.err_code
Naming.IllegalMethFun
) pos msg
1098 let illegal_inst_meth pos =
1099 let msg = "The argument to inst_meth() must be an expression and a "^
1100 "constant literal string representing a valid method name." in
1101 add
(Naming.err_code
Naming.IllegalInstMeth
) pos msg
1103 let illegal_meth_caller pos =
1105 "The two arguments to meth_caller() must be:"
1106 ^
"\n - first: ClassOrInterface::class"
1107 ^
"\n - second: a single-quoted string literal containing the name"
1108 ^
" of a non-static method of that class" in
1109 add
(Naming.err_code
Naming.IllegalMethCaller
) pos msg
1111 let illegal_class_meth pos =
1113 "The two arguments to class_meth() must be:"
1114 ^
"\n - first: ValidClassname::class"
1115 ^
"\n - second: a single-quoted string literal containing the name"
1116 ^
" of a static method of that class" in
1117 add
(Naming.err_code
Naming.IllegalClassMeth
) pos msg
1119 let assert_arity pos =
1120 add
(Naming.err_code
Naming.AssertArity
) pos
1121 "assert expects exactly one argument"
1123 let genva_arity pos =
1124 add
(Naming.err_code
Naming.GenvaArity
) pos
1125 "genva() expects at least 1 argument"
1127 let unexpected_ty_in_tast pos ~actual_ty ~expected_ty
=
1128 add
(Typing.err_code
Typing.UnexpectedTy
) pos (
1129 "Unexpected type in TAST: expected " ^ expected_ty ^
", got " ^ actual_ty
1132 let uninstantiable_class usage_pos decl_pos
name reason_msgl
=
1133 let name = strip_ns
name in
1135 usage_pos
, (name^
" is uninstantiable");
1136 decl_pos
, "Declaration is here"
1138 let msgl = match reason_msgl
with
1139 | (reason_pos
, reason_str
) :: tail
->
1140 (reason_pos
, reason_str^
" which must be instantiable") :: tail
@ msgl
1142 add_list
(Typing.err_code
Typing.UninstantiableClass
) msgl
1144 let abstract_const_usage usage_pos decl_pos
name =
1145 let name = strip_ns
name in
1146 add_list
(Typing.err_code
Typing.AbstractConstUsage
) [
1147 usage_pos
, ("Cannot reference abstract constant "^
name^
" directly");
1148 decl_pos
, "Declaration is here"
1151 let add_a_typehint pos =
1152 add
(Naming.err_code
Naming.AddATypehint
) pos
1153 "Please add a type hint"
1155 let local_const var_pos
=
1156 add
(Naming.err_code
Naming.LocalConst
) var_pos
1157 "You cannot use a local variable in a constant definition"
1159 let illegal_constant pos =
1160 add
(Naming.err_code
Naming.IllegalConstant
) pos
1161 "Illegal constant value"
1163 let invalid_req_implements pos =
1164 add
(Naming.err_code
Naming.InvalidReqImplements
) pos
1165 "Only traits may use 'require implements'"
1167 let invalid_req_extends pos =
1168 add
(Naming.err_code
Naming.InvalidReqExtends
) pos
1169 "Only traits and interfaces may use 'require extends'"
1171 let did_you_mean_naming pos name suggest_pos suggest_name
=
1172 add_list
(Naming.err_code
Naming.DidYouMeanNaming
) [
1173 pos, "Could not find "^
(strip_ns
name);
1174 suggest_pos
, "Did you mean "^
(strip_ns suggest_name
)^
"?"
1177 let using_internal_class pos name =
1178 add
(Naming.err_code
Naming.UsingInternalClass
) pos (
1179 name^
" is an implementation internal class that cannot be used directly"
1182 let too_few_type_arguments p =
1183 add
(Naming.err_code
Naming.TooFewTypeArguments
) p
1184 ("Too few type arguments for this type")
1186 let goto_label_already_defined
1189 original_delcaration_pos
=
1191 (Naming.err_code
Naming.GotoLabelAlreadyDefined
)
1193 redeclaration_pos
, "Cannot redeclare the goto label '" ^ label_name ^
"'";
1194 original_delcaration_pos
, "Declaration is here";
1197 let goto_label_undefined pos label_name
=
1198 add
(Naming.err_code
Naming.GotoLabelUndefined
) pos ("Undefined goto label: " ^ label_name
)
1200 let goto_label_defined_in_finally pos =
1201 add
(Naming.err_code
Naming.GotoLabelDefinedInFinally
)
1203 "It is illegal to define a goto label within a finally block."
1205 let unsupported_feature pos name =
1206 add
(Naming.err_code
Naming.UnsupportedFeature
) pos (name ^
" is not supported in Hack.")
1208 let goto_invoked_in_finally pos =
1209 add
(Naming.err_code
Naming.GotoInvokedInFinally
)
1211 "It is illegal to invoke goto within a finally block."
1213 let method_needs_visibility pos =
1214 add
(Naming.err_code
Naming.MethodNeedsVisibility
)
1215 pos ("Methods need to be marked public, private, or protected.")
1217 let dynamic_class_property_name_in_strict_mode pos =
1218 add
(Naming.err_code
Naming.DynamicClassPropertyNameInStrictMode
)
1220 "Cannot use dynamic class property name in strict mode"
1222 let dynamic_class_name_in_strict_mode pos =
1223 add
(Naming.err_code
Naming.DynamicClassNameInStrictMode
)
1225 "Cannot use dynamic class name in strict mode"
1227 let xhp_optional_required_attr pos id
=
1228 add
(Naming.err_code
Naming.XhpOptionalRequiredAttr
)
1230 ("XHP attribute " ^ id ^
" cannot be marked as nullable and required")
1232 let xhp_required_with_default pos id
=
1233 add
(Naming.err_code
Naming.XhpRequiredWithDefault
)
1235 ("XHP attribute " ^ id ^
" cannot be marked as required and provide a default")
1237 let array_typehints_disallowed pos =
1238 add
(Naming.err_code
Naming.ArrayTypehintsDisallowed
) pos
1239 "Array typehints are no longer legal; use varray or darray instead"
1241 let array_literals_disallowed pos =
1242 add
(Naming.err_code
Naming.ArrayLiteralsDisallowed
) pos
1243 "Array literals are no longer legal; use varray or darray instead"
1245 let wildcard_disallowed pos =
1246 add
(Naming.err_code
Naming.WildcardDisallowed
) pos
1247 "Wildcard typehints are not allowed in this position"
1249 let reference_in_strict_mode pos =
1250 add
(Naming.err_code
Naming.ReferenceInStrictMode
) pos
1251 "Don't use references!"
1253 let misplaced_mutability_hint pos =
1254 add
(Naming.err_code
Naming.MisplacedMutabilityHint
) pos
1255 "Setting mutability via type hints is only allowed for parameters of reactive function types. \
1256 For other cases consider using attributes."
1258 let mutability_hint_in_non_rx_function pos =
1259 add
(Naming.err_code
Naming.MutabilityHintInNonRx
) pos
1260 "Parameter with mutability hint cannot appear in non-reactive function type."
1262 let invalid_mutability_in_return_type_hint pos =
1263 add
(Naming.err_code
Naming.InvalidReturnMutableHint
) pos
1264 "OwnedMutable is the only mutability related hint allowed in return type annotation \
1265 for reactive function types."
1267 let anon_use_capture_by_ref pos =
1268 add
(Naming.err_code
Naming.ReferenceInAnonUseClause
) pos (
1269 "Capturing variables by PHP reference is no longer supported on anonymous "^
1270 "functions. If the variable is a value type, store it on an object "^
1271 "instead or refactor your code to avoid using a closure.")
1273 let no_tparams_on_type_consts pos =
1274 add
(Naming.err_code
Naming.NoTparamsOnTypeConsts
) pos
1275 "Type parameters are not allowed on class type constants"
1277 let pu_duplication pos name kind
=
1278 add
(Naming.err_code
Naming.PocketUniversesDuplication
) pos
1279 (sprintf
"[PocketUniverses] %s (%s) is declared multiple times" name kind
)
1281 (*****************************************************************************)
1282 (* Init check errors *)
1283 (*****************************************************************************)
1285 let no_construct_parent pos =
1286 add
(NastCheck.err_code
NastCheck.NoConstructParent
) pos (
1287 sl
["You are extending a class that needs to be initialized\n";
1288 "Make sure you call parent::__construct.\n"
1292 let nonstatic_method_in_abstract_final_class pos =
1293 add
(NastCheck.err_code
NastCheck.NonstaticMethodInAbstractFinalClass
) pos (
1294 "Abstract final classes cannot have nonstatic methods or constructors."
1297 let constructor_required (pos, name) prop_names
=
1298 let name = Utils.strip_ns
name in
1299 let props_str = SSet.fold ~f
:(fun x acc
-> x^
" "^acc
) prop_names ~init
:"" in
1300 add
(NastCheck.err_code
NastCheck.ConstructorRequired
) pos
1301 ("Lacking __construct, class "^
name^
" does not initialize its private member(s): "^
props_str)
1303 let not_initialized (pos, cname
) prop_names
=
1304 let cname = Utils.strip_ns
cname in
1305 let props_str = List.fold_right prop_names
1306 ~f
:(fun x acc
-> x^
" "^acc
) ~init
:"" in
1308 if 1 = List.length prop_names
1310 else "members", "are" in
1311 let setters_str = List.fold_right prop_names
1312 ~f
:(fun x acc
-> "$this->"^
x^
" "^acc
) ~init
:"" in
1313 add
(NastCheck.err_code
NastCheck.NotInitialized
) pos (
1315 "Class "; cname ; " does not initialize all of its members; ";
1316 props_str; verb
; " not always initialized.";
1317 "\nMake sure you systematically set "; setters_str;
1318 "when the method __construct is called.";
1319 "\nAlternatively, you can define the "; members ;" as optional (?...)\n"
1322 let call_before_init pos cv
=
1323 add
(NastCheck.err_code
NastCheck.CallBeforeInit
) pos (
1325 "Until the initialization of $this is over,";
1326 " you can only call private methods\n";
1327 "The initialization is not over because ";
1329 if cv
= "parent::__construct"
1330 then ["you forgot to call parent::__construct"]
1331 else ["$this->"; cv
; " can still potentially be null"])
1334 (*****************************************************************************)
1335 (* Nast errors check *)
1336 (*****************************************************************************)
1338 let type_arity pos name nargs
=
1339 add
(Typing.err_code
Typing.TypeArityMismatch
) pos (
1340 sl
["The type ";(Utils.strip_ns
name);
1341 " expects ";nargs
;" type parameter(s)"]
1344 let abstract_with_body (p, _
) =
1345 add
(NastCheck.err_code
NastCheck.AbstractWithBody
) p
1346 "This method is declared as abstract, but has a body"
1348 let not_abstract_without_body (p, _
) =
1349 add
(NastCheck.err_code
NastCheck.NotAbstractWithoutBody
) p
1350 "This method is not declared as abstract, it must have a body"
1352 let not_abstract_without_typeconst (p, _
) =
1353 add
(NastCheck.err_code
NastCheck.NotAbstractWithoutTypeconst
) p
1354 ("This type constant is not declared as abstract, it must have"^
1355 " an assigned type")
1357 let abstract_with_typeconst (p, _
) =
1358 add
(NastCheck.err_code
NastCheck.AbstractWithTypeconst
) p
1359 ("This type constant is declared as abstract, it cannot be assigned a type")
1361 let typeconst_depends_on_external_tparam pos ext_pos ext_name
=
1362 add_list
(NastCheck.err_code
NastCheck.TypeconstDependsOnExternalTparam
) [
1363 pos, ("A type constant can only use type parameters declared in its own"^
1364 " type parameter list");
1365 ext_pos
, (ext_name ^
" was declared as a type parameter here");
1368 let typeconst_assigned_tparam pos tp_name
=
1369 add
(NastCheck.err_code
NastCheck.TypeconstAssignedTparam
) pos
1370 (tp_name ^
" is a type parameter. It cannot be assigned to a type constant")
1372 let interface_with_partial_typeconst tconst_pos
=
1373 add
(NastCheck.err_code
NastCheck.InterfaceWithPartialTypeconst
) tconst_pos
1374 "An interface cannot contain a partially abstract type constant"
1376 let multiple_xhp_category pos =
1377 add
(NastCheck.err_code
NastCheck.MultipleXhpCategory
) pos
1378 "XHP classes can only contain one category declaration"
1380 let return_in_gen p =
1381 add
(NastCheck.err_code
NastCheck.ReturnInGen
) p
1382 ("You cannot return a value in a generator (a generator"^
1383 " is a function that uses yield)")
1385 let return_in_finally p =
1386 add
(NastCheck.err_code
NastCheck.ReturnInFinally
) p
1387 ("Don't use return in a finally block;"^
1388 " there's nothing to receive the return value")
1390 let toplevel_break p =
1391 add
(NastCheck.err_code
NastCheck.ToplevelBreak
) p
1392 "break can only be used inside loops or switch statements"
1394 let toplevel_continue p =
1395 add
(NastCheck.err_code
NastCheck.ToplevelContinue
) p
1396 "continue can only be used inside loops"
1398 let continue_in_switch p =
1399 add
(NastCheck.err_code
NastCheck.ContinueInSwitch
) p
1400 ("In PHP, 'continue;' inside a switch \
1401 statement is equivalent to 'break;'."^
1402 " Hack does not support this; use 'break' if that is what you meant.")
1404 let await_in_sync_function p =
1405 add
(NastCheck.err_code
NastCheck.AwaitInSyncFunction
) p
1406 "await can only be used inside async functions"
1408 let interface_use_trait p =
1409 add
(NastCheck.err_code
NastCheck.InterfaceUsesTrait
) p
1410 "Interfaces cannot use traits"
1412 let await_not_allowed p =
1413 add
(NastCheck.err_code
NastCheck.AwaitNotAllowed
) p
1414 "await is only permitted as a statement, expression in a return statement \
1415 or as a right hand side in top level assignment."
1417 let await_in_coroutine p =
1418 add
(NastCheck.err_code
NastCheck.AwaitInCoroutine
) p
1419 "await is not allowed in coroutines."
1421 let yield_in_coroutine p =
1422 add
(NastCheck.err_code
NastCheck.YieldInCoroutine
) p
1423 "yield is not allowed in coroutines."
1425 let suspend_outside_of_coroutine p =
1426 add
(NastCheck.err_code
NastCheck.SuspendOutsideOfCoroutine
) p
1427 "suspend is only allowed in coroutines."
1429 let suspend_in_finally p =
1430 add
(NastCheck.err_code
NastCheck.SuspendInFinally
) p
1431 "suspend is not allowed inside finally blocks."
1433 let break_continue_n_not_supported p =
1434 add
(NastCheck.err_code
NastCheck.BreakContinueNNotSupported
) p
1435 "Break/continue N operators are not supported."
1437 let static_memoized_function p =
1438 add
(NastCheck.err_code
NastCheck.StaticMemoizedFunction
) p
1439 "memoize is not allowed on static methods in classes that aren't final "
1442 add
(NastCheck.err_code
NastCheck.Magic
) p
1443 (s^
" is a magic method and cannot be called directly")
1445 let non_interface (p : Pos.t
) (c2
: string) (verb
: string): 'a
=
1446 add
(NastCheck.err_code
NastCheck.NonInterface
) p
1447 ("Cannot " ^ verb ^
" " ^
(strip_ns c2
) ^
" - it is not an interface")
1449 let toString_returns_string pos =
1450 add
(NastCheck.err_code
NastCheck.ToStringReturnsString
) pos "__toString should return a string"
1452 let toString_visibility pos =
1453 add
(NastCheck.err_code
NastCheck.ToStringVisibility
) pos
1454 "__toString must have public visibility and cannot be static"
1456 let uses_non_trait (p: Pos.t
) (n
: string) (t
: string) =
1457 add
(NastCheck.err_code
NastCheck.UsesNonTrait
) p
1458 ((Utils.strip_ns n
) ^
" is not a trait. It is " ^ t ^
".")
1460 let requires_non_class (p: Pos.t
) (n
: string) (t
: string) =
1461 add
(NastCheck.err_code
NastCheck.RequiresNonClass
) p
1462 ((Utils.strip_ns n
) ^
" is not a class. It is " ^ t ^
".")
1464 let requires_final_class (p: Pos.t
) (n
: string) =
1465 add
(NastCheck.err_code
NastCheck.RequiresFinalClass
) p
1466 ((Utils.strip_ns n
) ^
" is not an extendable class.")
1468 let abstract_body pos =
1469 add
(NastCheck.err_code
NastCheck.AbstractBody
) pos "This method shouldn't have a body"
1471 let not_public_or_protected_interface pos =
1472 add
(NastCheck.err_code
NastCheck.NotPublicInterface
) pos
1473 "Access type for interface method must be public or protected."
1475 let interface_with_member_variable pos =
1476 add
(NastCheck.err_code
NastCheck.InterfaceWithMemberVariable
) pos
1477 "Interfaces cannot have member variables"
1479 let interface_with_static_member_variable pos =
1480 add
(NastCheck.err_code
NastCheck.InterfaceWithStaticMemberVariable
) pos
1481 "Interfaces cannot have static variables"
1483 let illegal_function_name pos mname
=
1484 add
(NastCheck.err_code
NastCheck.IllegalFunctionName
) pos
1485 ("Illegal function name: " ^ strip_ns mname
)
1487 let dangerous_method_name pos =
1488 add
(NastCheck.err_code
NastCheck.DangerousMethodName
) pos (
1489 "This is a dangerous method name, "^
1490 "if you want to define a constructor, use "^
1494 let inout_params_outside_of_sync pos =
1495 add
(NastCheck.err_code
NastCheck.InoutParamsOutsideOfSync
) pos (
1496 "Inout parameters cannot be defined on async functions, "^
1497 "generators or coroutines."
1500 let mutable_params_outside_of_sync pos fpos
name fname
=
1501 add_list
(NastCheck.err_code
NastCheck.MutableParamsOutsideOfSync
) [
1502 pos, "Mutable parameters are not allowed on async functions";
1503 pos, "This parameter "^
(strip_ns
name) ^
" is marked mutable.";
1504 fpos
, "The function "^
(strip_ns fname
) ^
" is marked async.";
1507 let mutable_async_method pos =
1508 add
(NastCheck.err_code
NastCheck.MutableAsyncMethod
) pos (
1509 "Mutable methods must be synchronous. Try removing the async tag from the function."
1512 let mutable_attribute_on_function pos =
1513 add
(NastCheck.err_code
NastCheck.MutableAttributeOnFunction
) pos (
1514 "<<__Mutable>> only makes sense on methods, or parameters on functions or methods."
1517 let maybe_mutable_attribute_on_function pos =
1518 add
(NastCheck.err_code
NastCheck.MaybeMutableAttributeOnFunction
) pos (
1519 "<<__MaybeMutable>> only makes sense on methods, or parameters on functions or methods."
1522 let conflicting_mutable_and_maybe_mutable_attributes pos =
1523 add
(NastCheck.err_code
NastCheck.ConflictingMutableAndMaybeMutableAttributes
) pos (
1524 "Declaration cannot have both <<__Mutable>> and <<__MaybeMutable>> attributtes."
1527 let mutable_methods_must_be_reactive pos name =
1528 add
(NastCheck.err_code
NastCheck.MutableMethodsMustBeReactive
) pos (
1529 "The method " ^
(strip_ns
name) ^
" has a mutable parameter" ^
1530 " (or mutable this), so it must be marked reactive with <<__Rx>>."
1533 let mutable_return_annotated_decls_must_be_reactive kind
pos name =
1534 add
(NastCheck.err_code
NastCheck.MutableReturnAnnotatedDeclsMustBeReactive
) pos (
1535 "The " ^ kind ^
" " ^
(strip_ns
name) ^
" is annotated with <<__MutableReturn>>, " ^
1536 " so it must be marked reactive with <<__Rx>>."
1539 let maybe_mutable_methods_must_be_reactive pos name =
1540 add
(NastCheck.err_code
NastCheck.MaybeMutableMethodsMustBeReactive
) pos (
1541 "The method " ^
(strip_ns
name) ^
" is annotated with <<__MaybeMutable> attribute, \
1542 or has this attribute on one of parameters so it must be marked reactive."
1546 let inout_params_special pos =
1547 add
(NastCheck.err_code
NastCheck.InoutParamsSpecial
) pos
1548 "Methods with special semantics cannot have inout parameters."
1550 let inout_params_mix_byref pos1 pos2
=
1551 if pos1
<> pos2
then begin
1552 let msg1 = pos1
, "Cannot mix inout and byRef parameters" in
1553 let msg2 = pos2
, "This parameter is passed by reference" in
1554 add_list
(NastCheck.err_code
NastCheck.InoutParamsMixByref
) [msg1; msg2]
1557 let inout_params_memoize fpos
pos =
1558 let msg1 = fpos
, "Functions with inout parameters cannot be memoized" in
1559 let msg2 = pos, "This is an inout parameter" in
1560 add_list
(NastCheck.err_code
NastCheck.InoutParamsMemoize
) [msg1; msg2]
1562 let reading_from_append pos =
1563 add
(NastCheck.err_code
NastCheck.ReadingFromAppend
) pos "Cannot use [] for reading"
1565 let const_attribute_prohibited pos kind
=
1566 add
(NastCheck.err_code
NastCheck.ConstAttributeProhibited
) pos
1567 ("Cannot apply __Const attribute to " ^ kind
)
1569 let inout_argument_bad_expr pos =
1570 add
(NastCheck.err_code
NastCheck.InoutArgumentBadExpr
) pos (
1571 "Arguments for inout parameters must be local variables or simple " ^
1572 "subscript expressions on vecs, dicts, keysets, or arrays"
1575 let illegal_destructor pos =
1576 add
(NastCheck.err_code
NastCheck.IllegalDestructor
) pos (
1577 "Destructors are not supported in Hack; use other patterns like " ^
1578 "IDisposable/using or try/catch instead."
1581 let multiple_conditionally_reactive_annotations pos name =
1582 add
(NastCheck.err_code
NastCheck.MultipleConditionallyReactiveAnnotations
) pos (
1583 "Method '" ^
name ^
"' has multiple <<__OnlyRxIfImpl>> annotations."
1586 let rx_is_enabled_invalid_location pos =
1587 add
(NastCheck.err_code
NastCheck.RxIsEnabledInvalidLocation
) pos (
1588 "HH\\Rx\\IS_ENABLED must be the only condition in an if-statement, " ^
1589 "and that if-statement must be the only statement in the function body."
1592 let atmost_rx_as_rxfunc_invalid_location pos =
1593 add
(NastCheck.err_code
NastCheck.MaybeRxInvalidLocation
) pos (
1594 "<<__AtMostRxAsFunc>> attribute can only be put on parameters of \
1595 conditionally reactive function or method annotated with \
1596 <<__AtMostRxAsArgs>> attribute."
1599 let no_atmost_rx_as_rxfunc_for_rx_if_args pos =
1600 add
(NastCheck.err_code
NastCheck.NoOnlyrxIfRxfuncForRxIfArgs
) pos (
1601 "Function or method annotated with <<__AtMostRxAsArgs>> attribute \
1602 should have at least one parameter with <<__AtMostRxAsFunc>> or \
1603 <<__OnlyRxIfImpl>> annotations."
1606 let conditionally_reactive_annotation_invalid_arguments ~is_method
pos =
1607 let loc = if is_method
then "Method" else "Parameter" in
1608 add
(NastCheck.err_code
NastCheck.ConditionallyReactiveAnnotationInvalidArguments
) pos (
1609 loc ^
" is marked with <<__OnlyRxIfImpl>> attribute that have " ^
1610 "invalid arguments. This attribute must have one argument and it should be " ^
1611 "'::class' class constant."
1614 let coroutine_in_constructor pos =
1615 add
(NastCheck.err_code
NastCheck.CoroutineInConstructor
) pos
1616 "A class constructor may not be a coroutine"
1618 let illegal_by_ref_expr pos str verb
=
1619 add
(NastCheck.err_code
NastCheck.IllegalByRefExpr
) pos
1620 (str ^
" cannot be " ^ verb ^
" by reference")
1622 let variadic_byref_param pos =
1623 add
(NastCheck.err_code
NastCheck.VariadicByRefParam
) pos
1624 "Variadic parameters should not be taken by reference"
1626 let byref_on_construct pos =
1627 add
(NastCheck.err_code
NastCheck.ByRefParamOnConstruct
) pos
1628 "Constructors cannot take parameters by reference"
1630 let byref_dynamic_call pos =
1631 add
(NastCheck.err_code
NastCheck.ByRefDynamicCall
) pos
1632 "Arguments can not be passed by reference to dynamic function calls"
1634 let classname_const_instanceof class_name
pos =
1635 add
(NastCheck.err_code
NastCheck.ClassnameConstInstanceOf
) pos
1636 (class_name^
"::class is redundant in an instanceof, just write '"^class_name^
"'.")
1638 let byref_on_property pos =
1639 add
(NastCheck.err_code
NastCheck.ByRefProperty
) pos
1640 "Properties cannot be passed by reference"
1642 (*****************************************************************************)
1643 (* Nast terminality *)
1644 (*****************************************************************************)
1646 let case_fallthrough pos1 pos2
=
1647 add_list
(NastCheck.err_code
NastCheck.CaseFallthrough
) [
1648 pos1
, ("This switch has a case that implicitly falls through and is "^
1649 "not annotated with // FALLTHROUGH");
1650 pos2
, "This case implicitly falls through"
1653 let default_fallthrough pos =
1654 add
(NastCheck.err_code
NastCheck.DefaultFallthrough
) pos
1655 ("This switch has a default case that implicitly falls "^
1656 "through and is not annotated with // FALLTHROUGH")
1658 (*****************************************************************************)
1660 (*****************************************************************************)
1662 let visibility_extends vis
pos parent_pos parent_vis
=
1663 let msg1 = pos, "This member visibility is: " ^ vis
in
1664 let msg2 = parent_pos
, parent_vis ^
" was expected" in
1665 add_list
(Typing.err_code
Typing.VisibilityExtends
) [msg1; msg2]
1667 let member_not_implemented member_name parent_pos
pos defn_pos
=
1668 let msg1 = pos, "This type doesn't implement the method "^member_name
in
1669 let msg2 = parent_pos
, "Which is required by this interface" in
1670 let msg3 = defn_pos
, "As defined here" in
1671 add_list
(Typing.err_code
Typing.MemberNotImplemented
) [msg1; msg2; msg3]
1673 let bad_decl_override parent_pos parent_name
pos name (error
: error
) =
1674 let msg1 = pos, ("Class " ^
(strip_ns
name)
1675 ^
" does not correctly implement all required members ") in
1676 let msg2 = parent_pos
,
1677 ("Some members are incompatible with those declared in type "
1678 ^
(strip_ns parent_name
) ^
1679 "\nRead the following to see why:"
1681 (* This is a cascading error message *)
1682 let code, msgl = (get_code error
), (to_list error
) in
1683 add_list
code (msg1 :: msg2 :: msgl)
1685 let bad_method_override pos member_name
(error
: error
) =
1686 let msg = pos, ("Member " ^
(strip_ns member_name
)
1687 ^
" has the wrong type") in
1688 (* This is a cascading error message *)
1689 let code, msgl = (get_code error
), (to_list error
) in
1690 add_list
code (msg :: msgl)
1692 let bad_enum_decl pos (error
: error
) =
1694 "This enum declaration is invalid.\n\
1695 Read the following to see why:"
1697 (* This is a cascading error message *)
1698 let code, msgl = (get_code error
), (to_list error
) in
1699 add_list
code (msg :: msgl)
1701 let missing_constructor pos =
1702 add
(Typing.err_code
Typing.MissingConstructor
) pos
1703 "The constructor is not implemented"
1705 let typedef_trail_entry pos =
1706 pos, "Typedef definition comes from here"
1708 let add_with_trail code errs trail
=
1709 add_list
code (errs @ List.map trail
typedef_trail_entry)
1711 let enum_constant_type_bad pos ty_pos ty trail
=
1712 add_with_trail (Typing.err_code
Typing.EnumConstantTypeBad
)
1713 [pos, "Enum constants must be an int or string";
1714 ty_pos
, "Not " ^ ty
]
1717 let enum_type_bad pos ty trail
=
1718 add_with_trail (Typing.err_code
Typing.EnumTypeBad
)
1719 [pos, "Enums must be int or string, not " ^ ty
]
1722 let enum_type_typedef_nonnull pos =
1723 add
(Typing.err_code
Typing.EnumTypeTypedefNonnull
) pos
1724 "Can't use typedef that resolves to nonnull in enum"
1726 let enum_switch_redundant const first_pos second_pos
=
1727 add_list
(Typing.err_code
Typing.EnumSwitchRedundant
) [
1728 second_pos
, "Redundant case statement";
1729 first_pos
, const ^
" already handled here"
1732 let enum_switch_nonexhaustive pos missing enum_pos
=
1733 add_list
(Typing.err_code
Typing.EnumSwitchNonexhaustive
) [
1734 pos, "Switch statement nonexhaustive; the following cases are missing: " ^
1735 String.concat ~sep
:", " missing
;
1736 enum_pos
, "Enum declared here"
1739 let enum_switch_redundant_default pos enum_pos
=
1740 add_list
(Typing.err_code
Typing.EnumSwitchRedundantDefault
) [
1741 pos, "All cases already covered; a redundant default case prevents "^
1742 "detecting future errors";
1743 enum_pos
, "Enum declared here"
1746 let enum_switch_not_const pos =
1747 add
(Typing.err_code
Typing.EnumSwitchNotConst
) pos
1748 "Case in switch on enum is not an enum constant"
1750 let enum_switch_wrong_class pos expected got
=
1751 add
(Typing.err_code
Typing.EnumSwitchWrongClass
) pos
1752 ("Switching on enum " ^ expected ^
" but using constant from " ^ got
)
1754 let invalid_shape_field_name p =
1755 add
(Typing.err_code
Typing.InvalidShapeFieldName
) p
1756 "Was expecting a constant string, class constant, or int (for shape access)"
1758 let invalid_shape_field_name_empty p =
1759 add
(Typing.err_code
Typing.InvalidShapeFieldNameEmpty
) p
1760 "A shape field name cannot be an empty string"
1762 let invalid_shape_field_type pos ty_pos ty trail
=
1763 add_with_trail (Typing.err_code
Typing.InvalidShapeFieldType
)
1764 [pos, "A shape field name must be an int or string";
1765 ty_pos
, "Not " ^ ty
]
1768 let invalid_shape_field_literal key_pos witness_pos
=
1769 add_list
(Typing.err_code
Typing.InvalidShapeFieldLiteral
)
1770 [key_pos
, "Shape uses literal string as field name";
1771 witness_pos
, "But expected a class constant"]
1773 let invalid_shape_field_const key_pos witness_pos
=
1774 add_list
(Typing.err_code
Typing.InvalidShapeFieldConst
)
1775 [key_pos
, "Shape uses class constant as field name";
1776 witness_pos
, "But expected a literal string"]
1778 let shape_field_class_mismatch key_pos witness_pos key_class witness_class
=
1779 add_list
(Typing.err_code
Typing.ShapeFieldClassMismatch
)
1780 [key_pos
, "Shape field name is class constant from " ^ key_class
;
1781 witness_pos
, "But expected constant from " ^ witness_class
]
1783 let shape_field_type_mismatch key_pos witness_pos key_ty witness_ty
=
1784 add_list
(Typing.err_code
Typing.ShapeFieldTypeMismatch
)
1785 [key_pos
, "Shape field name is " ^ key_ty ^
" class constant";
1786 witness_pos
, "But expected " ^ witness_ty
]
1788 let missing_field pos1 pos2
name =
1789 add_list
(Typing.err_code
Typing.MissingField
) (
1790 (pos1
, "The field '"^
name^
"' is missing")::
1791 [pos2
, "The field '"^
name^
"' is defined"])
1793 let unknown_field_disallowed_in_shape pos1 pos2
name =
1795 (Typing.err_code
Typing.UnknownFieldDisallowedInShape
)
1798 "The field '" ^
name ^
"' is not defined in this shape type, and \
1799 this shape type does not allow unknown fields.";
1801 "The field '" ^
name ^
"' is set in the shape.";
1804 let shape_fields_unknown pos1 pos2
=
1805 add_list
(Typing.err_code
Typing.ShapeFieldsUnknown
)
1808 "This shape type allows unknown fields, and so it may contain fields \
1809 other than those explicitly declared in its declaration.";
1811 "It is incompatible with a shape that does not allow unknown fields.";
1814 let shape_field_unset pos1 pos2
name =
1815 add_list
(Typing.err_code
Typing.ShapeFieldUnset
) (
1816 [(pos1
, "The field '"^
name^
"' was unset here");
1817 (pos2
, "The field '"^
name^
"' might be present in this shape because of " ^
1818 "structural subtyping")]
1821 let invalid_shape_remove_key p =
1822 add
(Typing.err_code
Typing.InvalidShapeRemoveKey
) p
1823 "You can only unset fields of local variables"
1825 let unification_cycle pos ty
=
1826 add_list
(Typing.err_code
Typing.UnificationCycle
)
1827 [pos, "Type circularity: in order to type-check this expression it " ^
1828 "is necessary for a type [rec] to be equal to type " ^ ty
]
1830 let violated_constraint p_cstr
(p_tparam
, tparam
) left right
=
1831 add_list
(Typing.err_code
Typing.UnifyError
)
1832 ([(p_cstr
, "Some type constraint(s) are violated here");
1833 (p_tparam
, Printf.sprintf
"%s is a constrained type parameter" tparam
)]
1837 let method_variance pos =
1838 add
(Typing.err_code
Typing.MethodVariance
) pos
1839 ("Covariance or contravariance is not allowed in type parameter of \
1840 method or function.")
1842 let explain_constraint ~use_pos ~definition_pos ~param_name
(error
: error
) =
1843 let inst_msg = "Some type constraint(s) here are violated" in
1844 let code, msgl = (get_code error
), (to_list error
) in
1845 (* There may be multiple constraints instantiated at one spot; avoid
1846 * duplicating the instantiation message *)
1847 let msgl = match msgl with
1848 | (p, x) :: rest
when x = inst_msg && p = use_pos
-> rest
1850 let name = Utils.strip_ns param_name
in
1853 definition_pos
, "'" ^
name ^
"' is a constrained type parameter"] @ msgl
1856 let explain_where_constraint ~use_pos ~definition_pos
(error
: error
) =
1857 let inst_msg = "A 'where' type constraint is violated here" in
1858 let code, msgl = (get_code error
), (to_list error
) in
1861 definition_pos
, "This is the method with 'where' type constraints"] @ msgl
1864 let explain_tconst_where_constraint ~use_pos ~definition_pos
(error
: error
) =
1865 let inst_msg = "A 'where' type constraint is violated here" in
1866 let code, msgl = (get_code error
), (to_list error
) in
1870 "This method's where constraints contain a generic type access"] @ msgl
1873 let explain_type_constant reason_msgl
(error
: error
) =
1874 let code, msgl = (get_code error
), (to_list error
) in
1875 add_list
code (msgl @ reason_msgl
)
1878 add
(Typing.err_code
Typing.Overflow
) p "Value is too large"
1880 let format_string pos snippet s class_pos fname class_suggest
=
1881 add_list
(Typing.err_code
Typing.FormatString
) [
1882 (pos, "I don't understand the format string " ^ snippet ^
" in " ^ s
);
1884 "You can add a new format specifier by adding "
1885 ^fname^
"() to "^class_suggest
)]
1887 let expected_literal_format_string pos =
1888 add
(Typing.err_code
Typing.ExpectedLiteralFormatString
) pos
1889 "This argument must be a literal format string"
1891 let re_prefixed_non_string pos non_strings
=
1892 add
(Typing.err_code
Typing.RePrefixedNonString
) pos
1893 (non_strings^
" are not allowed to be to be `re`-prefixed")
1895 let bad_regex_pattern pos s
=
1896 add
(Typing.err_code
Typing.BadRegexPattern
) pos
1897 ("Bad regex pattern; "^s^
".")
1899 let generic_array_strict p =
1900 add
(Typing.err_code
Typing.GenericArrayStrict
) p
1901 "You cannot have an array without generics in strict mode"
1903 let strict_members_not_known p name =
1904 let name = Utils.strip_ns
name in
1905 add
(Typing.err_code
Typing.StrictMembersNotKnown
) p
1906 (name^
" has a non-<?hh grandparent; this is not allowed in strict mode"
1907 ^
" because that parent may define methods of unknowable name and type")
1909 let option_return_only_typehint p kind
=
1910 let (typehint
, reason) = match kind
with
1911 | `void
-> ("?void", "only return implicitly")
1912 | `noreturn
-> ("?noreturn", "never return")
1914 add
(Typing.err_code
Typing.OptionReturnOnlyTypehint
) p
1915 (typehint^
" is a nonsensical typehint; a function cannot both "^
reason
1916 ^
" and return null.")
1918 let tuple_syntax p =
1919 add
(Typing.err_code
Typing.TupleSyntax
) p
1920 ("Did you want a tuple? Try (X,Y), not tuple<X,Y>")
1922 let class_arity usage_pos class_pos class_name arity
=
1923 add_list
(Typing.err_code
Typing.ClassArity
)
1924 [usage_pos
, ("The class "^
(Utils.strip_ns class_name
)^
" expects "^
1925 soi arity^
" arguments");
1926 class_pos
, "Definition is here"]
1928 let redeclaring_missing_method p trait_method
=
1929 add
(Typing.err_code
Typing.RedeclaringMissingMethod
) p
1930 ("Attempting to redeclare a trait method " ^ trait_method ^
" which was never inherited. " ^
1931 "You might be trying to redeclare a non-static method as static or vice-versa.")
1933 let expecting_type_hint p =
1934 add
(Typing.err_code
Typing.ExpectingTypeHint
) p "Was expecting a type hint"
1936 let expecting_type_hint_suggest p ty
=
1937 add
(Typing.err_code
Typing.ExpectingTypeHintSuggest
) p
1938 ("Was expecting a type hint (what about: "^ty^
")")
1940 let expecting_return_type_hint p =
1941 add
(Typing.err_code
Typing.ExpectingReturnTypeHint
) p
1942 "Was expecting a return type hint"
1944 let expecting_return_type_hint_suggest p ty
=
1945 add
(Typing.err_code
Typing.ExpectingReturnTypeHintSuggest
) p
1946 ("Was expecting a return type hint (what about: ': "^ty^
"')")
1948 let expecting_awaitable_return_type_hint p =
1949 add
(Typing.err_code
Typing.ExpectingAwaitableReturnTypeHint
) p
1950 "Was expecting an Awaitable return type hint"
1952 let duplicate_using_var pos =
1953 add
(Typing.err_code
Typing.DuplicateUsingVar
) pos
1954 "Local variable already used in 'using' statement"
1956 let illegal_disposable pos verb
=
1957 add
(Typing.err_code
Typing.IllegalDisposable
) pos
1958 ("Disposable objects must only be " ^ verb ^
" in a 'using' statement")
1960 let escaping_disposable pos =
1961 add
(Typing.err_code
Typing.EscapingDisposable
) pos
1962 "Variable from 'using' clause may only be used as receiver in method invocation or \
1963 passed to function with <<__AcceptDisposable>> parameter attribute"
1965 let escaping_disposable_parameter pos =
1966 add
(Typing.err_code
Typing.EscapingDisposableParameter
) pos
1967 "Parameter with <<__AcceptDisposable>> attribute may only be used as receiver in method \
1968 invocation or passed to another function with <<__AcceptDisposable>> parameter attribute"
1970 let escaping_this pos =
1971 add
(Typing.err_code
Typing.EscapingThis
) pos
1972 "$this implementing IDisposable or IAsyncDisposable may only be used as receiver in method \
1973 invocation or passed to another function with <<__AcceptDisposable>> parameter attribute"
1975 let escaping_mutable_object pos =
1976 add
(Typing.err_code
Typing.EscapingMutableObject
) pos
1977 "Neither a Mutable nor MaybeMutable object may be captured by an \
1978 anonymous function."
1980 let must_extend_disposable pos =
1981 add
(Typing.err_code
Typing.MustExtendDisposable
) pos
1982 "A disposable type may not extend a class or use a trait that is not disposable"
1984 let accept_disposable_invariant pos1 pos2
=
1985 let msg1 = pos1
, "This parameter is marked <<__AcceptDisposable>>" in
1986 let msg2 = pos2
, "This parameter is not marked <<__AcceptDisposable>>" in
1987 add_list
(Typing.err_code
Typing.AcceptDisposableInvariant
) [msg1; msg2]
1989 let field_kinds pos1 pos2
=
1990 add_list
(Typing.err_code
Typing.FieldKinds
)
1991 [pos1
, "You cannot use this kind of field (value)";
1992 pos2
, "Mixed with this kind of field (key => value)"]
1994 let unbound_name_typing pos name =
1995 add
(Typing.err_code
Typing.UnboundNameTyping
) pos
1996 ("Unbound name (typing): "^
(strip_ns
name))
1998 let previous_default p =
1999 add
(Typing.err_code
Typing.PreviousDefault
) p
2000 ("A previous parameter has a default value.\n"^
2001 "Remove all the default values for the preceding parameters,\n"^
2002 "or add a default value to this one.")
2004 let return_only_typehint p kind
=
2005 let msg = match kind
with
2007 | `noreturn
-> "noreturn" in
2008 add
(Naming.err_code
Naming.ReturnOnlyTypehint
) p
2009 ("The "^
msg^
" typehint can only be used to describe a function return type")
2011 let unexpected_type_arguments p =
2012 add
(Naming.err_code
Naming.UnexpectedTypeArguments
) p
2013 ("Type arguments are not expected for this type")
2015 let too_many_type_arguments p =
2016 add
(Naming.err_code
Naming.TooManyTypeArguments
) p
2017 ("Too many type arguments for this type")
2019 let return_in_void pos1 pos2
=
2020 add_list
(Typing.err_code
Typing.ReturnInVoid
) [
2022 "You cannot return a value";
2024 "This is a void function"
2027 let this_var_outside_class p =
2028 add
(Typing.err_code
Typing.ThisVarOutsideClass
) p "Can't use $this outside of a class"
2030 let unbound_global cst_pos
=
2031 add
(Typing.err_code
Typing.UnboundGlobal
) cst_pos
"Unbound global constant (Typing)"
2033 let private_inst_meth ~def_pos ~use_pos
=
2034 add_list
(Typing.err_code
Typing.PrivateInstMeth
) [
2035 use_pos
, "You cannot use this method with inst_meth \
2036 (whether you are in the same class or not).";
2037 def_pos
, "It is declared as private here";
2040 let protected_inst_meth ~def_pos ~use_pos
=
2041 add_list
(Typing.err_code
Typing.ProtectedInstMeth
) [
2042 use_pos
, "You cannot use this method with inst_meth \
2043 (whether you are in the same class hierarchy or not).";
2044 def_pos
, "It is declared as protected here";
2047 let private_class_meth ~def_pos ~use_pos
=
2048 add_list
(Typing.err_code
Typing.PrivateClassMeth
) [
2049 use_pos
, "You cannot use this method with class_meth \
2050 (whether you are in the same class or not).";
2051 def_pos
, "It is declared as private here";
2054 let protected_class_meth ~def_pos ~use_pos
=
2055 add_list
(Typing.err_code
Typing.ProtectedClassMeth
) [
2056 use_pos
, "You cannot use this method with class_meth \
2057 (whether you are in the same class hierarchy or not).";
2058 def_pos
, "It is declared as protected here";
2061 let array_cast pos =
2062 add
(Typing.err_code
Typing.ArrayCast
) pos
2063 "(array) cast forbidden; arrays with unspecified \
2064 key and value types are not allowed"
2066 let string_cast pos ty
=
2067 add
(Typing.err_code
Typing.StringCast
) pos @@
2069 "Cannot cast a value of type %s to string.\n\
2070 Only primitives may be used in a (string) cast.\n\
2071 If you are trying to cast a Stringish type, please use `stringish_cast`.\n\
2072 This functionality is being removed from HHVM."
2075 let nullable_cast pos ty ty_pos
=
2076 add_list
(Typing.err_code
Typing.NullableCast
) [
2077 pos, "Casting from a nullable type is forbidden";
2078 ty_pos
, "This is "^ty
;
2081 let anonymous_recursive pos =
2082 add
(Typing.err_code
Typing.AnonymousRecursive
) pos
2083 "Anonymous functions cannot be recursive"
2085 let static_outside_class pos =
2086 add
(Typing.err_code
Typing.StaticOutsideClass
) pos
2087 "'static' is undefined outside of a class"
2089 let self_outside_class pos =
2090 add
(Typing.err_code
Typing.SelfOutsideClass
) pos
2091 "'self' is undefined outside of a class"
2093 let new_inconsistent_construct new_pos
(cpos
, cname) kind
=
2094 let name = Utils.strip_ns
cname in
2095 let preamble = match kind
with
2096 | `static
-> "Can't use new static() for "^
name
2097 | `classname
-> "Can't use new on classname<"^
name^
">"
2099 add_list
(Typing.err_code
Typing.NewStaticInconsistent
) [
2100 new_pos
, preamble^
"; __construct arguments are not \
2101 guaranteed to be consistent in child classes";
2102 cpos
, ("This declaration is neither final nor uses \
2103 the <<__ConsistentConstruct>> attribute")]
2105 let pair_arity pos =
2106 add
(Typing.err_code
Typing.PairArity
) pos "A pair has exactly 2 elements"
2108 let tuple_arity pos2 size2 pos1 size1
=
2109 add_list
(Typing.err_code
Typing.TupleArity
) [
2110 pos2
, "This tuple has "^ string_of_int size2^
" elements";
2111 pos1
, string_of_int size1 ^
" were expected"]
2113 let undefined_parent pos =
2114 add
(Typing.err_code
Typing.UndefinedParent
) pos
2115 "The parent class is undefined"
2117 let parent_outside_class pos =
2118 add
(Typing.err_code
Typing.ParentOutsideClass
) pos
2119 "'parent' is undefined outside of a class"
2121 let parent_abstract_call meth_name call_pos decl_pos
=
2122 add_list
(Typing.err_code
Typing.AbstractCall
) [
2123 call_pos
, ("Cannot call parent::"^meth_name^
"(); it is abstract");
2124 decl_pos
, "Declaration is here"
2127 let self_abstract_call meth_name call_pos decl_pos
=
2128 add_list
(Typing.err_code
Typing.AbstractCall
) [
2129 call_pos
, ("Cannot call self::"^meth_name^
"(); it is abstract. Did you mean static::"^meth_name^
"()?");
2130 decl_pos
, "Declaration is here"
2133 let classname_abstract_call cname meth_name call_pos decl_pos
=
2134 let cname = Utils.strip_ns
cname in
2135 add_list
(Typing.err_code
Typing.AbstractCall
) [
2136 call_pos
, ("Cannot call "^
cname^
"::"^meth_name^
"(); it is abstract");
2137 decl_pos
, "Declaration is here"
2140 let static_synthetic_method cname meth_name call_pos decl_pos
=
2141 let cname = Utils.strip_ns
cname in
2142 add_list
(Typing.err_code
Typing.StaticSyntheticMethod
) [
2143 call_pos
, ("Cannot call "^
cname^
"::"^meth_name^
"(); "^meth_name^
" is not defined in "^
cname);
2144 decl_pos
, "Declaration is here"
2147 let isset_in_strict pos =
2148 add
(Typing.err_code
Typing.IssetEmptyInStrict
) pos
2149 ("isset tends to hide errors due to variable typos and so is limited to dynamic checks in "
2152 let unset_nonidx_in_strict pos msgs =
2153 add_list
(Typing.err_code
Typing.UnsetNonidxInStrict
)
2154 ([pos, "In strict mode, unset is banned except on array, keyset, "^
2155 "or dict indexing"] @
2158 let unset_nonidx_in_strict_no_varray pos msgs =
2159 add_list
(Typing.err_code
Typing.UnsetNonidxInStrict
)
2160 ([pos, "In strict mode, unset is banned except on dict-like array, "^
2161 "darray, keyset, or dict indexing"] @
2164 let unpacking_disallowed_builtin_function pos name =
2165 let name = Utils.strip_ns
name in
2166 add
(Typing.err_code
Typing.UnpackingDisallowed
) pos
2167 ("Arg unpacking is disallowed for "^
name)
2169 let array_get_arity pos1
name pos2
=
2170 add_list
(Typing.err_code
Typing.ArrayGetArity
) [
2171 pos1
, "You cannot use this "^
(Utils.strip_ns
name);
2172 pos2
, "It is missing its type parameters"
2175 let typing_error pos msg =
2176 add
(Typing.err_code
Typing.GenericUnify
) pos msg
2178 let undefined_field ~use_pos ~
name ~shape_type_pos
=
2179 add_list
(Typing.err_code
Typing.UndefinedField
) [
2180 use_pos
, "The field "^
name^
" is undefined";
2181 shape_type_pos
, "Definition is here"
2184 let array_access pos1 pos2 ty
=
2185 add_list
(Typing.err_code
Typing.ArrayAccess
)
2186 ((pos1
, "This is not an object of type KeyedContainer, this is "^ty
) ::
2187 if not
(phys_equal pos2
Pos.none
)
2188 then [pos2
, "Definition is here"]
2191 let keyset_set pos1 pos2
=
2192 add_list
(Typing.err_code
Typing.KeysetSet
)
2193 ((pos1
, "Elements in a keyset cannot be assigned, use append instead.") ::
2194 if not
(phys_equal pos2
Pos.none
)
2195 then [pos2
, "Definition is here"]
2198 let array_append pos1 pos2 ty
=
2199 add_list
(Typing.err_code
Typing.ArrayAppend
)
2200 ((pos1
, ty^
" does not allow array append") ::
2201 if not
(phys_equal pos2
Pos.none
)
2202 then [pos2
, "Definition is here"]
2205 let const_mutation pos1 pos2 ty
=
2206 add_list
(Typing.err_code
Typing.ConstMutation
)
2207 ((pos1
, "You cannot mutate this") ::
2208 if not
(phys_equal pos2
Pos.none
)
2209 then [(pos2
, "This is " ^ ty
)]
2212 let expected_class ?
(suffix
="") pos =
2213 add
(Typing.err_code
Typing.ExpectedClass
) pos ("Was expecting a class"^suffix
)
2215 let unknown_type description
pos r
=
2216 let msg = ("Was expecting " ^ description ^
" but type is unknown") in
2217 add_list
(Typing.err_code
Typing.UnknownType
)
2220 let snot_found_hint = function
2223 | `closest
(pos, v
) ->
2224 [pos, "The closest thing is "^v^
" but it's not a static method"]
2225 | `did_you_mean
(pos, v
) ->
2226 [pos, "Did you mean: "^v
]
2228 let string_of_class_member_kind = function
2229 | `class_constant
-> "class constant"
2230 | `static_method
-> "static method"
2231 | `class_variable
-> "class variable"
2232 | `class_typeconst
-> "type constant"
2234 let smember_not_found kind
pos (cpos
, class_name
) member_name hint
=
2235 let kind = string_of_class_member_kind kind in
2236 let class_name = strip_ns
class_name in
2237 let msg = "Could not find "^
kind^
" "^member_name^
" in type "^
class_name in
2238 add_list
(Typing.err_code
Typing.SmemberNotFound
)
2239 ((pos, msg) :: (snot_found_hint hint
2240 @ [(cpos
, "Declaration of "^
class_name^
" is here")]))
2242 let not_found_hint = function
2245 | `closest
(pos, v
) ->
2246 [pos, "The closest thing is "^v^
" but it's a static method"]
2247 | `did_you_mean
(pos, v
) ->
2248 [pos, "Did you mean: "^v
]
2250 let member_not_found kind pos (cpos
, type_name
) member_name hint
reason =
2251 let type_name = strip_ns
type_name in
2254 | `method_
-> "method"
2255 | `member
-> "member"
2257 let msg = "Could not find "^
kind^
" "^member_name^
" in an object of type "^
2259 add_list
(Typing.err_code
Typing.MemberNotFound
)
2260 ((pos, msg) :: (not_found_hint hint
@ reason
2261 @ [(cpos
, "Declaration of "^
type_name^
" is here")]))
2263 let parent_in_trait pos =
2264 add
(Typing.err_code
Typing.ParentInTrait
) pos
2265 ("parent:: inside a trait is undefined"
2266 ^
" without 'require extends' of a class defined in <?hh")
2268 let parent_undefined pos =
2269 add
(Typing.err_code
Typing.ParentUndefined
) pos
2270 "parent is undefined"
2272 let constructor_no_args pos =
2273 add
(Typing.err_code
Typing.ConstructorNoArgs
) pos
2274 "This constructor expects no argument"
2276 let visibility p msg1 p_vis
msg2 =
2277 add_list
(Typing.err_code
Typing.Visibility
) [p, msg1; p_vis
, msg2]
2279 let typing_too_many_args expected actual
pos pos_def
=
2280 add_list
(Typing.err_code
Typing.TypingTooManyArgs
)
2282 Printf.sprintf
"Too many arguments (expected %d but got %d)" expected actual
);
2283 (pos_def
, "Definition is here")]
2285 let typing_too_few_args required actual
pos pos_def
=
2286 add_list
(Typing.err_code
Typing.TypingTooFewArgs
)
2288 Printf.sprintf
"Too few arguments (required %d but got %d)" required actual
);
2289 (pos_def
, "Definition is here")]
2291 let anonymous_recursive_call pos =
2292 add
(Typing.err_code
Typing.AnonymousRecursiveCall
) pos
2293 "recursive call to anonymous function"
2295 let bad_call pos ty
=
2296 add
(Typing.err_code
Typing.BadCall
) pos
2297 ("This call is invalid, this is not a function, it is "^ty
)
2299 let extend_final extend_pos decl_pos
name =
2300 let name = (strip_ns
name) in
2301 add_list
(Typing.err_code
Typing.ExtendFinal
) [
2302 extend_pos
, ("You cannot extend final class "^
name);
2303 decl_pos
, "Declaration is here"
2306 let extend_sealed child_pos parent_pos parent_name parent_kind verb
=
2307 let name = (strip_ns parent_name
) in
2308 add_list
(Typing.err_code
Typing.ExtendSealed
) [
2309 child_pos
, ("You cannot "^verb^
" sealed "^parent_kind^
" "^
name);
2310 parent_pos
, "Declaration is here"
2314 child_pos child_class_type child_is_ppl parent_pos parent_class_type parent_name verb
=
2315 let name = (strip_ns parent_name
) in
2318 then child_class_type^
" annotated with <<__PPL>> cannot "^verb^
2319 " non <<__PPL>> "^parent_class_type^
": "^
name
2320 else child_class_type^
" must be annotated with <<__PPL>> to "^verb^
2321 " <<__PPL>> "^parent_class_type^
": "^
name in
2322 add_list
(Typing.err_code
Typing.ExtendPPL
) [
2324 parent_pos
, "Declaration is here";
2327 let read_before_write (pos, v
) =
2328 add
(Typing.err_code
Typing.ReadBeforeWrite
) pos (
2330 "Read access to $this->"; v
; " before initialization"
2333 let interface_final pos =
2334 add
(Typing.err_code
Typing.InterfaceFinal
) pos
2335 "Interfaces cannot be final"
2337 let trait_final pos =
2338 add
(Typing.err_code
Typing.TraitFinal
) pos
2339 "Traits cannot be final"
2341 let final_property pos =
2342 add
(Typing.err_code
Typing.FinalProperty
) pos "Properties cannot be declared final"
2344 let implement_abstract ~is_final pos1 pos2
kind x =
2345 let name = "abstract "^
kind^
" '"^
x^
"'" in
2348 "This class was declared as final. It must provide an implementation \
2351 "This class must be declared abstract, or provide an implementation \
2353 add_list
(Typing.err_code
Typing.ImplementAbstract
) [
2355 pos2
, "Declaration is here";
2358 let generic_static pos x =
2359 add
(Typing.err_code
Typing.GenericStatic
) pos (
2360 "This static variable cannot use the type parameter "^
x^
"."
2363 let fun_too_many_args pos1 pos2
=
2364 add_list
(Typing.err_code
Typing.FunTooManyArgs
) [
2365 pos1
, "Too many mandatory arguments";
2366 pos2
, "Because of this definition";
2369 let fun_too_few_args pos1 pos2
=
2370 add_list
(Typing.err_code
Typing.FunTooFewArgs
) [
2371 pos1
, "Too few arguments";
2372 pos2
, "Because of this definition";
2375 let fun_unexpected_nonvariadic pos1 pos2
=
2376 add_list
(Typing.err_code
Typing.FunUnexpectedNonvariadic
) [
2377 pos1
, "Should have a variadic argument";
2378 pos2
, "Because of this definition";
2381 let fun_variadicity_hh_vs_php56 pos1 pos2
=
2382 add_list
(Typing.err_code
Typing.FunVariadicityHhVsPhp56
) [
2383 pos1
, "Variadic arguments: ...-style is not a subtype of ...$args";
2384 pos2
, "Because of this definition";
2387 let ellipsis_strict_mode ~require
pos =
2388 let msg = match require
with
2389 | `Type
-> "Cannot use ... without a type hint in strict mode. Please add a type hint."
2391 "Cannot use ... without a parameter name in strict mode. Please add a parameter name."
2392 | `Type_and_param_name
->
2393 "Cannot use ... without a type hint and parameter name in strict mode. \
2394 Please add a type hint and parameter name."
2396 add
(Typing.err_code
Typing.EllipsisStrictMode
) pos msg
2398 let untyped_lambda_strict_mode pos =
2400 "Cannot determine types of lambda parameters in strict mode. \
2401 Please add type hints on parameters."
2403 add
(Typing.err_code
Typing.UntypedLambdaStrictMode
) pos msg
2405 let echo_in_reactive_context pos =
2406 add
(Typing.err_code
Typing.EchoInReactiveContext
) pos (
2407 "'echo' or 'print' are not allowed in reactive functions."
2410 let expected_tparam ~use_pos ~definition_pos n
=
2411 add_list
(Typing.err_code
Typing.ExpectedTparam
)
2413 use_pos
, "Expected " ^
2415 | 0 -> "no type parameter"
2416 | 1 -> "a type parameter"
2417 | n
-> string_of_int n ^
" type parameters"
2419 definition_pos
, "Definition is here"
2422 let object_string pos1 pos2
=
2423 add_list
(Typing.err_code
Typing.ObjectString
) [
2424 pos1
, "You cannot use this object as a string";
2425 pos2
, "This object doesn't implement __toString";
2428 let object_string_deprecated pos =
2429 add
(Typing.err_code
Typing.ObjectString
) pos
2430 "You cannot use this object as a string\n\
2431 Implicit conversions of Stringish objects to string are deprecated."
2433 let type_param_arity pos x n
=
2434 add
(Typing.err_code
Typing.TypeParamArity
) pos (
2435 "The type "^
x^
" expects "^n^
" parameters"
2438 let cyclic_typedef p =
2439 add
(Typing.err_code
Typing.CyclicTypedef
) p
2442 let type_arity_mismatch pos1 n1 pos2 n2
=
2443 add_list
(Typing.err_code
Typing.TypeArityMismatch
) [
2444 pos1
, "This type has "^n1^
" arguments";
2445 pos2
, "This one has "^n2
;
2448 let this_final id pos2
(error
: error
) =
2449 let n = Utils.strip_ns
(snd id
) in
2450 let message1 = "Since "^
n^
" is not final" in
2451 let message2 = "this might not be a "^
n in
2452 let code, msgl = (get_code error
), (to_list error
) in
2453 add_list
code (msgl @ [(fst id
, message1); (pos2
, message2)])
2455 let exact_class_final id pos2
(error
: error
) =
2456 let n = Utils.strip_ns
(snd id
) in
2457 let message1 = "This requires the late-bound type to be exactly "^
n in
2459 "Since " ^
n^
" is not final this might be an instance of a child class" in
2460 let code, msgl = (get_code error
), (to_list error
) in
2461 add_list
code (msgl @ [(fst id
, message1); (pos2
, message2)])
2463 let tuple_arity_mismatch pos1 n1 pos2 n2
=
2464 add_list
(Typing.err_code
Typing.TupleArityMismatch
) [
2465 pos1
, "This tuple has "^n1^
" elements";
2466 pos2
, "This one has "^n2^
" elements"
2469 let fun_arity_mismatch pos1 pos2
=
2470 add_list
(Typing.err_code
Typing.FunArityMismatch
) [
2471 pos1
, "Number of arguments doesn't match";
2472 pos2
, "Because of this definition";
2475 let fun_reactivity_mismatch pos1 kind1 pos2 kind2
=
2476 let f k
= "This function is " ^ k ^
"." in
2478 (Typing.err_code
Typing.FunReactivityMismatch
)
2484 let inconsistent_unset pos1
=
2485 add
(Typing.err_code
Typing.InconsistentUnset
) pos1
2486 ("This variable is unset (via Rx\\freeze or Rx\\move) in one scope but not the other")
2488 let inconsistent_mutability pos1 mut1 p2_opt
=
2490 | Some
(pos2
, mut2
) ->
2491 add_list
(Typing.err_code
Typing.InconsistentMutability
) [
2492 pos1
, "Inconsistent mutability of local variable, here local is " ^ mut1
;
2493 pos2
, "But here it is " ^ mut2
;
2496 add
(Typing.err_code
Typing.InconsistentMutability
) pos1
2497 ("Local is " ^ mut1 ^
" in one scope and immutable in another.")
2499 let inconsistent_mutability_for_conditional p_mut p_other
=
2500 add_list
(Typing.err_code
Typing.InconsistentMutability
) [
2501 p_mut
, "Inconsistent mutability of conditional expression, this branch returns owned \
2503 p_other
, "But this one does not.";
2506 let invalid_mutability_flavor pos mut1 mut2
=
2507 add
(Typing.err_code
Typing.InvalidMutabilityFlavorInAssignment
) pos
2508 ("Cannot assign " ^ mut2 ^
" value to " ^ mut1 ^
" local variable. \
2509 Mutability flavor of local variable cannot be altered.")
2511 let reassign_mutable_var ~in_collection pos1
=
2514 then "This variable is mutable. You cannot create a new reference to it \
2515 by putting it into the collection."
2516 else "This variable is mutable. You cannot create a new reference to it." in
2517 add
(Typing.err_code
Typing.ReassignMutableVar
) pos1
msg
2519 let reassign_mutable_this ~in_collection ~is_maybe_mutable pos1
=
2522 then "maybe mutable"
2526 then "$this here is " ^
kind ^
". You cannot create a new reference to it \
2527 by putting it into the collection."
2528 else "$this here is " ^
kind ^
". You cannot create a new reference to it." in
2529 add
(Typing.err_code
Typing.ReassignMutableThis
) pos1
msg
2531 let mutable_expression_as_multiple_mutable_arguments pos param_kind prev_pos prev_param_kind
=
2532 add_list
(Typing.err_code
Typing.MutableExpressionAsMultipleMutableArguments
) [
2533 pos, "A mutable expression may not be passed as multiple arguments where \
2534 at least one matching parameter is mutable. Matching parameter here is " ^ param_kind
;
2535 prev_pos
, "This is where it was used before, being passed as " ^ prev_param_kind
2538 let reassign_maybe_mutable_var ~in_collection pos1
=
2541 then "This variable is maybe mutable. You cannot create a new reference to it \
2542 by putting it into the collection."
2543 else "This variable is maybe mutable. You cannot create a new reference to it." in
2544 add
(Typing.err_code
Typing.ReassignMaybeMutableVar
) pos1
msg
2546 let mutable_call_on_immutable fpos pos1 rx_mutable_hint_pos
=
2548 match rx_mutable_hint_pos
with
2550 [p, "Consider wrapping this expression with Rx\\mutable to forward mutability."]
2554 (pos1
, "Cannot call mutable function on immutable expression") ::
2555 (fpos
, "This function is marked <<__Mutable>>, so it has a mutable $this.") ::
2558 add_list
(Typing.err_code
Typing.MutableCallOnImmutable
) l
2560 let immutable_call_on_mutable fpos pos1
=
2561 add_list
(Typing.err_code
Typing.ImmutableCallOnMutable
)
2563 pos1
, "Cannot call non-mutable function on mutable expression";
2564 fpos
, "This function is not marked as <<__Mutable>>.";
2567 let mutability_mismatch ~is_receiver pos1 mut1 pos2 mut2
=
2569 let msg = if is_receiver
then "Receiver of this function" else "This parameter" in
2570 msg ^
" is " ^ mut
in
2571 add_list
(Typing.err_code
Typing.MutabilityMismatch
)
2573 pos1
, "Incompatible mutabilities:";
2578 let invalid_call_on_maybe_mutable ~fun_is_mutable
pos fpos
=
2580 "Cannot call " ^
(if fun_is_mutable
then "mutable" else "non-mutable") ^
" \
2581 function on maybe mutable value." in
2582 add_list
(Typing.err_code
Typing.InvalidCallMaybeMutable
)
2585 fpos
, "This function is not marked as <<__MaybeMutable>>."
2588 let mutable_argument_mismatch param_pos arg_pos
=
2589 add_list
(Typing.err_code
Typing.MutableArgumentMismatch
)
2591 arg_pos
, "Invalid argument";
2592 param_pos
, "This parameter is marked mutable";
2593 arg_pos
, "But this expression is not";
2596 let immutable_argument_mismatch param_pos arg_pos
=
2597 add_list
(Typing.err_code
Typing.ImmutableArgumentMismatch
)
2599 arg_pos
, "Invalid argument";
2600 param_pos
, "This parameter is not marked as mutable";
2601 arg_pos
, "But this expression is mutable";
2604 let mutably_owned_argument_mismatch ~arg_is_owned_local param_pos arg_pos
=
2606 if arg_is_owned_local
2607 then "Owned mutable locals used as argument should be passed via \
2609 else "But this expression is not owned mutable" in
2610 add_list
(Typing.err_code
Typing.ImmutableArgumentMismatch
)
2612 arg_pos
, "Invalid argument";
2613 param_pos
, "This parameter is marked with <<__OwnedMutable>>";
2617 let maybe_mutable_argument_mismatch param_pos arg_pos
=
2618 add_list
(Typing.err_code
Typing.MaybeMutableArgumentMismatch
)
2620 arg_pos
, "Invalid argument";
2621 param_pos
, "This parameter is not marked <<__MaybeMutable>>";
2622 arg_pos
, "But this expression is maybe mutable"
2625 let invalid_mutable_return_result error_pos function_pos value_kind
=
2626 add_list
(Typing.err_code
Typing.InvalidMutableReturnResult
)
2628 error_pos
, "Functions marked <<__MutableReturn>> must return mutably owned values: \
2629 mutably owned local variables and results of calling Rx\\mutable.";
2630 function_pos
, "This function is marked <<__MutableReturn>>";
2631 error_pos
, "This expression is " ^ value_kind
2634 let freeze_in_nonreactive_context pos1
=
2635 add
(Typing.err_code
Typing.FreezeInNonreactiveContext
) pos1
2636 ("\\HH\\Rx\\freeze can only be used in reactive functions")
2638 let mutable_in_nonreactive_context pos =
2639 add
(Typing.err_code
Typing.MutableInNonreactiveContext
) pos
2640 ("\\HH\\Rx\\mutable can only be used in reactive functions")
2642 let move_in_nonreactive_context pos =
2643 add
(Typing.err_code
Typing.MoveInNonreactiveContext
) pos
2644 ("\\HH\\Rx\\move can only be used in reactive functions")
2647 let invalid_argument_type_for_condition_in_rx
2648 ~is_receiver f_pos def_pos arg_pos expected_type actual_type
=
2650 if is_receiver
then "Receiver type" else "Argument type" in
2652 arg_msg ^
" must be a subtype of " ^ expected_type ^
2653 ", now " ^ actual_type ^
"." in
2654 add_list
(Typing.err_code
Typing.InvalidConditionallyReactiveCall
) [
2655 f_pos
, "Cannot invoke conditionally reactive function in reactive context, \
2656 because at least one reactivity condition is not met.";
2658 def_pos
, "This is the function declaration";
2661 let callsite_reactivity_mismatch f_pos def_pos callee_reactivity cause_pos_opt caller_reactivity
=
2662 add_list
(Typing.err_code
Typing.CallSiteReactivityMismatch
) ([
2663 f_pos
, "Reactivity mismatch: " ^ caller_reactivity ^
" function cannot call " ^
2664 callee_reactivity ^
" function.";
2665 def_pos
, "This is declaration of the function being called."
2666 ] @ Option.value_map cause_pos_opt ~default
:[] ~
f:(fun cause_pos
->
2667 [cause_pos
, "Reactivity of this argument was used as reactivity of the callee."]
2669 let invalid_function_type_for_condition_in_rx
2670 f_pos def_pos arg_pos actual_reactivity expected_reactivity
=
2672 "Argument type is must be " ^ expected_reactivity ^
" function, " ^
2673 actual_reactivity ^
" given." in
2674 add_list
(Typing.err_code
Typing.InvalidConditionallyReactiveCall
) [
2675 f_pos
, "Cannot invoke conditionally reactive function in reactive context, \
2676 because at least one reactivity condition is not met.";
2678 def_pos
, "This is the function declaration";
2682 let invalid_argument_of_rx_mutable_function pos =
2683 add
(Typing.err_code
Typing.InvalidArgumentOfRxMutableFunction
) pos (
2684 "Single argument to \\HH\\Rx\\mutable should be an expression that yields new \
2685 mutably-owned value, like 'new A()', Hack collection literal or 'f()' where f is function \
2686 annotated with <<__MutableReturn>> attribute."
2689 let invalid_freeze_use pos1
=
2690 add
(Typing.err_code
Typing.InvalidFreezeUse
) pos1
2691 ("freeze takes a single mutably-owned local variable as an argument")
2693 let invalid_move_use pos1
=
2694 add
(Typing.err_code
Typing.InvalidMoveUse
) pos1
2695 ("move takes a single mutably-owned local variable as an argument")
2697 let require_args_reify def_pos arg_pos
=
2698 add_list
(Typing.err_code
Typing.RequireArgsReify
) [
2699 arg_pos
, "All type arguments must be specified because a type parameter is reified";
2700 def_pos
, "Definition is here"
2703 let invalid_reified_argument (def_pos
, def_name
) arg_pos arg_kind
=
2704 add_list
(Typing.err_code
Typing.InvalidReifiedArgument
) [
2705 arg_pos
, "This is " ^ arg_kind ^
", it cannot be used as a reified type argument";
2706 def_pos
, def_name ^
" is reified"
2709 let new_static_class_reified pos =
2710 add
(Typing.err_code
Typing.NewStaticClassReified
) pos
2711 "Cannot call new static because the current class has reified generics"
2713 let consistent_construct_reified pos =
2714 add
(Typing.err_code
Typing.ConsistentConstructReified
) pos
2715 "This class or one of its ancestors is annotated with <<__ConsistentConstruct>>. \
2716 It cannot have reified generics."
2718 let new_without_newable pos name =
2719 add
(Typing.err_code
Typing.NewWithoutNewable
) pos
2720 (name ^
" cannot be used with `new` because it does not have the <<__Newable>> attribute")
2722 let reified_tparam_variadic pos =
2723 add
(Typing.err_code
Typing.NewWithoutNewable
) pos
2724 ("A function or method that has a reified type parameter cannot take reified arguments")
2726 let ignored_result_of_freeze pos =
2727 add
(Typing.err_code
Typing.IgnoredResultOfFreeze
) pos
2728 ("Result of freeze operation is unused. Note that freeze unsets local variable \
2729 that was passed as an argument so it won't be accessible after calling freeze.")
2731 let ignored_result_of_move pos =
2732 add
(Typing.err_code
Typing.IgnoredResultOfMove
) pos
2733 ("Result of move operation is unused. Note that move unsets local variable \
2734 that was passed as an argument so it won't be accessible after calling move.")
2737 let invalid_freeze_target pos1 var_pos var_mutability_str
=
2738 add_list
(Typing.err_code
Typing.InvalidFreezeTarget
)
2740 pos1
, "Invalid argument - freeze() takes a single mutable variable";
2741 var_pos
, "This variable is "^var_mutability_str
;
2744 let invalid_move_target pos1 var_pos var_mutability_str
=
2745 add_list
(Typing.err_code
Typing.InvalidMoveTarget
)
2747 pos1
, "Invalid argument - move() takes a single mutably-owned variable";
2748 var_pos
, "This variable is "^var_mutability_str
;
2751 let discarded_awaitable pos1 pos2
=
2752 add_list
(Typing.err_code
Typing.DiscardedAwaitable
) [
2753 pos1
, "This expression is of type Awaitable, but it's "^
2754 "either being discarded or used in a dangerous way before "^
2756 pos2
, "This is why I think it is Awaitable"
2759 let unify_error left right
=
2760 add_list
(Typing.err_code
Typing.UnifyError
) (left
@ right
)
2763 let elt_type_to_string = function
2764 | `Method
-> "method"
2765 | `Property
-> "property"
2767 let static_redeclared_as_dynamic dyn_position static_position member_name ~elt_type
=
2768 let dollar = match elt_type
with `Property
-> "$" | _
-> "" in
2769 let elt_type = elt_type_to_string elt_type in
2770 let msg_dynamic = "The "^
elt_type^
" "^
dollar^member_name^
" is declared here as non-static" in
2771 let msg_static = "But it conflicts with an inherited static declaration here" in
2772 add_list
(Typing.err_code
Typing.StaticDynamic
) [
2773 dyn_position
, msg_dynamic;
2774 static_position
, msg_static
2777 let dynamic_redeclared_as_static static_position dyn_position member_name ~
elt_type =
2778 let dollar = match elt_type with `Property
-> "$" | _
-> "" in
2779 let elt_type = elt_type_to_string elt_type in
2780 let msg_static = "The "^
elt_type^
" "^
dollar^member_name^
" is declared here as static" in
2781 let msg_dynamic = "But it conflicts with an inherited non-static declaration here" in
2782 add_list
(Typing.err_code
Typing.StaticDynamic
) [
2783 static_position
, msg_static;
2784 dyn_position
, msg_dynamic
2787 let null_member s
pos r
=
2788 add_list
(Typing.err_code
Typing.NullMember
) ([
2790 "You are trying to access the member "^s^
2791 " but this object can be null. "
2795 let non_object_member s pos1 ty pos2
=
2796 let msg_start = ("You are trying to access the member "^s^
2797 " but this is not an object, it is "^ty
) in
2799 if ty
= "a shape" then
2800 msg_start ^
". Did you mean $foo['" ^ s ^
"'] instead?"
2803 add_list
(Typing.err_code
Typing.NonObjectMember
) [
2805 pos2
, "Definition is here"
2808 let unknown_object_member s
pos r
=
2809 let msg = ("You are trying to access the member " ^ s ^
" on a value whose class is unknown") in
2810 add_list
(Typing.err_code
Typing.UnknownObjectMember
)
2813 let non_class_member s pos1 ty pos2
=
2814 add_list
(Typing.err_code
Typing.NonClassMember
) [
2816 ("You are trying to access the member "^s^
2817 " but this is not a class, it is "^
2820 "Definition is here"
2823 let ambiguous_member s pos1 ty pos2
=
2824 add_list
(Typing.err_code
Typing.AmbiguousMember
) [
2826 ("You are trying to access the member "^s^
2827 " but there is more than one implementation on "^
2830 "Definition is here"
2833 let null_container p null_witness
=
2834 add_list
(Typing.err_code
Typing.NullContainer
) (
2837 "You are trying to access an element of this container"^
2838 " but the container could be null. "
2841 let option_mixed pos =
2842 add
(Typing.err_code
Typing.OptionMixed
) pos
2843 "?mixed is a redundant typehint - just use mixed"
2845 let option_null pos =
2846 add
(Typing.err_code
Typing.OptionNull
) pos
2847 "?null is a redundant typehint - just use null"
2849 let declared_covariant pos1 pos2 emsg
=
2850 add_list
(Typing.err_code
Typing.DeclaredCovariant
) (
2851 [pos2
, "Illegal usage of a covariant type parameter";
2852 pos1
, "This is where the parameter was declared as covariant (+)"
2856 let declared_contravariant pos1 pos2 emsg
=
2857 add_list
(Typing.err_code
Typing.DeclaredContravariant
) (
2858 [pos2
, "Illegal usage of a contravariant type parameter";
2859 pos1
, "This is where the parameter was declared as contravariant (-)"
2863 let static_property_type_generic_param ~class_pos ~var_type_pos ~generic_pos
=
2864 add_list
(Typing.err_code
Typing.ClassVarTypeGenericParam
)
2865 [generic_pos
, "A generic parameter cannot be used in the type of a static property";
2866 var_type_pos
, "This is where the type of the static property was declared";
2867 class_pos
, "This is the class containing the static property"]
2869 let contravariant_this pos class_name tp
=
2870 add
(Typing.err_code
Typing.ContravariantThis
) pos (
2871 "The \"this\" type cannot be used in this " ^
2872 "contravariant position because its enclosing class \"" ^
class_name ^
2873 "\" " ^
"is final and has a variant type parameter \"" ^ tp ^
"\"")
2875 let cyclic_typeconst pos sl
=
2876 let sl = List.map
sl strip_ns
in
2877 add
(Typing.err_code
Typing.CyclicTypeconst
) pos
2878 ("Cyclic type constant:\n "^
String.concat ~sep
:" -> " sl)
2880 let abstract_concrete_override pos parent_pos
kind =
2881 let kind_str = match kind with
2882 | `method_
-> "method"
2883 | `typeconst
-> "type constant"
2884 | `constant
-> "constant" in
2885 add_list
(Typing.err_code
Typing.AbstractConcreteOverride
) ([
2886 pos, "Cannot re-declare this " ^
kind_str ^
" as abstract";
2887 parent_pos
, "Previously defined here"
2890 let instanceof_generic_classname pos name =
2891 add
(Typing.err_code
Typing.InstanceofGenericClassname
) pos
2892 ("'instanceof' cannot be used on 'classname<" ^
name ^
">' because '" ^
2893 name ^
"' may be instantiated with a type such as \
2894 'C<int>' that cannot be checked at runtime")
2896 let required_field_is_optional pos1 pos2
name =
2897 add_list
(Typing.err_code
Typing.RequiredFieldIsOptional
)
2899 pos1
, "The field '"^
name^
"' is optional";
2900 pos2
, "The field '"^
name^
"' is defined as required"
2903 let array_get_with_optional_field pos1 pos2
name =
2905 (Typing.err_code
Typing.ArrayGetWithOptionalField
)
2908 "Invalid index operation: '" ^
name ^
"' is marked as an optional shape \
2909 field. It may not be present in the shape. Use the `??` operator \
2912 "This is where the field was declared as optional."
2915 let non_call_argument_in_suspend pos msgs =
2917 (Typing.err_code
Typing.NonCallArgumentInSuspend
) (
2920 "'suspend' operator expects call to a coroutine as an argument."
2923 let non_coroutine_call_in_suspend pos msgs =
2925 (Typing.err_code
Typing.NonCoroutineCallInSuspend
) (
2928 "Only coroutine functions are allowed to be called in \
2929 'suspend' operator."
2933 let coroutine_call_outside_of_suspend pos =
2935 (Typing.err_code
Typing.CoroutineCallOutsideOfSuspend
)
2938 "Coroutine calls are only allowed when they are arguments to \
2942 let function_is_not_coroutine pos name =
2944 (Typing.err_code
Typing.FunctionIsNotCoroutine
)
2947 "Function '" ^
name ^
"' is not a coroutine and cannot be \
2948 used in as an argument of 'suspend' operator."
2951 let coroutinness_mismatch pos1_is_coroutine pos1 pos2
=
2952 let m1 = "This is a coroutine." in
2953 let m2 = "This is not a coroutine." in
2955 (Typing.err_code
Typing.CoroutinnessMismatch
)
2957 pos1
, if pos1_is_coroutine
then m1 else m2;
2958 pos2
, if pos1_is_coroutine
then m2 else m1;
2961 let invalid_ppl_call pos context
=
2962 let error_msg = "Cannot call a method on an object of a <<__PPL>> class "^context
in
2963 add
(Typing.err_code
Typing.InvalidPPLCall
) pos error_msg
2965 let invalid_ppl_static_call pos reason =
2966 let error_msg = "Cannot call a static method on a <<__PPL>> class "^
reason in
2967 add
(Typing.err_code
Typing.InvalidPPLStaticCall
) pos error_msg
2969 let ppl_meth_pointer pos func
=
2970 let error_msg = func^
" cannot be used with a <<__PPL>> class" in
2971 add
(Typing.err_code
Typing.PPLMethPointer
) pos error_msg
2973 let coroutine_outside_experimental pos =
2974 add
(Typing.err_code
Typing.CoroutineOutsideExperimental
) pos
2975 Coroutine_errors.error_message
2977 let return_disposable_mismatch pos1_return_disposable pos1 pos2
=
2978 let m1 = "This is marked <<__ReturnDisposable>>." in
2979 let m2 = "This is not marked <<__ReturnDisposable>>." in
2981 (Typing.err_code
Typing.ReturnDisposableMismatch
)
2983 pos1
, if pos1_return_disposable
then m1 else m2;
2984 pos2
, if pos1_return_disposable
then m2 else m1;
2987 let return_void_to_rx_mismatch ~pos1_has_attribute pos1 pos2
=
2988 let m1 = "This is marked <<__ReturnsVoidToRx>>." in
2989 let m2 = "This is not marked <<__ReturnsVoidToRx>>." in
2991 (Typing.err_code
Typing.ReturnVoidToRxMismatch
)
2993 pos1
, if pos1_has_attribute
then m1 else m2;
2994 pos2
, if pos1_has_attribute
then m2 else m1;
2997 let this_as_lexical_variable pos =
2998 add
(Naming.err_code
Naming.ThisAsLexicalVariable
) pos "Cannot use $this as lexical variable"
3000 let dollardollar_lvalue pos =
3001 add
(Typing.err_code
Typing.DollardollarLvalue
) pos
3002 "Cannot assign a value to the special pipe variable ($$)"
3004 let assigning_to_const pos =
3005 add
(Typing.err_code
Typing.AssigningToConst
) pos
3006 "Cannot assign to a __Const property"
3008 let self_const_parent_not pos =
3009 add
(Typing.err_code
Typing.SelfConstParentNot
) pos
3010 "A __Const class may only extend other __Const classes"
3012 let parent_const_self_not pos =
3013 add
(Typing.err_code
Typing.ParentConstSelfNot
) pos
3014 "Only __Const classes may extend a __Const class"
3016 let overriding_prop_const_mismatch parent_pos parent_const child_pos child_const
=
3017 let m1 = "This property is __Const" in
3018 let m2 = "This property is not __Const" in
3019 add_list
(Typing.err_code
Typing.OverridingPropConstMismatch
)
3021 parent_pos
, if parent_const
then m1 else m2;
3022 child_pos
, if child_const
then m1 else m2;
3025 let mutable_return_result_mismatch pos1_has_mutable_return pos1 pos2
=
3026 let m1 = "This is marked <<__MutableReturn>>." in
3027 let m2 = "This is not marked <<__MutableReturn>>." in
3029 (Typing.err_code
Typing.MutableReturnResultMismatch
)
3031 pos1
, if pos1_has_mutable_return
then m1 else m2;
3032 pos2
, if pos1_has_mutable_return
then m2 else m1;
3035 (*****************************************************************************)
3036 (* Typing decl errors *)
3037 (*****************************************************************************)
3039 let wrong_extend_kind child_pos child parent_pos parent
=
3040 let msg1 = child_pos
, child^
" cannot extend "^parent
in
3041 let msg2 = parent_pos
, "This is "^parent
in
3042 add_list
(Typing.err_code
Typing.WrongExtendKind
) [msg1; msg2]
3044 let unsatisfied_req parent_pos req_name req_pos
=
3045 let s1 = "Failure to satisfy requirement: "^
(Utils.strip_ns req_name
) in
3046 let s2 = "Required here" in
3047 if req_pos
= parent_pos
3048 then add
(Typing.err_code
Typing.UnsatisfiedReq
) parent_pos
s1
3049 else add_list
(Typing.err_code
Typing.UnsatisfiedReq
) [parent_pos
, s1; req_pos
, s2]
3051 let cyclic_class_def stack
pos =
3053 SSet.fold ~
f:(fun x y -> (Utils.strip_ns
x)^
" "^
y) stack ~init
:"" in
3054 add
(Typing.err_code
Typing.CyclicClassDef
) pos ("Cyclic class definition : "^
stack)
3056 let trait_reuse p_pos p_name
class_name trait
=
3057 let c_pos, c_name
= class_name in
3058 let c_name = Utils.strip_ns
c_name in
3059 let trait = Utils.strip_ns
trait in
3060 let err = "Class "^
c_name^
" reuses trait "^
trait^
" in its hierarchy" in
3061 let err'
= "It is already used through "^
(Utils.strip_ns p_name
) in
3062 add_list
(Typing.err_code
Typing.TraitReuse
) [c_pos, err; p_pos
, err'
]
3064 let invalid_is_as_expression_hint op hint_pos ty_pos ty_str
=
3065 add_list
(Typing.err_code
Typing.InvalidIsAsExpressionHint
) [
3066 hint_pos
, ("Invalid \"" ^ op ^
"\" expression hint");
3067 ty_pos
, ("The \"" ^ op ^
"\" operator cannot be used with " ^ ty_str
);
3070 let invalid_enforceable_type kind_str (tp_pos
, tp_name
) targ_pos ty_pos ty_str
=
3071 add_list
(Typing.err_code
Typing.InvalidEnforceableTypeArgument
) [
3072 targ_pos
, "Invalid type";
3073 tp_pos
, "Type " ^
kind_str ^
" " ^ tp_name ^
" was declared __Enforceable here";
3074 ty_pos
, "This type is not enforceable because it has " ^ ty_str
3077 let invalid_newable_type_argument (tp_pos
, tp_name
) ta_pos
=
3078 add_list
(Typing.err_code
Typing.InvalidNewableTypeArgument
) [
3079 ta_pos
, "A newable type argument must be a concrete class or a newable type parameter.";
3080 tp_pos
, "Type parameter " ^ tp_name ^
" was declared __Newable here";
3083 let invalid_newable_type_param_constraints (tparam_pos
, tparam_name
) constraint_list
=
3085 if List.is_empty constraint_list
3086 then "No constraints"
3087 else "The constraints " ^
(String.concat ~sep
:", " (List.map ~
f:Utils.strip_ns constraint_list
)) in
3088 let msg = "The type parameter " ^ tparam_name ^
" has the <<__Newable>> attribute. \
3089 Newable type parameters must be constrained with `as`, and exactly one of those constraints must be \
3090 a valid newable class. The class must either be final, or it must have the <<__ConsistentConstruct>> \
3091 attribute or extend a class that has it. " ^
partial ^
" are valid newable classes" in
3092 add
(Typing.err_code
Typing.InvalidNewableTypeParamConstraints
) tparam_pos
msg
3094 let override_final ~parent ~child
=
3095 add_list
(Typing.err_code
Typing.OverrideFinal
) [child
, "You cannot override this method";
3096 parent
, "It was declared as final"]
3098 let override_memoizelsb ~parent ~child
=
3099 add_list
(Typing.err_code
Typing.OverrideMemoizeLSB
) [
3100 child
, "__MemoizeLSB method may not be an override (temporary due to HHVM bug)";
3101 parent
, "This method is being overridden"]
3103 let override_lsb ~member_name ~parent ~child
=
3104 add_list
(Typing.err_code
Typing.OverrideLSB
) [
3105 child
, "Member " ^ member_name ^
" may not override __LSB member of parent";
3106 parent
, "This is being overridden"]
3108 let should_be_override pos class_id id
=
3109 add
(Typing.err_code
Typing.ShouldBeOverride
) pos
3110 ((Utils.strip_ns class_id
)^
"::"^id^
"() is marked as override; \
3111 no non-private parent definition found \
3112 or overridden parent is defined in non-<?hh code")
3114 let override_per_trait class_name id m_pos
=
3115 let c_pos, c_name = class_name in
3117 ("Method "^
(Utils.strip_ns
c_name)^
"::"^id^
" should be an override \
3118 per the declaring trait; no non-private parent definition found \
3119 or overridden parent is defined in non-<?hh code")
3120 in add_list
(Typing.err_code
Typing.OverridePerTrait
) [
3122 m_pos
, "Declaration of "^id^
"() is here"
3125 let missing_assign pos =
3126 add
(Typing.err_code
Typing.MissingAssign
) pos "Please assign a value"
3128 let private_override pos class_id id
=
3129 add
(Typing.err_code
Typing.PrivateOverride
) pos ((Utils.strip_ns class_id
)^
"::"^id
3130 ^
": combining private and override is nonsensical")
3132 let invalid_memoized_param pos ty_reason_msg
=
3133 add_list
(Typing.err_code
Typing.InvalidMemoizedParam
) (
3135 "Parameters to memoized function must be null, bool, int, float, string, \
3136 an object deriving IMemoizeParam, or a Container thereof. See also \
3137 http://docs.hhvm.com/hack/attributes/special#__memoize") :: ty_reason_msg
)
3139 let invalid_disposable_hint pos class_name =
3140 add
(Typing.err_code
Typing.InvalidDisposableHint
) pos
3141 ("Parameter with type '" ^
class_name ^
"' must not \
3142 implement IDisposable or IAsyncDisposable. Please use <<__AcceptDisposable>> attribute or \
3143 create disposable object with 'using' statement instead.")
3145 let invalid_disposable_return_hint pos class_name =
3146 add
(Typing.err_code
Typing.InvalidDisposableReturnHint
) pos
3147 ("Return type '" ^
class_name ^
"' must not \
3148 implement IDisposable or IAsyncDisposable. Please add <<__ReturnDisposable>> attribute.")
3150 let xhp_required pos why_xhp ty_reason_msg
=
3151 let msg = "An XHP instance was expected" in
3152 add_list
(Typing.err_code
Typing.XhpRequired
) ((pos, msg)::(pos, why_xhp
)::ty_reason_msg
)
3154 let illegal_xhp_child pos ty_reason_msg
=
3155 let msg = "XHP children must be compatible with XHPChild" in
3156 add_list
(Typing.err_code
Typing.IllegalXhpChild
) ((pos, msg)::ty_reason_msg
)
3158 let missing_xhp_required_attr pos attr ty_reason_msg
=
3159 let msg = "Required attribute " ^ attr ^
" is missing." in
3160 add_list
(Typing.err_code
Typing.MissingXhpRequiredAttr
) ((pos, msg)::ty_reason_msg
)
3161 let nullsafe_not_needed p nonnull_witness
=
3162 add_list
(Typing.err_code
Typing.NullsafeNotNeeded
) (
3165 "You are using the ?-> operator but this object cannot be null. "
3166 ] @ nonnull_witness
)
3168 let generic_at_runtime p prefix
=
3169 add
(Typing.err_code
Typing.ErasedGenericAtRuntime
) p
3170 (prefix ^
" generics can only be used in type hints because \
3171 they do not exist at runtime.")
3173 let generics_not_allowed p =
3174 add
(Typing.err_code
Typing.GenericsNotAllowed
) p
3175 "Generics are not allowed in this position."
3177 let trivial_strict_eq p b left right left_trail right_trail
=
3178 let msg = "This expression is always "^b
in
3179 let left_trail = List.map
left_trail typedef_trail_entry in
3180 let right_trail = List.map
right_trail typedef_trail_entry in
3181 add_list
(Typing.err_code
Typing.TrivialStrictEq
)
3182 ((p, msg) :: left
@ left_trail @ right
@ right_trail)
3184 let trivial_strict_not_nullable_compare_null p result type_reason
=
3185 let msg = "This expression is always "^
result in
3186 add_list
(Typing.err_code
Typing.NotNullableCompareNullTrivial
)
3187 ((p, msg) :: type_reason
)
3189 let eq_incompatible_types p left right
=
3190 let msg = "This equality test has incompatible types" in
3191 add_list
(Typing.err_code
Typing.EqIncompatibleTypes
)
3192 ((p, msg) :: left
@ right
)
3194 let comparison_invalid_types p left right
=
3195 let msg = "This comparison has invalid types. Only comparisons in which \
3196 both arguments are strings, nums, DateTime, or DateTimeImmutable \
3198 add_list
(Typing.err_code
Typing.ComparisonInvalidTypes
) ((p, msg) :: left
@ right
)
3200 let void_usage p void_witness
=
3201 let msg = "You are using the return value of a void function" in
3202 add_list
(Typing.err_code
Typing.VoidUsage
) ((p, msg) :: void_witness
)
3204 let noreturn_usage p noreturn_witness
=
3205 let msg = "You are using the return value of a noreturn function" in
3206 add_list
(Typing.err_code
Typing.NoreturnUsage
) ((p, msg) :: noreturn_witness
)
3208 let attribute_too_few_arguments pos x n =
3209 let n = string_of_int
n in
3210 add
(Typing.err_code
Typing.AttributeTooFewArguments
) pos (
3211 "The attribute "^
x^
" expects at least "^
n^
" arguments"
3214 let attribute_too_many_arguments pos x n =
3215 let n = string_of_int
n in
3216 add
(Typing.err_code
Typing.AttributeTooManyArguments
) pos (
3217 "The attribute "^
x^
" expects at most "^
n^
" arguments"
3220 let attribute_param_type pos x =
3221 add
(Typing.err_code
Typing.AttributeParamType
) pos (
3222 "This attribute parameter should be "^
x
3225 let deprecated_use pos pos_def
msg =
3226 add_list
(Typing.err_code
Typing.DeprecatedUse
) [
3228 pos_def
, "Definition is here";
3231 let cannot_declare_constant kind pos (class_pos
, class_name) =
3234 | `enum
-> "an enum"
3235 | `
trait -> "a trait"
3236 | `record
-> "a record"
3238 add_list
(Typing.err_code
Typing.CannotDeclareConstant
) [
3239 pos, "Cannot declare a constant in "^
kind_str;
3240 class_pos
, (strip_ns
class_name)^
" was defined as "^
kind_str^
" here";
3243 let ambiguous_inheritance pos class_ origin
(error
: error
) =
3244 let origin = strip_ns
origin in
3245 let class_ = strip_ns
class_ in
3246 let message = "This declaration was inherited from an object of type "^
origin^
3247 ". Redeclare this member in "^
class_^
" with a compatible signature." in
3248 let code, msgl = (get_code error
), (to_list error
) in
3249 add_list
code (msgl @ [pos, message])
3251 let multiple_concrete_defs child_pos parent_pos child_origin parent_origin
name class_ =
3252 let child_origin = strip_ns
child_origin in
3253 let parent_origin = strip_ns
parent_origin in
3254 let class_ = strip_ns
class_ in
3255 add_list
(Typing.err_code
Typing.MultipleConcreteDefs
) [
3256 child_pos
, child_origin ^
" and " ^
parent_origin ^
3257 " both declare ambiguous implementations of " ^
name ^
".";
3258 child_pos
, child_origin ^
"'s definition is here.";
3259 parent_pos
, parent_origin ^
"'s definition is here.";
3260 child_pos
, "Redeclare " ^
name ^
" in " ^
class_ ^
" with a compatible signature.";
3263 let explain_contravariance pos c_name error
=
3264 let message = "Considering that this type argument is contravariant "^
3265 "with respect to " ^ strip_ns
c_name in
3266 let code, msgl = (get_code error
), (to_list error
) in
3267 add_list
code (msgl @ [pos, message])
3269 let explain_invariance pos c_name suggestion error
=
3270 let message = "Considering that this type argument is invariant "^
3271 "with respect to " ^ strip_ns
c_name ^ suggestion
in
3272 let code, msgl = (get_code error
), (to_list error
) in
3273 add_list
code (msgl @ [pos, message])
3275 let local_variable_modified_and_used pos_modified pos_used_l
=
3276 let used_msg p = p, "And accessed here" in
3277 add_list
(Typing.err_code
Typing.LocalVariableModifedAndUsed
)
3278 ((pos_modified
, "Unsequenced modification and access to local \
3279 variable. Modified here") ::
3280 List.map pos_used_l
used_msg)
3282 let local_variable_modified_twice pos_modified pos_modified_l
=
3283 let modified_msg p = p, "And also modified here" in
3284 add_list
(Typing.err_code
Typing.LocalVariableModifedTwice
)
3285 ((pos_modified
, "Unsequenced modifications to local variable. \
3287 List.map pos_modified_l
modified_msg)
3289 let assign_during_case p =
3290 add
(Typing.err_code
Typing.AssignDuringCase
) p
3291 "Don't assign to variables inside of case labels"
3293 let cyclic_enum_constraint pos =
3294 add
(Typing.err_code
Typing.CyclicEnumConstraint
) pos "Cyclic enum constraint"
3296 let invalid_classname p =
3297 add
(Typing.err_code
Typing.InvalidClassname
) p "Not a valid class name"
3299 let illegal_type_structure pos errmsg
=
3301 "The two arguments to type_structure() must be:"
3302 ^
"\n - first: ValidClassname::class or an object of that class"
3303 ^
"\n - second: a single-quoted string literal containing the name"
3304 ^
" of a type constant of that class"
3306 add
(Typing.err_code
Typing.IllegalTypeStructure
) pos msg
3308 let illegal_typeconst_direct_access pos =
3310 "Type constants cannot be directly accessed. "
3311 ^
"Use type_structure(ValidClassname::class, 'TypeConstName') instead" in
3312 add
(Typing.err_code
Typing.IllegalTypeStructure
) pos msg
3314 let override_no_default_typeconst pos_child pos_parent
=
3315 add_list
(Typing.err_code
Typing.OverrideNoDefaultTypeconst
) [
3316 pos_child
, "This abstract type constant does not have a default type";
3317 pos_parent
, "It cannot override an abstract type constant that has a default type"
3320 let class_property_only_static_literal pos =
3322 "Initialization of class property must be a static literal expression." in
3323 add
(Typing.err_code
Typing.ClassPropertyOnlyStaticLiteralDEPRECATED
) pos msg
3325 let reference_expr pos =
3326 let msg = "References are only allowed as function call arguments" in
3327 add
(Typing.err_code
Typing.ReferenceExprNotFunctionArg
) pos msg
3329 let pass_by_ref_annotation_missing pos1 pos2
=
3330 let msg1 = pos1
, "This argument should be annotated with &" in
3331 let msg2 = pos2
, "Because this parameter is passed by reference" in
3332 add_list
(Typing.err_code
Typing.PassByRefAnnotationMissing
) [msg1; msg2]
3334 let pass_by_ref_annotation_unexpected pos1 pos2 pos2_is_variadic
=
3335 let msg1 = pos1
, "This argument should not be annotated with &" in
3336 let param_str = if pos2_is_variadic
3337 then "variadic parameters are"
3338 else "this parameter is" in
3339 let msg2 = pos2
, "Because " ^
param_str ^
" passed by value" in
3340 add_list
(Typing.err_code
Typing.PassByRefAnnotationUnexpected
) [msg1; msg2]
3342 let reffiness_invariant pos1 pos2 mode2
=
3343 let msg1 = pos1
, "This parameter is passed by reference" in
3344 let mode_str = match mode2
with
3345 | `normal
-> "a normal parameter"
3346 | `inout
-> "an inout parameter" in
3347 let msg2 = pos2
, "It is incompatible with " ^
mode_str in
3348 add_list
(Typing.err_code
Typing.ReffinessInvariant
) [msg1; msg2]
3350 let inout_annotation_missing pos1 pos2
=
3351 let msg1 = pos1
, "This argument should be annotated with 'inout'" in
3352 let msg2 = pos2
, "Because this is an inout parameter" in
3353 add_list
(Typing.err_code
Typing.InoutAnnotationMissing
) [msg1; msg2]
3355 let inout_annotation_unexpected pos1 pos2 pos2_is_variadic
=
3356 let msg1 = pos1
, "Unexpected inout annotation for argument" in
3357 let msg2 = pos2
, if pos2_is_variadic
3358 then "A variadic parameter can never be inout"
3359 else "This is a normal parameter (does not have 'inout')" in
3360 add_list
(Typing.err_code
Typing.InoutAnnotationUnexpected
) [msg1; msg2]
3362 let inoutness_mismatch pos1 pos2
=
3363 let msg1 = pos1
, "This is an inout parameter" in
3364 let msg2 = pos2
, "It is incompatible with a normal parameter" in
3365 add_list
(Typing.err_code
Typing.InoutnessMismatch
) [msg1; msg2]
3367 let invalid_new_disposable pos =
3369 "Disposable objects may only be created in a 'using' statement or 'return' from function marked <<__ReturnDisposable>>" in
3370 add
(Typing.err_code
Typing.InvalidNewDisposable
) pos msg
3372 let invalid_return_disposable pos =
3374 "Return expression must be new disposable in function marked <<__ReturnDisposable>>" in
3375 add
(Typing.err_code
Typing.InvalidReturnDisposable
) pos msg
3377 let nonreactive_function_call pos decl_pos callee_reactivity cause_pos_opt
=
3378 add_list
(Typing.err_code
Typing.NonreactiveFunctionCall
) ([
3379 pos, "Reactive functions can only call other reactive functions.";
3380 decl_pos
, "This function is " ^ callee_reactivity ^
"."
3381 ] @ Option.value_map cause_pos_opt ~default
:[] ~
f:(fun cause_pos
->
3382 [cause_pos
, "This argument caused function to be " ^ callee_reactivity ^
"."]
3385 let nonreactive_call_from_shallow pos decl_pos callee_reactivity cause_pos_opt
=
3386 add_list
(Typing.err_code
Typing.NonreactiveCallFromShallow
) ([
3387 pos, "Shallow reactive functions cannot call non-reactive functions.";
3388 decl_pos
, "This function is " ^ callee_reactivity ^
"."
3389 ] @ Option.value_map cause_pos_opt ~default
:[] ~
f:(fun cause_pos
->
3390 [cause_pos
, "This argument caused function to be " ^ callee_reactivity ^
"."]
3392 let rx_enabled_in_non_rx_context pos =
3393 add
(Typing.err_code
Typing.RxEnabledInNonRxContext
) pos (
3394 "\\HH\\Rx\\IS_ENABLED can only be used in reactive functions."
3397 let rx_enabled_in_lambdas pos =
3398 add
(Typing.err_code
Typing.RxEnabledInLambdas
) pos (
3399 "\\HH\\Rx\\IS_ENABLED cannot be used inside lambdas."
3402 let rx_parameter_condition_mismatch cond
pos def_pos
=
3403 add_list
(Typing.err_code
Typing.RxParameterConditionMismatch
) [
3404 pos, "This parameter does not satisfy "^ cond ^
" condition defined on \
3405 matching parameter in function super type.";
3406 def_pos
, "This is parameter declaration from the function super type."
3408 let nonreactive_indexing is_append
pos =
3411 then "Cannot append to a Hack Collection object in a reactive context. \
3412 Instead, use the 'add' method."
3413 else "Cannot assign to element of Hack Collection object via [] in a reactive context. \
3414 Instead, use the 'set' method." in
3415 add
(Typing.err_code
Typing.NonreactiveIndexing
) pos msg
3417 let obj_set_reactive pos =
3418 let msg = ("This object's property is being mutated(used as an lvalue)" ^
3419 "\nYou cannot set non-mutable object properties in reactive functions") in
3420 add
(Typing.err_code
Typing.ObjSetReactive
) pos msg
3422 let invalid_unset_target_rx pos =
3423 add
(Typing.err_code
Typing.InvalidUnsetTargetInRx
) pos (
3424 "Non-mutable argument for 'unset' is not allowed in reactive functions."
3427 let inout_argument_bad_type pos msgl =
3429 "Expected argument marked inout to be contained in a local or " ^
3430 "a value-typed container (e.g. vec, dict, keyset, array). " ^
3431 "To use inout here, assign to/from a temporary local variable." in
3432 add_list
(Typing.err_code
Typing.InoutArgumentBadType
) ((pos, msg) :: msgl)
3434 let ambiguous_lambda pos uses
=
3436 "Lambda has parameter types that could not be determined at definition site." in
3439 "%d distinct use types were determined: please add type hints to lambda parameters."
3440 (List.length uses
) in
3441 add_list
(Typing.err_code
Typing.AmbiguousLambda
) ([(pos, msg1); (pos, msg2)] @
3442 List.map uses
(fun (pos, ty
) -> (pos, "This use has type " ^ ty
)))
3444 let wrong_expression_kind_attribute expr_kind
pos attr attr_class_pos attr_class_name intf_name
=
3446 Printf.sprintf
"The %s attribute cannot be used on %s." (Utils.strip_ns attr
) expr_kind
in
3448 Printf.sprintf
"The attribute's class is defined here. To be available for use on \
3449 %s, the %s class must implement %s." expr_kind
3450 (String_utils.string_after attr_class_name
1)
3451 (String_utils.string_after intf_name
1) in
3452 add_list
(Typing.err_code
Typing.WrongExpressionKindAttribute
) [
3454 attr_class_pos
, msg2
3457 let attribute_class_no_constructor_args pos def_pos
=
3459 "The class associated with this attribute has no constructor. " ^
3460 "Please add a constructor to use arguments with this attribute." in
3461 add_list
(Typing.err_code
Typing.AttributeClassNoConstructorArgs
) [
3463 def_pos
, "The attribute's class is defined here."
3466 let cannot_return_borrowed_value_as_immutable fun_pos value_pos
=
3467 add_list
(Typing.err_code
Typing.CannotReturnBorrowedValueAsImmutable
) [
3468 fun_pos
, "Values returned from reactive function by default are treated \
3470 value_pos
, "This value is mutably borrowed and cannot be returned as immutable"
3473 let decl_override_missing_hint pos =
3474 add
(Typing.err_code
Typing.DeclOverrideMissingHint
) pos
3475 "When redeclaring class members, both declarations must have a typehint"
3477 let let_var_immutability_violation pos id
=
3478 add
(Typing.err_code
Typing.LetVarImmutabilityViolation
) pos
3479 ("Let variables are immutable. Using let variable " ^ id ^
" in write context is not allowed.")
3481 let invalid_type_for_atmost_rx_as_rxfunc_parameter pos type_str
=
3482 add
(Typing.err_code
Typing.InvalidTypeForOnlyrxIfRxfuncParameter
) pos (
3483 "Parameter annotated with <<__AtMostRxAsFunc>> attribute must be function, \
3484 now '" ^ type_str ^
"'."
3487 let missing_annotation_for_atmost_rx_as_rxfunc_parameter pos =
3488 add
(Typing.err_code
Typing.MissingAnnotationForOnlyrxIfRxfuncParameter
) pos (
3489 "Missing function type annotation on parameter marked with <<__AtMostRxAsFunc>> attribute."
3492 let binding_ref_in_array pos =
3493 let msg = "Arrays cannot contain references." in
3494 add
(Typing.err_code
Typing.BindingRefInArray
) pos msg
3496 let binding_ref_to_array pos =
3497 let msg = "Cannot take references to array elements." in
3498 add
(Typing.err_code
Typing.BindingRefInArray
) pos msg
3500 let passing_array_cell_by_ref pos =
3501 let msg = "Passing array elements by reference is no longer supported; " ^
3502 "use 'inout' instead" in
3503 add
(Typing.err_code
Typing.PassingArrayCellByRef
) pos msg
3505 let superglobal_in_reactive_context pos name =
3506 add
(Typing.err_code
Typing.SuperglobalInReactiveContext
) pos (
3507 "Superglobal "^
name ^
" cannot be used in a reactive context."
3510 let static_property_in_reactive_context pos =
3511 add
(Typing.err_code
Typing.StaticPropertyInReactiveContext
) pos (
3512 "Static property cannot be used in a reactive context."
3515 let static_in_reactive_context pos name =
3516 add
(Typing.err_code
Typing.StaticInReactiveContext
) pos (
3517 "Static " ^
name ^
" cannot be used in a reactive context."
3520 let returns_void_to_rx_function_as_non_expression_statement pos fpos
=
3521 add_list
(Typing.err_code
Typing.ReturnsVoidToRxAsNonExpressionStatement
) [
3522 pos, "Cannot use result of function annotated with <<__ReturnsVoidToRx>> \
3523 in reactive context";
3524 fpos
, "This is function declaration."
3527 let non_awaited_awaitable_in_rx pos =
3528 add
(Typing.err_code
Typing.NonawaitedAwaitableInReactiveContext
) pos (
3529 "This value has Awaitable type. Awaitable typed values in reactive code \
3530 must be either immediately await'ed or passed as arguments to 'genva' function."
3533 let shapes_key_exists_always_true pos1
name pos2
=
3534 add_list
(Typing.err_code
Typing.ShapesKeyExistsAlwaysTrue
) [
3535 pos1
, "This Shapes::keyExists() check is always true";
3536 pos2
, "The field '" ^
name ^
"' exists because of this definition"
3539 let shape_field_non_existence_reason name = function
3541 "The field '" ^
name ^
"' is not defined in this shape"
3543 "The field '" ^
name ^
"' was unset here"
3545 let shapes_key_exists_always_false pos1
name pos2
reason =
3546 add_list
(Typing.err_code
Typing.ShapesKeyExistsAlwaysFalse
) [
3547 pos1
, "This Shapes::keyExists() check is always false";
3548 pos2
, shape_field_non_existence_reason name reason
3551 let shapes_method_access_with_non_existent_field pos1
name pos2 method_name
reason =
3552 add_list
(Typing.err_code
Typing.ShapesMethodAccessWithNonExistentField
) [
3553 pos1
, "You are calling Shapes::" ^ method_name ^
"() on a field known to not exist";
3554 pos2
, shape_field_non_existence_reason name reason
3557 let ambiguous_object_access pos name self_pos vis subclass_pos class_self class_subclass
=
3558 let class_self = Utils.strip_ns
class_self in
3559 let class_subclass = Utils.strip_ns
class_subclass in
3560 add_list
(Typing.err_code
Typing.AmbiguousObjectAccess
) [
3561 pos, "This object access to " ^
name ^
" is ambiguous";
3562 self_pos
, "You will access the private instance declared in " ^
class_self;
3563 subclass_pos
, "Instead of the " ^ vis ^
" instance declared in " ^
class_subclass;
3566 let invalid_traversable_in_rx pos =
3567 add
(Typing.err_code
Typing.InvalidTraversableInRx
) pos (
3568 "Cannot traverse over non-reactive traversable in reactive code."
3571 let lateinit_with_default pos =
3572 add
(Typing.err_code
Typing.LateInitWithDefault
) pos
3573 "A late-initialized property cannot have a default value"
3575 let bad_lateinit_override parent_is_lateinit parent_pos child_pos
=
3576 let verb = if parent_is_lateinit
then "is" else "is not" in
3577 add_list
(Typing.err_code
Typing.BadLateInitOverride
) [
3578 child_pos
, "Redeclared properties must be consistently declared as late-initialized";
3579 parent_pos
, "The property "^
verb^
" late-initialized here";
3582 let bad_xhp_attr_required_override parent_tag child_tag parent_pos child_pos
=
3583 add_list
(Typing.err_code
Typing.BadXhpAttrRequiredOverride
) [
3584 child_pos
, "Redeclared attribute must not be less strict";
3585 parent_pos
, "The attribute is " ^ parent_tag ^
", which is stricter than " ^ child_tag
;
3588 let invalid_truthiness_test pos ty
=
3589 add
(Typing.err_code
Typing.InvalidTruthinessTest
) pos @@
3591 "Invalid condition: a value of type %s will always be truthy" ty
3593 let invalid_truthiness_test_falsy pos ty
=
3594 add
(Typing.err_code
Typing.InvalidTruthinessTest
) pos @@
3596 "Invalid condition: a value of type %s will always be falsy" ty
3598 let sketchy_truthiness_test pos ty truthiness
=
3599 add
(Typing.err_code
Typing.SketchyTruthinessTest
) pos @@
3600 match truthiness
with
3603 "Sketchy condition: testing the truthiness of %s may not behave as expected.\n\
3604 The values '' and '0' are both considered falsy. \
3605 To check for emptiness, use Str\\is_empty."
3609 "Sketchy condition: testing the truthiness of %s may not behave as expected.\n\
3610 The values 0, '', and '0' are all considered falsy. \
3611 Test for them explicitly."
3615 "Sketchy condition: testing the truthiness of a %s may not behave as expected.\n\
3616 The values '' and '0' are both considered falsy, \
3617 but objects will be truthy even if their __toString returns '' or '0'.\n\
3618 To check for emptiness, convert to a string and use Str\\is_empty."
3622 "Sketchy condition: testing the truthiness of an %s may not behave as expected.\n\
3623 The values '' and '0' are both considered falsy, \
3624 but objects (including XHP elements) will be truthy \
3625 even if their __toString returns '' or '0'."
3628 (* We have a truthiness test on a value with an interface type which is a
3629 subtype of Traversable, but not a subtype of Container.
3630 Since the runtime value may be a falsy-when-empty Container or an
3631 always-truthy Iterable/Generator, we forbid the test. *)
3633 "Sketchy condition: a value of type %s may be truthy even when empty.\n\
3634 Hack collections and arrays are falsy when empty, but user-defined \
3635 Traversables will always be truthy, even when empty.\n\
3636 If you would like to only allow containers which are falsy \
3637 when empty, use the Container or KeyedContainer interfaces."
3640 let invalid_switch_case_value_type case_value_p case_value_ty scrutinee_ty
=
3641 add
(Typing.err_code
Typing.InvalidSwitchCaseValueType
) case_value_p
@@
3643 "This case value has type %s, which is incompatible with type %s."
3647 let unserializable_type pos message =
3648 add
(Typing.err_code
Typing.UnserializableType
) pos
3649 ("Unserializable type (could not be converted to JSON and back again): "
3652 let redundant_rx_condition pos =
3653 add
(Typing.err_code
Typing.RedundantRxCondition
) pos
3654 "Reactivity condition for this method is always true, consider removing it."
3656 let invalid_arraykey pos (cpos
, ctype
) (kpos
, ktype
) =
3657 add_list
(Typing.err_code
Typing.InvalidArrayKey
) [
3658 pos, "This value is not a valid key type for this container";
3659 cpos
, "This container is " ^ ctype
;
3660 kpos
, (String.capitalize ktype
) ^
" cannot be used as a key for " ^ ctype
;
3663 let invalid_sub_string pos ty
=
3664 add
(Typing.err_code
Typing.InvalidSubString
) pos @@
3665 "Expected an object convertible to string but got " ^ ty
3667 let typechecker_timeout (pos, fun_name
) seconds
=
3668 add
(Typing.err_code
Typing.TypecheckerTimeout
) pos
3669 (Printf.sprintf
"Type checker timed out after %d seconds whilst checking function %s" seconds fun_name
)
3671 let unresolved_type_variable pos =
3672 add
(Typing.err_code
Typing.UnresolvedTypeVariable
) pos
3673 ("The type of this expression contains an unresolved type variable")
3675 let invalid_arraykey_constraint pos t
=
3676 add
(Typing.err_code
Typing.InvalidArrayKeyConstraint
) pos
3677 ("This type is " ^ t ^
", which cannot be used as an arraykey (string | int)")
3679 (*****************************************************************************)
3681 (*****************************************************************************)
3683 let to_json (error
: Pos.absolute error_
) =
3684 let error_code, msgl = (get_code error
), (to_list error
) in
3685 let elts = List.map
msgl begin fun (p, w
) ->
3686 let line, scol
, ecol
= Pos.info_pos
p in
3687 Hh_json.JSON_Object
[
3688 "descr", Hh_json.JSON_String w
;
3689 "path", Hh_json.JSON_String
(Pos.filename p);
3690 "line", Hh_json.int_
line;
3691 "start", Hh_json.int_ scol
;
3692 "end", Hh_json.int_ ecol
;
3693 "code", Hh_json.int_
error_code
3696 Hh_json.JSON_Object
[ "message", Hh_json.JSON_Array
elts ]
3698 (*****************************************************************************)
3699 (* Try if errors. *)
3700 (*****************************************************************************)
3702 let try_ f1 f2
= try_with_result f1
(fun _
l -> f2
l)
3704 let try_with_error f1 f2
= try_ f1
(fun err -> add_error err; f2
())
3706 let try_add_err pos err f1 f2
=
3707 try_ f1
begin fun error
->
3708 let error_code, l = (get_code error
), (to_list error
) in
3709 add_list
error_code ((pos, err) :: l);
3713 let has_no_errors f =
3714 try_ (fun () -> let _ = f () in true) (fun _ -> false)
3716 (*****************************************************************************)
3718 (*****************************************************************************)
3721 let allow_errors_in_default_path_copy = !allow_errors_in_default_path in
3722 set_allow_errors_in_default_path true;
3723 let _, result = (do_ f) in
3724 set_allow_errors_in_default_path allow_errors_in_default_path_copy;
3727 let try_when f ~when_ ~
do_ =
3728 try_with_result f begin fun result (error
: error
) ->
3731 else add_error error
;
3735 (* Runs the first function that is expected to produce an error. If it doesn't
3736 * then we run the second function we are given
3738 let must_error f error_fun
=
3739 let had_no_errors = try_with_error (fun () -> f(); true) (fun _ -> false) in
3740 if had_no_errors then error_fun
();