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.
11 open Reordered_argument_collections
14 type error_code
= int [@@deriving eq
]
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 [@@deriving eq
]
35 type typing_error_callback
=
36 (Pos.t
* string) list
-> (Pos.t
* string) list
-> unit
38 (* The file and phase of analysis being currently performed *)
39 let current_context : (Relative_path.t
* phase
) ref =
40 ref (Relative_path.default
, Typing
)
42 let allow_errors_in_default_path = ref true
44 module PhaseMap
= Reordered_argument_map
(WrappedMap.Make
(struct
54 let compare x y
= rank x
- rank y
57 (* Results of single file analysis. *)
58 type 'a file_t
= 'a list
PhaseMap.t
[@@deriving eq
]
60 (* Results of multi-file analysis. *)
61 type 'a files_t
= 'a file_t
Relative_path.Map.t
[@@deriving eq
]
63 let files_t_fold v ~f ~init
=
64 Relative_path.Map.fold v ~init ~f
:(fun path v acc
->
65 PhaseMap.fold v ~init
:acc ~f
:(fun phase v acc
-> f path phase v acc
))
67 let files_t_map v ~f
= Relative_path.Map.map v ~f
:(fun v
-> PhaseMap.map v ~f
)
69 let files_t_merge ~f x y
=
70 (* Using fold instead of merge to make the runtime proportional to the size
71 * of first argument (like List.rev_append ) *)
72 Relative_path.Map.fold x ~init
:y ~f
:(fun k x acc
->
74 Option.value (Relative_path.Map.find_opt
y k
) ~default
:PhaseMap.empty
79 (PhaseMap.merge x
y ~f
:(fun phase x
y -> f phase k x
y)))
81 let files_t_to_list x
=
82 files_t_fold x ~f
:(fun _ _ x acc
-> List.rev_append x acc
) ~init
:[]
85 let list_to_files_t = function
86 | [] -> Relative_path.Map.empty
88 (* Values constructed here should not be used with incremental mode.
89 * See assert in incremental_update. *)
90 Relative_path.Map.singleton
92 (PhaseMap.singleton Typing x
)
94 let get_code_severity code
=
97 = Error_codes.Init.err_code
Error_codes.Init.ForwardCompatibilityNotCurrent
103 (* Get most recently-ish added error. *)
104 let get_last error_map
=
105 (* If this map has more than one element, we pick an arbitrary file. Because
106 * of that, we might not end up with the most recent error and generate a
107 * less-specific error message. This should be rare. *)
108 match Relative_path.Map.max_binding_opt error_map
with
110 | Some
(_
, phase_map
) ->
112 PhaseMap.max_binding_opt phase_map
|> Option.value_map ~f
:snd ~default
:[]
114 (match List.rev
error_list with
118 type 'a error_
= error_code
* 'a message list
[@@deriving eq
]
120 type error
= Pos.t error_
[@@deriving eq
]
122 type applied_fixme
= Pos.t
* int [@@deriving eq
]
124 let applied_fixmes : applied_fixme files_t
ref = ref Relative_path.Map.empty
126 let (error_map
: error files_t
ref) = ref Relative_path.Map.empty
128 let accumulate_errors = ref false
130 (* Some filename when declaring *)
131 let in_lazy_decl = ref None
133 let (is_hh_fixme
: (Pos.t
-> error_code
-> bool) ref) = ref (fun _ _
-> false)
135 let try_with_result f1 f2
=
136 let error_map_copy = !error_map
in
137 let accumulate_errors_copy = !accumulate_errors in
138 let is_hh_fixme_copy = !is_hh_fixme
in
139 (is_hh_fixme
:= (fun _ _
-> false));
140 error_map
:= Relative_path.Map.empty
;
141 accumulate_errors := true;
142 let (result
, errors
) =
147 let result = f1
() in
153 error_map
:= error_map_copy;
154 accumulate_errors := accumulate_errors_copy;
155 is_hh_fixme
:= is_hh_fixme_copy
158 match get_last errors
with
161 (* Remove bad position sentinel if present: we might be about to add a new primary
165 | (_
, msg
) :: l when msg
= Badpos_sentinel.message
-> l
171 let error_map_copy = !error_map
in
172 let accumulate_errors_copy = !accumulate_errors in
173 let applied_fixmes_copy = !applied_fixmes in
174 error_map
:= Relative_path.Map.empty
;
175 applied_fixmes := Relative_path.Map.empty
;
176 accumulate_errors := true;
177 let (result, out_errors
, out_applied_fixmes
) =
183 (result, !error_map
, !applied_fixmes)
188 error_map
:= error_map_copy;
189 applied_fixmes := applied_fixmes_copy;
190 accumulate_errors := accumulate_errors_copy
193 let out_errors = files_t_map ~f
:List.rev
out_errors in
194 ((out_errors, out_applied_fixmes
), result)
196 let run_in_context path phase f
=
197 let context_copy = !current_context in
198 current_context := (path
, phase
);
199 Utils.try_finally ~f ~finally
:(fun () -> current_context := context_copy)
201 (* Log important data if lazy_decl triggers a crash *)
202 let lazy_decl_error_logging error error_map to_absolute to_string
=
203 let error_list = files_t_to_list !error_map
in
204 (* Print the current error list, which should be empty *)
205 Printf.eprintf
"%s" "Error list(should be empty):\n";
206 List.iter
error_list ~f
:(fun err
->
207 let msg = err
|> to_absolute
|> to_string
in
208 Printf.eprintf
"%s\n" msg);
209 Printf.eprintf
"%s" "Offending error:\n";
210 Printf.eprintf
"%s" error
;
212 (* Print out a larger stack trace *)
213 Printf.eprintf
"%s" "Callstack:\n";
216 (Caml.Printexc.raw_backtrace_to_string
(Caml.Printexc.get_callstack
500));
218 (* Exit with special error code so we can see the log after *)
219 Exit_status.exit
Exit_status.Lazy_decl_bug
221 (*****************************************************************************)
222 (* Error code printing. *)
223 (*****************************************************************************)
225 let error_kind error_code
=
226 match error_code
/ 1000 with
235 let error_code_to_string error_code
=
236 let error_kind = error_kind error_code
in
237 let error_number = Printf.sprintf
"%04d" error_code
in
238 error_kind ^
"[" ^
error_number ^
"]"
240 let phase_to_string (phase
: phase
) : string =
243 | Parsing
-> "Parsing"
248 let rec get_pos (error
: error
) = fst
(List.hd_exn
(snd error
))
255 Pos.compare (get_pos x
) (get_pos y)
258 |> List.remove_consecutive_duplicates ~equal
:( = )
260 and get_sorted_error_list
(err
, _
) = sort
(files_t_to_list err
)
262 (* Getters and setter for passed-in map, based on current context *)
263 let get_current_file_t file_t_map
=
264 let current_file = fst
!current_context in
265 Relative_path.Map.find_opt file_t_map
current_file
266 |> Option.value ~default
:PhaseMap.empty
268 let get_current_list file_t_map
=
269 let current_phase = snd
!current_context in
270 get_current_file_t file_t_map
|> fun x
->
271 PhaseMap.find_opt x
current_phase |> Option.value ~default
:[]
273 let set_current_list file_t_map new_list
=
274 let (current_file, current_phase) = !current_context in
276 Relative_path.Map.add
279 (PhaseMap.add
(get_current_file_t !file_t_map
) current_phase new_list
)
281 let do_with_context path phase f
= run_in_context path phase
(fun () -> do_ f
)
283 (* Turn on lazy decl mode for the duration of the closure.
284 This runs without returning the original state,
285 since we collect it later in do_with_lazy_decls_
287 let run_in_decl_mode filename f
=
288 let old_in_lazy_decl = !in_lazy_decl in
289 in_lazy_decl := Some filename
;
290 Utils.try_finally ~f ~finally
:(fun () -> in_lazy_decl := old_in_lazy_decl)
292 and make_error code
(x
: (Pos.t
* string) list
) : error
= (code
, x
)
294 (*****************************************************************************)
296 (*****************************************************************************)
297 and get_code
(error
: 'a error_
) = (fst error
: error_code
)
299 let get_severity (error
: 'a error_
) = get_code_severity (get_code error
)
301 let to_list (error
: 'a error_
) = snd error
303 let to_absolute error
=
304 let (code
, msg_l
) = (get_code error
, to_list error
) in
305 let msg_l = List.map
msg_l (fun (p
, s
) -> (Pos.to_absolute p
, s
)) in
308 let read_lines path
= In_channel.read_lines path
310 let line_margin (line_num
: int option) col_width
: string =
313 | Some line_num
-> Printf.sprintf
"%*d" col_width line_num
314 | None
-> String.make col_width ' '
316 Tty.apply_color
(Tty.Normal
Tty.Cyan
) (padded_num ^
" |")
318 (* Get the lines of source code associated with this position. *)
319 let load_context_lines (pos
: Pos.absolute
) : string list
=
320 let path = Pos.filename pos
in
321 let line = Pos.line pos
in
322 let end_line = Pos.end_line pos
in
323 let lines = (try read_lines path with Sys_error _
-> []) in
324 (* Line numbers are 1-indexed. *)
325 List.filteri
lines ~f
:(fun i _
-> i
+ 1 >= line && i
+ 1 <= end_line)
327 let format_context_lines (pos
: Pos.absolute
) (lines : string list
) col_width
:
331 | [] -> [Tty.apply_color
(Tty.Dim
Tty.Default
) "No source found"]
334 let line_num = Pos.line pos
in
335 let format_line i
(line : string) =
336 Printf.sprintf
"%s %s" (line_margin (Some
(line_num + i
)) col_width
) line
338 let formatted_lines = List.mapi ~f
:format_line lines in
339 (* TODO: display all the lines, showing the underline on all of them. *)
340 List.hd_exn
formatted_lines
342 (* Format this message as " ^^^ You did something wrong here". *)
343 let format_substring_underline
346 (first_context_line
: string option)
349 let (start_line
, start_column
) = Pos.line_column pos
in
350 let (end_line, end_column
) = Pos.end_line_column pos
in
351 let underline_width =
352 match first_context_line
with
353 | None
-> 4 (* Arbitrary choice when source isn't available. *)
354 | Some first_context_line
->
355 if start_line
= end_line then
356 end_column
- start_column
358 String.length first_context_line
- start_column
360 let underline = String.make
(max
underline_width 1) '^'
in
361 let underline_padding =
362 if Option.is_some first_context_line
then
363 String.make start_column ' '
375 (line_margin None col_width
)
382 underline ^
" " ^
msg ))
384 let format_filename (pos
: Pos.absolute
) : string =
385 let relative_path path =
386 let cwd = Filename.concat
(Sys.getcwd
()) "" in
389 let filename = relative_path (Pos.filename pos
) in
392 (Tty.apply_color
(Tty.Normal
Tty.Cyan
) "-->")
393 (Tty.apply_color
(Tty.Normal
Tty.Green
) filename)
395 let column_width line_number
=
396 let num_digits x
= int_of_float
(Float.log10
(float_of_int x
)) + 1 in
397 max
3 (num_digits line_number
)
399 (* Format the line of code associated with this message, and the message itself. *)
400 let format_message (msg : string) (pos
: Pos.absolute
) ~is_first ~col_width
:
403 Option.value col_width ~default
:(column_width (Pos.line pos
))
405 let context_lines = load_context_lines pos
in
406 let pretty_ctx = format_context_lines pos
context_lines col_width in
408 format_substring_underline
411 (List.hd
context_lines)
415 (pretty_ctx, pretty_msg)
417 (** Sort messages such that messages in the same file are together.
418 Do not reorder the files or messages within a file.
420 let group_by_file (msgs
: Pos.absolute message list
) : Pos.absolute message list
422 let rec build_map msgs grouped filenames
=
425 let filename = Pos.filename (fst
msg) in
426 (match String.Map.find grouped
filename with
429 String.Map.set
grouped ~key
:filename ~data
:(file_msgs
@ [msg])
431 build_map msgs
grouped filenames
433 let grouped = String.Map.set
grouped ~key
:filename ~data
:[msg] in
434 build_map msgs
grouped (filename :: filenames
))
435 | [] -> (grouped, filenames
)
437 let (grouped, filenames
) = build_map msgs
String.Map.empty
[] in
438 List.concat_map
(List.rev filenames
) ~f
:(fun fn
->
439 String.Map.find_exn
grouped fn
)
441 (* Work out the column width needed for each file. Files with many
442 lines need a wider column due to the higher line numbers. *)
443 let col_widths (msgs
: Pos.absolute message list
) : int Core_kernel.String.Map.t
445 (* Find the longest line number for every file in msgs. *)
447 List.fold msgs ~init
:String.Map.empty ~f
:(fun acc
msg ->
448 let filename = Pos.filename (fst
msg) in
450 Option.value (String.Map.find acc
filename) ~default
:0
455 ~data
:(max
current_max (Pos.line (fst
msg))))
457 String.Map.map
longest_lines ~f
:column_width
459 (** Given a list of error messages, format them with context.
460 The list may not be ordered, and multiple messages may occur on one line.
462 let format_messages (msgs
: Pos.absolute message list
) : string =
463 let msgs = group_by_file msgs in
464 (* The first message is the 'primary' message, so add a boolean to distinguish it. *)
465 let rec label_first msgs is_first
=
467 | msg :: msgs -> (msg, is_first
) :: label_first msgs false
470 let labelled_msgs = label_first msgs true in
471 (* Sort messages by line number, so we can display with context. *)
472 let cmp (m1
, _
) (m2
, _
) =
473 match compare (Pos.filename (fst m1
)) (Pos.filename (fst m2
)) with
474 | 0 -> compare (Pos.line (fst m1
)) (Pos.line (fst m2
))
477 let sorted_msgs = List.stable_sort
cmp labelled_msgs in
478 (* For every message, show it alongside the relevant line. If there
479 are multiple messages associated with the line, only show it once. *)
480 let col_widths = col_widths msgs in
481 let rec aux msgs prev
: string list
=
483 | (msg, is_first
) :: msgs ->
484 let (pos
, err_msg
) = msg in
485 let filename = Pos.filename pos
in
486 let line = Pos.line pos
in
487 let col_width = String.Map.find
col_widths filename in
488 let (pretty_ctx, pretty_msg) =
489 format_message err_msg pos ~is_first ~
col_width
491 let formatted : string list
=
493 | Some
(prev_filename
, prev_line
)
494 when prev_filename
= filename && prev_line
= line ->
495 (* Previous message was on this line too, just show the message itself*)
497 | Some
(prev_filename
, _
) when prev_filename
= filename ->
498 (* Previous message was this file, but an earlier line. *)
499 [pretty_ctx; pretty_msg]
500 | _
-> [format_filename pos
; pretty_ctx; pretty_msg]
502 formatted @ aux msgs (Some
(filename, line))
505 String.concat ~sep
:"\n" (aux sorted_msgs None
) ^
"\n"
507 (* E.g. "10 errors found." *)
508 let format_summary format errors dropped_count max_errors
: string option =
511 let total = List.length errors
+ dropped_count
in
512 let formatted_total =
522 match max_errors
with
523 | Some max_errors
when dropped_count
> 0 ->
525 " (only showing first %d, dropped %d).\n"
530 Some
(formatted_total ^
truncated)
533 let to_contextual_string (error
: Pos.absolute error_
) : string =
534 let error_code = get_code error
in
535 let msgl = to_list error
in
536 let buf = Buffer.create
50 in
538 | [] -> failwith
"Impossible: an error always has non-empty list of messages"
544 (Tty.apply_color
(Tty.Bold
Tty.Red
) (error_code_to_string error_code))
545 (Tty.apply_color
(Tty.Bold
Tty.Default
) msg)));
546 (try Buffer.add_string
buf (format_messages msgl)
550 "Error could not be pretty-printed. Please file a bug.");
551 Buffer.add_string
buf "\n";
554 let to_absolute_for_test error
=
555 let (code
, msg_l) = (get_code error
, to_list error
) in
557 List.map
msg_l (fun (p
, s
) ->
558 let path = Pos.filename p
in
559 let path_without_prefix = Relative_path.suffix
path in
562 (Relative_path.create
Relative_path.Dummy
path_without_prefix)
565 (Pos.to_absolute p, s
))
569 let to_string ?
(indent
= false) (error
: Pos.absolute error_
) : string =
570 let (error_code, msgl) = (get_code error
, to_list error
) in
571 let buf = Buffer.create
50 in
574 | (pos1
, msg1
) :: rest_of_error
->
578 let error_code = error_code_to_string error_code in
579 Printf.sprintf
"%s\n%s (%s)\n" (Pos.string pos1
) msg1
error_code
587 List.iter rest_of_error
(fun (p, w
) ->
589 Printf.sprintf
"%s%s\n%s%s\n" indentstr (Pos.string p) indentstr w
591 Buffer.add_string
buf msg));
594 let add_error_impl error
=
595 if !accumulate_errors then
597 match !current_context with
599 when path = Relative_path.default
&& not
!allow_errors_in_default_path
602 "WARNING: adding an error in default path\n%s\n"
603 (Caml.Printexc.raw_backtrace_to_string
604 (Caml.Printexc.get_callstack
100))
607 (* Cheap test to avoid duplicating most recent error *)
608 let error_list = get_current_list !error_map
in
609 match error_list with
610 | old_error
:: _
when error
= old_error
-> ()
611 | _
-> set_current_list error_map
(error
:: error_list)
613 (* We have an error, but haven't handled it in any way *)
614 let msg = error
|> to_absolute |> to_string in
615 match !in_lazy_decl with
616 | Some _
-> lazy_decl_error_logging msg error_map
to_absolute to_string
617 | None
-> Utils.assert_false_log_backtrace
(Some
msg)
619 (* Whether we've found at least one error *)
620 let currently_has_errors () = get_current_list !error_map
<> []
622 module Parsing
= Error_codes.Parsing
623 module Naming
= Error_codes.Naming
624 module NastCheck
= Error_codes.NastCheck
625 module Typing
= Error_codes.Typing
627 (*****************************************************************************)
629 (*****************************************************************************)
631 type t
= error files_t
* applied_fixme files_t
[@@deriving eq
]
633 module type Error_category
= sig
640 val of_enum
: int -> t
option
642 val show
: t
-> string
644 val err_code
: t
-> int
647 (*****************************************************************************)
649 (*****************************************************************************)
651 let error_codes_treated_strictly = ref (ISet.of_list
[])
653 let is_strict_code code
= ISet.mem code
!error_codes_treated_strictly
655 (* The 'phps FixmeAllHackErrors' tool must be kept in sync with this list *)
656 let default_ignored_fixme_codes =
659 Typing.err_code
Typing.InvalidIsAsExpressionHint
;
660 Typing.err_code
Typing.InvalidEnforceableTypeArgument
;
661 Typing.err_code
Typing.RequireArgsReify
;
662 Typing.err_code
Typing.InvalidReifiedArgument
;
663 Typing.err_code
Typing.GenericsNotAllowed
;
664 Typing.err_code
Typing.InvalidNewableTypeArgument
;
665 Typing.err_code
Typing.InvalidNewableTypeParamConstraints
;
666 Typing.err_code
Typing.NewWithoutNewable
;
667 Typing.err_code
Typing.NewStaticClassReified
;
668 Typing.err_code
Typing.MemoizeReified
;
669 Typing.err_code
Typing.ClassGetReified
;
672 let ignored_fixme_codes = ref default_ignored_fixme_codes
674 let set_allow_errors_in_default_path x
= allow_errors_in_default_path := x
676 let is_ignored_code code
= ISet.mem code
!ignored_fixme_codes || code
/ 1000 = 5
678 let is_ignored_fixme code
= is_ignored_code code
680 let (get_hh_fixme_pos
: (Pos.t
-> error_code -> Pos.t
option) ref) =
681 ref (fun _ _
-> None
)
683 let (is_hh_fixme_disallowed
: (Pos.t
-> error_code -> bool) ref) =
684 ref (fun _ _
-> false)
686 let add_ignored_fixme_code_error pos code
=
687 if !is_hh_fixme_disallowed pos code
then
694 "You cannot use HH_FIXME or HH_IGNORE_ERROR comments to suppress error %d in declarations"
697 else if !is_hh_fixme pos code
&& is_ignored_code code
then
698 let pos = Option.value (!get_hh_fixme_pos
pos code
) ~default
:pos in
699 if code
/ 1000 = 5 then
706 "You cannot use HH_FIXME or HH_IGNORE_ERROR comments to suppress error %d.Please use @lint-ignore."
716 "You cannot use HH_FIXME or HH_IGNORE_ERROR comments to suppress error %d"
720 (*****************************************************************************)
721 (* Errors accumulator. *)
722 (*****************************************************************************)
724 (* If primary position in error list isn't in current file, wrap with a sentinel error *)
725 let check_pos_msg pos_msg_l
=
726 let pos = fst
(List.hd_exn pos_msg_l
) in
727 let current_file = fst
!current_context in
728 if current_file <> Relative_path.default
&& Pos.filename pos <> current_file
730 (Pos.make_from
current_file, Badpos_sentinel.message
) :: pos_msg_l
734 let rec add_applied_fixme code
pos =
735 if ServerLoadFlag.get_no_load
() then
736 let applied_fixmes_list = get_current_list !applied_fixmes in
737 set_current_list applied_fixmes ((pos, code
) :: applied_fixmes_list)
741 and add code
pos msg =
742 let pos_msg_l = check_pos_msg [(pos, msg)] in
743 if (not
(is_ignored_fixme code
)) && !is_hh_fixme
pos code
then
744 add_applied_fixme code
pos
746 add_error_impl (make_error code
pos_msg_l);
747 add_ignored_fixme_code_error pos code
749 and add_error_with_check
(error
: error
) : unit =
750 add_list
(fst error
) (snd error
)
752 and add_list code
pos_msg_l =
753 let pos = fst
(List.hd_exn
pos_msg_l) in
754 let pos_msg_l = check_pos_msg pos_msg_l in
755 if (not
(is_ignored_fixme code
)) && !is_hh_fixme
pos code
then
756 add_applied_fixme code
pos
758 add_error_impl (make_error code
pos_msg_l);
759 add_ignored_fixme_code_error pos code
761 and add_error
(code
, pos_msg_l) = add_list code
pos_msg_l
763 and merge
(err'
, fixmes'
) (err
, fixmes
) =
765 let x = Option.value x ~default
:[] in
766 let y = Option.value y ~default
:[] in
767 Some
(List.rev_append
x y)
769 (files_t_merge ~f
:append err' err
, files_t_merge ~f
:append fixmes' fixmes
)
771 and merge_into_current errors
=
772 let merged = merge errors
(!error_map
, !applied_fixmes) in
773 error_map
:= fst
merged;
774 applied_fixmes := snd
merged
776 and incremental_update
:
777 type (* Need to write out the entire ugly type to convince OCaml it's polymorphic
778 * and can update both error_map as well as applied_fixmes map *)
782 ((* function folding over paths of rechecked files *)
784 (Relative_path.t
-> a files_t
-> a files_t
) ->
788 fun old new_ fold phase
->
789 (* Helper to remove acc[path][phase]. If acc[path] becomes empty afterwards,
790 * remove it too (i.e do not store empty maps or lists ever). *)
791 let remove path phase acc
=
793 match Relative_path.Map.find_opt acc
path with
796 let new_phase_map = PhaseMap.remove phase_map phase
in
797 if PhaseMap.is_empty
new_phase_map then
802 match new_phase_map with
803 | None
-> Relative_path.Map.remove acc
path
804 | Some
x -> Relative_path.Map.add acc
path x
806 (* Replace old errors with new *)
808 files_t_merge new_ old ~f
:(fun phase
path new_ old
->
809 ( if path = Relative_path.default
then
813 | Parsing
-> "Parsing"
818 Utils.assert_false_log_backtrace
820 ( "Default (untracked) error sources should not get into incremental "
821 ^
"mode. There might be a missing call to Errors.do_with_context/"
822 ^
"run_in_context somwhere or incorrectly used Errors.from_error_list."
826 | Some new_
-> Some
(List.rev new_
)
829 (* For files that were rechecked, but had no errors - remove them from maps *)
830 fold
res (fun path acc
->
832 match Relative_path.Map.find_opt new_
path with
834 | Some phase_map
-> PhaseMap.mem phase_map
phase
839 remove path phase acc
)
841 and incremental_update_set ~old ~new_ ~rechecked
phase =
843 Relative_path.Set.fold
852 ( incremental_update
(fst old
) (fst new_
) fold phase,
853 incremental_update
(snd old
) (snd new_
) fold phase )
855 and incremental_update_map ~old ~new_ ~rechecked
phase =
857 Relative_path.Map.fold
866 ( incremental_update
(fst old
) (fst new_
) fold phase,
867 incremental_update
(snd old
) (snd new_
) fold phase )
869 and empty
= (Relative_path.Map.empty
, Relative_path.Map.empty
)
871 and is_empty
(err
, _fixmes
) = Relative_path.Map.is_empty err
873 and count
(err
, _fixmes
) =
874 files_t_fold err ~f
:(fun _ _
x acc
-> acc
+ List.length
x) ~init
:0
876 and get_error_list
(err
, _fixmes
) = files_t_to_list err
878 and get_applied_fixmes
(_err
, fixmes
) = files_t_to_list fixmes
880 and from_error_list err
= (list_to_files_t err
, Relative_path.Map.empty
)
882 (*****************************************************************************)
883 (* Accessors. (All methods delegated to the parameterized module.) *)
884 (*****************************************************************************)
886 let iter_error_list f err
= List.iter ~f
(get_sorted_error_list err
)
888 let fold_errors ?
phase err ~init ~f
=
891 files_t_fold (fst err
) ~init ~f
:(fun source _ errors acc
->
892 List.fold_right errors ~init
:acc ~f
:(f source
))
894 Relative_path.Map.fold (fst err
) ~init ~f
:(fun source phases acc
->
895 match PhaseMap.find_opt phases
phase with
897 | Some errors
-> List.fold_right errors ~init
:acc ~f
:(f source
))
899 let fold_errors_in ?
phase err ~source ~init ~f
=
900 Relative_path.Map.find_opt
(fst err
) source
901 |> Option.value ~default
:PhaseMap.empty
902 |> PhaseMap.fold ~init ~f
:(fun p errors acc
->
903 if phase <> None
&& phase <> Some
p then
906 List.fold_right errors ~init
:acc ~f
)
908 let get_failed_files err
phase =
909 files_t_fold (fst err
) ~init
:Relative_path.Set.empty ~f
:(fun source
p _ acc
->
913 Relative_path.Set.add acc source
)
915 (*****************************************************************************)
916 (* Error code printing. *)
917 (*****************************************************************************)
919 let internal_error pos msg = add
0 pos ("Internal error: " ^
msg)
921 let unimplemented_feature pos msg = add
0 pos ("Feature not implemented: " ^
msg)
923 let experimental_feature pos msg =
924 add
0 pos ("Cannot use experimental feature: " ^
msg)
926 let strip_ns id
= id
|> Utils.strip_ns |> Hh_autoimport.reverse_type
928 (*****************************************************************************)
929 (* Parsing errors. *)
930 (*****************************************************************************)
932 let fixme_format pos =
934 (Parsing.err_code
Parsing.FixmeFormat
)
936 "HH_FIXME wrong format, expected '/* HH_FIXME[ERROR_NUMBER] */'"
938 let parsing_error (p, msg) = add
(Parsing.err_code
Parsing.ParsingError
) p msg
940 (*****************************************************************************)
941 (* Legacy AST / AAST errors *)
942 (*****************************************************************************)
944 let mk_unsupported_trait_use_as pos =
945 ( Naming.err_code
Naming.UnsupportedTraitUseAs
,
946 [(pos, "Trait use as is a PHP feature that is unsupported in Hack")] )
948 let unsupported_trait_use_as pos =
949 add_error_with_check
(mk_unsupported_trait_use_as pos)
951 let mk_unsupported_instead_of pos =
952 ( Naming.err_code
Naming.UnsupportedInsteadOf
,
953 [(pos, "insteadof is a PHP feature that is unsupported in Hack")] )
955 let unsupported_instead_of pos =
956 add_error_with_check
(mk_unsupported_instead_of pos)
958 let mk_invalid_trait_use_as_visibility pos =
959 ( Naming.err_code
Naming.InvalidTraitUseAsVisibility
,
960 [(pos, "Cannot redeclare trait method's visibility in this manner")] )
962 let invalid_trait_use_as_visibility pos =
963 add_error_with_check
(mk_invalid_trait_use_as_visibility pos)
965 (*****************************************************************************)
967 (*****************************************************************************)
969 let unexpected_arrow pos cname
=
971 (Naming.err_code
Naming.UnexpectedArrow
)
973 ("Keys may not be specified for " ^ cname ^
" initialization")
975 let missing_arrow pos cname
=
977 (Naming.err_code
Naming.MissingArrow
)
979 ("Keys must be specified for " ^ cname ^
" initialization")
981 let disallowed_xhp_type pos name
=
983 (Naming.err_code
Naming.DisallowedXhpType
)
985 (name ^
" is not a valid type. Use :xhp or XHPChild.")
987 let name_is_reserved name
pos =
988 let name = Utils.strip_all_ns
name in
990 (Naming.err_code
Naming.NameIsReserved
)
992 (name ^
" cannot be used as it is reserved.")
994 let dollardollar_unused pos =
996 (Naming.err_code
Naming.DollardollarUnused
)
998 ( "This expression does not contain a "
999 ^
"usage of the special pipe variable. Did you forget to use the ($$) "
1002 let method_name_already_bound pos name =
1004 (Naming.err_code
Naming.MethodNameAlreadyBound
)
1006 ("Method name already bound: " ^
name)
1008 let reference_in_rx pos =
1010 (Naming.err_code
Naming.ReferenceInRx
)
1012 "References are not allowed in reactive code."
1014 let error_name_already_bound name name_prev
p p_prev
=
1015 let name = strip_ns name in
1016 let name_prev = strip_ns name_prev in
1019 (p, "Name already bound: " ^
name);
1021 if String.compare name name_prev = 0 then
1022 "Previous definition is here"
1024 "Previous definition "
1026 ^
" differs only in capitalization " );
1030 "This appears to be defined in an hhi file included in your project "
1031 ^
"root. The hhi files for the standard library are now a part of the "
1032 ^
"typechecker and must be removed from your project. Typically, you can "
1033 ^
"do this by deleting the \"hhi\" directory you copied into your "
1034 ^
"project when first starting with Hack."
1037 if Relative_path.prefix
(Pos.filename p) = Relative_path.Hhi
then
1038 errs @ [(p_prev
, hhi_msg)]
1039 else if Relative_path.prefix
(Pos.filename p_prev
) = Relative_path.Hhi
then
1040 errs @ [(p, hhi_msg)]
1044 add_list
(Naming.err_code
Naming.ErrorNameAlreadyBound
) errs
1046 let error_class_attribute_already_bound name name_prev p p_prev
=
1047 let name = strip_ns name in
1048 let name_prev = strip_ns name_prev in
1052 "A class and an attribute class cannot share the same name. Conflicting class: "
1054 (p_prev
, "Previous definition: " ^
name_prev);
1057 add_list
(Naming.err_code
Naming.AttributeClassNameConflict
) errs
1059 let unbound_name pos name kind
=
1062 | `cls
-> "an object type"
1063 | `func
-> "a global function"
1064 | `const
-> "a global constant"
1065 | `record
-> "a record type"
1068 (Naming.err_code
Naming.UnboundName
)
1070 ("Unbound name: " ^
strip_ns name ^
" (" ^
kind_str ^
")")
1072 let invalid_fun_pointer pos name =
1074 (Naming.err_code
Naming.InvalidFunPointer
)
1076 ( "Unbound global function: '"
1078 ^
"' is not a valid name for fun()" )
1080 let rx_move_invalid_location pos =
1082 (Naming.err_code
Naming.RxMoveInvalidLocation
)
1084 "Rx\\move is only allowed in argument position or as right hand side of the assignment."
1086 let undefined ~in_rx_scope
pos var_name did_you_mean
=
1090 "Variable %s is undefined, not always defined, or unset afterwards"
1093 Printf.sprintf
"Variable %s is undefined, or not always defined" var_name
1096 match did_you_mean
with
1097 | Some var_name
-> Printf.sprintf
" (did you mean %s instead?)" var_name
1100 add_list
(Naming.err_code
Naming.Undefined
) [(pos, msg ^
suggestion)]
1102 let this_reserved pos =
1104 (Naming.err_code
Naming.ThisReserved
)
1106 "The type parameter \"this\" is reserved"
1108 let start_with_T pos =
1110 (Naming.err_code
Naming.StartWith_T
)
1112 "Please make your type parameter start with the letter T (capital)"
1114 let already_bound pos name =
1116 (Naming.err_code
Naming.NameAlreadyBound
)
1118 ("Argument already bound: " ^
name)
1120 let unexpected_typedef pos def_pos
=
1122 (Naming.err_code
Naming.UnexpectedTypedef
)
1123 [(pos, "Unexpected typedef"); (def_pos
, "Definition is here")]
1125 let mk_fd_name_already_bound pos =
1126 ( Naming.err_code
Naming.FdNameAlreadyBound
,
1127 [(pos, "Field name already bound")] )
1129 let fd_name_already_bound pos =
1130 add_error_with_check
(mk_fd_name_already_bound pos)
1132 let repeated_record_field name pos prev_pos
=
1133 let msg = Printf.sprintf
"Duplicate record field `%s`" name in
1135 (NastCheck.err_code
NastCheck.RepeatedRecordFieldName
)
1136 [(pos, msg); (prev_pos
, "Previous field is here")]
1138 let unexpected_record_field_name ~field_name ~field_pos ~record_name ~decl_pos
=
1141 "Record `%s` has no field `%s`"
1142 (strip_ns record_name
)
1146 (Typing.err_code
Typing.RecordUnknownField
)
1147 [(field_pos
, msg); (decl_pos
, "Definition is here")]
1149 let missing_record_field_name ~field_name ~new_pos ~record_name ~field_decl_pos
1153 "Mising required field `%s` in `%s`"
1155 (strip_ns record_name
)
1158 (Typing.err_code
Typing.RecordMissingRequiredField
)
1159 [(new_pos
, msg); (field_decl_pos
, "Field definition is here")]
1161 let primitive_toplevel pos =
1163 (Naming.err_code
Naming.PrimitiveToplevel
)
1165 "Primitive type annotations are always available and may no longer be referred to in the toplevel namespace."
1167 let primitive_invalid_alias pos used valid
=
1169 (Naming.err_code
Naming.PrimitiveInvalidAlias
)
1171 ( "Invalid Hack type. Using '"
1173 ^
"' in Hack is considered an error. Use '"
1175 ^
"' instead, to keep the codebase consistent." )
1177 let dynamic_new_in_strict_mode pos =
1179 (Naming.err_code
Naming.DynamicNewInStrictMode
)
1181 "Cannot use dynamic new in strict mode"
1183 let invalid_type_access_root (pos, id
) =
1185 (Naming.err_code
Naming.InvalidTypeAccessRoot
)
1187 (id ^
" must be an identifier for a class, \"self\", or \"this\"")
1189 let duplicate_user_attribute (pos, name) existing_attr_pos
=
1191 (Naming.err_code
Naming.DuplicateUserAttribute
)
1193 (pos, "You cannot reuse the attribute " ^
name);
1194 (existing_attr_pos
, name ^
" was already used here");
1197 let unbound_attribute_name pos name =
1199 if string_starts_with
name "__" then
1200 "starts with __ but is not a standard attribute"
1202 "does not have a class. Please declare a class for the attribute."
1205 (Naming.err_code
Naming.UnboundName
)
1207 ("Unrecognized user attribute: " ^
strip_ns name ^
" " ^
reason)
1209 let this_no_argument pos =
1211 (Naming.err_code
Naming.ThisNoArgument
)
1213 "\"this\" expects no arguments"
1215 let object_cast pos cls_opt
=
1216 let msg1 = "Object casts are unsupported." in
1220 " Try 'if ($var instanceof "
1222 ^
")' or 'invariant($var instanceof "
1227 add
(Naming.err_code
Naming.ObjectCast
) pos (msg1 ^
msg2)
1229 let this_hint_outside_class pos =
1231 (Naming.err_code
Naming.ThisHintOutsideClass
)
1233 "Cannot use \"this\" outside of a class"
1235 let this_type_forbidden pos =
1237 (Naming.err_code
Naming.ThisMustBeReturn
)
1239 "The type \"this\" cannot be used as a constraint on a class' generic, or as the type of a static member variable"
1241 let nonstatic_property_with_lsb pos =
1243 (Naming.err_code
Naming.NonstaticPropertyWithLSB
)
1245 "__LSB attribute may only be used on static properties"
1247 let lowercase_this pos type_
=
1249 (Naming.err_code
Naming.LowercaseThis
)
1251 ("Invalid Hack type \"" ^ type_ ^
"\". Use \"this\" instead")
1253 let classname_param pos =
1255 (Naming.err_code
Naming.ClassnameParam
)
1257 ( "Missing type parameter to classname; classname is entirely"
1258 ^
" meaningless without one" )
1260 let tparam_with_tparam pos x =
1262 (Naming.err_code
Naming.TparamWithTparam
)
1265 "%s is a type parameter. Type parameters cannot themselves take type parameters (e.g. %s<int> doesn't make sense)"
1269 let shadowed_type_param p pos name =
1271 (Naming.err_code
Naming.ShadowedTypeParam
)
1273 (p, Printf.sprintf
"You cannot re-bind the type parameter %s" name);
1274 (pos, Printf.sprintf
"%s is already bound here" name);
1277 let missing_typehint pos =
1278 add
(Naming.err_code
Naming.MissingTypehint
) pos "Please add a type hint"
1280 let expected_variable pos =
1282 (Naming.err_code
Naming.ExpectedVariable
)
1284 "Was expecting a variable name"
1286 let clone_too_many_arguments pos =
1288 (Naming.err_code
Naming.NamingTooManyArguments
)
1290 "__clone method cannot take arguments"
1292 let naming_too_few_arguments pos =
1293 add
(Naming.err_code
Naming.NamingTooFewArguments
) pos "Too few arguments"
1295 let naming_too_many_arguments pos =
1296 add
(Naming.err_code
Naming.NamingTooManyArguments
) pos "Too many arguments"
1298 let expected_collection pos cn
=
1300 (Naming.err_code
Naming.ExpectedCollection
)
1302 ("Unexpected collection type " ^
strip_ns cn
)
1304 let illegal_CLASS pos =
1306 (Naming.err_code
Naming.IllegalClass
)
1308 "Using __CLASS__ outside a class or trait"
1310 let illegal_TRAIT pos =
1312 (Naming.err_code
Naming.IllegalTrait
)
1314 "Using __TRAIT__ outside a trait"
1316 let lvar_in_obj_get pos =
1318 (Naming.err_code
Naming.LvarInObjGet
)
1320 "Dynamic method or attribute access is not allowed on a non-dynamic value."
1322 let nullsafe_property_write_context pos =
1324 (Typing.err_code
Typing.NullsafePropertyWriteContext
)
1326 "?-> syntax not supported here, this function effectively does a write"
1328 let illegal_fun pos =
1330 "The argument to fun() must be a single-quoted, constant "
1331 ^
"literal string representing a valid function name."
1333 add
(Naming.err_code
Naming.IllegalFun
) pos msg
1335 let illegal_member_variable_class pos =
1337 "Cannot declare a constant named 'class'. The name 'class' is reserved for the class constant that represents the name of the class"
1339 add
(Naming.err_code
Naming.IllegalMemberVariableClass
) pos msg
1341 let illegal_meth_fun pos =
1343 "String argument to fun() contains ':';"
1344 ^
" for static class methods, use"
1345 ^
" class_meth(Cls::class, 'method_name'), not fun('Cls::method_name')"
1347 add
(Naming.err_code
Naming.IllegalMethFun
) pos msg
1349 let illegal_inst_meth pos =
1351 "The argument to inst_meth() must be an expression and a "
1352 ^
"constant literal string representing a valid method name."
1354 add
(Naming.err_code
Naming.IllegalInstMeth
) pos msg
1356 let illegal_meth_caller pos =
1358 "The two arguments to meth_caller() must be:"
1359 ^
"\n - first: ClassOrInterface::class"
1360 ^
"\n - second: a single-quoted string literal containing the name"
1361 ^
" of a non-static method of that class"
1363 add
(Naming.err_code
Naming.IllegalMethCaller
) pos msg
1365 let illegal_class_meth pos =
1367 "The two arguments to class_meth() must be:"
1368 ^
"\n - first: ValidClassname::class"
1369 ^
"\n - second: a single-quoted string literal containing the name"
1370 ^
" of a static method of that class"
1372 add
(Naming.err_code
Naming.IllegalClassMeth
) pos msg
1374 let assert_arity pos =
1376 (Naming.err_code
Naming.AssertArity
)
1378 "assert expects exactly one argument"
1380 let unexpected_ty_in_tast pos ~actual_ty ~expected_ty
=
1382 (Typing.err_code
Typing.UnexpectedTy
)
1384 ("Unexpected type in TAST: expected " ^ expected_ty ^
", got " ^ actual_ty
)
1386 let uninstantiable_class usage_pos decl_pos
name reason_msgl
=
1387 let name = strip_ns name in
1390 (usage_pos
, name ^
" is uninstantiable"); (decl_pos
, "Declaration is here");
1394 match reason_msgl
with
1395 | (reason_pos
, reason_str
) :: tail
->
1396 ((reason_pos
, reason_str ^
" which must be instantiable") :: tail
) @ msgl
1399 add_list
(Typing.err_code
Typing.UninstantiableClass
) msgl
1401 let new_abstract_record (pos, name) =
1402 let name = strip_ns name in
1404 (Typing.err_code
Typing.NewAbstractRecord
)
1406 (Printf.sprintf
"Cannot create instance of abstract record `%s`" name)
1408 let abstract_const_usage usage_pos decl_pos
name =
1409 let name = strip_ns name in
1411 (Typing.err_code
Typing.AbstractConstUsage
)
1413 (usage_pos
, "Cannot reference abstract constant " ^
name ^
" directly");
1414 (decl_pos
, "Declaration is here");
1417 let const_without_typehint sid
=
1418 let (pos, name) = sid
in
1421 "Please add a type hint 'const SomeType %s'"
1422 (Utils.strip_all_ns
name)
1424 add
(Naming.err_code
Naming.AddATypehint
) pos msg
1426 let prop_without_typehint visibility sid
=
1427 let (pos, name) = sid
in
1429 Printf.sprintf
"Please add a type hint '%s SomeType %s'" visibility
name
1431 add
(Naming.err_code
Naming.AddATypehint
) pos msg
1433 let illegal_constant pos =
1434 add
(Naming.err_code
Naming.IllegalConstant
) pos "Illegal constant value"
1436 let invalid_req_implements pos =
1438 (Naming.err_code
Naming.InvalidReqImplements
)
1440 "Only traits may use 'require implements'"
1442 let invalid_req_extends pos =
1444 (Naming.err_code
Naming.InvalidReqExtends
)
1446 "Only traits and interfaces may use 'require extends'"
1448 let did_you_mean_naming pos name suggest_pos suggest_name
=
1450 (Naming.err_code
Naming.DidYouMeanNaming
)
1452 (pos, "Could not find " ^
strip_ns name);
1453 (suggest_pos
, "Did you mean " ^
strip_ns suggest_name ^
"?");
1456 let using_internal_class pos name =
1458 (Naming.err_code
Naming.UsingInternalClass
)
1460 (name ^
" is an implementation internal class that cannot be used directly")
1462 let too_few_type_arguments p =
1464 (Naming.err_code
Naming.TooFewTypeArguments
)
1466 "Too few type arguments for this type"
1468 let goto_label_already_defined
1469 label_name redeclaration_pos original_delcaration_pos
=
1471 (Naming.err_code
Naming.GotoLabelAlreadyDefined
)
1473 (redeclaration_pos
, "Cannot redeclare the goto label '" ^ label_name ^
"'");
1474 (original_delcaration_pos
, "Declaration is here");
1477 let goto_label_undefined pos label_name
=
1479 (Naming.err_code
Naming.GotoLabelUndefined
)
1481 ("Undefined goto label: " ^ label_name
)
1483 let goto_label_defined_in_finally pos =
1485 (Naming.err_code
Naming.GotoLabelDefinedInFinally
)
1487 "It is illegal to define a goto label within a finally block."
1489 let goto_invoked_in_finally pos =
1491 (Naming.err_code
Naming.GotoInvokedInFinally
)
1493 "It is illegal to invoke goto within a finally block."
1495 let mk_method_needs_visibility pos =
1496 ( Naming.err_code
Naming.MethodNeedsVisibility
,
1497 [(pos, "Methods need to be marked public, private, or protected.")] )
1499 let method_needs_visibility pos =
1500 add_error_with_check
(mk_method_needs_visibility pos)
1502 let dynamic_class_name_in_strict_mode pos =
1504 (Naming.err_code
Naming.DynamicClassNameInStrictMode
)
1506 "Cannot use dynamic class name in strict mode"
1508 let xhp_optional_required_attr pos id
=
1510 (Naming.err_code
Naming.XhpOptionalRequiredAttr
)
1512 ("XHP attribute " ^ id ^
" cannot be marked as nullable and required")
1514 let xhp_required_with_default pos id
=
1516 (Naming.err_code
Naming.XhpRequiredWithDefault
)
1520 ^
" cannot be marked as required and provide a default" )
1522 let array_typehints_disallowed pos =
1524 (Naming.err_code
Naming.ArrayTypehintsDisallowed
)
1526 "Array typehints are no longer legal; use varray or darray instead"
1528 let array_literals_disallowed pos =
1530 (Naming.err_code
Naming.ArrayLiteralsDisallowed
)
1532 "Array literals are no longer legal; use varray or darray instead"
1534 let wildcard_disallowed pos =
1536 (Naming.err_code
Naming.WildcardDisallowed
)
1538 "Wildcard typehints are not allowed in this position"
1540 let reference_in_strict_mode pos =
1541 add
(Naming.err_code
Naming.ReferenceInStrictMode
) pos "Don't use references!"
1543 let misplaced_mutability_hint pos =
1545 (Naming.err_code
Naming.MisplacedMutabilityHint
)
1547 "Setting mutability via type hints is only allowed for parameters of reactive function types. For other cases consider using attributes."
1549 let mutability_hint_in_non_rx_function pos =
1551 (Naming.err_code
Naming.MutabilityHintInNonRx
)
1553 "Parameter with mutability hint cannot appear in non-reactive function type."
1555 let invalid_mutability_in_return_type_hint pos =
1557 (Naming.err_code
Naming.InvalidReturnMutableHint
)
1559 "OwnedMutable is the only mutability related hint allowed in return type annotation for reactive function types."
1561 let pu_duplication pos kind
name seen
=
1562 let name = strip_ns name in
1563 let seen = strip_ns seen in
1565 (Naming.err_code
Naming.PocketUniversesDuplication
)
1567 (sprintf
"Pocket Universe %s %s is already declared in %s" kind
name seen)
1569 let pu_not_in_class pos name loc
=
1570 let name = strip_ns name in
1571 let loc = strip_ns loc in
1573 (Naming.err_code
Naming.PocketUniversesNotInClass
)
1575 (sprintf
"Pocket Universe %s is defined outside a class (%s)" name loc)
1577 let pu_atom_missing pos name kind
loc missing
=
1578 let name = strip_ns name in
1579 let loc = strip_ns loc in
1581 (Naming.err_code
Naming.PocketUniversesAtomMissing
)
1584 "In Pocket Universe %s, atom %s is missing %s %s"
1590 let pu_atom_unknown pos name kind
loc unk
=
1591 let name = strip_ns name in
1592 let loc = strip_ns loc in
1594 (Naming.err_code
Naming.PocketUniversesAtomUnknown
)
1597 "In Pocket Universe %s, atom %s declares unknown %s %s"
1603 let illegal_use_of_dynamically_callable attr_pos meth_pos visibility
=
1605 (Naming.err_code
Naming.IllegalUseOfDynamicallyCallable
)
1607 (attr_pos
, "__DynamicallyCallable can only be used on public methods");
1608 (meth_pos
, sprintf
"But this method is %s" visibility
);
1611 (*****************************************************************************)
1612 (* Init check errors *)
1613 (*****************************************************************************)
1615 let no_construct_parent pos =
1617 (NastCheck.err_code
NastCheck.NoConstructParent
)
1621 "You are extending a class that needs to be initialized\n";
1622 "Make sure you call parent::__construct.\n";
1625 let nonstatic_method_in_abstract_final_class pos =
1627 (NastCheck.err_code
NastCheck.NonstaticMethodInAbstractFinalClass
)
1629 "Abstract final classes cannot have nonstatic methods or constructors."
1631 let constructor_required (pos, name) prop_names
=
1632 let name = strip_ns name in
1634 SSet.fold ~f
:(fun x acc
-> x ^
" " ^ acc
) prop_names ~init
:""
1637 (NastCheck.err_code
NastCheck.ConstructorRequired
)
1639 ( "Lacking __construct, class "
1641 ^
" does not initialize its private member(s): "
1644 let not_initialized (pos, cname
) prop_names
=
1645 let cname = strip_ns cname in
1647 List.fold_right prop_names ~f
:(fun x acc
-> x ^
" " ^ acc
) ~init
:""
1649 let (members
, verb
) =
1650 if 1 = List.length prop_names
then
1658 ~f
:(fun x acc
-> "$this->" ^
x ^
" " ^ acc
)
1662 (NastCheck.err_code
NastCheck.NotInitialized
)
1668 " does not initialize all of its members; ";
1671 " not always initialized.";
1672 "\nMake sure you systematically set ";
1674 "when the method __construct is called.";
1675 "\nAlternatively, you can define the ";
1677 " as optional (?...)\n";
1680 let call_before_init pos cv
=
1682 (NastCheck.err_code
NastCheck.CallBeforeInit
)
1686 "Until the initialization of $this is over,";
1687 " you can only call private methods\n";
1688 "The initialization is not over because ";
1691 if cv
= "parent::__construct" then
1692 ["you forgot to call parent::__construct"]
1694 ["$this->"; cv
; " can still potentially be null"] ))
1696 (*****************************************************************************)
1697 (* Nast errors check *)
1698 (*****************************************************************************)
1700 let type_arity pos name nargs c_pos
=
1702 (Typing.err_code
Typing.TypeArityMismatch
)
1705 "The type " ^
strip_ns name ^
" expects " ^ nargs ^
" type parameter(s)"
1707 (c_pos
, "Definition is here");
1710 let abstract_with_body (p, _
) =
1712 (NastCheck.err_code
NastCheck.AbstractWithBody
)
1714 "This method is declared as abstract, but has a body"
1716 let not_abstract_without_body (p, _
) =
1718 (NastCheck.err_code
NastCheck.NotAbstractWithoutBody
)
1720 "This method is not declared as abstract, it must have a body"
1722 let mk_not_abstract_without_typeconst (p, _
) =
1723 ( NastCheck.err_code
NastCheck.NotAbstractWithoutTypeconst
,
1726 "This type constant is not declared as abstract, it must have"
1727 ^
" an assigned type" );
1730 let not_abstract_without_typeconst node
=
1731 add_error_with_check
(mk_not_abstract_without_typeconst node
)
1733 let typeconst_depends_on_external_tparam pos ext_pos ext_name
=
1735 (NastCheck.err_code
NastCheck.TypeconstDependsOnExternalTparam
)
1738 "A type constant can only use type parameters declared in its own"
1739 ^
" type parameter list" );
1740 (ext_pos
, ext_name ^
" was declared as a type parameter here");
1743 let interface_with_partial_typeconst tconst_pos
=
1745 (NastCheck.err_code
NastCheck.InterfaceWithPartialTypeconst
)
1747 "An interface cannot contain a partially abstract type constant"
1749 let mk_multiple_xhp_category pos =
1750 ( NastCheck.err_code
NastCheck.MultipleXhpCategory
,
1751 [(pos, "XHP classes can only contain one category declaration")] )
1753 let multiple_xhp_category pos =
1754 add_error_with_check
(mk_multiple_xhp_category pos)
1756 let return_in_gen p =
1758 (NastCheck.err_code
NastCheck.ReturnInGen
)
1760 ( "You cannot return a value in a generator (a generator"
1761 ^
" is a function that uses yield)" )
1763 let return_in_finally p =
1765 (NastCheck.err_code
NastCheck.ReturnInFinally
)
1767 ( "Don't use return in a finally block;"
1768 ^
" there's nothing to receive the return value" )
1770 let toplevel_break p =
1772 (NastCheck.err_code
NastCheck.ToplevelBreak
)
1774 "break can only be used inside loops or switch statements"
1776 let toplevel_continue p =
1778 (NastCheck.err_code
NastCheck.ToplevelContinue
)
1780 "continue can only be used inside loops"
1782 let continue_in_switch p =
1784 (NastCheck.err_code
NastCheck.ContinueInSwitch
)
1786 ( "In PHP, 'continue;' inside a switch statement is equivalent to 'break;'."
1787 ^
" Hack does not support this; use 'break' if that is what you meant." )
1789 let await_in_sync_function p =
1791 (NastCheck.err_code
NastCheck.AwaitInSyncFunction
)
1793 "await can only be used inside async functions"
1795 let interface_use_trait p =
1797 (NastCheck.err_code
NastCheck.InterfaceUsesTrait
)
1799 "Interfaces cannot use traits"
1801 let await_in_coroutine p =
1803 (NastCheck.err_code
NastCheck.AwaitInCoroutine
)
1805 "await is not allowed in coroutines."
1807 let yield_in_coroutine p =
1809 (NastCheck.err_code
NastCheck.YieldInCoroutine
)
1811 "yield is not allowed in coroutines."
1813 let suspend_outside_of_coroutine p =
1815 (NastCheck.err_code
NastCheck.SuspendOutsideOfCoroutine
)
1817 "suspend is only allowed in coroutines."
1819 let suspend_in_finally p =
1821 (NastCheck.err_code
NastCheck.SuspendInFinally
)
1823 "suspend is not allowed inside finally blocks."
1825 let static_memoized_function p =
1827 (NastCheck.err_code
NastCheck.StaticMemoizedFunction
)
1829 "memoize is not allowed on static methods in classes that aren't final "
1833 (NastCheck.err_code
NastCheck.Magic
)
1835 (s ^
" is a magic method and cannot be called directly")
1837 let non_interface (p : Pos.t
) (c2
: string) (verb
: string) : 'a
=
1839 (NastCheck.err_code
NastCheck.NonInterface
)
1841 ("Cannot " ^ verb ^
" " ^
strip_ns c2 ^
" - it is not an interface")
1843 let toString_returns_string pos =
1845 (NastCheck.err_code
NastCheck.ToStringReturnsString
)
1847 "__toString should return a string"
1849 let toString_visibility pos =
1851 (NastCheck.err_code
NastCheck.ToStringVisibility
)
1853 "__toString must have public visibility and cannot be static"
1855 let uses_non_trait (p : Pos.t
) (n
: string) (t
: string) =
1857 (NastCheck.err_code
NastCheck.UsesNonTrait
)
1859 (strip_ns n ^
" is not a trait. It is " ^ t ^
".")
1861 let requires_non_class (p : Pos.t
) (n
: string) (t
: string) =
1863 (NastCheck.err_code
NastCheck.RequiresNonClass
)
1865 (strip_ns n ^
" is not a class. It is " ^ t ^
".")
1867 let requires_final_class (p : Pos.t
) (n
: string) =
1869 (NastCheck.err_code
NastCheck.RequiresFinalClass
)
1871 (strip_ns n ^
" is not an extendable class.")
1873 let abstract_body pos =
1875 (NastCheck.err_code
NastCheck.AbstractBody
)
1877 "This method shouldn't have a body"
1879 let not_public_or_protected_interface pos =
1881 (NastCheck.err_code
NastCheck.NotPublicInterface
)
1883 "Access type for interface method must be public or protected."
1885 let interface_with_member_variable pos =
1887 (NastCheck.err_code
NastCheck.InterfaceWithMemberVariable
)
1889 "Interfaces cannot have member variables"
1891 let interface_with_static_member_variable pos =
1893 (NastCheck.err_code
NastCheck.InterfaceWithStaticMemberVariable
)
1895 "Interfaces cannot have static variables"
1897 let illegal_function_name pos mname
=
1899 (NastCheck.err_code
NastCheck.IllegalFunctionName
)
1901 ("Illegal function name: " ^
strip_ns mname
)
1903 let inout_params_outside_of_sync pos =
1905 (NastCheck.err_code
NastCheck.InoutParamsOutsideOfSync
)
1907 ( "Inout parameters cannot be defined on async functions, "
1908 ^
"generators or coroutines." )
1910 let mutable_attribute_on_function pos =
1912 (NastCheck.err_code
NastCheck.MutableAttributeOnFunction
)
1914 "<<__Mutable>> only makes sense on methods, or parameters on functions or methods."
1916 let maybe_mutable_attribute_on_function pos =
1918 (NastCheck.err_code
NastCheck.MaybeMutableAttributeOnFunction
)
1920 "<<__MaybeMutable>> only makes sense on methods, or parameters on functions or methods."
1922 let conflicting_mutable_and_maybe_mutable_attributes pos =
1924 (NastCheck.err_code
NastCheck.ConflictingMutableAndMaybeMutableAttributes
)
1926 "Declaration cannot have both <<__Mutable>> and <<__MaybeMutable>> attributtes."
1928 let mutable_methods_must_be_reactive pos name =
1930 (NastCheck.err_code
NastCheck.MutableMethodsMustBeReactive
)
1934 ^
" has a mutable parameter"
1935 ^
" (or mutable this), so it must be marked reactive with <<__Rx>>." )
1937 let mutable_return_annotated_decls_must_be_reactive kind
pos name =
1939 (NastCheck.err_code
NastCheck.MutableReturnAnnotatedDeclsMustBeReactive
)
1945 ^
" is annotated with <<__MutableReturn>>, "
1946 ^
" so it must be marked reactive with <<__Rx>>." )
1948 let maybe_mutable_methods_must_be_reactive pos name =
1950 (NastCheck.err_code
NastCheck.MaybeMutableMethodsMustBeReactive
)
1954 ^
" is annotated with <<__MaybeMutable> attribute, or has this attribute on one of parameters so it must be marked reactive."
1957 let inout_params_special pos =
1959 (NastCheck.err_code
NastCheck.InoutParamsSpecial
)
1961 "Methods with special semantics cannot have inout parameters."
1963 let inout_params_mix_byref pos1 pos2
=
1964 if pos1
<> pos2
then
1965 let msg1 = (pos1
, "Cannot mix inout and byRef parameters") in
1966 let msg2 = (pos2
, "This parameter is passed by reference") in
1967 add_list
(NastCheck.err_code
NastCheck.InoutParamsMixByref
) [msg1; msg2]
1969 let inout_params_memoize fpos
pos =
1970 let msg1 = (fpos
, "Functions with inout parameters cannot be memoized") in
1971 let msg2 = (pos, "This is an inout parameter") in
1972 add_list
(NastCheck.err_code
NastCheck.InoutParamsMemoize
) [msg1; msg2]
1974 let reading_from_append pos =
1976 (NastCheck.err_code
NastCheck.ReadingFromAppend
)
1978 "Cannot use [] for reading"
1980 let inout_argument_bad_expr pos =
1982 (NastCheck.err_code
NastCheck.InoutArgumentBadExpr
)
1984 ( "Arguments for inout parameters must be local variables or simple "
1985 ^
"subscript expressions on vecs, dicts, keysets, or arrays" )
1987 let illegal_destructor pos =
1989 (NastCheck.err_code
NastCheck.IllegalDestructor
)
1991 ( "Destructors are not supported in Hack; use other patterns like "
1992 ^
"IDisposable/using or try/catch instead." )
1994 let multiple_conditionally_reactive_annotations pos name =
1996 (NastCheck.err_code
NastCheck.MultipleConditionallyReactiveAnnotations
)
1998 ("Method '" ^
name ^
"' has multiple <<__OnlyRxIfImpl>> annotations.")
2000 let rx_is_enabled_invalid_location pos =
2002 (NastCheck.err_code
NastCheck.RxIsEnabledInvalidLocation
)
2004 ( "HH\\Rx\\IS_ENABLED must be the only condition in an if-statement, "
2005 ^
"and that if-statement must be the only statement in the function body."
2008 let atmost_rx_as_rxfunc_invalid_location pos =
2010 (NastCheck.err_code
NastCheck.MaybeRxInvalidLocation
)
2012 "<<__AtMostRxAsFunc>> attribute can only be put on parameters of conditionally reactive function or method annotated with <<__AtMostRxAsArgs>> attribute."
2014 let no_atmost_rx_as_rxfunc_for_rx_if_args pos =
2016 (NastCheck.err_code
NastCheck.NoOnlyrxIfRxfuncForRxIfArgs
)
2018 "Function or method annotated with <<__AtMostRxAsArgs>> attribute should have at least one parameter with <<__AtMostRxAsFunc>> or <<__OnlyRxIfImpl>> annotations."
2020 let conditionally_reactive_annotation_invalid_arguments ~is_method
pos =
2029 NastCheck.ConditionallyReactiveAnnotationInvalidArguments
)
2032 ^
" is marked with <<__OnlyRxIfImpl>> attribute that have "
2033 ^
"invalid arguments. This attribute must have one argument and it should be "
2034 ^
"'::class' class constant." )
2036 let coroutine_in_constructor pos =
2038 (NastCheck.err_code
NastCheck.CoroutineInConstructor
)
2040 "A class constructor may not be a coroutine"
2042 let illegal_by_ref_expr pos str verb
=
2044 (NastCheck.err_code
NastCheck.IllegalByRefExpr
)
2046 (str ^
" cannot be " ^ verb ^
" by reference")
2048 let variadic_byref_param pos =
2050 (NastCheck.err_code
NastCheck.VariadicByRefParam
)
2052 "Variadic parameters should not be taken by reference"
2054 let byref_dynamic_call pos =
2056 (NastCheck.err_code
NastCheck.ByRefDynamicCall
)
2058 "Arguments can not be passed by reference to dynamic function calls"
2060 let byref_call pos =
2062 (NastCheck.err_code
NastCheck.ByRefCall
)
2064 "Arguments can not be passed by reference"
2066 let byref_on_property pos =
2068 (NastCheck.err_code
NastCheck.ByRefProperty
)
2070 "Properties cannot be passed by reference"
2072 let switch_non_terminal_default pos =
2074 (NastCheck.err_code
NastCheck.SwitchNonTerminalDefault
)
2076 "Default case in switch must be terminal"
2078 let switch_multiple_default pos =
2080 (NastCheck.err_code
NastCheck.SwitchMultipleDefault
)
2082 "There can be only one default case in switch"
2084 (*****************************************************************************)
2085 (* Nast terminality *)
2086 (*****************************************************************************)
2088 let case_fallthrough pos1 pos2
=
2090 (NastCheck.err_code
NastCheck.CaseFallthrough
)
2093 "This switch has a case that implicitly falls through and is "
2094 ^
"not annotated with // FALLTHROUGH" );
2095 (pos2
, "This case implicitly falls through");
2098 let default_fallthrough pos =
2100 (NastCheck.err_code
NastCheck.DefaultFallthrough
)
2102 ( "This switch has a default case that implicitly falls "
2103 ^
"through and is not annotated with // FALLTHROUGH" )
2105 (*****************************************************************************)
2107 (*****************************************************************************)
2109 let visibility_extends vis
pos parent_pos parent_vis
=
2110 let msg1 = (pos, "This member visibility is: " ^ vis
) in
2111 let msg2 = (parent_pos
, parent_vis ^
" was expected") in
2112 add_list
(Typing.err_code
Typing.VisibilityExtends
) [msg1; msg2]
2114 let member_not_implemented member_name parent_pos
pos defn_pos
=
2115 let msg1 = (pos, "This type doesn't implement the method " ^ member_name
) in
2116 let msg2 = (parent_pos
, "Which is required by this interface") in
2117 let msg3 = (defn_pos
, "As defined here") in
2118 add_list
(Typing.err_code
Typing.MemberNotImplemented
) [msg1; msg2; msg3]
2120 let bad_decl_override parent_pos parent_name
pos name (error
: error
) =
2125 ^
" does not correctly implement all required members " )
2129 "Some members are incompatible with those declared in type "
2130 ^
strip_ns parent_name
2131 ^
"\nRead the following to see why:" )
2133 (* This is a cascading error message *)
2134 let msgl = to_list error
in
2135 add_list
(Typing.err_code
Typing.BadDeclOverride
) (msg1 :: msg2 :: msgl)
2137 let bad_method_override pos member_name
(error
: error
) =
2138 let msg = (pos, "Member " ^
strip_ns member_name ^
" has the wrong type") in
2139 (* This is a cascading error message *)
2140 let msgl = to_list error
in
2141 add_list
(Typing.err_code
Typing.BadMethodOverride
) (msg :: msgl)
2143 let bad_enum_decl pos (error
: error
) =
2145 (pos, "This enum declaration is invalid.\nRead the following to see why:")
2147 (* This is a cascading error message *)
2148 let msgl = to_list error
in
2149 add_list
(Typing.err_code
Typing.BadEnumExtends
) (msg :: msgl)
2151 let missing_constructor pos =
2153 (Typing.err_code
Typing.MissingConstructor
)
2155 "The constructor is not implemented"
2157 let typedef_trail_entry pos = (pos, "Typedef definition comes from here")
2159 let abstract_tconst_not_allowed pos (p, tconst_name
) =
2161 (Typing.err_code
Typing.AbstractTconstNotAllowed
)
2163 (pos, "An abstract type constant is not allowed in this position.");
2164 (p, Printf.sprintf
"%s is abstract here." tconst_name
);
2167 let add_with_trail code
errs trail
=
2168 add_list code
(errs @ List.map trail
typedef_trail_entry)
2170 let enum_constant_type_bad pos ty_pos ty trail
=
2172 (Typing.err_code
Typing.EnumConstantTypeBad
)
2173 [(pos, "Enum constants must be an int or string"); (ty_pos
, "Not " ^ ty
)]
2176 let enum_type_bad pos ty trail
=
2178 (Typing.err_code
Typing.EnumTypeBad
)
2179 [(pos, "Enums must be int or string or arraykey, not " ^ ty
)]
2182 let enum_type_typedef_nonnull pos =
2184 (Typing.err_code
Typing.EnumTypeTypedefNonnull
)
2186 "Can't use typedef that resolves to nonnull in enum"
2188 let enum_switch_redundant const first_pos second_pos
=
2190 (Typing.err_code
Typing.EnumSwitchRedundant
)
2192 (second_pos
, "Redundant case statement");
2193 (first_pos
, const ^
" already handled here");
2196 let enum_switch_nonexhaustive pos missing enum_pos
=
2198 (Typing.err_code
Typing.EnumSwitchNonexhaustive
)
2201 "Switch statement nonexhaustive; the following cases are missing: "
2202 ^
String.concat ~sep
:", " missing
);
2203 (enum_pos
, "Enum declared here");
2206 let enum_switch_redundant_default pos enum_pos
=
2208 (Typing.err_code
Typing.EnumSwitchRedundantDefault
)
2211 "All cases already covered; a redundant default case prevents "
2212 ^
"detecting future errors" );
2213 (enum_pos
, "Enum declared here");
2216 let enum_switch_not_const pos =
2218 (Typing.err_code
Typing.EnumSwitchNotConst
)
2220 "Case in switch on enum is not an enum constant"
2222 let enum_switch_wrong_class pos expected got
=
2224 (Typing.err_code
Typing.EnumSwitchWrongClass
)
2226 ("Switching on enum " ^ expected ^
" but using constant from " ^ got
)
2228 let invalid_shape_field_name p =
2230 (Typing.err_code
Typing.InvalidShapeFieldName
)
2232 "Was expecting a constant string, class constant, or int (for shape access)"
2234 let invalid_shape_field_name_empty p =
2236 (Typing.err_code
Typing.InvalidShapeFieldNameEmpty
)
2238 "A shape field name cannot be an empty string"
2240 let invalid_shape_field_type pos ty_pos ty trail
=
2242 (Typing.err_code
Typing.InvalidShapeFieldType
)
2244 (pos, "A shape field name must be an int or string"); (ty_pos
, "Not " ^ ty
);
2248 let invalid_shape_field_literal key_pos witness_pos
=
2250 (Typing.err_code
Typing.InvalidShapeFieldLiteral
)
2252 (key_pos
, "Shape uses literal string as field name");
2253 (witness_pos
, "But expected a class constant");
2256 let invalid_shape_field_const key_pos witness_pos
=
2258 (Typing.err_code
Typing.InvalidShapeFieldConst
)
2260 (key_pos
, "Shape uses class constant as field name");
2261 (witness_pos
, "But expected a literal string");
2264 let shape_field_class_mismatch key_pos witness_pos key_class witness_class
=
2266 (Typing.err_code
Typing.ShapeFieldClassMismatch
)
2268 (key_pos
, "Shape field name is class constant from " ^ key_class
);
2269 (witness_pos
, "But expected constant from " ^ witness_class
);
2272 let shape_field_type_mismatch key_pos witness_pos key_ty witness_ty
=
2274 (Typing.err_code
Typing.ShapeFieldTypeMismatch
)
2276 (key_pos
, "Shape field name is " ^ key_ty ^
" class constant");
2277 (witness_pos
, "But expected " ^ witness_ty
);
2280 let missing_field pos1 pos2
name =
2282 (Typing.err_code
Typing.MissingField
)
2284 (pos1
, "The field '" ^
name ^
"' is missing");
2285 (pos2
, "The field '" ^
name ^
"' is defined");
2288 let shape_fields_unknown pos1 pos2
=
2290 (Typing.err_code
Typing.ShapeFieldsUnknown
)
2293 "This shape type allows unknown fields, and so it may contain fields other than those explicitly declared in its declaration."
2296 "It is incompatible with a shape that does not allow unknown fields." );
2299 let invalid_shape_remove_key p =
2301 (Typing.err_code
Typing.InvalidShapeRemoveKey
)
2303 "You can only unset fields of local variables"
2305 let unification_cycle pos ty
=
2307 (Typing.err_code
Typing.UnificationCycle
)
2310 "Type circularity: in order to type-check this expression it "
2311 ^
"is necessary for a type [rec] to be equal to type "
2315 let violated_constraint p_cstr
(p_tparam
, tparam
) left right
=
2317 (Typing.err_code
Typing.TypeConstraintViolation
)
2319 (p_cstr
, "Some type constraint(s) are violated here");
2320 (p_tparam
, Printf.sprintf
"%s is a constrained type parameter" tparam
);
2325 let method_variance pos =
2327 (Typing.err_code
Typing.MethodVariance
)
2329 "Covariance or contravariance is not allowed in type parameter of method or function."
2331 let explain_constraint ~use_pos ~definition_pos ~param_name
(error
: error
) =
2332 let inst_msg = "Some type constraint(s) here are violated" in
2333 let msgl = to_list error
in
2334 (* There may be multiple constraints instantiated at one spot; avoid
2335 * duplicating the instantiation message *)
2338 | (p, x) :: rest
when x = inst_msg && p = use_pos
-> rest
2341 let name = strip_ns param_name
in
2343 (Typing.err_code
Typing.TypeConstraintViolation
)
2345 (use_pos
, inst_msg);
2346 (definition_pos
, "'" ^
name ^
"' is a constrained type parameter");
2350 let explain_where_constraint ~in_class ~use_pos ~definition_pos
(error
: error
)
2358 let definition_head =
2359 Printf.sprintf
"This is the %s with 'where' type constraints" callsite_ty
2361 let inst_msg = "A 'where' type constraint is violated here" in
2362 let msgl = to_list error
in
2364 (Typing.err_code
Typing.TypeConstraintViolation
)
2365 ([(use_pos
, inst_msg); (definition_pos
, definition_head)] @ msgl)
2367 let explain_tconst_where_constraint ~use_pos ~definition_pos
(error
: error
) =
2368 let inst_msg = "A 'where' type constraint is violated here" in
2369 let msgl = to_list error
in
2371 (Typing.err_code
Typing.TypeConstraintViolation
)
2373 (use_pos
, inst_msg);
2375 "This method's where constraints contain a generic type access" );
2379 let format_string pos snippet s class_pos fname class_suggest
=
2381 (Typing.err_code
Typing.FormatString
)
2383 (pos, "I don't understand the format string " ^ snippet ^
" in " ^ s
);
2385 "You can add a new format specifier by adding "
2391 let expected_literal_format_string pos =
2393 (Typing.err_code
Typing.ExpectedLiteralFormatString
)
2395 "This argument must be a literal format string"
2397 let re_prefixed_non_string pos non_strings
=
2399 (Typing.err_code
Typing.RePrefixedNonString
)
2401 (non_strings ^
" are not allowed to be to be `re`-prefixed")
2403 let bad_regex_pattern pos s
=
2405 (Typing.err_code
Typing.BadRegexPattern
)
2407 ("Bad regex pattern; " ^ s ^
".")
2409 let generic_array_strict p =
2411 (Typing.err_code
Typing.GenericArrayStrict
)
2413 "You cannot have an array without generics in strict mode"
2415 let strict_members_not_known p name =
2416 let name = strip_ns name in
2418 (Typing.err_code
Typing.StrictMembersNotKnown
)
2421 ^
" has a non-<?hh grandparent; this is not allowed in strict mode"
2422 ^
" because that parent may define methods of unknowable name and type" )
2424 let option_return_only_typehint p kind
=
2425 let (typehint
, reason) =
2427 | `void
-> ("?void", "only return implicitly")
2428 | `noreturn
-> ("?noreturn", "never return")
2431 (Typing.err_code
Typing.OptionReturnOnlyTypehint
)
2434 ^
" is a nonsensical typehint; a function cannot both "
2436 ^
" and return null." )
2438 let tuple_syntax p =
2440 (Typing.err_code
Typing.TupleSyntax
)
2442 "Did you want a tuple? Try (X,Y), not tuple<X,Y>"
2444 let redeclaring_missing_method p trait_method
=
2446 (Typing.err_code
Typing.RedeclaringMissingMethod
)
2448 ( "Attempting to redeclare a trait method "
2450 ^
" which was never inherited. "
2451 ^
"You might be trying to redeclare a non-static method as static or vice-versa."
2454 let expecting_type_hint p =
2455 add
(Typing.err_code
Typing.ExpectingTypeHint
) p "Was expecting a type hint"
2457 let expecting_type_hint_variadic p =
2459 (Typing.err_code
Typing.ExpectingTypeHintVariadic
)
2461 "Was expecting a type hint on this variadic parameter"
2463 let expecting_return_type_hint p =
2465 (Typing.err_code
Typing.ExpectingReturnTypeHint
)
2467 "Was expecting a return type hint"
2469 let expecting_awaitable_return_type_hint p =
2471 (Typing.err_code
Typing.ExpectingAwaitableReturnTypeHint
)
2473 "Was expecting an Awaitable return type hint"
2475 let duplicate_using_var pos =
2477 (Typing.err_code
Typing.DuplicateUsingVar
)
2479 "Local variable already used in 'using' statement"
2481 let illegal_disposable pos verb
=
2483 (Typing.err_code
Typing.IllegalDisposable
)
2485 ("Disposable objects must only be " ^ verb ^
" in a 'using' statement")
2487 let escaping_disposable pos =
2489 (Typing.err_code
Typing.EscapingDisposable
)
2491 "Variable from 'using' clause may only be used as receiver in method invocation or passed to function with <<__AcceptDisposable>> parameter attribute"
2493 let escaping_disposable_parameter pos =
2495 (Typing.err_code
Typing.EscapingDisposableParameter
)
2497 "Parameter with <<__AcceptDisposable>> attribute may only be used as receiver in method invocation or passed to another function with <<__AcceptDisposable>> parameter attribute"
2499 let escaping_this pos =
2501 (Typing.err_code
Typing.EscapingThis
)
2503 "$this implementing IDisposable or IAsyncDisposable may only be used as receiver in method invocation or passed to another function with <<__AcceptDisposable>> parameter attribute"
2505 let escaping_mutable_object pos =
2507 (Typing.err_code
Typing.EscapingMutableObject
)
2509 "Neither a Mutable nor MaybeMutable object may be captured by an anonymous function."
2511 let must_extend_disposable pos =
2513 (Typing.err_code
Typing.MustExtendDisposable
)
2515 "A disposable type may not extend a class or use a trait that is not disposable"
2517 let accept_disposable_invariant pos1 pos2
=
2518 let msg1 = (pos1
, "This parameter is marked <<__AcceptDisposable>>") in
2519 let msg2 = (pos2
, "This parameter is not marked <<__AcceptDisposable>>") in
2520 add_list
(Typing.err_code
Typing.AcceptDisposableInvariant
) [msg1; msg2]
2522 let field_kinds pos1 pos2
=
2524 (Typing.err_code
Typing.FieldKinds
)
2526 (pos1
, "You cannot use this kind of field (value)");
2527 (pos2
, "Mixed with this kind of field (key => value)");
2530 let unbound_name_typing pos name =
2532 (Typing.err_code
Typing.UnboundNameTyping
)
2534 ("Unbound name (typing): " ^
strip_ns name)
2536 let previous_default p =
2538 (Typing.err_code
Typing.PreviousDefault
)
2540 ( "A previous parameter has a default value.\n"
2541 ^
"Remove all the default values for the preceding parameters,\n"
2542 ^
"or add a default value to this one." )
2544 let return_only_typehint p kind
=
2548 | `noreturn
-> "noreturn"
2551 (Naming.err_code
Naming.ReturnOnlyTypehint
)
2555 ^
" typehint can only be used to describe a function return type" )
2557 let unexpected_type_arguments p =
2559 (Naming.err_code
Naming.UnexpectedTypeArguments
)
2561 "Type arguments are not expected for this type"
2563 let too_many_type_arguments p =
2565 (Naming.err_code
Naming.TooManyTypeArguments
)
2567 "Too many type arguments for this type"
2569 let return_in_void pos1 pos2
=
2571 (Typing.err_code
Typing.ReturnInVoid
)
2572 [(pos1
, "You cannot return a value"); (pos2
, "This is a void function")]
2574 let this_var_outside_class p =
2576 (Typing.err_code
Typing.ThisVarOutsideClass
)
2578 "Can't use $this outside of a class"
2580 let unbound_global cst_pos
=
2582 (Typing.err_code
Typing.UnboundGlobal
)
2584 "Unbound global constant (Typing)"
2586 let private_inst_meth ~def_pos ~use_pos
=
2588 (Typing.err_code
Typing.PrivateInstMeth
)
2591 "You cannot use this method with inst_meth (whether you are in the same class or not)."
2593 (def_pos
, "It is declared as private here");
2596 let protected_inst_meth ~def_pos ~use_pos
=
2598 (Typing.err_code
Typing.ProtectedInstMeth
)
2601 "You cannot use this method with inst_meth (whether you are in the same class hierarchy or not)."
2603 (def_pos
, "It is declared as protected here");
2606 let private_class_meth ~def_pos ~use_pos
=
2608 (Typing.err_code
Typing.PrivateClassMeth
)
2611 "You cannot use this method with class_meth (whether you are in the same class or not)."
2613 (def_pos
, "It is declared as private here");
2616 let protected_class_meth ~def_pos ~use_pos
=
2618 (Typing.err_code
Typing.ProtectedClassMeth
)
2621 "You cannot use this method with class_meth (whether you are in the same class hierarchy or not)."
2623 (def_pos
, "It is declared as protected here");
2626 let array_cast pos =
2628 (Typing.err_code
Typing.ArrayCast
)
2630 "(array) cast forbidden; arrays with unspecified key and value types are not allowed"
2632 let string_cast pos ty
=
2633 add
(Typing.err_code
Typing.StringCast
) pos
2635 "Cannot cast a value of type %s to string.\nOnly primitives may be used in a (string) cast.\nIf you are trying to cast a Stringish type, please use `stringish_cast`.\nThis functionality is being removed from HHVM."
2638 let nullable_cast pos ty ty_pos
=
2640 (Typing.err_code
Typing.NullableCast
)
2642 (pos, "Casting from a nullable type is forbidden");
2643 (ty_pos
, "This is " ^ ty
);
2646 let anonymous_recursive pos =
2648 (Typing.err_code
Typing.AnonymousRecursive
)
2650 "Anonymous functions cannot be recursive"
2652 let static_outside_class pos =
2654 (Typing.err_code
Typing.StaticOutsideClass
)
2656 "'static' is undefined outside of a class"
2658 let self_outside_class pos =
2660 (Typing.err_code
Typing.SelfOutsideClass
)
2662 "'self' is undefined outside of a class"
2664 let new_inconsistent_construct new_pos
(cpos
, cname) kind
=
2665 let name = strip_ns cname in
2668 | `static
-> "Can't use new static() for " ^
name
2669 | `classname
-> "Can't use new on classname<" ^
name ^
">"
2672 (Typing.err_code
Typing.NewStaticInconsistent
)
2676 ^
"; __construct arguments are not guaranteed to be consistent in child classes"
2679 "This declaration is neither final nor uses the <<__ConsistentConstruct>> attribute"
2683 let undefined_parent pos =
2685 (Typing.err_code
Typing.UndefinedParent
)
2687 "The parent class is undefined"
2689 let parent_outside_class pos =
2691 (Typing.err_code
Typing.ParentOutsideClass
)
2693 "'parent' is undefined outside of a class"
2695 let parent_abstract_call meth_name call_pos decl_pos
=
2697 (Typing.err_code
Typing.AbstractCall
)
2699 (call_pos
, "Cannot call parent::" ^ meth_name ^
"(); it is abstract");
2700 (decl_pos
, "Declaration is here");
2703 let self_abstract_call meth_name call_pos decl_pos
=
2705 (Typing.err_code
Typing.AbstractCall
)
2708 "Cannot call self::"
2710 ^
"(); it is abstract. Did you mean static::"
2713 (decl_pos
, "Declaration is here");
2716 let classname_abstract_call cname meth_name call_pos decl_pos
=
2717 let cname = strip_ns cname in
2719 (Typing.err_code
Typing.AbstractCall
)
2722 "Cannot call " ^
cname ^
"::" ^ meth_name ^
"(); it is abstract" );
2723 (decl_pos
, "Declaration is here");
2726 let static_synthetic_method cname meth_name call_pos decl_pos
=
2727 let cname = strip_ns cname in
2729 (Typing.err_code
Typing.StaticSyntheticMethod
)
2738 ^
" is not defined in "
2740 (decl_pos
, "Declaration is here");
2743 let isset_in_strict pos =
2745 (Typing.err_code
Typing.IssetEmptyInStrict
)
2747 ( "isset tends to hide errors due to variable typos and so is limited to dynamic checks in "
2750 let unset_nonidx_in_strict pos msgs =
2752 (Typing.err_code
Typing.UnsetNonidxInStrict
)
2755 "In strict mode, unset is banned except on dynamic, "
2756 ^
"darray, keyset, or dict indexing" );
2760 let unpacking_disallowed_builtin_function pos name =
2761 let name = strip_ns name in
2763 (Typing.err_code
Typing.UnpackingDisallowed
)
2765 ("Arg unpacking is disallowed for " ^
name)
2767 let array_get_arity pos1
name pos2
=
2769 (Typing.err_code
Typing.ArrayGetArity
)
2771 (pos1
, "You cannot use this " ^
strip_ns name);
2772 (pos2
, "It is missing its type parameters");
2775 let typing_error pos msg = add
(Typing.err_code
Typing.GenericUnify
) pos msg
2777 let undefined_field ~use_pos ~
name ~shape_type_pos
=
2779 (Typing.err_code
Typing.UndefinedField
)
2781 (use_pos
, "The field " ^
name ^
" is undefined");
2782 (shape_type_pos
, "Definition is here");
2785 let array_access pos1 pos2 ty
=
2787 (Typing.err_code
Typing.ArrayAccess
)
2788 ( (pos1
, "This is not an object of type KeyedContainer, this is " ^ ty
)
2790 ( if not
(phys_equal pos2
Pos.none
) then
2791 [(pos2
, "Definition is here")]
2795 let keyset_set pos1 pos2
=
2797 (Typing.err_code
Typing.KeysetSet
)
2798 ( (pos1
, "Elements in a keyset cannot be assigned, use append instead.")
2800 ( if not
(phys_equal pos2
Pos.none
) then
2801 [(pos2
, "Definition is here")]
2805 let array_append pos1 pos2 ty
=
2807 (Typing.err_code
Typing.ArrayAppend
)
2808 ( (pos1
, ty ^
" does not allow array append")
2810 ( if not
(phys_equal pos2
Pos.none
) then
2811 [(pos2
, "Definition is here")]
2815 let const_mutation pos1 pos2 ty
=
2817 (Typing.err_code
Typing.ConstMutation
)
2818 ( (pos1
, "You cannot mutate this")
2820 ( if not
(phys_equal pos2
Pos.none
) then
2821 [(pos2
, "This is " ^ ty
)]
2825 let expected_class ?
(suffix
= "") pos =
2827 (Typing.err_code
Typing.ExpectedClass
)
2829 ("Was expecting a class" ^ suffix
)
2831 let unknown_type description
pos r
=
2832 let msg = "Was expecting " ^ description ^
" but type is unknown" in
2833 add_list
(Typing.err_code
Typing.UnknownType
) ([(pos, msg)] @ r
)
2835 let not_found_hint = function
2837 | `closest
(_pos
, v
) -> Printf.sprintf
" (did you mean static method '%s'?)" v
2838 | `did_you_mean
(_pos
, v
) -> Printf.sprintf
" (did you mean '%s'?)" v
2840 let snot_found_hint = function
2842 | `closest
(_pos
, v
) ->
2843 Printf.sprintf
" (did you mean instance method '%s'?)" v
2844 | `did_you_mean
(_pos
, v
) -> Printf.sprintf
" (did you mean '%s'?)" v
2846 let string_of_class_member_kind = function
2847 | `class_constant
-> "class constant"
2848 | `static_method
-> "static method"
2849 | `class_variable
-> "class variable"
2850 | `class_typeconst
-> "type constant"
2852 let smember_not_found kind
pos (cpos
, class_name
) member_name hint
=
2853 let kind = string_of_class_member_kind kind in
2854 let class_name = strip_ns class_name in
2855 let msg = Printf.sprintf
"No %s '%s' in %s" kind member_name
class_name in
2857 (Typing.err_code
Typing.SmemberNotFound
)
2859 (pos, msg ^
snot_found_hint hint
);
2860 (cpos
, "Declaration of " ^
class_name ^
" is here");
2863 let member_not_found kind pos (cpos
, type_name
) member_name hint
reason =
2864 let type_name = strip_ns type_name in
2867 | `method_
-> "method"
2868 | `member
-> "member"
2870 let msg = Printf.sprintf
"No %s '%s' in %s" kind member_name
type_name in
2872 (Typing.err_code
Typing.MemberNotFound
)
2873 ( (pos, msg ^
not_found_hint hint
)
2874 :: (reason @ [(cpos
, "Declaration of " ^
type_name ^
" is here")]) )
2876 let parent_in_trait pos =
2878 (Typing.err_code
Typing.ParentInTrait
)
2880 ( "parent:: inside a trait is undefined"
2881 ^
" without 'require extends' of a class defined in <?hh" )
2883 let parent_undefined pos =
2884 add
(Typing.err_code
Typing.ParentUndefined
) pos "parent is undefined"
2886 let constructor_no_args pos =
2888 (Typing.err_code
Typing.ConstructorNoArgs
)
2890 "This constructor expects no argument"
2892 let visibility p msg1 p_vis
msg2 =
2893 add_list
(Typing.err_code
Typing.Visibility
) [(p, msg1); (p_vis
, msg2)]
2895 let typing_too_many_args expected actual
pos pos_def
=
2897 (Typing.err_code
Typing.TypingTooManyArgs
)
2901 "Too many arguments (expected %d but got %d)"
2904 (pos_def
, "Definition is here");
2907 let typing_too_few_args required actual
pos pos_def
=
2909 (Typing.err_code
Typing.TypingTooFewArgs
)
2913 "Too few arguments (required %d but got %d)"
2916 (pos_def
, "Definition is here");
2919 let anonymous_recursive_call pos =
2921 (Typing.err_code
Typing.AnonymousRecursiveCall
)
2923 "recursive call to anonymous function"
2925 let bad_call pos ty
=
2927 (Typing.err_code
Typing.BadCall
)
2929 ("This call is invalid, this is not a function, it is " ^ ty
)
2931 let extend_final extend_pos decl_pos
name =
2932 let name = strip_ns name in
2934 (Typing.err_code
Typing.ExtendFinal
)
2936 (extend_pos
, "You cannot extend final class " ^
name);
2937 (decl_pos
, "Declaration is here");
2940 let extend_non_abstract_record name extend_pos decl_pos
=
2941 let name = strip_ns name in
2943 Printf.sprintf
"Cannot extend record `%s` because it isn't abstract" name
2946 (Typing.err_code
Typing.ExtendFinal
)
2947 [(extend_pos
, msg); (decl_pos
, "Declaration is here")]
2949 let extend_sealed child_pos parent_pos parent_name parent_kind verb
=
2950 let name = strip_ns parent_name
in
2952 (Typing.err_code
Typing.ExtendSealed
)
2954 (child_pos
, "You cannot " ^ verb ^
" sealed " ^ parent_kind ^
" " ^
name);
2955 (parent_pos
, "Declaration is here");
2958 let trait_prop_const_class pos x =
2960 (Typing.err_code
Typing.TraitPropConstClass
)
2962 ( "Trait declaration of non-const property "
2964 ^
" is incompatible with a const class" )
2974 let name = strip_ns parent_name
in
2976 if child_is_ppl
then
2978 ^
" annotated with <<__PPL>> cannot "
2986 ^
" must be annotated with <<__PPL>> to "
2994 (Typing.err_code
Typing.ExtendPPL
)
2995 [(child_pos
, warning); (parent_pos
, "Declaration is here")]
2997 let read_before_write (pos, v
) =
2999 (Typing.err_code
Typing.ReadBeforeWrite
)
3001 (Utils.sl
["Read access to $this->"; v
; " before initialization"])
3003 let final_property pos =
3005 (Typing.err_code
Typing.FinalProperty
)
3007 "Properties cannot be declared final"
3009 let implement_abstract ~is_final pos1 pos2
kind x =
3010 let name = "abstract " ^
kind ^
" '" ^
x ^
"'" in
3013 "This class was declared as final. It must provide an implementation for the "
3016 "This class must be declared abstract, or provide an implementation for the "
3020 (Typing.err_code
Typing.ImplementAbstract
)
3021 [(pos1
, msg1); (pos2
, "Declaration is here")]
3023 let generic_static pos x =
3025 (Typing.err_code
Typing.GenericStatic
)
3027 ("This static variable cannot use the type parameter " ^
x ^
".")
3029 let fun_too_many_args pos1 pos2
=
3031 (Typing.err_code
Typing.FunTooManyArgs
)
3033 (pos1
, "Too many mandatory arguments");
3034 (pos2
, "Because of this definition");
3037 let fun_too_few_args pos1 pos2
=
3039 (Typing.err_code
Typing.FunTooFewArgs
)
3040 [(pos1
, "Too few arguments"); (pos2
, "Because of this definition")]
3042 let fun_unexpected_nonvariadic pos1 pos2
=
3044 (Typing.err_code
Typing.FunUnexpectedNonvariadic
)
3046 (pos1
, "Should have a variadic argument");
3047 (pos2
, "Because of this definition");
3050 let fun_variadicity_hh_vs_php56 pos1 pos2
=
3052 (Typing.err_code
Typing.FunVariadicityHhVsPhp56
)
3054 (pos1
, "Variadic arguments: ...-style is not a subtype of ...$args");
3055 (pos2
, "Because of this definition");
3058 let ellipsis_strict_mode ~require
pos =
3062 "Cannot use ... without a type hint in strict mode. Please add a type hint."
3064 "Cannot use ... without a parameter name in strict mode. Please add a parameter name."
3065 | `Type_and_param_name
->
3066 "Cannot use ... without a type hint and parameter name in strict mode. Please add a type hint and parameter name."
3068 add
(Typing.err_code
Typing.EllipsisStrictMode
) pos msg
3070 let untyped_lambda_strict_mode pos =
3072 "Cannot determine types of lambda parameters in strict mode. Please add type hints on parameters."
3074 add
(Typing.err_code
Typing.UntypedLambdaStrictMode
) pos msg
3076 let echo_in_reactive_context pos =
3078 (Typing.err_code
Typing.EchoInReactiveContext
)
3080 "'echo' or 'print' are not allowed in reactive functions."
3082 let expected_tparam ~use_pos ~definition_pos n
=
3084 (Typing.err_code
Typing.ExpectedTparam
)
3090 | 0 -> "no type parameter"
3091 | 1 -> "a type parameter"
3092 | n
-> string_of_int n ^
" type parameters" );
3093 (definition_pos
, "Definition is here");
3096 let object_string pos1 pos2
=
3098 (Typing.err_code
Typing.ObjectString
)
3100 (pos1
, "You cannot use this object as a string");
3101 (pos2
, "This object doesn't implement __toString");
3104 let object_string_deprecated pos =
3106 (Typing.err_code
Typing.ObjectString
)
3108 "You cannot use this object as a string\nImplicit conversions of Stringish objects to string are deprecated."
3110 let cyclic_typedef p =
3111 add
(Typing.err_code
Typing.CyclicTypedef
) p "Cyclic typedef"
3113 let type_arity_mismatch pos1 n1 pos2 n2
=
3115 (Typing.err_code
Typing.TypeArityMismatch
)
3116 [(pos1
, "This type has " ^ n1 ^
" arguments"); (pos2
, "This one has " ^ n2
)]
3118 let this_final id pos2
(error
: error
) =
3119 let n = strip_ns (snd id
) in
3120 let message1 = "Since " ^
n ^
" is not final" in
3121 let message2 = "this might not be a " ^
n in
3122 let (code
, msgl) = (get_code error
, to_list error
) in
3123 add_list code
(msgl @ [(fst id
, message1); (pos2
, message2)])
3125 let exact_class_final id pos2
(error
: error
) =
3126 let n = strip_ns (snd id
) in
3127 let message1 = "This requires the late-bound type to be exactly " ^
n in
3129 "Since " ^
n ^
" is not final this might be an instance of a child class"
3131 let (code
, msgl) = (get_code error
, to_list error
) in
3132 add_list code
(msgl @ [(fst id
, message1); (pos2
, message2)])
3134 let fun_arity_mismatch pos1 pos2
=
3136 (Typing.err_code
Typing.FunArityMismatch
)
3138 (pos1
, "Number of arguments doesn't match");
3139 (pos2
, "Because of this definition");
3142 let fun_reactivity_mismatch pos1 kind1 pos2 kind2
=
3143 let f k
= "This function is " ^ k ^
"." in
3145 (Typing.err_code
Typing.FunReactivityMismatch
)
3146 [(pos1
, f kind1
); (pos2
, f kind2
)]
3148 let inconsistent_mutability pos1 mut1 p2_opt
=
3150 | Some
(pos2
, mut2
) ->
3152 (Typing.err_code
Typing.InconsistentMutability
)
3155 "Inconsistent mutability of local variable, here local is " ^ mut1
);
3156 (pos2
, "But here it is " ^ mut2
);
3160 (Typing.err_code
Typing.InconsistentMutability
)
3162 ("Local is " ^ mut1 ^
" in one scope and immutable in another.")
3164 let inconsistent_mutability_for_conditional p_mut p_other
=
3166 (Typing.err_code
Typing.InconsistentMutability
)
3169 "Inconsistent mutability of conditional expression, this branch returns owned mutable value"
3171 (p_other
, "But this one does not.");
3174 let invalid_mutability_flavor pos mut1 mut2
=
3176 (Typing.err_code
Typing.InvalidMutabilityFlavorInAssignment
)
3182 ^
" local variable. Mutability flavor of local variable cannot be altered."
3185 let reassign_mutable_var ~in_collection pos1
=
3187 if in_collection
then
3188 "This variable is mutable. You cannot create a new reference to it by putting it into the collection."
3190 "This variable is mutable. You cannot create a new reference to it."
3192 add
(Typing.err_code
Typing.ReassignMutableVar
) pos1
msg
3194 let reassign_mutable_this ~in_collection ~is_maybe_mutable pos1
=
3196 if is_maybe_mutable
then
3202 if in_collection
then
3205 ^
". You cannot create a new reference to it by putting it into the collection."
3207 "$this here is " ^
kind ^
". You cannot create a new reference to it."
3209 add
(Typing.err_code
Typing.ReassignMutableThis
) pos1
msg
3211 let mutable_expression_as_multiple_mutable_arguments
3212 pos param_kind prev_pos prev_param_kind
=
3214 (Typing.err_code
Typing.MutableExpressionAsMultipleMutableArguments
)
3217 "A mutable expression may not be passed as multiple arguments where at least one matching parameter is mutable. Matching parameter here is "
3220 "This is where it was used before, being passed as " ^ prev_param_kind
3224 let reassign_maybe_mutable_var ~in_collection pos1
=
3226 if in_collection
then
3227 "This variable is maybe mutable. You cannot create a new reference to it by putting it into the collection."
3229 "This variable is maybe mutable. You cannot create a new reference to it."
3231 add
(Typing.err_code
Typing.ReassignMaybeMutableVar
) pos1
msg
3233 let mutable_call_on_immutable fpos pos1 rx_mutable_hint_pos
=
3235 match rx_mutable_hint_pos
with
3239 "Consider wrapping this expression with Rx\\mutable to forward mutability."
3245 (pos1
, "Cannot call mutable function on immutable expression")
3247 "This function is marked <<__Mutable>>, so it has a mutable $this." )
3250 add_list
(Typing.err_code
Typing.MutableCallOnImmutable
) l
3252 let immutable_call_on_mutable fpos pos1
=
3254 (Typing.err_code
Typing.ImmutableCallOnMutable
)
3256 (pos1
, "Cannot call non-mutable function on mutable expression");
3257 (fpos
, "This function is not marked as <<__Mutable>>.");
3260 let mutability_mismatch ~is_receiver pos1 mut1 pos2 mut2
=
3264 "Receiver of this function"
3271 (Typing.err_code
Typing.MutabilityMismatch
)
3272 [(pos1
, "Incompatible mutabilities:"); (pos1
, msg mut1
); (pos2
, msg mut2
)]
3274 let invalid_call_on_maybe_mutable ~fun_is_mutable
pos fpos
=
3277 ^
( if fun_is_mutable
then
3281 ^
" function on maybe mutable value."
3284 (Typing.err_code
Typing.InvalidCallMaybeMutable
)
3285 [(pos, msg); (fpos
, "This function is not marked as <<__MaybeMutable>>.")]
3287 let mutable_argument_mismatch param_pos arg_pos
=
3289 (Typing.err_code
Typing.MutableArgumentMismatch
)
3291 (arg_pos
, "Invalid argument");
3292 (param_pos
, "This parameter is marked mutable");
3293 (arg_pos
, "But this expression is not");
3296 let immutable_argument_mismatch param_pos arg_pos
=
3298 (Typing.err_code
Typing.ImmutableArgumentMismatch
)
3300 (arg_pos
, "Invalid argument");
3301 (param_pos
, "This parameter is not marked as mutable");
3302 (arg_pos
, "But this expression is mutable");
3305 let mutably_owned_argument_mismatch ~arg_is_owned_local param_pos arg_pos
=
3307 if arg_is_owned_local
then
3308 "Owned mutable locals used as argument should be passed via Rx\\move function"
3310 "But this expression is not owned mutable"
3313 (Typing.err_code
Typing.ImmutableArgumentMismatch
)
3315 (arg_pos
, "Invalid argument");
3316 (param_pos
, "This parameter is marked with <<__OwnedMutable>>");
3320 let maybe_mutable_argument_mismatch param_pos arg_pos
=
3322 (Typing.err_code
Typing.MaybeMutableArgumentMismatch
)
3324 (arg_pos
, "Invalid argument");
3325 (param_pos
, "This parameter is not marked <<__MaybeMutable>>");
3326 (arg_pos
, "But this expression is maybe mutable");
3329 let invalid_mutable_return_result error_pos function_pos value_kind
=
3331 (Typing.err_code
Typing.InvalidMutableReturnResult
)
3334 "Functions marked <<__MutableReturn>> must return mutably owned values: mutably owned local variables and results of calling Rx\\mutable."
3336 (function_pos
, "This function is marked <<__MutableReturn>>");
3337 (error_pos
, "This expression is " ^ value_kind
);
3340 let freeze_in_nonreactive_context pos1
=
3342 (Typing.err_code
Typing.FreezeInNonreactiveContext
)
3344 "\\HH\\Rx\\freeze can only be used in reactive functions"
3346 let mutable_in_nonreactive_context pos =
3348 (Typing.err_code
Typing.MutableInNonreactiveContext
)
3350 "\\HH\\Rx\\mutable can only be used in reactive functions"
3352 let move_in_nonreactive_context pos =
3354 (Typing.err_code
Typing.MoveInNonreactiveContext
)
3356 "\\HH\\Rx\\move can only be used in reactive functions"
3358 let invalid_argument_type_for_condition_in_rx
3359 ~is_receiver f_pos def_pos arg_pos expected_type actual_type
=
3368 ^
" must be a subtype of "
3375 (Typing.err_code
Typing.InvalidConditionallyReactiveCall
)
3378 "Cannot invoke conditionally reactive function in reactive context, because at least one reactivity condition is not met."
3381 (def_pos
, "This is the function declaration");
3384 let callsite_reactivity_mismatch
3385 f_pos def_pos callee_reactivity cause_pos_opt caller_reactivity
=
3387 (Typing.err_code
Typing.CallSiteReactivityMismatch
)
3390 "Reactivity mismatch: "
3392 ^
" function cannot call "
3395 (def_pos
, "This is declaration of the function being called.");
3397 @ Option.value_map cause_pos_opt ~default
:[] ~
f:(fun cause_pos
->
3400 "Reactivity of this argument was used as reactivity of the callee."
3404 let invalid_argument_of_rx_mutable_function pos =
3406 (Typing.err_code
Typing.InvalidArgumentOfRxMutableFunction
)
3408 "Single argument to \\HH\\Rx\\mutable should be an expression that yields new mutably-owned value, like 'new A()', Hack collection literal or 'f()' where f is function annotated with <<__MutableReturn>> attribute."
3410 let invalid_freeze_use pos1
=
3412 (Typing.err_code
Typing.InvalidFreezeUse
)
3414 "freeze takes a single mutably-owned local variable as an argument"
3416 let invalid_move_use pos1
=
3418 (Typing.err_code
Typing.InvalidMoveUse
)
3420 "move takes a single mutably-owned local variable as an argument"
3422 let require_args_reify def_pos arg_pos
=
3424 (Typing.err_code
Typing.RequireArgsReify
)
3427 "All type arguments must be specified because a type parameter is reified"
3429 (def_pos
, "Definition is here");
3432 let require_generic_explicit (def_pos
, def_name
) arg_pos
=
3434 (Typing.err_code
Typing.RequireGenericExplicit
)
3437 "Generic type parameter " ^ def_name ^
" must be specified explicitly"
3439 (def_pos
, "Definition is here");
3442 let invalid_reified_argument (def_pos
, def_name
) hint_pos arg_pos arg_kind
=
3444 (Typing.err_code
Typing.InvalidReifiedArgument
)
3446 (hint_pos
, "Invalid reified hint");
3448 "This is " ^ arg_kind ^
", it cannot be used as a reified type argument"
3450 (def_pos
, def_name ^
" is reified");
3453 let invalid_reified_argument_reifiable (def_pos
, def_name
) arg_pos ty_pos ty_msg
3456 (Typing.err_code
Typing.InvalidReifiedArgument
)
3458 (arg_pos
, "PHP arrays cannot be used as a reified type argument");
3459 (ty_pos
, String.capitalize ty_msg
);
3460 (def_pos
, def_name ^
" is reified");
3463 let new_static_class_reified pos =
3465 (Typing.err_code
Typing.NewStaticClassReified
)
3467 "Cannot call new static because the current class has reified generics"
3469 let class_get_reified pos =
3471 (Typing.err_code
Typing.ClassGetReified
)
3473 "Cannot access static properties on reified generics"
3475 let consistent_construct_reified pos =
3477 (Typing.err_code
Typing.ConsistentConstructReified
)
3479 "This class or one of its ancestors is annotated with <<__ConsistentConstruct>>. It cannot have reified generics."
3481 let new_without_newable pos name =
3483 (Typing.err_code
Typing.NewWithoutNewable
)
3486 ^
" cannot be used with `new` because it does not have the <<__Newable>> attribute"
3489 let invalid_freeze_target pos1 var_pos var_mutability_str
=
3491 (Typing.err_code
Typing.InvalidFreezeTarget
)
3493 (pos1
, "Invalid argument - freeze() takes a single mutable variable");
3494 (var_pos
, "This variable is " ^ var_mutability_str
);
3497 let invalid_move_target pos1 var_pos var_mutability_str
=
3499 (Typing.err_code
Typing.InvalidMoveTarget
)
3501 (pos1
, "Invalid argument - move() takes a single mutably-owned variable");
3502 (var_pos
, "This variable is " ^ var_mutability_str
);
3505 let discarded_awaitable pos1 pos2
=
3507 (Typing.err_code
Typing.DiscardedAwaitable
)
3510 "This expression is of type Awaitable, but it's "
3511 ^
"either being discarded or used in a dangerous way before "
3512 ^
"being awaited" );
3513 (pos2
, "This is why I think it is Awaitable");
3516 let unify_error left right
=
3517 add_list
(Typing.err_code
Typing.UnifyError
) (left
@ right
)
3519 let maybe_unify_error specific_code left right
=
3520 add_list
(Typing.err_code specific_code
) (left
@ right
)
3522 let index_type_mismatch = maybe_unify_error Typing.IndexTypeMismatch
3524 let expected_stringlike = maybe_unify_error Typing.ExpectedStringlike
3526 let type_constant_mismatch = maybe_unify_error Typing.TypeConstantMismatch
3528 let class_constant_type_mismatch =
3529 maybe_unify_error Typing.ClassConstantTypeMismatch
3531 let constant_does_not_match_enum_type =
3532 maybe_unify_error Typing.ConstantDoesNotMatchEnumType
3534 let enum_underlying_type_must_be_arraykey =
3535 maybe_unify_error Typing.EnumUnderlyingTypeMustBeArraykey
3537 let enum_constraint_must_be_arraykey =
3538 maybe_unify_error Typing.EnumConstraintMustBeArraykey
3540 let enum_subtype_must_have_compatible_constraint =
3541 maybe_unify_error Typing.EnumSubtypeMustHaveCompatibleConstraint
3543 let parameter_default_value_wrong_type =
3544 maybe_unify_error Typing.ParameterDefaultValueWrongType
3546 let newtype_alias_must_satisfy_constraint =
3547 maybe_unify_error Typing.NewtypeAliasMustSatisfyConstraint
3549 let bad_function_typevar = maybe_unify_error Typing.BadFunctionTypevar
3551 let bad_class_typevar = maybe_unify_error Typing.BadClassTypevar
3553 let bad_method_typevar = maybe_unify_error Typing.BadMethodTypevar
3555 let missing_return = maybe_unify_error Typing.MissingReturnInNonVoidFunction
3557 let inout_return_type_mismatch =
3558 maybe_unify_error Typing.InoutReturnTypeMismatch
3560 let class_constant_value_does_not_match_hint =
3561 maybe_unify_error Typing.ClassConstantValueDoesNotMatchHint
3563 let class_property_initializer_type_does_not_match_hint =
3564 maybe_unify_error Typing.ClassPropertyInitializerTypeDoesNotMatchHint
3566 let xhp_attribute_does_not_match_hint =
3567 maybe_unify_error Typing.XhpAttributeValueDoesNotMatchHint
3569 let pocket_universes_typing = maybe_unify_error Typing.PocketUniversesTyping
3571 let record_init_value_does_not_match_hint =
3572 maybe_unify_error Typing.RecordInitValueDoesNotMatchHint
3574 let elt_type_to_string = function
3575 | `Method
-> "method"
3576 | `Property
-> "property"
3578 let static_redeclared_as_dynamic
3579 dyn_position static_position member_name ~elt_type
=
3585 let elt_type = elt_type_to_string elt_type in
3592 ^
" is declared here as non-static"
3595 "But it conflicts with an inherited static declaration here"
3598 (Typing.err_code
Typing.StaticDynamic
)
3599 [(dyn_position
, msg_dynamic); (static_position
, msg_static)]
3601 let dynamic_redeclared_as_static
3602 static_position dyn_position member_name ~
elt_type =
3608 let elt_type = elt_type_to_string elt_type in
3615 ^
" is declared here as static"
3618 "But it conflicts with an inherited non-static declaration here"
3621 (Typing.err_code
Typing.StaticDynamic
)
3622 [(static_position
, msg_static); (dyn_position
, msg_dynamic)]
3624 let null_member ~is_method s
pos r
=
3627 "You are trying to access the %s '%s' but this object can be null."
3634 add_list
(Typing.err_code
Typing.NullMember
) ([(pos, msg)] @ r
)
3636 (* Trying to access a member on a mixed or nonnull value. *)
3637 let top_member ~is_method ~is_nullable s pos1 ty pos2
=
3640 "You are trying to access the %s '%s' but this is %s. Use a specific class or interface name."
3650 ( if is_nullable
then
3653 Typing.NonObjectMember
))
3654 [(pos1
, msg); (pos2
, "Definition is here")]
3656 let non_object_member ~is_method s pos1 ty pos2
=
3659 "You are trying to access the %s '%s' but this is %s"
3668 if ty
= "a shape" then
3669 msg_start ^
". Did you mean $foo['" ^ s ^
"'] instead?"
3674 (Typing.err_code
Typing.NonObjectMember
)
3675 [(pos1
, msg); (pos2
, "Definition is here")]
3677 let unknown_object_member ~is_method s
pos r
=
3680 "You are trying to access the %s '%s' on a value whose class is unknown."
3687 add_list
(Typing.err_code
Typing.UnknownObjectMember
) ([(pos, msg)] @ r
)
3689 let non_class_member ~is_method s pos1 ty pos2
=
3692 "You are trying to access the static %s '%s' but this is %s"
3701 (Typing.err_code
Typing.NonClassMember
)
3702 [(pos1
, msg); (pos2
, "Definition is here")]
3704 let ambiguous_member ~is_method s pos1 ty pos2
=
3707 "You are trying to access the %s '%s' but there is more than one implementation on %s"
3716 (Typing.err_code
Typing.AmbiguousMember
)
3717 [(pos1
, msg); (pos2
, "Definition is here")]
3719 let null_container p null_witness
=
3721 (Typing.err_code
Typing.NullContainer
)
3724 "You are trying to access an element of this container"
3725 ^
" but the container could be null. " );
3729 let option_mixed pos =
3731 (Typing.err_code
Typing.OptionMixed
)
3733 "?mixed is a redundant typehint - just use mixed"
3735 let option_null pos =
3737 (Typing.err_code
Typing.OptionNull
)
3739 "?null is a redundant typehint - just use null"
3741 let declared_covariant pos1 pos2 emsg
=
3743 (Typing.err_code
Typing.DeclaredCovariant
)
3745 (pos2
, "Illegal usage of a covariant type parameter");
3746 (pos1
, "This is where the parameter was declared as covariant (+)");
3750 let declared_contravariant pos1 pos2 emsg
=
3752 (Typing.err_code
Typing.DeclaredContravariant
)
3754 (pos2
, "Illegal usage of a contravariant type parameter");
3755 (pos1
, "This is where the parameter was declared as contravariant (-)");
3759 let static_property_type_generic_param ~class_pos ~var_type_pos ~generic_pos
=
3761 (Typing.err_code
Typing.ClassVarTypeGenericParam
)
3764 "A generic parameter cannot be used in the type of a static property" );
3766 "This is where the type of the static property was declared" );
3767 (class_pos
, "This is the class containing the static property");
3770 let contravariant_this pos class_name tp
=
3772 (Typing.err_code
Typing.ContravariantThis
)
3774 ( "The \"this\" type cannot be used in this "
3775 ^
"contravariant position because its enclosing class \""
3778 ^
"is final and has a variant type parameter \""
3782 let cyclic_typeconst pos sl
=
3783 let sl = List.map
sl strip_ns in
3785 (Typing.err_code
Typing.CyclicTypeconst
)
3787 ("Cyclic type constant:\n " ^
String.concat ~sep
:" -> " sl)
3789 let abstract_concrete_override pos parent_pos
kind =
3792 | `method_
-> "method"
3793 | `typeconst
-> "type constant"
3794 | `constant
-> "constant"
3795 | `property
-> "property"
3798 (Typing.err_code
Typing.AbstractConcreteOverride
)
3800 (pos, "Cannot re-declare this " ^
kind_str ^
" as abstract");
3801 (parent_pos
, "Previously defined here");
3804 let required_field_is_optional pos1 pos2
name =
3806 (Typing.err_code
Typing.RequiredFieldIsOptional
)
3808 (pos1
, "The field '" ^
name ^
"' is optional");
3809 (pos2
, "The field '" ^
name ^
"' is defined as required");
3812 let array_get_with_optional_field pos1 pos2
name =
3814 (Typing.err_code
Typing.ArrayGetWithOptionalField
)
3817 "Invalid index operation: '"
3819 ^
"' is marked as an optional shape field. It may not be present in the shape. Use the `??` operator instead."
3821 (pos2
, "This is where the field was declared as optional.");
3824 let non_call_argument_in_suspend pos msgs =
3826 (Typing.err_code
Typing.NonCallArgumentInSuspend
)
3827 ( [(pos, "'suspend' operator expects call to a coroutine as an argument.")]
3830 let non_coroutine_call_in_suspend pos msgs =
3832 (Typing.err_code
Typing.NonCoroutineCallInSuspend
)
3835 "Only coroutine functions are allowed to be called in 'suspend' operator."
3840 let coroutine_call_outside_of_suspend pos =
3842 (Typing.err_code
Typing.CoroutineCallOutsideOfSuspend
)
3845 "Coroutine calls are only allowed when they are arguments to 'suspend' operator"
3849 let function_is_not_coroutine pos name =
3851 (Typing.err_code
Typing.FunctionIsNotCoroutine
)
3856 ^
"' is not a coroutine and cannot be used in as an argument of 'suspend' operator."
3860 let coroutinness_mismatch pos1_is_coroutine pos1 pos2
=
3861 let m1 = "This is a coroutine." in
3862 let m2 = "This is not a coroutine." in
3864 (Typing.err_code
Typing.CoroutinnessMismatch
)
3867 if pos1_is_coroutine
then
3872 if pos1_is_coroutine
then
3878 let invalid_ppl_call pos context
=
3880 "Cannot call a method on an object of a <<__PPL>> class " ^ context
3882 add
(Typing.err_code
Typing.InvalidPPLCall
) pos error_msg
3884 let invalid_ppl_static_call pos reason =
3886 "Cannot call a static method on a <<__PPL>> class " ^
reason
3888 add
(Typing.err_code
Typing.InvalidPPLStaticCall
) pos error_msg
3890 let ppl_meth_pointer pos func
=
3891 let error_msg = func ^
" cannot be used with a <<__PPL>> class" in
3892 add
(Typing.err_code
Typing.PPLMethPointer
) pos error_msg
3894 let coroutine_outside_experimental pos =
3896 (Typing.err_code
Typing.CoroutineOutsideExperimental
)
3898 Coroutine_errors.error_message
3900 let return_disposable_mismatch pos1_return_disposable pos1 pos2
=
3901 let m1 = "This is marked <<__ReturnDisposable>>." in
3902 let m2 = "This is not marked <<__ReturnDisposable>>." in
3904 (Typing.err_code
Typing.ReturnDisposableMismatch
)
3907 if pos1_return_disposable
then
3912 if pos1_return_disposable
then
3918 let return_void_to_rx_mismatch ~pos1_has_attribute pos1 pos2
=
3919 let m1 = "This is marked <<__ReturnsVoidToRx>>." in
3920 let m2 = "This is not marked <<__ReturnsVoidToRx>>." in
3922 (Typing.err_code
Typing.ReturnVoidToRxMismatch
)
3925 if pos1_has_attribute
then
3930 if pos1_has_attribute
then
3936 let this_as_lexical_variable pos =
3938 (Naming.err_code
Naming.ThisAsLexicalVariable
)
3940 "Cannot use $this as lexical variable"
3942 let dollardollar_lvalue pos =
3944 (Typing.err_code
Typing.DollardollarLvalue
)
3946 "Cannot assign a value to the special pipe variable ($$)"
3948 let mutating_const_property pos =
3950 (Typing.err_code
Typing.AssigningToConst
)
3952 "Cannot mutate a __Const property"
3954 let self_const_parent_not pos =
3956 (Typing.err_code
Typing.SelfConstParentNot
)
3958 "A __Const class may only extend other __Const classes"
3960 let overriding_prop_const_mismatch parent_pos parent_const child_pos child_const
3962 let m1 = "This property is __Const" in
3963 let m2 = "This property is not __Const" in
3965 (Typing.err_code
Typing.OverridingPropConstMismatch
)
3968 if parent_const
then
3979 let mutable_return_result_mismatch pos1_has_mutable_return pos1 pos2
=
3980 let m1 = "This is marked <<__MutableReturn>>." in
3981 let m2 = "This is not marked <<__MutableReturn>>." in
3983 (Typing.err_code
Typing.MutableReturnResultMismatch
)
3986 if pos1_has_mutable_return
then
3991 if pos1_has_mutable_return
then
3997 let pu_expansion pos =
3999 (Typing.err_code
Typing.PocketUniversesExpansion
)
4001 "[PocketUniverses] Type expansion is not supported."
4003 let pu_typing pos kind msg =
4005 (Typing.err_code
Typing.PocketUniversesTyping
)
4008 "Unexpected Pocket Universes %s %s while typing expressions."
4012 let php_lambda_disallowed pos =
4014 (NastCheck.err_code
NastCheck.PhpLambdaDisallowed
)
4016 "PHP style anonymous functions are not allowed."
4018 (*****************************************************************************)
4019 (* Typing decl errors *)
4020 (*****************************************************************************)
4022 let wrong_extend_kind child_pos child parent_pos parent
=
4023 let msg1 = (child_pos
, child ^
" cannot extend " ^ parent
) in
4024 let msg2 = (parent_pos
, "This is " ^ parent
) in
4025 add_list
(Typing.err_code
Typing.WrongExtendKind
) [msg1; msg2]
4027 let unsatisfied_req parent_pos req_name req_pos
=
4028 let s1 = "Failure to satisfy requirement: " ^
strip_ns req_name
in
4029 let s2 = "Required here" in
4030 if req_pos
= parent_pos
then
4031 add
(Typing.err_code
Typing.UnsatisfiedReq
) parent_pos
s1
4034 (Typing.err_code
Typing.UnsatisfiedReq
)
4035 [(parent_pos
, s1); (req_pos
, s2)]
4037 let cyclic_class_def stack
pos =
4038 let stack = SSet.fold ~
f:(fun x y -> strip_ns x ^
" " ^
y) stack ~init
:"" in
4040 (Typing.err_code
Typing.CyclicClassDef
)
4042 ("Cyclic class definition : " ^
stack)
4044 let trait_reuse p_pos p_name
class_name trait
=
4045 let (c_pos
, c_name
) = class_name in
4046 let c_name = strip_ns c_name in
4047 let trait = strip_ns trait in
4049 "Class " ^
c_name ^
" reuses trait " ^
trait ^
" in its hierarchy"
4051 let err'
= "It is already used through " ^
strip_ns p_name
in
4052 add_list
(Typing.err_code
Typing.TraitReuse
) [(c_pos
, err); (p_pos
, err'
)]
4054 let invalid_is_as_expression_hint op hint_pos ty_pos ty_str
=
4056 (Typing.err_code
Typing.InvalidIsAsExpressionHint
)
4058 (hint_pos
, "Invalid \"" ^ op ^
"\" expression hint");
4059 (ty_pos
, "The \"" ^ op ^
"\" operator cannot be used with " ^ ty_str
);
4062 let invalid_enforceable_type kind_str (tp_pos
, tp_name
) targ_pos ty_pos ty_str
=
4064 (Typing.err_code
Typing.InvalidEnforceableTypeArgument
)
4066 (targ_pos
, "Invalid type");
4068 "Type " ^
kind_str ^
" " ^ tp_name ^
" was declared __Enforceable here"
4070 (ty_pos
, "This type is not enforceable because it has " ^ ty_str
);
4073 let reifiable_attr attr_pos decl_kind decl_pos ty_pos ty_msg
=
4075 (Typing.err_code
Typing.DisallowPHPArraysAttr
)
4077 (decl_pos
, "Invalid " ^ decl_kind
);
4078 (attr_pos
, "This type constant has the __Reifiable attribute");
4079 (ty_pos
, "It cannot contain " ^ ty_msg
);
4082 let invalid_newable_type_argument (tp_pos
, tp_name
) ta_pos
=
4084 (Typing.err_code
Typing.InvalidNewableTypeArgument
)
4087 "A newable type argument must be a concrete class or a newable type parameter."
4089 (tp_pos
, "Type parameter " ^ tp_name ^
" was declared __Newable here");
4092 let invalid_newable_type_param_constraints
4093 (tparam_pos
, tparam_name
) constraint_list
=
4095 if List.is_empty constraint_list
then
4099 ^
String.concat ~sep
:", " (List.map ~
f:strip_ns constraint_list
)
4102 "The type parameter "
4104 ^
" has the <<__Newable>> attribute. Newable type parameters must be constrained with `as`, and exactly one of those constraints must be a valid newable class. The class must either be final, or it must have the <<__ConsistentConstruct>> attribute or extend a class that has it. "
4106 ^
" are valid newable classes"
4108 add
(Typing.err_code
Typing.InvalidNewableTypeParamConstraints
) tparam_pos
msg
4110 let override_final ~parent ~child
=
4112 (Typing.err_code
Typing.OverrideFinal
)
4114 (child
, "You cannot override this method");
4115 (parent
, "It was declared as final");
4118 let override_memoizelsb ~parent ~child
=
4120 (Typing.err_code
Typing.OverrideMemoizeLSB
)
4123 "__MemoizeLSB method may not be an override (temporary due to HHVM bug)"
4125 (parent
, "This method is being overridden");
4128 let override_lsb ~member_name ~parent ~child
=
4130 (Typing.err_code
Typing.OverrideLSB
)
4133 "Member " ^ member_name ^
" may not override __LSB member of parent" );
4134 (parent
, "This is being overridden");
4137 let should_be_override pos class_id id
=
4139 (Typing.err_code
Typing.ShouldBeOverride
)
4144 ^
"() is marked as override; no non-private parent definition found or overridden parent is defined in non-<?hh code"
4147 let override_per_trait class_name id m_pos
=
4148 let (c_pos
, c_name) = class_name in
4154 ^
" should be an override per the declaring trait; no non-private parent definition found or overridden parent is defined in non-<?hh code"
4157 (Typing.err_code
Typing.OverridePerTrait
)
4158 [(c_pos
, err_msg); (m_pos
, "Declaration of " ^ id ^
"() is here")]
4160 let missing_assign pos =
4161 add
(Typing.err_code
Typing.MissingAssign
) pos "Please assign a value"
4163 let private_override pos class_id id
=
4165 (Typing.err_code
Typing.PrivateOverride
)
4170 ^
": combining private and override is nonsensical" )
4172 let invalid_memoized_param pos ty_reason_msg
=
4174 (Typing.err_code
Typing.InvalidMemoizedParam
)
4176 "Parameters to memoized function must be null, bool, int, float, string, an object deriving IMemoizeParam, or a Container thereof. See also http://docs.hhvm.com/hack/attributes/special#__memoize"
4180 let invalid_disposable_hint pos class_name =
4182 (Typing.err_code
Typing.InvalidDisposableHint
)
4184 ( "Parameter with type '"
4186 ^
"' must not implement IDisposable or IAsyncDisposable. Please use <<__AcceptDisposable>> attribute or create disposable object with 'using' statement instead."
4189 let invalid_disposable_return_hint pos class_name =
4191 (Typing.err_code
Typing.InvalidDisposableReturnHint
)
4195 ^
"' must not implement IDisposable or IAsyncDisposable. Please add <<__ReturnDisposable>> attribute."
4198 let xhp_required pos why_xhp ty_reason_msg
=
4199 let msg = "An XHP instance was expected" in
4201 (Typing.err_code
Typing.XhpRequired
)
4202 ((pos, msg) :: (pos, why_xhp
) :: ty_reason_msg
)
4204 let illegal_xhp_child pos ty_reason_msg
=
4205 let msg = "XHP children must be compatible with XHPChild" in
4206 add_list
(Typing.err_code
Typing.IllegalXhpChild
) ((pos, msg) :: ty_reason_msg
)
4208 let missing_xhp_required_attr pos attr ty_reason_msg
=
4209 let msg = "Required attribute " ^ attr ^
" is missing." in
4211 (Typing.err_code
Typing.MissingXhpRequiredAttr
)
4212 ((pos, msg) :: ty_reason_msg
)
4214 let nullsafe_not_needed p nonnull_witness
=
4216 (Typing.err_code
Typing.NullsafeNotNeeded
)
4217 ( [(p, "You are using the ?-> operator but this object cannot be null. ")]
4220 let generic_at_runtime p prefix
=
4222 (Typing.err_code
Typing.ErasedGenericAtRuntime
)
4225 ^
" generics can only be used in type hints because they do not exist at runtime."
4228 let generics_not_allowed p =
4230 (Typing.err_code
Typing.GenericsNotAllowed
)
4232 "Generics are not allowed in this position."
4234 let trivial_strict_eq p b left right left_trail right_trail
=
4235 let msg = "This expression is always " ^ b
in
4236 let left_trail = List.map
left_trail typedef_trail_entry in
4237 let right_trail = List.map
right_trail typedef_trail_entry in
4239 (Typing.err_code
Typing.TrivialStrictEq
)
4240 (((p, msg) :: left
) @ left_trail @ right
@ right_trail)
4242 let trivial_strict_not_nullable_compare_null p result type_reason
=
4243 let msg = "This expression is always " ^
result in
4245 (Typing.err_code
Typing.NotNullableCompareNullTrivial
)
4246 ((p, msg) :: type_reason
)
4248 let eq_incompatible_types p left right
=
4249 let msg = "This equality test has incompatible types" in
4251 (Typing.err_code
Typing.EqIncompatibleTypes
)
4252 (((p, msg) :: left
) @ right
)
4254 let comparison_invalid_types p left right
=
4256 "This comparison has invalid types. Only comparisons in which both arguments are strings, nums, DateTime, or DateTimeImmutable are allowed"
4259 (Typing.err_code
Typing.ComparisonInvalidTypes
)
4260 (((p, msg) :: left
) @ right
)
4262 let void_usage p void_witness
=
4263 let msg = "You are using the return value of a void function" in
4264 add_list
(Typing.err_code
Typing.VoidUsage
) ((p, msg) :: void_witness
)
4266 let noreturn_usage p noreturn_witness
=
4267 let msg = "You are using the return value of a noreturn function" in
4268 add_list
(Typing.err_code
Typing.NoreturnUsage
) ((p, msg) :: noreturn_witness
)
4270 let attribute_too_few_arguments pos x n =
4271 let n = string_of_int
n in
4273 (Typing.err_code
Typing.AttributeTooFewArguments
)
4275 ("The attribute " ^
x ^
" expects at least " ^
n ^
" arguments")
4277 let attribute_too_many_arguments pos x n =
4278 let n = string_of_int
n in
4280 (Typing.err_code
Typing.AttributeTooManyArguments
)
4282 ("The attribute " ^
x ^
" expects at most " ^
n ^
" arguments")
4284 let attribute_param_type pos x =
4286 (Typing.err_code
Typing.AttributeParamType
)
4288 ("This attribute parameter should be " ^
x)
4290 let deprecated_use pos pos_def
msg =
4292 (Typing.err_code
Typing.DeprecatedUse
)
4293 [(pos, msg); (pos_def
, "Definition is here")]
4295 let cannot_declare_constant kind pos (class_pos
, class_name) =
4298 | `enum
-> "an enum"
4299 | `
trait -> "a trait"
4300 | `record
-> "a record"
4303 (Typing.err_code
Typing.CannotDeclareConstant
)
4305 (pos, "Cannot declare a constant in " ^
kind_str);
4306 (class_pos
, strip_ns class_name ^
" was defined as " ^
kind_str ^
" here");
4309 let ambiguous_inheritance pos class_ origin
(error
: error
) =
4310 let origin = strip_ns origin in
4311 let class_ = strip_ns class_ in
4313 "This declaration was inherited from an object of type "
4315 ^
". Redeclare this member in "
4317 ^
" with a compatible signature."
4319 let (code
, msgl) = (get_code error
, to_list error
) in
4320 add_list code
(msgl @ [(pos, message)])
4322 let multiple_concrete_defs
4323 child_pos parent_pos child_origin parent_origin
name class_ =
4324 let child_origin = strip_ns child_origin in
4325 let parent_origin = strip_ns parent_origin in
4326 let class_ = strip_ns class_ in
4328 (Typing.err_code
Typing.MultipleConcreteDefs
)
4334 ^
" both declare ambiguous implementations of "
4337 (child_pos
, child_origin ^
"'s definition is here.");
4338 (parent_pos
, parent_origin ^
"'s definition is here.");
4340 "Redeclare " ^
name ^
" in " ^
class_ ^
" with a compatible signature."
4344 let local_variable_modified_and_used pos_modified pos_used_l
=
4345 let used_msg p = (p, "And accessed here") in
4347 (Typing.err_code
Typing.LocalVariableModifedAndUsed
)
4349 "Unsequenced modification and access to local variable. Modified here"
4351 :: List.map pos_used_l
used_msg )
4353 let local_variable_modified_twice pos_modified pos_modified_l
=
4354 let modified_msg p = (p, "And also modified here") in
4356 (Typing.err_code
Typing.LocalVariableModifedTwice
)
4358 "Unsequenced modifications to local variable. Modified here" )
4359 :: List.map pos_modified_l
modified_msg )
4361 let assign_during_case p =
4363 (Typing.err_code
Typing.AssignDuringCase
)
4365 "Don't assign to variables inside of case labels"
4367 let cyclic_enum_constraint pos =
4368 add
(Typing.err_code
Typing.CyclicEnumConstraint
) pos "Cyclic enum constraint"
4370 let invalid_classname p =
4371 add
(Typing.err_code
Typing.InvalidClassname
) p "Not a valid class name"
4373 let illegal_type_structure pos errmsg
=
4375 "The two arguments to type_structure() must be:"
4376 ^
"\n - first: ValidClassname::class or an object of that class"
4377 ^
"\n - second: a single-quoted string literal containing the name"
4378 ^
" of a type constant of that class"
4382 add
(Typing.err_code
Typing.IllegalTypeStructure
) pos msg
4384 let illegal_typeconst_direct_access pos =
4386 "Type constants cannot be directly accessed. "
4387 ^
"Use type_structure(ValidClassname::class, 'TypeConstName') instead"
4389 add
(Typing.err_code
Typing.IllegalTypeStructure
) pos msg
4391 let override_no_default_typeconst pos_child pos_parent
=
4393 (Typing.err_code
Typing.OverrideNoDefaultTypeconst
)
4395 (pos_child
, "This abstract type constant does not have a default type");
4397 "It cannot override an abstract type constant that has a default type"
4401 let reference_expr pos =
4402 let msg = "References are only allowed as function call arguments" in
4403 add
(Typing.err_code
Typing.ReferenceExprNotFunctionArg
) pos msg
4405 let pass_by_ref_annotation_missing pos1 pos2
=
4406 let msg1 = (pos1
, "This argument should be annotated with &") in
4407 let msg2 = (pos2
, "Because this parameter is passed by reference") in
4408 add_list
(Typing.err_code
Typing.PassByRefAnnotationMissing
) [msg1; msg2]
4410 let pass_by_ref_annotation_unexpected pos1 pos2 pos2_is_variadic
=
4411 let msg1 = (pos1
, "This argument should not be annotated with &") in
4413 if pos2_is_variadic
then
4414 "variadic parameters are"
4418 let msg2 = (pos2
, "Because " ^
param_str ^
" passed by value") in
4419 add_list
(Typing.err_code
Typing.PassByRefAnnotationUnexpected
) [msg1; msg2]
4421 let reffiness_invariant pos1 pos2 mode2
=
4422 let msg1 = (pos1
, "This parameter is passed by reference") in
4425 | `normal
-> "a normal parameter"
4426 | `inout
-> "an inout parameter"
4428 let msg2 = (pos2
, "It is incompatible with " ^
mode_str) in
4429 add_list
(Typing.err_code
Typing.ReffinessInvariant
) [msg1; msg2]
4431 let inout_annotation_missing pos1 pos2
=
4432 let msg1 = (pos1
, "This argument should be annotated with 'inout'") in
4433 let msg2 = (pos2
, "Because this is an inout parameter") in
4434 add_list
(Typing.err_code
Typing.InoutAnnotationMissing
) [msg1; msg2]
4436 let inout_annotation_unexpected pos1 pos2 pos2_is_variadic
=
4437 let msg1 = (pos1
, "Unexpected inout annotation for argument") in
4440 if pos2_is_variadic
then
4441 "A variadic parameter can never be inout"
4443 "This is a normal parameter (does not have 'inout')" )
4445 add_list
(Typing.err_code
Typing.InoutAnnotationUnexpected
) [msg1; msg2]
4447 let inoutness_mismatch pos1 pos2
=
4448 let msg1 = (pos1
, "This is an inout parameter") in
4449 let msg2 = (pos2
, "It is incompatible with a normal parameter") in
4450 add_list
(Typing.err_code
Typing.InoutnessMismatch
) [msg1; msg2]
4452 let invalid_new_disposable pos =
4454 "Disposable objects may only be created in a 'using' statement or 'return' from function marked <<__ReturnDisposable>>"
4456 add
(Typing.err_code
Typing.InvalidNewDisposable
) pos msg
4458 let invalid_return_disposable pos =
4460 "Return expression must be new disposable in function marked <<__ReturnDisposable>>"
4462 add
(Typing.err_code
Typing.InvalidReturnDisposable
) pos msg
4464 let nonreactive_function_call pos decl_pos callee_reactivity cause_pos_opt
=
4466 (Typing.err_code
Typing.NonreactiveFunctionCall
)
4468 (pos, "Reactive functions can only call other reactive functions.");
4469 (decl_pos
, "This function is " ^ callee_reactivity ^
".");
4471 @ Option.value_map cause_pos_opt ~default
:[] ~
f:(fun cause_pos
->
4474 "This argument caused function to be " ^ callee_reactivity ^
"."
4478 let nonreactive_call_from_shallow pos decl_pos callee_reactivity cause_pos_opt
=
4480 (Typing.err_code
Typing.NonreactiveCallFromShallow
)
4482 (pos, "Shallow reactive functions cannot call non-reactive functions.");
4483 (decl_pos
, "This function is " ^ callee_reactivity ^
".");
4485 @ Option.value_map cause_pos_opt ~default
:[] ~
f:(fun cause_pos
->
4488 "This argument caused function to be " ^ callee_reactivity ^
"."
4492 let rx_enabled_in_non_rx_context pos =
4494 (Typing.err_code
Typing.RxEnabledInNonRxContext
)
4496 "\\HH\\Rx\\IS_ENABLED can only be used in reactive functions."
4498 let rx_parameter_condition_mismatch cond
pos def_pos
=
4500 (Typing.err_code
Typing.RxParameterConditionMismatch
)
4503 "This parameter does not satisfy "
4505 ^
" condition defined on matching parameter in function super type." );
4506 (def_pos
, "This is parameter declaration from the function super type.");
4509 let nonreactive_indexing is_append
pos =
4512 "Cannot append to a Hack Collection object in a reactive context. Instead, use the 'add' method."
4514 "Cannot assign to element of Hack Collection object via [] in a reactive context. Instead, use the 'set' method."
4516 add
(Typing.err_code
Typing.NonreactiveIndexing
) pos msg
4518 let obj_set_reactive pos =
4520 "This object's property is being mutated(used as an lvalue)"
4521 ^
"\nYou cannot set non-mutable object properties in reactive functions"
4523 add
(Typing.err_code
Typing.ObjSetReactive
) pos msg
4525 let invalid_unset_target_rx pos =
4527 (Typing.err_code
Typing.InvalidUnsetTargetInRx
)
4529 "Non-mutable argument for 'unset' is not allowed in reactive functions."
4531 let inout_argument_bad_type pos msgl =
4533 "Expected argument marked inout to be contained in a local or "
4534 ^
"a value-typed container (e.g. vec, dict, keyset, array). "
4535 ^
"To use inout here, assign to/from a temporary local variable."
4537 add_list
(Typing.err_code
Typing.InoutArgumentBadType
) ((pos, msg) :: msgl)
4539 let ambiguous_lambda pos uses
=
4541 "Lambda has parameter types that could not be determined at definition site."
4545 "%d distinct use types were determined: please add type hints to lambda parameters."
4549 (Typing.err_code
Typing.AmbiguousLambda
)
4550 ( [(pos, msg1); (pos, msg2)]
4551 @ List.map uses
(fun (pos, ty
) -> (pos, "This use has type " ^ ty
)) )
4553 let wrong_expression_kind_attribute
4554 expr_kind
pos attr attr_class_pos attr_class_name intf_name
=
4557 "The %s attribute cannot be used on %s."
4563 "The attribute's class is defined here. To be available for use on %s, the %s class must implement %s."
4565 (strip_ns attr_class_name
)
4566 (strip_ns intf_name
)
4569 (Typing.err_code
Typing.WrongExpressionKindAttribute
)
4570 [(pos, msg1); (attr_class_pos
, msg2)]
4572 let wrong_expression_kind_builtin_attribute expr_kind
pos attr
=
4575 "The %s attribute cannot be used on %s."
4579 add_list
(Typing.err_code
Typing.WrongExpressionKindAttribute
) [(pos, msg1)]
4581 let cannot_return_borrowed_value_as_immutable fun_pos value_pos
=
4583 (Typing.err_code
Typing.CannotReturnBorrowedValueAsImmutable
)
4586 "Values returned from reactive function by default are treated as immutable."
4589 "This value is mutably borrowed and cannot be returned as immutable" );
4592 let decl_override_missing_hint pos =
4594 (Typing.err_code
Typing.DeclOverrideMissingHint
)
4596 "When redeclaring class members, both declarations must have a typehint"
4598 let let_var_immutability_violation pos id
=
4600 (Typing.err_code
Typing.LetVarImmutabilityViolation
)
4602 ( "Let variables are immutable. Using let variable "
4604 ^
" in write context is not allowed." )
4606 let invalid_type_for_atmost_rx_as_rxfunc_parameter pos type_str
=
4608 (Typing.err_code
Typing.InvalidTypeForOnlyrxIfRxfuncParameter
)
4610 ( "Parameter annotated with <<__AtMostRxAsFunc>> attribute must be function, now '"
4614 let missing_annotation_for_atmost_rx_as_rxfunc_parameter pos =
4616 (Typing.err_code
Typing.MissingAnnotationForOnlyrxIfRxfuncParameter
)
4618 "Missing function type annotation on parameter marked with <<__AtMostRxAsFunc>> attribute."
4620 let binding_ref_in_array pos =
4621 let msg = "Arrays cannot contain references." in
4622 add
(Typing.err_code
Typing.BindingRefInArray
) pos msg
4624 let binding_ref_to_array pos =
4625 let msg = "Cannot take references to array elements." in
4626 add
(Typing.err_code
Typing.BindingRefInArray
) pos msg
4628 let passing_array_cell_by_ref pos =
4630 "Passing array elements by reference is no longer supported; "
4631 ^
"use 'inout' instead"
4633 add
(Typing.err_code
Typing.PassingArrayCellByRef
) pos msg
4635 let superglobal_in_reactive_context pos name =
4637 (Typing.err_code
Typing.SuperglobalInReactiveContext
)
4639 ("Superglobal " ^
name ^
" cannot be used in a reactive context.")
4641 let static_property_in_reactive_context pos =
4643 (Typing.err_code
Typing.StaticPropertyInReactiveContext
)
4645 "Static property cannot be used in a reactive context."
4647 let returns_void_to_rx_function_as_non_expression_statement pos fpos
=
4649 (Typing.err_code
Typing.ReturnsVoidToRxAsNonExpressionStatement
)
4652 "Cannot use result of function annotated with <<__ReturnsVoidToRx>> in reactive context"
4654 (fpos
, "This is function declaration.");
4657 let non_awaited_awaitable_in_rx pos =
4659 (Typing.err_code
Typing.NonawaitedAwaitableInReactiveContext
)
4661 "This value has Awaitable type. Awaitable typed values in reactive code must be immediately await'ed."
4663 let shapes_key_exists_always_true pos1
name pos2
=
4665 (Typing.err_code
Typing.ShapesKeyExistsAlwaysTrue
)
4667 (pos1
, "This Shapes::keyExists() check is always true");
4668 (pos2
, "The field '" ^
name ^
"' exists because of this definition");
4671 let shape_field_non_existence_reason pos name = function
4673 [(pos, "The field '" ^
name ^
"' is not defined in this shape")]
4674 | `Nothing
reason ->
4676 "The type of the field '"
4678 ^
"' in this shape doesn't allow any values" )
4681 let shapes_key_exists_always_false pos1
name pos2
reason =
4682 add_list
(Typing.err_code
Typing.ShapesKeyExistsAlwaysFalse
)
4683 @@ (pos1
, "This Shapes::keyExists() check is always false")
4684 :: shape_field_non_existence_reason pos2
name reason
4686 let shapes_method_access_with_non_existent_field
4687 pos1
name pos2 method_name
reason =
4688 add_list
(Typing.err_code
Typing.ShapesMethodAccessWithNonExistentField
)
4690 "You are calling Shapes::"
4692 ^
"() on a field known to not exist" )
4693 :: shape_field_non_existence_reason pos2
name reason
4695 let shape_access_with_non_existent_field pos1
name pos2
reason =
4696 add_list
(Typing.err_code
Typing.ShapeAccessWithNonExistentField
)
4697 @@ (pos1
, "You are accessing a field known to not exist")
4698 :: shape_field_non_existence_reason pos2
name reason
4700 let ambiguous_object_access
4701 pos name self_pos vis subclass_pos class_self class_subclass
=
4702 let class_self = strip_ns class_self in
4703 let class_subclass = strip_ns class_subclass in
4705 (Typing.err_code
Typing.AmbiguousObjectAccess
)
4707 (pos, "This object access to " ^
name ^
" is ambiguous");
4709 "You will access the private instance declared in " ^
class_self );
4711 "Instead of the " ^ vis ^
" instance declared in " ^
class_subclass );
4714 let invalid_traversable_in_rx pos =
4716 (Typing.err_code
Typing.InvalidTraversableInRx
)
4718 "Cannot traverse over non-reactive traversable in reactive code."
4720 let lateinit_with_default pos =
4722 (Typing.err_code
Typing.LateInitWithDefault
)
4724 "A late-initialized property cannot have a default value"
4726 let bad_lateinit_override parent_is_lateinit parent_pos child_pos
=
4728 if parent_is_lateinit
then
4734 (Typing.err_code
Typing.BadLateInitOverride
)
4737 "Redeclared properties must be consistently declared __LateInit" );
4738 (parent_pos
, "The property " ^
verb ^
" declared __LateInit here");
4741 let bad_xhp_attr_required_override parent_tag child_tag parent_pos child_pos
=
4743 (Typing.err_code
Typing.BadXhpAttrRequiredOverride
)
4745 (child_pos
, "Redeclared attribute must not be less strict");
4749 ^
", which is stricter than "
4753 let invalid_switch_case_value_type case_value_p case_value_ty scrutinee_ty
=
4754 add
(Typing.err_code
Typing.InvalidSwitchCaseValueType
) case_value_p
4756 "This case value has type %s, which is incompatible with type %s."
4760 let unserializable_type pos message =
4762 (Typing.err_code
Typing.UnserializableType
)
4764 ( "Unserializable type (could not be converted to JSON and back again): "
4767 let redundant_rx_condition pos =
4769 (Typing.err_code
Typing.RedundantRxCondition
)
4771 "Reactivity condition for this method is always true, consider removing it."
4773 let invalid_arraykey pos (cpos
, ctype
) (kpos
, ktype
) =
4775 (Typing.err_code
Typing.InvalidArrayKey
)
4777 (pos, "This value is not a valid key type for this container");
4778 (cpos
, "This container is " ^ ctype
);
4779 (kpos
, String.capitalize ktype ^
" cannot be used as a key for " ^ ctype
);
4782 let invalid_sub_string pos ty
=
4783 add
(Typing.err_code
Typing.InvalidSubString
) pos
4784 @@ "Expected an object convertible to string but got "
4787 let typechecker_timeout (pos, fun_name
) seconds
=
4789 (Typing.err_code
Typing.TypecheckerTimeout
)
4792 "Type checker timed out after %d seconds whilst checking function %s"
4796 let unresolved_type_variable pos =
4798 (Typing.err_code
Typing.UnresolvedTypeVariable
)
4800 "The type of this expression contains an unresolved type variable"
4802 let invalid_arraykey_constraint pos t
=
4804 (Typing.err_code
Typing.InvalidArrayKeyConstraint
)
4808 ^
", which cannot be used as an arraykey (string | int)" )
4810 (*****************************************************************************)
4812 (*****************************************************************************)
4814 let to_json (error
: Pos.absolute error_
) =
4815 let (error_code, msgl) = (get_code error
, to_list error
) in
4817 List.map
msgl (fun (p, w
) ->
4818 let (line, scol
, ecol
) = Pos.info_pos
p in
4821 ("descr", Hh_json.JSON_String w
);
4822 ("path", Hh_json.JSON_String
(Pos.filename p));
4823 ("line", Hh_json.int_
line);
4824 ("start", Hh_json.int_ scol
);
4825 ("end", Hh_json.int_ ecol
);
4826 ("code", Hh_json.int_
error_code);
4829 Hh_json.JSON_Object
[("message", Hh_json.JSON_Array
elts)]
4831 let convert_errors_to_string ?
(include_filename
= false) (errors
: error list
) :
4835 ~
f:(fun err acc_out
->
4838 ~
f:(fun (pos, msg) acc_in
->
4839 let result = Format.asprintf
"%a %s" Pos.pp
pos msg in
4840 if include_filename
then
4844 (Pos.to_absolute pos |> Pos.filename)
4847 full_result :: acc_in
4853 (*****************************************************************************)
4854 (* Try if errors. *)
4855 (*****************************************************************************)
4857 let try_ f1 f2
= try_with_result f1
(fun _
l -> f2
l)
4859 let try_with_error f1 f2
=
4861 let (error_code, l) = (get_code
err, to_list err) in
4862 add_list
error_code l;
4865 let try_add_err pos err f1 f2
=
4866 try_ f1
(fun error
->
4867 let (error_code, l) = (get_code error
, to_list error
) in
4868 add_list
error_code ((pos, err) :: l);
4871 let has_no_errors f =
4878 let try_unless_error_in_different_file file
f error_file_mismatch_handler
=
4879 try_with_result f (fun r
err ->
4881 | (_, first
:: _) ->
4882 let (err_pos
, _) = first
in
4883 if Pos.filename err_pos
<> file
then
4884 error_file_mismatch_handler
err
4888 (* No errors? This fun shouldn't even get called... *)
4892 (*****************************************************************************)
4894 (*****************************************************************************)
4897 let allow_errors_in_default_path_copy = !allow_errors_in_default_path in
4898 set_allow_errors_in_default_path true;
4899 let (_, result) = do_ f in
4900 set_allow_errors_in_default_path allow_errors_in_default_path_copy;
4903 let try_when f ~when_ ~
do_ =
4904 try_with_result f (fun result (error
: error
) ->