Ignore fixmes when doing Errors.try_
[hiphop-php.git] / hphp / hack / src / errors / errors.ml
blobcdc047ea755ab72e8f88a2dcd4fe1e2eaf16374c
1 (*
2 * Copyright (c) 2015, Facebook, Inc.
3 * All rights reserved.
5 * This source code is licensed under the MIT license found in the
6 * LICENSE file in the "hack" directory of this source tree.
8 *)
10 open Core_kernel
11 open Reordered_argument_collections
12 open String_utils
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]
20 type phase =
21 | Init
22 | Parsing
23 | Naming
24 | Decl
25 | Typing
27 type severity =
28 | Warning
29 | Error
31 type format =
32 | Context
33 | Raw
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
45 type t = phase
47 let rank = function
48 | Init -> 0
49 | Parsing -> 1
50 | Naming -> 2
51 | Decl -> 3
52 | Typing -> 4
54 let compare x y = rank x - rank y
55 end))
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 ->
73 let y =
74 Option.value (Relative_path.Map.find_opt y k) ~default:PhaseMap.empty
76 Relative_path.Map.add
77 acc
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:[]
83 |> List.rev
85 let list_to_files_t = function
86 | [] -> Relative_path.Map.empty
87 | x ->
88 (* Values constructed here should not be used with incremental mode.
89 * See assert in incremental_update. *)
90 Relative_path.Map.singleton
91 Relative_path.default
92 (PhaseMap.singleton Typing x)
94 let get_code_severity code =
96 code
97 = Error_codes.Init.err_code Error_codes.Init.ForwardCompatibilityNotCurrent
98 then
99 Warning
100 else
101 Error
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
109 | None -> None
110 | Some (_, phase_map) ->
111 let error_list =
112 PhaseMap.max_binding_opt phase_map |> Option.value_map ~f:snd ~default:[]
114 (match List.rev error_list with
115 | [] -> None
116 | e :: _ -> Some e)
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) =
143 Utils.try_finally
145 begin
146 fun () ->
147 let result = f1 () in
148 (result, !error_map)
150 ~finally:
151 begin
152 fun () ->
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
159 | None -> result
160 | Some (code, l) ->
161 (* Remove bad position sentinel if present: we might be about to add a new primary
162 * error position*)
163 let l =
164 match l with
165 | (_, msg) :: l when msg = Badpos_sentinel.message -> l
166 | _ -> l
168 f2 result (code, l)
170 let do_ f =
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) =
178 Utils.try_finally
180 begin
181 fun () ->
182 let result = f () in
183 (result, !error_map, !applied_fixmes)
185 ~finally:
186 begin
187 fun () ->
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";
214 Printf.eprintf
215 "%s"
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
227 | 1 -> "Parsing"
228 | 2 -> "Naming"
229 | 3 -> "NastCheck"
230 | 4 -> "Typing"
231 | 5 -> "Lint"
232 | 8 -> "Init"
233 | _ -> "Other"
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 =
241 match phase with
242 | Init -> "Init"
243 | Parsing -> "Parsing"
244 | Naming -> "Naming"
245 | Decl -> "Decl"
246 | Typing -> "Typing"
248 let rec get_pos (error : error) = fst (List.hd_exn (snd error))
250 and sort err =
251 List.sort
252 ~compare:
253 begin
254 fun x y ->
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
275 file_t_map :=
276 Relative_path.Map.add
277 !file_t_map
278 current_file
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 (*****************************************************************************)
295 (* Accessors. *)
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
306 (code, msg_l)
308 let read_lines path = In_channel.read_lines path
310 let line_margin (line_num : int option) col_width : string =
311 let padded_num =
312 match line_num with
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 :
328 string =
329 let lines =
330 match lines with
331 | [] -> [Tty.apply_color (Tty.Dim Tty.Default) "No source found"]
332 | ls -> ls
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
344 (pos : Pos.absolute)
345 (msg : string)
346 (first_context_line : string option)
347 is_first
348 col_width : string =
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
357 else
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 ' '
364 else
367 let color =
368 if is_first then
369 Tty.Bold Tty.Red
370 else
371 Tty.Dim Tty.Default
373 Printf.sprintf
374 "%s %s%s"
375 (line_margin None col_width)
376 underline_padding
377 (Tty.apply_color
378 color
379 ( if is_first then
380 underline
381 else
382 underline ^ " " ^ msg ))
384 let format_filename (pos : Pos.absolute) : string =
385 let relative_path path =
386 let cwd = Filename.concat (Sys.getcwd ()) "" in
387 lstrip path cwd
389 let filename = relative_path (Pos.filename pos) in
390 Printf.sprintf
391 " %s %s"
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 :
401 string * string =
402 let 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
407 let pretty_msg =
408 format_substring_underline
411 (List.hd context_lines)
412 is_first
413 col_width
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 =
423 match msgs with
424 | msg :: msgs ->
425 let filename = Pos.filename (fst msg) in
426 (match String.Map.find grouped filename with
427 | Some file_msgs ->
428 let grouped =
429 String.Map.set grouped ~key:filename ~data:(file_msgs @ [msg])
431 build_map msgs grouped filenames
432 | None ->
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. *)
446 let longest_lines =
447 List.fold msgs ~init:String.Map.empty ~f:(fun acc msg ->
448 let filename = Pos.filename (fst msg) in
449 let current_max =
450 Option.value (String.Map.find acc filename) ~default:0
452 String.Map.set
454 ~key:filename
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 =
466 match msgs with
467 | msg :: msgs -> (msg, is_first) :: label_first msgs false
468 | [] -> []
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))
475 | _ -> 0
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 =
482 match msgs with
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 =
492 match prev with
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*)
496 [pretty_msg]
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))
503 | [] -> []
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 =
509 match format with
510 | Context ->
511 let total = List.length errors + dropped_count in
512 let formatted_total =
513 Printf.sprintf
514 "%d error%s found"
515 total
516 ( if total = 1 then
518 else
519 "s" )
521 let truncated =
522 match max_errors with
523 | Some max_errors when dropped_count > 0 ->
524 Printf.sprintf
525 " (only showing first %d, dropped %d).\n"
526 max_errors
527 dropped_count
528 | _ -> ".\n"
530 Some (formatted_total ^ truncated)
531 | Raw -> None
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
537 (match msgl with
538 | [] -> failwith "Impossible: an error always has non-empty list of messages"
539 | (_, msg) :: _ ->
540 Buffer.add_string
542 (Printf.sprintf
543 "%s %s\n"
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)
547 with _ ->
548 Buffer.add_string
550 "Error could not be pretty-printed. Please file a bug.");
551 Buffer.add_string buf "\n";
552 Buffer.contents buf
554 let to_absolute_for_test error =
555 let (code, msg_l) = (get_code error, to_list error) in
556 let msg_l =
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
560 let p =
561 Pos.set_file
562 (Relative_path.create Relative_path.Dummy path_without_prefix)
565 (Pos.to_absolute p, s))
567 (code, msg_l)
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
572 (match msgl with
573 | [] -> assert false
574 | (pos1, msg1) :: rest_of_error ->
575 Buffer.add_string
577 begin
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
580 end;
581 let indentstr =
582 if indent then
584 else
587 List.iter rest_of_error (fun (p, w) ->
588 let msg =
589 Printf.sprintf "%s%s\n%s%s\n" indentstr (Pos.string p) indentstr w
591 Buffer.add_string buf msg));
592 Buffer.contents buf
594 let add_error_impl error =
595 if !accumulate_errors then
596 let () =
597 match !current_context with
598 | (path, _)
599 when path = Relative_path.default && not !allow_errors_in_default_path
601 Hh_logger.log
602 "WARNING: adding an error in default path\n%s\n"
603 (Caml.Printexc.raw_backtrace_to_string
604 (Caml.Printexc.get_callstack 100))
605 | _ -> ()
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)
612 else
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 (*****************************************************************************)
628 (* Types *)
629 (*****************************************************************************)
631 type t = error files_t * applied_fixme files_t [@@deriving eq]
633 module type Error_category = sig
634 type t
636 val min : int
638 val max : int
640 val of_enum : int -> t option
642 val show : t -> string
644 val err_code : t -> int
647 (*****************************************************************************)
648 (* HH_FIXMEs hook *)
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 =
657 ISet.of_list
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
688 add_error_impl
689 (make_error
690 code
692 ( pos,
693 Printf.sprintf
694 "You cannot use HH_FIXME or HH_IGNORE_ERROR comments to suppress error %d in declarations"
695 code );
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
700 add_error_impl
701 (make_error
702 code
704 ( pos,
705 Printf.sprintf
706 "You cannot use HH_FIXME or HH_IGNORE_ERROR comments to suppress error %d.Please use @lint-ignore."
707 code );
709 else
710 add_error_impl
711 (make_error
712 code
714 ( pos,
715 Printf.sprintf
716 "You cannot use HH_FIXME or HH_IGNORE_ERROR comments to suppress error %d"
717 code );
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
729 then
730 (Pos.make_from current_file, Badpos_sentinel.message) :: pos_msg_l
731 else
732 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)
738 else
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
745 else
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
757 else
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) =
764 let append _ _ x y =
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 *)
780 a files_t ->
781 a files_t ->
782 ((* function folding over paths of rechecked files *)
783 a files_t ->
784 (Relative_path.t -> a files_t -> a files_t) ->
785 a files_t) ->
786 phase ->
787 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 =
792 let new_phase_map =
793 match Relative_path.Map.find_opt acc path with
794 | None -> None
795 | Some phase_map ->
796 let new_phase_map = PhaseMap.remove phase_map phase in
797 if PhaseMap.is_empty new_phase_map then
798 None
799 else
800 Some new_phase_map
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 *)
807 let res =
808 files_t_merge new_ old ~f:(fun phase path new_ old ->
809 ( if path = Relative_path.default then
810 let phase =
811 match phase with
812 | Init -> "Init"
813 | Parsing -> "Parsing"
814 | Naming -> "Naming"
815 | Decl -> "Decl"
816 | Typing -> "Typing"
818 Utils.assert_false_log_backtrace
819 (Some
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."
823 ^ "Phase: "
824 ^ phase )) );
825 match new_ with
826 | Some new_ -> Some (List.rev new_)
827 | None -> old)
829 (* For files that were rechecked, but had no errors - remove them from maps *)
830 fold res (fun path acc ->
831 let has_errors =
832 match Relative_path.Map.find_opt new_ path with
833 | None -> false
834 | Some phase_map -> PhaseMap.mem phase_map phase
836 if has_errors then
838 else
839 remove path phase acc)
841 and incremental_update_set ~old ~new_ ~rechecked phase =
842 let fold init g =
843 Relative_path.Set.fold
845 begin
846 fun path acc ->
847 g path acc
849 ~init
850 rechecked
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 =
856 let fold init g =
857 Relative_path.Map.fold
859 begin
860 fun path _ acc ->
861 g path acc
863 ~init
864 rechecked
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 =
889 match phase with
890 | None ->
891 files_t_fold (fst err) ~init ~f:(fun source _ errors acc ->
892 List.fold_right errors ~init:acc ~f:(f source))
893 | Some phase ->
894 Relative_path.Map.fold (fst err) ~init ~f:(fun source phases acc ->
895 match PhaseMap.find_opt phases phase with
896 | None -> acc
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
905 else
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 ->
910 if phase <> p then
912 else
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 (*****************************************************************************)
966 (* Naming errors *)
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 ($$) "
1000 ^ "variable?" )
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
1017 let errs =
1019 (p, "Name already bound: " ^ name);
1020 ( p_prev,
1021 if String.compare name name_prev = 0 then
1022 "Previous definition is here"
1023 else
1024 "Previous definition "
1025 ^ name_prev
1026 ^ " differs only in capitalization " );
1029 let hhi_msg =
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."
1036 let errs =
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)]
1041 else
1042 errs
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
1049 let errs =
1051 ( p,
1052 "A class and an attribute class cannot share the same name. Conflicting class: "
1053 ^ name );
1054 (p_prev, "Previous definition: " ^ name_prev);
1057 add_list (Naming.err_code Naming.AttributeClassNameConflict) errs
1059 let unbound_name pos name kind =
1060 let kind_str =
1061 match kind with
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: '"
1077 ^ strip_ns name
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 =
1087 let msg =
1088 if in_rx_scope then
1089 Printf.sprintf
1090 "Variable %s is undefined, not always defined, or unset afterwards"
1091 var_name
1092 else
1093 Printf.sprintf "Variable %s is undefined, or not always defined" var_name
1095 let suggestion =
1096 match did_you_mean with
1097 | Some var_name -> Printf.sprintf " (did you mean %s instead?)" var_name
1098 | None -> ""
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 =
1121 add_list
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
1134 add_list
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 =
1139 let msg =
1140 Printf.sprintf
1141 "Record `%s` has no field `%s`"
1142 (strip_ns record_name)
1143 field_name
1145 add_list
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
1151 let msg =
1152 Printf.sprintf
1153 "Mising required field `%s` in `%s`"
1154 field_name
1155 (strip_ns record_name)
1157 add_list
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 '"
1172 ^ used
1173 ^ "' in Hack is considered an error. Use '"
1174 ^ valid
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 =
1190 add_list
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 =
1198 let reason =
1199 if string_starts_with name "__" then
1200 "starts with __ but is not a standard attribute"
1201 else
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
1217 let msg2 =
1218 match cls_opt with
1219 | Some c ->
1220 " Try 'if ($var instanceof "
1222 ^ ")' or 'invariant($var instanceof "
1224 ^ ", ...)'."
1225 | None -> ""
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)
1264 (Printf.sprintf
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 =
1270 add_list
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 =
1329 let msg =
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 =
1336 let msg =
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 =
1342 let msg =
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 =
1350 let msg =
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 =
1357 let msg =
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 =
1366 let msg =
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
1388 let msgl =
1390 (usage_pos, name ^ " is uninstantiable"); (decl_pos, "Declaration is here");
1393 let msgl =
1394 match reason_msgl with
1395 | (reason_pos, reason_str) :: tail ->
1396 ((reason_pos, reason_str ^ " which must be instantiable") :: tail) @ msgl
1397 | _ -> 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
1410 add_list
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
1419 let msg =
1420 Printf.sprintf
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
1428 let msg =
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 =
1449 add_list
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 =
1470 add_list
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)
1518 ( "XHP attribute "
1519 ^ id
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)
1583 (sprintf
1584 "In Pocket Universe %s, atom %s is missing %s %s"
1586 name
1587 kind
1588 missing)
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)
1596 (sprintf
1597 "In Pocket Universe %s, atom %s declares unknown %s %s"
1599 name
1600 kind
1601 unk)
1603 let illegal_use_of_dynamically_callable attr_pos meth_pos visibility =
1604 add_list
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)
1619 (Utils.sl
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
1633 let props_str =
1634 SSet.fold ~f:(fun x acc -> x ^ " " ^ acc) prop_names ~init:""
1637 (NastCheck.err_code NastCheck.ConstructorRequired)
1639 ( "Lacking __construct, class "
1640 ^ name
1641 ^ " does not initialize its private member(s): "
1642 ^ props_str )
1644 let not_initialized (pos, cname) prop_names =
1645 let cname = strip_ns cname in
1646 let props_str =
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
1651 ("member", "is")
1652 else
1653 ("members", "are")
1655 let setters_str =
1656 List.fold_right
1657 prop_names
1658 ~f:(fun x acc -> "$this->" ^ x ^ " " ^ acc)
1659 ~init:""
1662 (NastCheck.err_code NastCheck.NotInitialized)
1664 (Utils.sl
1666 "Class ";
1667 cname;
1668 " does not initialize all of its members; ";
1669 props_str;
1670 verb;
1671 " not always initialized.";
1672 "\nMake sure you systematically set ";
1673 setters_str;
1674 "when the method __construct is called.";
1675 "\nAlternatively, you can define the ";
1676 members;
1677 " as optional (?...)\n";
1680 let call_before_init pos cv =
1682 (NastCheck.err_code NastCheck.CallBeforeInit)
1684 (Utils.sl
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"]
1693 else
1694 ["$this->"; cv; " can still potentially be null"] ))
1696 (*****************************************************************************)
1697 (* Nast errors check *)
1698 (*****************************************************************************)
1700 let type_arity pos name nargs c_pos =
1701 add_list
1702 (Typing.err_code Typing.TypeArityMismatch)
1704 ( pos,
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,
1725 ( p,
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 =
1734 add_list
1735 (NastCheck.err_code NastCheck.TypeconstDependsOnExternalTparam)
1737 ( pos,
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)
1746 tconst_pos
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 "
1831 let magic (p, s) =
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)
1932 ( "The method "
1933 ^ strip_ns name
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)
1941 ( "The "
1942 ^ kind
1943 ^ " "
1944 ^ strip_ns name
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)
1952 ( "The method "
1953 ^ strip_ns name
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 =
2021 let loc =
2022 if is_method then
2023 "Method"
2024 else
2025 "Parameter"
2028 (NastCheck.err_code
2029 NastCheck.ConditionallyReactiveAnnotationInvalidArguments)
2031 ( loc
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 =
2089 add_list
2090 (NastCheck.err_code NastCheck.CaseFallthrough)
2092 ( pos1,
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 (*****************************************************************************)
2106 (* Typing errors *)
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) =
2121 let msg1 =
2122 ( pos,
2123 "Class "
2124 ^ strip_ns name
2125 ^ " does not correctly implement all required members " )
2127 let msg2 =
2128 ( parent_pos,
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) =
2144 let msg =
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) =
2160 add_list
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 =
2171 add_with_trail
2172 (Typing.err_code Typing.EnumConstantTypeBad)
2173 [(pos, "Enum constants must be an int or string"); (ty_pos, "Not " ^ ty)]
2174 trail
2176 let enum_type_bad pos ty trail =
2177 add_with_trail
2178 (Typing.err_code Typing.EnumTypeBad)
2179 [(pos, "Enums must be int or string or arraykey, not " ^ ty)]
2180 trail
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 =
2189 add_list
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 =
2197 add_list
2198 (Typing.err_code Typing.EnumSwitchNonexhaustive)
2200 ( pos,
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 =
2207 add_list
2208 (Typing.err_code Typing.EnumSwitchRedundantDefault)
2210 ( pos,
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 =
2241 add_with_trail
2242 (Typing.err_code Typing.InvalidShapeFieldType)
2244 (pos, "A shape field name must be an int or string"); (ty_pos, "Not " ^ ty);
2246 trail
2248 let invalid_shape_field_literal key_pos witness_pos =
2249 add_list
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 =
2257 add_list
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 =
2265 add_list
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 =
2273 add_list
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 =
2281 add_list
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 =
2289 add_list
2290 (Typing.err_code Typing.ShapeFieldsUnknown)
2292 ( pos1,
2293 "This shape type allows unknown fields, and so it may contain fields other than those explicitly declared in its declaration."
2295 ( pos2,
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 =
2306 add_list
2307 (Typing.err_code Typing.UnificationCycle)
2309 ( pos,
2310 "Type circularity: in order to type-check this expression it "
2311 ^ "is necessary for a type [rec] to be equal to type "
2312 ^ ty );
2315 let violated_constraint p_cstr (p_tparam, tparam) left right =
2316 add_list
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);
2322 @ left
2323 @ right )
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 *)
2336 let msgl =
2337 match msgl with
2338 | (p, x) :: rest when x = inst_msg && p = use_pos -> rest
2339 | _ -> msgl
2341 let name = strip_ns param_name in
2342 add_list
2343 (Typing.err_code Typing.TypeConstraintViolation)
2345 (use_pos, inst_msg);
2346 (definition_pos, "'" ^ name ^ "' is a constrained type parameter");
2348 @ msgl )
2350 let explain_where_constraint ~in_class ~use_pos ~definition_pos (error : error)
2352 let callsite_ty =
2353 if in_class then
2354 "class"
2355 else
2356 "method"
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
2363 add_list
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
2370 add_list
2371 (Typing.err_code Typing.TypeConstraintViolation)
2373 (use_pos, inst_msg);
2374 ( definition_pos,
2375 "This method's where constraints contain a generic type access" );
2377 @ msgl )
2379 let format_string pos snippet s class_pos fname class_suggest =
2380 add_list
2381 (Typing.err_code Typing.FormatString)
2383 (pos, "I don't understand the format string " ^ snippet ^ " in " ^ s);
2384 ( class_pos,
2385 "You can add a new format specifier by adding "
2386 ^ fname
2387 ^ "() to "
2388 ^ class_suggest );
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)
2420 ( name
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) =
2426 match kind with
2427 | `void -> ("?void", "only return implicitly")
2428 | `noreturn -> ("?noreturn", "never return")
2431 (Typing.err_code Typing.OptionReturnOnlyTypehint)
2433 ( typehint
2434 ^ " is a nonsensical typehint; a function cannot both "
2435 ^ reason
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 "
2449 ^ 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 =
2523 add_list
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 =
2545 let msg =
2546 match kind with
2547 | `void -> "void"
2548 | `noreturn -> "noreturn"
2551 (Naming.err_code Naming.ReturnOnlyTypehint)
2553 ( "The "
2554 ^ msg
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 =
2570 add_list
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)
2583 cst_pos
2584 "Unbound global constant (Typing)"
2586 let private_inst_meth ~def_pos ~use_pos =
2587 add_list
2588 (Typing.err_code Typing.PrivateInstMeth)
2590 ( use_pos,
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 =
2597 add_list
2598 (Typing.err_code Typing.ProtectedInstMeth)
2600 ( use_pos,
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 =
2607 add_list
2608 (Typing.err_code Typing.PrivateClassMeth)
2610 ( use_pos,
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 =
2617 add_list
2618 (Typing.err_code Typing.ProtectedClassMeth)
2620 ( use_pos,
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
2634 @@ Printf.sprintf
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 =
2639 add_list
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
2666 let preamble =
2667 match kind with
2668 | `static -> "Can't use new static() for " ^ name
2669 | `classname -> "Can't use new on classname<" ^ name ^ ">"
2671 add_list
2672 (Typing.err_code Typing.NewStaticInconsistent)
2674 ( new_pos,
2675 preamble
2676 ^ "; __construct arguments are not guaranteed to be consistent in child classes"
2678 ( cpos,
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 =
2696 add_list
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 =
2704 add_list
2705 (Typing.err_code Typing.AbstractCall)
2707 ( call_pos,
2708 "Cannot call self::"
2709 ^ meth_name
2710 ^ "(); it is abstract. Did you mean static::"
2711 ^ meth_name
2712 ^ "()?" );
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
2718 add_list
2719 (Typing.err_code Typing.AbstractCall)
2721 ( call_pos,
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
2728 add_list
2729 (Typing.err_code Typing.StaticSyntheticMethod)
2731 ( call_pos,
2732 "Cannot call "
2733 ^ cname
2734 ^ "::"
2735 ^ meth_name
2736 ^ "(); "
2737 ^ meth_name
2738 ^ " is not defined in "
2739 ^ cname );
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 "
2748 ^ "strict mode" )
2750 let unset_nonidx_in_strict pos msgs =
2751 add_list
2752 (Typing.err_code Typing.UnsetNonidxInStrict)
2754 ( pos,
2755 "In strict mode, unset is banned except on dynamic, "
2756 ^ "darray, keyset, or dict indexing" );
2758 @ msgs )
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 =
2768 add_list
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 =
2778 add_list
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 =
2786 add_list
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")]
2792 else
2793 [] ) )
2795 let keyset_set pos1 pos2 =
2796 add_list
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")]
2802 else
2803 [] ) )
2805 let array_append pos1 pos2 ty =
2806 add_list
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")]
2812 else
2813 [] ) )
2815 let const_mutation pos1 pos2 ty =
2816 add_list
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)]
2822 else
2823 [] ) )
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
2836 | `no_hint -> ""
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
2841 | `no_hint -> ""
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
2856 add_list
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
2865 let kind =
2866 match kind with
2867 | `method_ -> "method"
2868 | `member -> "member"
2870 let msg = Printf.sprintf "No %s '%s' in %s" kind member_name type_name in
2871 add_list
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 =
2896 add_list
2897 (Typing.err_code Typing.TypingTooManyArgs)
2899 ( pos,
2900 Printf.sprintf
2901 "Too many arguments (expected %d but got %d)"
2902 expected
2903 actual );
2904 (pos_def, "Definition is here");
2907 let typing_too_few_args required actual pos pos_def =
2908 add_list
2909 (Typing.err_code Typing.TypingTooFewArgs)
2911 ( pos,
2912 Printf.sprintf
2913 "Too few arguments (required %d but got %d)"
2914 required
2915 actual );
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
2933 add_list
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
2942 let msg =
2943 Printf.sprintf "Cannot extend record `%s` because it isn't abstract" name
2945 add_list
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
2951 add_list
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" )
2966 let extend_ppl
2967 child_pos
2968 child_class_type
2969 child_is_ppl
2970 parent_pos
2971 parent_class_type
2972 parent_name
2973 verb =
2974 let name = strip_ns parent_name in
2975 let warning =
2976 if child_is_ppl then
2977 child_class_type
2978 ^ " annotated with <<__PPL>> cannot "
2979 ^ verb
2980 ^ " non <<__PPL>> "
2981 ^ parent_class_type
2982 ^ ": "
2983 ^ name
2984 else
2985 child_class_type
2986 ^ " must be annotated with <<__PPL>> to "
2987 ^ verb
2988 ^ " <<__PPL>> "
2989 ^ parent_class_type
2990 ^ ": "
2991 ^ name
2993 add_list
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
3011 let msg1 =
3012 if is_final then
3013 "This class was declared as final. It must provide an implementation for the "
3014 ^ name
3015 else
3016 "This class must be declared abstract, or provide an implementation for the "
3017 ^ name
3019 add_list
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 =
3030 add_list
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 =
3038 add_list
3039 (Typing.err_code Typing.FunTooFewArgs)
3040 [(pos1, "Too few arguments"); (pos2, "Because of this definition")]
3042 let fun_unexpected_nonvariadic pos1 pos2 =
3043 add_list
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 =
3051 add_list
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 =
3059 let msg =
3060 match require with
3061 | `Type ->
3062 "Cannot use ... without a type hint in strict mode. Please add a type hint."
3063 | `Param_name ->
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 =
3071 let msg =
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 =
3083 add_list
3084 (Typing.err_code Typing.ExpectedTparam)
3086 ( use_pos,
3087 "Expected "
3089 match n with
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 =
3097 add_list
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 =
3114 add_list
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
3128 let message2 =
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 =
3135 add_list
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
3144 add_list
3145 (Typing.err_code Typing.FunReactivityMismatch)
3146 [(pos1, f kind1); (pos2, f kind2)]
3148 let inconsistent_mutability pos1 mut1 p2_opt =
3149 match p2_opt with
3150 | Some (pos2, mut2) ->
3151 add_list
3152 (Typing.err_code Typing.InconsistentMutability)
3154 ( pos1,
3155 "Inconsistent mutability of local variable, here local is " ^ mut1 );
3156 (pos2, "But here it is " ^ mut2);
3158 | None ->
3160 (Typing.err_code Typing.InconsistentMutability)
3161 pos1
3162 ("Local is " ^ mut1 ^ " in one scope and immutable in another.")
3164 let inconsistent_mutability_for_conditional p_mut p_other =
3165 add_list
3166 (Typing.err_code Typing.InconsistentMutability)
3168 ( p_mut,
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)
3178 ( "Cannot assign "
3179 ^ mut2
3180 ^ " value to "
3181 ^ mut1
3182 ^ " local variable. Mutability flavor of local variable cannot be altered."
3185 let reassign_mutable_var ~in_collection pos1 =
3186 let msg =
3187 if in_collection then
3188 "This variable is mutable. You cannot create a new reference to it by putting it into the collection."
3189 else
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 =
3195 let kind =
3196 if is_maybe_mutable then
3197 "maybe mutable"
3198 else
3199 "mutable"
3201 let msg =
3202 if in_collection then
3203 "$this here is "
3204 ^ kind
3205 ^ ". You cannot create a new reference to it by putting it into the collection."
3206 else
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 =
3213 add_list
3214 (Typing.err_code Typing.MutableExpressionAsMultipleMutableArguments)
3216 ( pos,
3217 "A mutable expression may not be passed as multiple arguments where at least one matching parameter is mutable. Matching parameter here is "
3218 ^ param_kind );
3219 ( prev_pos,
3220 "This is where it was used before, being passed as " ^ prev_param_kind
3224 let reassign_maybe_mutable_var ~in_collection pos1 =
3225 let msg =
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."
3228 else
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 =
3234 let l =
3235 match rx_mutable_hint_pos with
3236 | Some p ->
3238 ( p,
3239 "Consider wrapping this expression with Rx\\mutable to forward mutability."
3242 | None -> []
3244 let l =
3245 (pos1, "Cannot call mutable function on immutable expression")
3246 :: ( fpos,
3247 "This function is marked <<__Mutable>>, so it has a mutable $this." )
3248 :: l
3250 add_list (Typing.err_code Typing.MutableCallOnImmutable) l
3252 let immutable_call_on_mutable fpos pos1 =
3253 add_list
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 =
3261 let msg mut =
3262 let msg =
3263 if is_receiver then
3264 "Receiver of this function"
3265 else
3266 "This parameter"
3268 msg ^ " is " ^ mut
3270 add_list
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 =
3275 let msg =
3276 "Cannot call "
3277 ^ ( if fun_is_mutable then
3278 "mutable"
3279 else
3280 "non-mutable" )
3281 ^ " function on maybe mutable value."
3283 add_list
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 =
3288 add_list
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 =
3297 add_list
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 =
3306 let arg_msg =
3307 if arg_is_owned_local then
3308 "Owned mutable locals used as argument should be passed via Rx\\move function"
3309 else
3310 "But this expression is not owned mutable"
3312 add_list
3313 (Typing.err_code Typing.ImmutableArgumentMismatch)
3315 (arg_pos, "Invalid argument");
3316 (param_pos, "This parameter is marked with <<__OwnedMutable>>");
3317 (arg_pos, arg_msg);
3320 let maybe_mutable_argument_mismatch param_pos arg_pos =
3321 add_list
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 =
3330 add_list
3331 (Typing.err_code Typing.InvalidMutableReturnResult)
3333 ( error_pos,
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)
3343 pos1
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 =
3360 let arg_msg =
3361 if is_receiver then
3362 "Receiver type"
3363 else
3364 "Argument type"
3366 let arg_msg =
3367 arg_msg
3368 ^ " must be a subtype of "
3369 ^ expected_type
3370 ^ ", now "
3371 ^ actual_type
3372 ^ "."
3374 add_list
3375 (Typing.err_code Typing.InvalidConditionallyReactiveCall)
3377 ( f_pos,
3378 "Cannot invoke conditionally reactive function in reactive context, because at least one reactivity condition is not met."
3380 (arg_pos, arg_msg);
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 =
3386 add_list
3387 (Typing.err_code Typing.CallSiteReactivityMismatch)
3389 ( f_pos,
3390 "Reactivity mismatch: "
3391 ^ caller_reactivity
3392 ^ " function cannot call "
3393 ^ callee_reactivity
3394 ^ " function." );
3395 (def_pos, "This is declaration of the function being called.");
3397 @ Option.value_map cause_pos_opt ~default:[] ~f:(fun cause_pos ->
3399 ( cause_pos,
3400 "Reactivity of this argument was used as reactivity of the callee."
3402 ]) )
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)
3413 pos1
3414 "freeze takes a single mutably-owned local variable as an argument"
3416 let invalid_move_use pos1 =
3418 (Typing.err_code Typing.InvalidMoveUse)
3419 pos1
3420 "move takes a single mutably-owned local variable as an argument"
3422 let require_args_reify def_pos arg_pos =
3423 add_list
3424 (Typing.err_code Typing.RequireArgsReify)
3426 ( arg_pos,
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 =
3433 add_list
3434 (Typing.err_code Typing.RequireGenericExplicit)
3436 ( arg_pos,
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 =
3443 add_list
3444 (Typing.err_code Typing.InvalidReifiedArgument)
3446 (hint_pos, "Invalid reified hint");
3447 ( arg_pos,
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
3455 add_list
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)
3485 ( name
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 =
3490 add_list
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 =
3498 add_list
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 =
3506 add_list
3507 (Typing.err_code Typing.DiscardedAwaitable)
3509 ( pos1,
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 =
3580 let dollar =
3581 match elt_type with
3582 | `Property -> "$"
3583 | _ -> ""
3585 let elt_type = elt_type_to_string elt_type in
3586 let msg_dynamic =
3587 "The "
3588 ^ elt_type
3589 ^ " "
3590 ^ dollar
3591 ^ member_name
3592 ^ " is declared here as non-static"
3594 let msg_static =
3595 "But it conflicts with an inherited static declaration here"
3597 add_list
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 =
3603 let dollar =
3604 match elt_type with
3605 | `Property -> "$"
3606 | _ -> ""
3608 let elt_type = elt_type_to_string elt_type in
3609 let msg_static =
3610 "The "
3611 ^ elt_type
3612 ^ " "
3613 ^ dollar
3614 ^ member_name
3615 ^ " is declared here as static"
3617 let msg_dynamic =
3618 "But it conflicts with an inherited non-static declaration here"
3620 add_list
3621 (Typing.err_code Typing.StaticDynamic)
3622 [(static_position, msg_static); (dyn_position, msg_dynamic)]
3624 let null_member ~is_method s pos r =
3625 let msg =
3626 Printf.sprintf
3627 "You are trying to access the %s '%s' but this object can be null."
3628 ( if is_method then
3629 "method"
3630 else
3631 "property" )
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 =
3638 let msg =
3639 Printf.sprintf
3640 "You are trying to access the %s '%s' but this is %s. Use a specific class or interface name."
3641 ( if is_method then
3642 "method"
3643 else
3644 "property" )
3648 add_list
3649 (Typing.err_code
3650 ( if is_nullable then
3651 Typing.NullMember
3652 else
3653 Typing.NonObjectMember ))
3654 [(pos1, msg); (pos2, "Definition is here")]
3656 let non_object_member ~is_method s pos1 ty pos2 =
3657 let msg_start =
3658 Printf.sprintf
3659 "You are trying to access the %s '%s' but this is %s"
3660 ( if is_method then
3661 "method"
3662 else
3663 "property" )
3667 let msg =
3668 if ty = "a shape" then
3669 msg_start ^ ". Did you mean $foo['" ^ s ^ "'] instead?"
3670 else
3671 msg_start
3673 add_list
3674 (Typing.err_code Typing.NonObjectMember)
3675 [(pos1, msg); (pos2, "Definition is here")]
3677 let unknown_object_member ~is_method s pos r =
3678 let msg =
3679 Printf.sprintf
3680 "You are trying to access the %s '%s' on a value whose class is unknown."
3681 ( if is_method then
3682 "method"
3683 else
3684 "property" )
3687 add_list (Typing.err_code Typing.UnknownObjectMember) ([(pos, msg)] @ r)
3689 let non_class_member ~is_method s pos1 ty pos2 =
3690 let msg =
3691 Printf.sprintf
3692 "You are trying to access the static %s '%s' but this is %s"
3693 ( if is_method then
3694 "method"
3695 else
3696 "property" )
3700 add_list
3701 (Typing.err_code Typing.NonClassMember)
3702 [(pos1, msg); (pos2, "Definition is here")]
3704 let ambiguous_member ~is_method s pos1 ty pos2 =
3705 let msg =
3706 Printf.sprintf
3707 "You are trying to access the %s '%s' but there is more than one implementation on %s"
3708 ( if is_method then
3709 "method"
3710 else
3711 "property" )
3715 add_list
3716 (Typing.err_code Typing.AmbiguousMember)
3717 [(pos1, msg); (pos2, "Definition is here")]
3719 let null_container p null_witness =
3720 add_list
3721 (Typing.err_code Typing.NullContainer)
3723 ( p,
3724 "You are trying to access an element of this container"
3725 ^ " but the container could be null. " );
3727 @ null_witness )
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 =
3742 add_list
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 (+)");
3748 @ emsg )
3750 let declared_contravariant pos1 pos2 emsg =
3751 add_list
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 (-)");
3757 @ emsg )
3759 let static_property_type_generic_param ~class_pos ~var_type_pos ~generic_pos =
3760 add_list
3761 (Typing.err_code Typing.ClassVarTypeGenericParam)
3763 ( generic_pos,
3764 "A generic parameter cannot be used in the type of a static property" );
3765 ( var_type_pos,
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 \""
3776 ^ class_name
3777 ^ "\" "
3778 ^ "is final and has a variant type parameter \""
3779 ^ tp
3780 ^ "\"" )
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 =
3790 let kind_str =
3791 match kind with
3792 | `method_ -> "method"
3793 | `typeconst -> "type constant"
3794 | `constant -> "constant"
3795 | `property -> "property"
3797 add_list
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 =
3805 add_list
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 =
3813 add_list
3814 (Typing.err_code Typing.ArrayGetWithOptionalField)
3816 ( pos1,
3817 "Invalid index operation: '"
3818 ^ name
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 =
3825 add_list
3826 (Typing.err_code Typing.NonCallArgumentInSuspend)
3827 ( [(pos, "'suspend' operator expects call to a coroutine as an argument.")]
3828 @ msgs )
3830 let non_coroutine_call_in_suspend pos msgs =
3831 add_list
3832 (Typing.err_code Typing.NonCoroutineCallInSuspend)
3834 ( pos,
3835 "Only coroutine functions are allowed to be called in 'suspend' operator."
3838 @ msgs )
3840 let coroutine_call_outside_of_suspend pos =
3841 add_list
3842 (Typing.err_code Typing.CoroutineCallOutsideOfSuspend)
3844 ( pos,
3845 "Coroutine calls are only allowed when they are arguments to 'suspend' operator"
3849 let function_is_not_coroutine pos name =
3850 add_list
3851 (Typing.err_code Typing.FunctionIsNotCoroutine)
3853 ( pos,
3854 "Function '"
3855 ^ name
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
3863 add_list
3864 (Typing.err_code Typing.CoroutinnessMismatch)
3866 ( pos1,
3867 if pos1_is_coroutine then
3869 else
3870 m2 );
3871 ( pos2,
3872 if pos1_is_coroutine then
3874 else
3875 m1 );
3878 let invalid_ppl_call pos context =
3879 let error_msg =
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 =
3885 let error_msg =
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
3903 add_list
3904 (Typing.err_code Typing.ReturnDisposableMismatch)
3906 ( pos1,
3907 if pos1_return_disposable then
3909 else
3910 m2 );
3911 ( pos2,
3912 if pos1_return_disposable then
3914 else
3915 m1 );
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
3921 add_list
3922 (Typing.err_code Typing.ReturnVoidToRxMismatch)
3924 ( pos1,
3925 if pos1_has_attribute then
3927 else
3928 m2 );
3929 ( pos2,
3930 if pos1_has_attribute then
3932 else
3933 m1 );
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
3964 add_list
3965 (Typing.err_code Typing.OverridingPropConstMismatch)
3967 ( parent_pos,
3968 if parent_const then
3970 else
3971 m2 );
3972 ( child_pos,
3973 if child_const then
3975 else
3976 m2 );
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
3982 add_list
3983 (Typing.err_code Typing.MutableReturnResultMismatch)
3985 ( pos1,
3986 if pos1_has_mutable_return then
3988 else
3989 m2 );
3990 ( pos2,
3991 if pos1_has_mutable_return then
3993 else
3994 m1 );
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)
4007 (sprintf
4008 "Unexpected Pocket Universes %s %s while typing expressions."
4009 kind
4010 msg)
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
4032 else
4033 add_list
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
4048 let err =
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 =
4055 add_list
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 =
4063 add_list
4064 (Typing.err_code Typing.InvalidEnforceableTypeArgument)
4066 (targ_pos, "Invalid type");
4067 ( tp_pos,
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 =
4074 add_list
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 =
4083 add_list
4084 (Typing.err_code Typing.InvalidNewableTypeArgument)
4086 ( ta_pos,
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 =
4094 let partial =
4095 if List.is_empty constraint_list then
4096 "No constraints"
4097 else
4098 "The constraints "
4099 ^ String.concat ~sep:", " (List.map ~f:strip_ns constraint_list)
4101 let msg =
4102 "The type parameter "
4103 ^ tparam_name
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. "
4105 ^ partial
4106 ^ " are valid newable classes"
4108 add (Typing.err_code Typing.InvalidNewableTypeParamConstraints) tparam_pos msg
4110 let override_final ~parent ~child =
4111 add_list
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 =
4119 add_list
4120 (Typing.err_code Typing.OverrideMemoizeLSB)
4122 ( child,
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 =
4129 add_list
4130 (Typing.err_code Typing.OverrideLSB)
4132 ( child,
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)
4141 ( strip_ns class_id
4142 ^ "::"
4143 ^ id
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
4149 let err_msg =
4150 "Method "
4151 ^ strip_ns c_name
4152 ^ "::"
4153 ^ id
4154 ^ " should be an override per the declaring trait; no non-private parent definition found or overridden parent is defined in non-<?hh code"
4156 add_list
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)
4167 ( strip_ns class_id
4168 ^ "::"
4169 ^ id
4170 ^ ": combining private and override is nonsensical" )
4172 let invalid_memoized_param pos ty_reason_msg =
4173 add_list
4174 (Typing.err_code Typing.InvalidMemoizedParam)
4175 ( ( pos,
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"
4178 :: ty_reason_msg )
4180 let invalid_disposable_hint pos class_name =
4182 (Typing.err_code Typing.InvalidDisposableHint)
4184 ( "Parameter with type '"
4185 ^ class_name
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)
4193 ( "Return type '"
4194 ^ class_name
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
4200 add_list
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
4210 add_list
4211 (Typing.err_code Typing.MissingXhpRequiredAttr)
4212 ((pos, msg) :: ty_reason_msg)
4214 let nullsafe_not_needed p nonnull_witness =
4215 add_list
4216 (Typing.err_code Typing.NullsafeNotNeeded)
4217 ( [(p, "You are using the ?-> operator but this object cannot be null. ")]
4218 @ nonnull_witness )
4220 let generic_at_runtime p prefix =
4222 (Typing.err_code Typing.ErasedGenericAtRuntime)
4224 ( prefix
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
4238 add_list
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
4244 add_list
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
4250 add_list
4251 (Typing.err_code Typing.EqIncompatibleTypes)
4252 (((p, msg) :: left) @ right)
4254 let comparison_invalid_types p left right =
4255 let msg =
4256 "This comparison has invalid types. Only comparisons in which both arguments are strings, nums, DateTime, or DateTimeImmutable are allowed"
4258 add_list
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 =
4291 add_list
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) =
4296 let kind_str =
4297 match kind with
4298 | `enum -> "an enum"
4299 | `trait -> "a trait"
4300 | `record -> "a record"
4302 add_list
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
4312 let message =
4313 "This declaration was inherited from an object of type "
4314 ^ origin
4315 ^ ". Redeclare this member in "
4316 ^ class_
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
4327 add_list
4328 (Typing.err_code Typing.MultipleConcreteDefs)
4330 ( child_pos,
4331 child_origin
4332 ^ " and "
4333 ^ parent_origin
4334 ^ " both declare ambiguous implementations of "
4335 ^ name
4336 ^ "." );
4337 (child_pos, child_origin ^ "'s definition is here.");
4338 (parent_pos, parent_origin ^ "'s definition is here.");
4339 ( child_pos,
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
4346 add_list
4347 (Typing.err_code Typing.LocalVariableModifedAndUsed)
4348 ( ( pos_modified,
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
4355 add_list
4356 (Typing.err_code Typing.LocalVariableModifedTwice)
4357 ( ( pos_modified,
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 =
4374 let msg =
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"
4379 ^ "\n"
4380 ^ errmsg
4382 add (Typing.err_code Typing.IllegalTypeStructure) pos msg
4384 let illegal_typeconst_direct_access pos =
4385 let msg =
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 =
4392 add_list
4393 (Typing.err_code Typing.OverrideNoDefaultTypeconst)
4395 (pos_child, "This abstract type constant does not have a default type");
4396 ( pos_parent,
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
4412 let param_str =
4413 if pos2_is_variadic then
4414 "variadic parameters are"
4415 else
4416 "this parameter is"
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
4423 let mode_str =
4424 match mode2 with
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
4438 let msg2 =
4439 ( pos2,
4440 if pos2_is_variadic then
4441 "A variadic parameter can never be inout"
4442 else
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 =
4453 let msg =
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 =
4459 let msg =
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 =
4465 add_list
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 ->
4473 ( cause_pos,
4474 "This argument caused function to be " ^ callee_reactivity ^ "."
4476 ]) )
4478 let nonreactive_call_from_shallow pos decl_pos callee_reactivity cause_pos_opt =
4479 add_list
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 ->
4487 ( cause_pos,
4488 "This argument caused function to be " ^ callee_reactivity ^ "."
4490 ]) )
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 =
4499 add_list
4500 (Typing.err_code Typing.RxParameterConditionMismatch)
4502 ( pos,
4503 "This parameter does not satisfy "
4504 ^ cond
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 =
4510 let msg =
4511 if is_append then
4512 "Cannot append to a Hack Collection object in a reactive context. Instead, use the 'add' method."
4513 else
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 =
4519 let msg =
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 =
4532 let msg =
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 =
4540 let msg1 =
4541 "Lambda has parameter types that could not be determined at definition site."
4543 let msg2 =
4544 Printf.sprintf
4545 "%d distinct use types were determined: please add type hints to lambda parameters."
4546 (List.length uses)
4548 add_list
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 =
4555 let msg1 =
4556 Printf.sprintf
4557 "The %s attribute cannot be used on %s."
4558 (strip_ns attr)
4559 expr_kind
4561 let msg2 =
4562 Printf.sprintf
4563 "The attribute's class is defined here. To be available for use on %s, the %s class must implement %s."
4564 expr_kind
4565 (strip_ns attr_class_name)
4566 (strip_ns intf_name)
4568 add_list
4569 (Typing.err_code Typing.WrongExpressionKindAttribute)
4570 [(pos, msg1); (attr_class_pos, msg2)]
4572 let wrong_expression_kind_builtin_attribute expr_kind pos attr =
4573 let msg1 =
4574 Printf.sprintf
4575 "The %s attribute cannot be used on %s."
4576 (strip_ns attr)
4577 expr_kind
4579 add_list (Typing.err_code Typing.WrongExpressionKindAttribute) [(pos, msg1)]
4581 let cannot_return_borrowed_value_as_immutable fun_pos value_pos =
4582 add_list
4583 (Typing.err_code Typing.CannotReturnBorrowedValueAsImmutable)
4585 ( fun_pos,
4586 "Values returned from reactive function by default are treated as immutable."
4588 ( value_pos,
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 "
4603 ^ id
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 '"
4611 ^ type_str
4612 ^ "'." )
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 =
4629 let msg =
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 =
4648 add_list
4649 (Typing.err_code Typing.ReturnsVoidToRxAsNonExpressionStatement)
4651 ( pos,
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 =
4664 add_list
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
4672 | `Undefined ->
4673 [(pos, "The field '" ^ name ^ "' is not defined in this shape")]
4674 | `Nothing reason ->
4675 ( pos,
4676 "The type of the field '"
4677 ^ name
4678 ^ "' in this shape doesn't allow any values" )
4679 :: reason
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)
4689 @@ ( pos1,
4690 "You are calling Shapes::"
4691 ^ method_name
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
4704 add_list
4705 (Typing.err_code Typing.AmbiguousObjectAccess)
4707 (pos, "This object access to " ^ name ^ " is ambiguous");
4708 ( self_pos,
4709 "You will access the private instance declared in " ^ class_self );
4710 ( subclass_pos,
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 =
4727 let verb =
4728 if parent_is_lateinit then
4729 "is"
4730 else
4731 "is not"
4733 add_list
4734 (Typing.err_code Typing.BadLateInitOverride)
4736 ( child_pos,
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 =
4742 add_list
4743 (Typing.err_code Typing.BadXhpAttrRequiredOverride)
4745 (child_pos, "Redeclared attribute must not be less strict");
4746 ( parent_pos,
4747 "The attribute is "
4748 ^ parent_tag
4749 ^ ", which is stricter than "
4750 ^ child_tag );
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
4755 @@ Printf.sprintf
4756 "This case value has type %s, which is incompatible with type %s."
4757 case_value_ty
4758 scrutinee_ty
4760 let unserializable_type pos message =
4762 (Typing.err_code Typing.UnserializableType)
4764 ( "Unserializable type (could not be converted to JSON and back again): "
4765 ^ message )
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) =
4774 add_list
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 "
4785 ^ ty
4787 let typechecker_timeout (pos, fun_name) seconds =
4789 (Typing.err_code Typing.TypecheckerTimeout)
4791 (Printf.sprintf
4792 "Type checker timed out after %d seconds whilst checking function %s"
4793 seconds
4794 fun_name)
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)
4806 ( "This type is "
4808 ^ ", which cannot be used as an arraykey (string | int)" )
4810 (*****************************************************************************)
4811 (* Printing *)
4812 (*****************************************************************************)
4814 let to_json (error : Pos.absolute error_) =
4815 let (error_code, msgl) = (get_code error, to_list error) in
4816 let elts =
4817 List.map msgl (fun (p, w) ->
4818 let (line, scol, ecol) = Pos.info_pos p in
4819 Hh_json.JSON_Object
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) :
4832 string list =
4833 List.fold_right
4834 ~init:[]
4835 ~f:(fun err acc_out ->
4836 List.fold_right
4837 ~init: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
4841 let full_result =
4842 Printf.sprintf
4843 "%s %s"
4844 (Pos.to_absolute pos |> Pos.filename)
4845 result
4847 full_result :: acc_in
4848 else
4849 result :: acc_in)
4850 (to_list err))
4851 errors
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 =
4860 try_ f1 (fun err ->
4861 let (error_code, l) = (get_code err, to_list err) in
4862 add_list error_code l;
4863 f2 ())
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);
4869 f2 ())
4871 let has_no_errors f =
4872 try_
4873 (fun () ->
4874 let _ = f () in
4875 true)
4876 (fun _ -> false)
4878 let try_unless_error_in_different_file file f error_file_mismatch_handler =
4879 try_with_result f (fun r err ->
4880 (match err with
4881 | (_, first :: _) ->
4882 let (err_pos, _) = first in
4883 if Pos.filename err_pos <> file then
4884 error_file_mismatch_handler err
4885 else
4886 add_error err
4887 | _ ->
4888 (* No errors? This fun shouldn't even get called... *)
4889 ());
4892 (*****************************************************************************)
4893 (* Do. *)
4894 (*****************************************************************************)
4896 let ignore_ f =
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;
4901 result
4903 let try_when f ~when_ ~do_ =
4904 try_with_result f (fun result (error : error) ->
4905 if when_ () then
4906 do_ error
4907 else
4908 add_error error;
4909 result)