Isolate contextual error formatter code
[hiphop-php.git] / hphp / hack / src / errors / errors.ml
blob70df1e6ebd716ea721ba659eac7a5582f3a2964b
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 Hh_prelude
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 let get_message_pos (msg : 'a message) = fst msg
22 let get_message_str (msg : 'a message) = snd msg
24 type phase =
25 | Init
26 | Parsing
27 | Naming
28 | Decl
29 | Typing
30 [@@deriving eq]
32 type severity =
33 | Warning
34 | Error
36 type format =
37 | Context
38 | Raw
39 | Highlighted
41 type typing_error_callback = ?code:int -> (Pos.t * string) list -> unit
43 type name_context =
44 | FunctionNamespace
45 | ConstantNamespace
46 | TypeNamespace (** Classes, interfaces, traits, records and type aliases.*)
47 (* The following are all subsets of TypeNamespace, used when we can
48 give a more specific naming error. E.g. `use Foo;` only allows
49 traits. *)
50 | TraitContext
51 | ClassContext
52 | RecordContext
54 (* The file and phase of analysis being currently performed *)
55 let current_context : (Relative_path.t * phase) ref =
56 ref (Relative_path.default, Typing)
58 let current_span : Pos.t ref = ref Pos.none
60 let allow_errors_in_default_path = ref true
62 module PhaseMap = Reordered_argument_map (WrappedMap.Make (struct
63 type t = phase
65 let rank = function
66 | Init -> 0
67 | Parsing -> 1
68 | Naming -> 2
69 | Decl -> 3
70 | Typing -> 4
72 let compare x y = rank x - rank y
73 end))
75 (** Results of single file analysis. *)
76 type 'a file_t = 'a list PhaseMap.t [@@deriving eq]
78 (** Results of multi-file analysis. *)
79 type 'a files_t = 'a file_t Relative_path.Map.t [@@deriving eq]
81 let files_t_fold v ~f ~init =
82 Relative_path.Map.fold v ~init ~f:(fun path v acc ->
83 PhaseMap.fold v ~init:acc ~f:(fun phase v acc -> f path phase v acc))
85 let files_t_map v ~f = Relative_path.Map.map v ~f:(fun v -> PhaseMap.map v ~f)
87 let files_t_merge ~f x y =
88 (* Using fold instead of merge to make the runtime proportional to the size
89 * of first argument (like List.rev_append ) *)
90 Relative_path.Map.fold x ~init:y ~f:(fun k x acc ->
91 let y =
92 Option.value (Relative_path.Map.find_opt y k) ~default:PhaseMap.empty
94 Relative_path.Map.add
95 acc
97 (PhaseMap.merge x y ~f:(fun phase x y -> f phase k x y)))
99 let files_t_to_list x =
100 files_t_fold x ~f:(fun _ _ x acc -> List.rev_append x acc) ~init:[]
101 |> List.rev
103 let list_to_files_t = function
104 | [] -> Relative_path.Map.empty
105 | x ->
106 (* Values constructed here should not be used with incremental mode.
107 * See assert in incremental_update. *)
108 Relative_path.Map.singleton
109 Relative_path.default
110 (PhaseMap.singleton Typing x)
112 let get_code_severity code =
114 code
115 = Error_codes.Init.err_code Error_codes.Init.ForwardCompatibilityNotCurrent
116 then
117 Warning
118 else
119 Error
121 (* Get most recently-ish added error. *)
122 let get_last error_map =
123 (* If this map has more than one element, we pick an arbitrary file. Because
124 * of that, we might not end up with the most recent error and generate a
125 * less-specific error message. This should be rare. *)
126 match Relative_path.Map.max_binding_opt error_map with
127 | None -> None
128 | Some (_, phase_map) ->
129 let error_list =
130 PhaseMap.max_binding_opt phase_map |> Option.value_map ~f:snd ~default:[]
132 (match List.rev error_list with
133 | [] -> None
134 | e :: _ -> Some e)
136 type 'a error_ = error_code * 'a message list [@@deriving eq]
138 type error = Pos.t error_ [@@deriving eq]
140 type applied_fixme = Pos.t * int [@@deriving eq]
142 let applied_fixmes : applied_fixme files_t ref = ref Relative_path.Map.empty
144 let (error_map : error files_t ref) = ref Relative_path.Map.empty
146 let accumulate_errors = ref false
148 (* Some filename when declaring *)
149 let in_lazy_decl = ref None
151 let (is_hh_fixme : (Pos.t -> error_code -> bool) ref) = ref (fun _ _ -> false)
153 let badpos_message =
154 Printf.sprintf
155 "There is an error somewhere in this file. However the type checker reports that the error is in another file. %s"
156 Error_message_sentinel.please_file_a_bug_message
158 let badpos_message_2 =
159 Printf.sprintf
160 "There is an error somewhere in this definition. However the type checker reports that the error is elsewhere. %s"
161 Error_message_sentinel.please_file_a_bug_message
163 let try_with_result f1 f2 =
164 let error_map_copy = !error_map in
165 let accumulate_errors_copy = !accumulate_errors in
166 let is_hh_fixme_copy = !is_hh_fixme in
167 (is_hh_fixme := (fun _ _ -> false));
168 error_map := Relative_path.Map.empty;
169 accumulate_errors := true;
170 let (result, errors) =
171 Utils.try_finally
173 begin
174 fun () ->
175 let result = f1 () in
176 (result, !error_map)
178 ~finally:
179 begin
180 fun () ->
181 error_map := error_map_copy;
182 accumulate_errors := accumulate_errors_copy;
183 is_hh_fixme := is_hh_fixme_copy
186 match get_last errors with
187 | None -> result
188 | Some (code, l) ->
189 (* Remove bad position sentinel if present: we might be about to add a new primary
190 * error position*)
191 let l =
192 match l with
193 | (_, msg) :: l
194 when String.equal msg badpos_message
195 || String.equal msg badpos_message_2 ->
197 | _ -> l
199 f2 result (code, l)
201 let do_ f =
202 let error_map_copy = !error_map in
203 let accumulate_errors_copy = !accumulate_errors in
204 let applied_fixmes_copy = !applied_fixmes in
205 error_map := Relative_path.Map.empty;
206 applied_fixmes := Relative_path.Map.empty;
207 accumulate_errors := true;
208 let (result, out_errors, out_applied_fixmes) =
209 Utils.try_finally
211 begin
212 fun () ->
213 let result = f () in
214 (result, !error_map, !applied_fixmes)
216 ~finally:
217 begin
218 fun () ->
219 error_map := error_map_copy;
220 applied_fixmes := applied_fixmes_copy;
221 accumulate_errors := accumulate_errors_copy
224 let out_errors = files_t_map ~f:List.rev out_errors in
225 ((out_errors, out_applied_fixmes), result)
227 let run_in_context path phase f =
228 let context_copy = !current_context in
229 current_context := (path, phase);
230 Utils.try_finally ~f ~finally:(fun () -> current_context := context_copy)
232 let run_with_span span f =
233 let old_span = !current_span in
234 current_span := span;
235 Utils.try_finally ~f ~finally:(fun () -> current_span := old_span)
237 (* Log important data if lazy_decl triggers a crash *)
238 let lazy_decl_error_logging error error_map to_absolute to_string =
239 let error_list = files_t_to_list !error_map in
240 (* Print the current error list, which should be empty *)
241 Printf.eprintf "%s" "Error list(should be empty):\n";
242 List.iter error_list ~f:(fun err ->
243 let msg = err |> to_absolute |> to_string in
244 Printf.eprintf "%s\n" msg);
245 Printf.eprintf "%s" "Offending error:\n";
246 Printf.eprintf "%s" error;
248 (* Print out a larger stack trace *)
249 Printf.eprintf "%s" "Callstack:\n";
250 Printf.eprintf
251 "%s"
252 (Caml.Printexc.raw_backtrace_to_string (Caml.Printexc.get_callstack 500));
254 (* Exit with special error code so we can see the log after *)
255 Exit_status.exit Exit_status.Lazy_decl_bug
257 (*****************************************************************************)
258 (* Error code printing. *)
259 (*****************************************************************************)
261 let error_kind error_code =
262 match error_code / 1000 with
263 | 1 -> "Parsing"
264 | 2 -> "Naming"
265 | 3 -> "NastCheck"
266 | 4 -> "Typing"
267 | 5 -> "Lint"
268 | 8 -> "Init"
269 | _ -> "Other"
271 let error_code_to_string error_code =
272 let error_kind = error_kind error_code in
273 let error_number = Printf.sprintf "%04d" error_code in
274 error_kind ^ "[" ^ error_number ^ "]"
276 let phase_to_string (phase : phase) : string =
277 match phase with
278 | Init -> "Init"
279 | Parsing -> "Parsing"
280 | Naming -> "Naming"
281 | Decl -> "Decl"
282 | Typing -> "Typing"
284 let phase_of_string (value : string) : phase option =
285 match Caml.String.lowercase_ascii value with
286 | "init" -> Some Init
287 | "parsing" -> Some Parsing
288 | "naming" -> Some Naming
289 | "decl" -> Some Decl
290 | "typing" -> Some Typing
291 | _ -> None
293 let (name_context_to_string : name_context -> string) = function
294 | FunctionNamespace -> "function"
295 | ConstantNamespace -> "constant"
296 | TypeNamespace -> "type"
297 | TraitContext -> "trait"
298 | ClassContext -> "class"
299 | RecordContext -> "record"
301 let get_message (error : error) =
302 (* We get the position of the first item in the message error list, which
303 represents the location of the error (error claim). Other messages represent
304 the reason for the error (the warrant and the grounds). *)
305 let message_list = snd error in
306 let first_message = List.hd_exn message_list in
307 first_message
309 let get_pos (error : error) = fst (get_message error)
311 let sort err =
312 let rec compare (x_code, x_messages) (y_code, y_messages) =
313 match (x_messages, y_messages) with
314 | ([], []) -> 0
315 | (_x_messages, []) -> -1
316 | ([], _y_messages) -> 1
317 | (x_message :: x_messages, y_message :: y_messages) ->
318 (* The primary sort order is position *)
319 let comparison = Pos.compare (fst x_message) (fst y_message) in
320 (* If the positions are the same, sort by error code *)
321 let comparison =
322 if comparison = 0 then
323 Int.compare x_code y_code
324 else
325 comparison
327 (* If the error codes are also the same, sort by message text *)
328 let comparison =
329 if comparison = 0 then
330 String.compare (snd x_message) (snd y_message)
331 else
332 comparison
334 (* Finally, if the message text is also the same, then continue comparing
335 the rest of the messages (which indicate the reason why Hack believes
336 there is an error reported in the 1st message) *)
337 if comparison = 0 then
338 compare (x_code, x_messages) (y_code, y_messages)
339 else
340 comparison
342 let equal x y = compare x y = 0 in
343 List.sort ~compare err |> List.remove_consecutive_duplicates ~equal
345 let get_sorted_error_list (err, _) = sort (files_t_to_list err)
347 (* Getters and setter for passed-in map, based on current context *)
348 let get_current_file_t file_t_map =
349 let current_file = fst !current_context in
350 Relative_path.Map.find_opt file_t_map current_file
351 |> Option.value ~default:PhaseMap.empty
353 let get_current_list file_t_map =
354 let current_phase = snd !current_context in
355 get_current_file_t file_t_map |> fun x ->
356 PhaseMap.find_opt x current_phase |> Option.value ~default:[]
358 let set_current_list file_t_map new_list =
359 let (current_file, current_phase) = !current_context in
360 file_t_map :=
361 Relative_path.Map.add
362 !file_t_map
363 current_file
364 (PhaseMap.add (get_current_file_t !file_t_map) current_phase new_list)
366 let do_with_context path phase f = run_in_context path phase (fun () -> do_ f)
368 (* Turn on lazy decl mode for the duration of the closure.
369 This runs without returning the original state,
370 since we collect it later in do_with_lazy_decls_
372 let run_in_decl_mode filename f =
373 let old_in_lazy_decl = !in_lazy_decl in
374 in_lazy_decl := Some filename;
375 Utils.try_finally ~f ~finally:(fun () -> in_lazy_decl := old_in_lazy_decl)
377 and make_error code (x : (Pos.t * string) list) : error = (code, x)
379 (*****************************************************************************)
380 (* Accessors. *)
381 (*****************************************************************************)
382 and get_code (error : 'a error_) = (fst error : error_code)
384 let get_severity (error : 'a error_) = get_code_severity (get_code error)
386 let to_list (error : 'a error_) = snd error
388 let to_absolute error =
389 let (code, msg_l) = (get_code error, to_list error) in
390 let msg_l = List.map msg_l (fun (p, s) -> (Pos.to_absolute p, s)) in
391 (code, msg_l)
393 let make_absolute_error code (x : (Pos.absolute * string) list) :
394 Pos.absolute error_ =
395 (code, x)
397 let read_lines path = In_channel.read_lines path
399 let num_digits x = int_of_float (Float.log10 (float_of_int x)) + 1
401 (** Sort messages such that messages in the same file are together.
402 Do not reorder the files or messages within a file.
404 let group_messages_by_file (error : Pos.absolute error_) :
405 Pos.absolute message list =
406 let msgs = to_list error in
407 let rec build_map msgs grouped filenames =
408 match msgs with
409 | msg :: msgs ->
410 let filename = Pos.filename (fst msg) in
411 (match String.Map.find grouped filename with
412 | Some file_msgs ->
413 let grouped =
414 String.Map.set grouped ~key:filename ~data:(file_msgs @ [msg])
416 build_map msgs grouped filenames
417 | None ->
418 let grouped = String.Map.set grouped ~key:filename ~data:[msg] in
419 build_map msgs grouped (filename :: filenames))
420 | [] -> (grouped, filenames)
422 let (grouped, filenames) = build_map msgs String.Map.empty [] in
423 List.concat_map (List.rev filenames) ~f:(fun fn ->
424 String.Map.find_exn grouped fn)
426 (* E.g. "10 errors found." *)
427 let format_summary format errors dropped_count max_errors : string option =
428 match format with
429 | Context
430 | Highlighted ->
431 let total = List.length errors + dropped_count in
432 let formatted_total =
433 Printf.sprintf
434 "%d error%s found"
435 total
436 ( if total = 1 then
438 else
439 "s" )
441 let truncated =
442 match max_errors with
443 | Some max_errors when dropped_count > 0 ->
444 Printf.sprintf
445 " (only showing first %d, dropped %d).\n"
446 max_errors
447 dropped_count
448 | _ -> ".\n"
450 Some (formatted_total ^ truncated)
451 | Raw -> None
453 let to_absolute_for_test error =
454 let (code, msg_l) = (get_code error, to_list error) in
455 let msg_l =
456 List.map msg_l (fun (p, s) ->
457 let path = Pos.filename p in
458 let path_without_prefix = Relative_path.suffix path in
459 let p =
460 Pos.set_file
461 (Relative_path.create Relative_path.Dummy path_without_prefix)
464 (Pos.to_absolute p, s))
466 (code, msg_l)
468 let to_string ?(indent = false) (error : Pos.absolute error_) : string =
469 let (error_code, msgl) = (get_code error, to_list error) in
470 let buf = Buffer.create 50 in
471 (match msgl with
472 | [] -> assert false
473 | (pos1, msg1) :: rest_of_error ->
474 Buffer.add_string
476 begin
477 let error_code = error_code_to_string error_code in
478 Printf.sprintf "%s\n%s (%s)\n" (Pos.string pos1) msg1 error_code
479 end;
480 let indentstr =
481 if indent then
483 else
486 List.iter rest_of_error (fun (p, w) ->
487 let msg =
488 Printf.sprintf "%s%s\n%s%s\n" indentstr (Pos.string p) indentstr w
490 Buffer.add_string buf msg));
491 Buffer.contents buf
493 let add_error_impl error =
494 if !accumulate_errors then
495 let () =
496 match !current_context with
497 | (path, _)
498 when Relative_path.equal path Relative_path.default
499 && not !allow_errors_in_default_path ->
500 Hh_logger.log
501 "WARNING: adding an error in default path\n%s\n"
502 (Caml.Printexc.raw_backtrace_to_string
503 (Caml.Printexc.get_callstack 100))
504 | _ -> ()
506 (* Cheap test to avoid duplicating most recent error *)
507 let error_list = get_current_list !error_map in
508 match error_list with
509 | old_error :: _ when equal_error error old_error -> ()
510 | _ -> set_current_list error_map (error :: error_list)
511 else
512 (* We have an error, but haven't handled it in any way *)
513 let msg = error |> to_absolute |> to_string in
514 match !in_lazy_decl with
515 | Some _ -> lazy_decl_error_logging msg error_map to_absolute to_string
516 | None -> Utils.assert_false_log_backtrace (Some msg)
518 (* Whether we've found at least one error *)
519 let currently_has_errors () = not (List.is_empty (get_current_list !error_map))
521 module Parsing = Error_codes.Parsing
522 module Naming = Error_codes.Naming
523 module NastCheck = Error_codes.NastCheck
524 module Typing = Error_codes.Typing
526 (*****************************************************************************)
527 (* Types *)
528 (*****************************************************************************)
530 type t = error files_t * applied_fixme files_t [@@deriving eq]
532 module type Error_category = sig
533 type t
535 val min : int
537 val max : int
539 val of_enum : int -> t option
541 val show : t -> string
543 val err_code : t -> int
546 (*****************************************************************************)
547 (* HH_FIXMEs hook *)
548 (*****************************************************************************)
550 let error_codes_treated_strictly = ref (ISet.of_list [])
552 let is_strict_code code = ISet.mem code !error_codes_treated_strictly
554 (* The 'phps FixmeAllHackErrors' tool must be kept in sync with this list *)
555 let hard_banned_codes =
556 ISet.of_list
558 Typing.err_code Typing.InvalidIsAsExpressionHint;
559 Typing.err_code Typing.InvalidEnforceableTypeArgument;
560 Typing.err_code Typing.RequireArgsReify;
561 Typing.err_code Typing.InvalidReifiedArgument;
562 Typing.err_code Typing.GenericsNotAllowed;
563 Typing.err_code Typing.InvalidNewableTypeArgument;
564 Typing.err_code Typing.InvalidNewableTypeParamConstraints;
565 Typing.err_code Typing.NewWithoutNewable;
566 Typing.err_code Typing.NewStaticClassReified;
567 Typing.err_code Typing.MemoizeReified;
568 Typing.err_code Typing.ClassGetReified;
569 Typing.err_code Typing.PocketUniversesReservedSyntax;
572 let allowed_fixme_codes_strict = ref ISet.empty
574 let allowed_fixme_codes_partial = ref ISet.empty
576 let codes_not_raised_partial = ref ISet.empty
578 let set_allow_errors_in_default_path x = allow_errors_in_default_path := x
580 let is_allowed_code_strict code = ISet.mem code !allowed_fixme_codes_strict
582 let is_allowed_code_partial code = ISet.mem code !allowed_fixme_codes_partial
584 let is_not_raised_partial code = ISet.mem code !codes_not_raised_partial
586 let (get_hh_fixme_pos : (Pos.t -> error_code -> Pos.t option) ref) =
587 ref (fun _ _ -> None)
589 let (is_hh_fixme_disallowed : (Pos.t -> error_code -> bool) ref) =
590 ref (fun _ _ -> false)
592 (*****************************************************************************)
593 (* Errors accumulator. *)
594 (*****************************************************************************)
596 (* If primary position in error list isn't in current file, wrap with a sentinel error *)
597 let check_pos_msg pos_msg_l =
598 let pos = fst (List.hd_exn pos_msg_l) in
599 let current_file = fst !current_context in
600 let current_span = !current_span in
601 (* If error is reported inside the current span, or no span has been set but the error
602 * is reported in the current file, then accept the error *)
604 Pos.contains current_span pos
605 || Pos.equal current_span Pos.none
606 && Relative_path.equal (Pos.filename pos) current_file
607 || Relative_path.equal current_file Relative_path.default
608 then
609 pos_msg_l
610 else
611 let message =
612 pos_msg_l
613 |> List.map ~f:(fun (pos, msg) ->
614 Pos.print_verbose_relative pos ^ ": " ^ msg)
616 let stack =
617 Exception.get_current_callstack_string 99 |> Exception.clean_stack
619 HackEventLogger.type_check_primary_position_bug
620 ~current_file
621 ~message
622 ~stack;
623 let err =
624 if Pos.equal current_span Pos.none then
625 (Pos.make_from current_file, badpos_message)
626 else
627 (current_span, badpos_message_2)
629 err :: pos_msg_l
631 let add_error_with_fixme_error code explanation pos_msg_list =
632 let (pos, _) = List.hd_exn pos_msg_list in
633 let pos = Option.value (!get_hh_fixme_pos pos code) ~default:pos in
634 add_error_impl (make_error code pos_msg_list);
635 add_error_impl (make_error code [(pos, explanation)])
637 let rec add_applied_fixme code pos =
638 if ServerLoadFlag.get_no_load () then
639 let applied_fixmes_list = get_current_list !applied_fixmes in
640 set_current_list applied_fixmes ((pos, code) :: applied_fixmes_list)
641 else
644 and add code pos msg = add_list code [(pos, msg)]
646 and add_error_with_check (error : error) : unit =
647 add_list (fst error) (snd error)
649 and fixme_present pos code =
650 !is_hh_fixme pos code || !is_hh_fixme_disallowed pos code
652 and add_list code pos_msg_l =
653 let pos = fst (List.hd_exn pos_msg_l) in
654 let pos_msg_l = check_pos_msg pos_msg_l in
656 if ISet.mem code hard_banned_codes then
657 if fixme_present pos code then
658 let explanation =
659 Printf.sprintf
660 "You cannot use HH_FIXME or HH_IGNORE_ERROR comments to suppress error %d, and this cannot be enabled by configuration"
661 code
663 add_error_with_fixme_error code explanation pos_msg_l
664 else
665 add_error_impl (make_error code pos_msg_l)
666 else if
667 is_not_raised_partial code && Relative_path.is_partial (Pos.filename pos)
668 then
670 else if not (fixme_present pos code) then
671 (* Fixmes and banned decl fixmes are separated by the parser because Errors can't recover
672 * the position information after the fact. This is the default case, where an HH_FIXME
673 * comment is not present. Therefore, the remaining cases are variations on behavior when
674 * a fixme is present *)
675 add_error_impl (make_error code pos_msg_l)
676 else if Relative_path.(is_hhi (prefix (Pos.filename pos))) then
677 add_applied_fixme code pos
678 else if !is_hh_fixme_disallowed pos code then
679 let explanation =
680 Printf.sprintf
681 "You cannot use HH_FIXME or HH_IGNORE_ERROR comments to suppress error %d in declarations"
682 code
684 add_error_with_fixme_error code explanation pos_msg_l
685 else
686 let whitelist =
688 (not (ISet.is_empty !allowed_fixme_codes_partial))
689 && Relative_path.is_partial (Pos.filename pos)
690 then
691 is_allowed_code_partial
692 else
693 is_allowed_code_strict
695 if whitelist code then
696 add_applied_fixme code pos
697 else
698 let explanation =
699 Printf.sprintf
700 "You cannot use HH_FIXME or HH_IGNORE_ERROR comments to suppress error %d"
701 code
703 add_error_with_fixme_error code explanation pos_msg_l
705 and add_error (code, pos_msg_l) = add_list code pos_msg_l
707 and merge (err', fixmes') (err, fixmes) =
708 let append _ _ x y =
709 let x = Option.value x ~default:[] in
710 let y = Option.value y ~default:[] in
711 Some (List.rev_append x y)
713 (files_t_merge ~f:append err' err, files_t_merge ~f:append fixmes' fixmes)
715 and merge_into_current errors =
716 let merged = merge errors (!error_map, !applied_fixmes) in
717 error_map := fst merged;
718 applied_fixmes := snd merged
720 and incremental_update :
721 type (* Need to write out the entire ugly type to convince OCaml it's polymorphic
722 * and can update both error_map as well as applied_fixmes map *)
724 a files_t ->
725 a files_t ->
726 ((* function folding over paths of rechecked files *)
727 a files_t ->
728 (Relative_path.t -> a files_t -> a files_t) ->
729 a files_t) ->
730 phase ->
731 a files_t =
732 fun old new_ fold phase ->
733 (* Helper to remove acc[path][phase]. If acc[path] becomes empty afterwards,
734 * remove it too (i.e do not store empty maps or lists ever). *)
735 let remove path phase acc =
736 let new_phase_map =
737 match Relative_path.Map.find_opt acc path with
738 | None -> None
739 | Some phase_map ->
740 let new_phase_map = PhaseMap.remove phase_map phase in
741 if PhaseMap.is_empty new_phase_map then
742 None
743 else
744 Some new_phase_map
746 match new_phase_map with
747 | None -> Relative_path.Map.remove acc path
748 | Some x -> Relative_path.Map.add acc path x
750 (* Replace old errors with new *)
751 let res =
752 files_t_merge new_ old ~f:(fun phase path new_ old ->
753 ( if Relative_path.equal path Relative_path.default then
754 let phase =
755 match phase with
756 | Init -> "Init"
757 | Parsing -> "Parsing"
758 | Naming -> "Naming"
759 | Decl -> "Decl"
760 | Typing -> "Typing"
762 Utils.assert_false_log_backtrace
763 (Some
764 ( "Default (untracked) error sources should not get into incremental "
765 ^ "mode. There might be a missing call to Errors.do_with_context/"
766 ^ "run_in_context somwhere or incorrectly used Errors.from_error_list."
767 ^ "Phase: "
768 ^ phase )) );
769 match new_ with
770 | Some new_ -> Some (List.rev new_)
771 | None -> old)
773 (* For files that were rechecked, but had no errors - remove them from maps *)
774 fold res (fun path acc ->
775 let has_errors =
776 match Relative_path.Map.find_opt new_ path with
777 | None -> false
778 | Some phase_map -> PhaseMap.mem phase_map phase
780 if has_errors then
782 else
783 remove path phase acc)
785 and incremental_update_set ~old ~new_ ~rechecked phase =
786 let fold init g =
787 Relative_path.Set.fold
789 begin
790 fun path acc ->
791 g path acc
793 ~init
794 rechecked
796 ( incremental_update (fst old) (fst new_) fold phase,
797 incremental_update (snd old) (snd new_) fold phase )
799 and incremental_update_map ~old ~new_ ~rechecked phase =
800 let fold init g =
801 Relative_path.Map.fold
803 begin
804 fun path _ acc ->
805 g path acc
807 ~init
808 rechecked
810 ( incremental_update (fst old) (fst new_) fold phase,
811 incremental_update (snd old) (snd new_) fold phase )
813 and empty = (Relative_path.Map.empty, Relative_path.Map.empty)
815 and is_empty (err, _fixmes) = Relative_path.Map.is_empty err
817 and count (err, _fixmes) =
818 files_t_fold err ~f:(fun _ _ x acc -> acc + List.length x) ~init:0
820 and get_error_list (err, _fixmes) = files_t_to_list err
822 and get_applied_fixmes (_err, fixmes) = files_t_to_list fixmes
824 and from_error_list err = (list_to_files_t err, Relative_path.Map.empty)
826 (*****************************************************************************)
827 (* Accessors. (All methods delegated to the parameterized module.) *)
828 (*****************************************************************************)
830 let iter_error_list f err = List.iter ~f (get_sorted_error_list err)
832 let fold_errors ?phase err ~init ~f =
833 match phase with
834 | None ->
835 files_t_fold (fst err) ~init ~f:(fun source _ errors acc ->
836 List.fold_right errors ~init:acc ~f:(f source))
837 | Some phase ->
838 Relative_path.Map.fold (fst err) ~init ~f:(fun source phases acc ->
839 match PhaseMap.find_opt phases phase with
840 | None -> acc
841 | Some errors -> List.fold_right errors ~init:acc ~f:(f source))
843 let fold_errors_in ?phase err ~source ~init ~f =
844 Relative_path.Map.find_opt (fst err) source
845 |> Option.value ~default:PhaseMap.empty
846 |> PhaseMap.fold ~init ~f:(fun p errors acc ->
847 match phase with
848 | Some x when not (equal_phase x p) -> acc
849 | _ -> List.fold_right errors ~init:acc ~f)
851 let get_failed_files err phase =
852 files_t_fold (fst err) ~init:Relative_path.Set.empty ~f:(fun source p _ acc ->
853 if not (equal_phase phase p) then
855 else
856 Relative_path.Set.add acc source)
858 (*****************************************************************************)
859 (* Error code printing. *)
860 (*****************************************************************************)
862 let internal_error pos msg = add 0 pos ("Internal error: " ^ msg)
864 let unimplemented_feature pos msg = add 0 pos ("Feature not implemented: " ^ msg)
866 let experimental_feature pos msg =
867 add 0 pos ("Cannot use experimental feature: " ^ msg)
869 let strip_ns id = id |> Utils.strip_ns |> Hh_autoimport.reverse_type
871 let on_error_or_add (on_error : typing_error_callback option) code errl =
872 match on_error with
873 | None -> add_list code errl
874 | Some f -> f ~code errl
876 (*****************************************************************************)
877 (* Parsing errors. *)
878 (*****************************************************************************)
880 let fixme_format pos =
882 (Parsing.err_code Parsing.FixmeFormat)
884 "HH_FIXME wrong format, expected '/* HH_FIXME[ERROR_NUMBER] */'"
886 let parsing_error (p, msg) = add (Parsing.err_code Parsing.ParsingError) p msg
888 let xhp_parsing_error (p, msg) =
889 add (Parsing.err_code Parsing.XhpParsingError) p msg
891 (*****************************************************************************)
892 (* Legacy AST / AAST errors *)
893 (*****************************************************************************)
895 let mk_unsupported_trait_use_as pos =
896 ( Naming.err_code Naming.UnsupportedTraitUseAs,
897 [(pos, "Trait use as is a PHP feature that is unsupported in Hack")] )
899 let unsupported_trait_use_as pos =
900 add_error_with_check (mk_unsupported_trait_use_as pos)
902 let mk_unsupported_instead_of pos =
903 ( Naming.err_code Naming.UnsupportedInsteadOf,
904 [(pos, "insteadof is a PHP feature that is unsupported in Hack")] )
906 let unsupported_instead_of pos =
907 add_error_with_check (mk_unsupported_instead_of pos)
909 let mk_invalid_trait_use_as_visibility pos =
910 ( Naming.err_code Naming.InvalidTraitUseAsVisibility,
911 [(pos, "Cannot redeclare trait method's visibility in this manner")] )
913 let invalid_trait_use_as_visibility pos =
914 add_error_with_check (mk_invalid_trait_use_as_visibility pos)
916 (*****************************************************************************)
917 (* Naming errors *)
918 (*****************************************************************************)
920 let unexpected_arrow pos cname =
922 (Naming.err_code Naming.UnexpectedArrow)
924 ("Keys may not be specified for " ^ cname ^ " initialization")
926 let missing_arrow pos cname =
928 (Naming.err_code Naming.MissingArrow)
930 ("Keys must be specified for " ^ cname ^ " initialization")
932 let disallowed_xhp_type pos name =
934 (Naming.err_code Naming.DisallowedXhpType)
936 (name ^ " is not a valid type. Use :xhp or XHPChild.")
938 let name_is_reserved name pos =
939 let name = Utils.strip_all_ns name in
941 (Naming.err_code Naming.NameIsReserved)
943 (name ^ " cannot be used as it is reserved.")
945 let dollardollar_unused pos =
947 (Naming.err_code Naming.DollardollarUnused)
949 ( "This expression does not contain a "
950 ^ "usage of the special pipe variable. Did you forget to use the ($$) "
951 ^ "variable?" )
953 let method_name_already_bound pos name =
955 (Naming.err_code Naming.MethodNameAlreadyBound)
957 ("Method name already bound: " ^ name)
959 let error_name_already_bound name name_prev p p_prev =
960 let name = strip_ns name in
961 let name_prev = strip_ns name_prev in
962 let errs =
964 (p, "Name already bound: " ^ name);
965 ( p_prev,
966 if String.compare name name_prev = 0 then
967 "Previous definition is here"
968 else
969 "Previous definition "
970 ^ name_prev
971 ^ " differs only in capitalization " );
974 let hhi_msg =
975 "This appears to be defined in an hhi file included in your project "
976 ^ "root. The hhi files for the standard library are now a part of the "
977 ^ "typechecker and must be removed from your project. Typically, you can "
978 ^ "do this by deleting the \"hhi\" directory you copied into your "
979 ^ "project when first starting with Hack."
981 let errs =
982 if Relative_path.(is_hhi (prefix (Pos.filename p))) then
983 errs @ [(p_prev, hhi_msg)]
984 else if Relative_path.(is_hhi (prefix (Pos.filename p_prev))) then
985 errs @ [(p, hhi_msg)]
986 else
987 errs
989 add_list (Naming.err_code Naming.ErrorNameAlreadyBound) errs
991 let error_class_attribute_already_bound name name_prev p p_prev =
992 let name = strip_ns name in
993 let name_prev = strip_ns name_prev in
994 let errs =
996 ( p,
997 "A class and an attribute class cannot share the same name. Conflicting class: "
998 ^ name );
999 (p_prev, "Previous definition: " ^ name_prev);
1002 add_list (Naming.err_code Naming.AttributeClassNameConflict) errs
1004 let unbound_name pos name kind =
1005 let kind_str =
1006 match kind with
1007 | ConstantNamespace -> " (a global constant)"
1008 | FunctionNamespace -> " (a global function)"
1009 | TypeNamespace -> ""
1010 | ClassContext -> " (an object type)"
1011 | TraitContext -> " (a trait)"
1012 | RecordContext -> " (a record type)"
1015 (Naming.err_code Naming.UnboundName)
1017 ("Unbound name: " ^ strip_ns name ^ kind_str)
1019 let invalid_fun_pointer pos name =
1021 (Naming.err_code Naming.InvalidFunPointer)
1023 ( "Unbound global function: '"
1024 ^ strip_ns name
1025 ^ "' is not a valid name for fun()" )
1027 let rx_move_invalid_location pos =
1029 (Naming.err_code Naming.RxMoveInvalidLocation)
1031 "Rx\\move is only allowed in argument position or as right hand side of the assignment."
1033 let undefined ~in_rx_scope pos var_name did_you_mean =
1034 let msg =
1035 if in_rx_scope then
1036 Printf.sprintf
1037 "Variable %s is undefined, not always defined, or unset afterwards"
1038 var_name
1039 else
1040 Printf.sprintf "Variable %s is undefined, or not always defined" var_name
1042 let suggestion =
1043 match did_you_mean with
1044 | Some var_name -> Printf.sprintf " (did you mean %s instead?)" var_name
1045 | None -> ""
1047 add_list (Naming.err_code Naming.Undefined) [(pos, msg ^ suggestion)]
1049 let this_reserved pos =
1051 (Naming.err_code Naming.ThisReserved)
1053 "The type parameter \"this\" is reserved"
1055 let start_with_T pos =
1057 (Naming.err_code Naming.StartWith_T)
1059 "Please make your type parameter start with the letter T (capital)"
1061 let already_bound pos name =
1063 (Naming.err_code Naming.NameAlreadyBound)
1065 ("Argument already bound: " ^ name)
1067 let unexpected_typedef pos def_pos expected_kind =
1068 let expected_type = name_context_to_string expected_kind in
1069 add_list
1070 (Naming.err_code Naming.UnexpectedTypedef)
1072 (pos, Printf.sprintf "Expected a %s but got a type alias." expected_type);
1073 (def_pos, "Alias definition is here.");
1076 let mk_fd_name_already_bound pos =
1077 ( Naming.err_code Naming.FdNameAlreadyBound,
1078 [(pos, "Field name already bound")] )
1080 let fd_name_already_bound pos =
1081 add_error_with_check (mk_fd_name_already_bound pos)
1083 let repeated_record_field name pos prev_pos =
1084 let msg = Printf.sprintf "Duplicate record field `%s`" name in
1085 add_list
1086 (NastCheck.err_code NastCheck.RepeatedRecordFieldName)
1087 [(pos, msg); (prev_pos, "Previous field is here")]
1089 let unexpected_record_field_name ~field_name ~field_pos ~record_name ~decl_pos =
1090 let msg =
1091 Printf.sprintf
1092 "Record `%s` has no field `%s`"
1093 (strip_ns record_name)
1094 field_name
1096 add_list
1097 (Typing.err_code Typing.RecordUnknownField)
1098 [(field_pos, msg); (decl_pos, "Definition is here")]
1100 let missing_record_field_name ~field_name ~new_pos ~record_name ~field_decl_pos
1102 let msg =
1103 Printf.sprintf
1104 "Mising required field `%s` in `%s`"
1105 field_name
1106 (strip_ns record_name)
1108 add_list
1109 (Typing.err_code Typing.RecordMissingRequiredField)
1110 [(new_pos, msg); (field_decl_pos, "Field definition is here")]
1112 let type_not_record id pos =
1114 (Typing.err_code Typing.NotARecord)
1116 (Printf.sprintf "Expected a record type, but got `%s`." (strip_ns id))
1118 let primitive_toplevel pos =
1120 (Naming.err_code Naming.PrimitiveToplevel)
1122 "Primitive type annotations are always available and may no longer be referred to in the toplevel namespace."
1124 let primitive_invalid_alias pos used valid =
1126 (Naming.err_code Naming.PrimitiveInvalidAlias)
1128 ( "Invalid Hack type. Using '"
1129 ^ used
1130 ^ "' in Hack is considered an error. Use '"
1131 ^ valid
1132 ^ "' instead, to keep the codebase consistent." )
1134 let dynamic_new_in_strict_mode pos =
1136 (Naming.err_code Naming.DynamicNewInStrictMode)
1138 "Cannot use dynamic new."
1140 let invalid_type_access_root (pos, id) =
1142 (Naming.err_code Naming.InvalidTypeAccessRoot)
1144 (id ^ " must be an identifier for a class, \"self\", or \"this\"")
1146 let duplicate_user_attribute (pos, name) existing_attr_pos =
1147 add_list
1148 (Naming.err_code Naming.DuplicateUserAttribute)
1150 (pos, "You cannot reuse the attribute " ^ name);
1151 (existing_attr_pos, name ^ " was already used here");
1154 let unbound_attribute_name pos name =
1155 let reason =
1156 if string_starts_with name "__" then
1157 "starts with __ but is not a standard attribute"
1158 else
1159 "does not have a class. Please declare a class for the attribute."
1162 (Naming.err_code Naming.UnboundName)
1164 ("Unrecognized user attribute: " ^ strip_ns name ^ " " ^ reason)
1166 let this_no_argument pos =
1168 (Naming.err_code Naming.ThisNoArgument)
1170 "\"this\" expects no arguments"
1172 let object_cast pos =
1174 (Naming.err_code Naming.ObjectCast)
1176 "Casts are only supported for bool, int, float and string."
1178 let this_hint_outside_class pos =
1180 (Naming.err_code Naming.ThisHintOutsideClass)
1182 "Cannot use \"this\" outside of a class"
1184 let this_type_forbidden pos =
1186 (Naming.err_code Naming.ThisMustBeReturn)
1188 "The type \"this\" cannot be used as a constraint on a class' generic, or as the type of a static member variable"
1190 let nonstatic_property_with_lsb pos =
1192 (Naming.err_code Naming.NonstaticPropertyWithLSB)
1194 "__LSB attribute may only be used on static properties"
1196 let lowercase_this pos type_ =
1198 (Naming.err_code Naming.LowercaseThis)
1200 ("Invalid Hack type \"" ^ type_ ^ "\". Use \"this\" instead")
1202 let classname_param pos =
1204 (Naming.err_code Naming.ClassnameParam)
1206 ( "Missing type parameter to classname; classname is entirely"
1207 ^ " meaningless without one" )
1209 (** Used if higher-kinded types are disabled *)
1210 let typaram_applied_to_type pos x =
1212 (Naming.err_code Naming.HigherKindedTypesUnsupportedFeature)
1214 (Printf.sprintf
1215 "%s is a type parameter. Type parameters cannot take type arguments (e.g. %s<int> isn't allowed)"
1219 (** Used if higher-kinded types are disabled *)
1220 let tparam_with_tparam pos x =
1221 let param_desc =
1222 match x with
1223 | "_" -> ""
1224 | _ -> x ^ " is a type parameter. "
1227 (Naming.err_code Naming.HigherKindedTypesUnsupportedFeature)
1229 (Printf.sprintf
1230 "%sType parameters cannot themselves have type parameters"
1231 param_desc)
1233 let shadowed_type_param p pos name =
1234 add_list
1235 (Naming.err_code Naming.ShadowedTypeParam)
1237 (p, Printf.sprintf "You cannot re-bind the type parameter %s" name);
1238 (pos, Printf.sprintf "%s is already bound here" name);
1241 let missing_typehint pos =
1242 add (Naming.err_code Naming.MissingTypehint) pos "Please add a type hint"
1244 let expected_variable pos =
1246 (Naming.err_code Naming.ExpectedVariable)
1248 "Was expecting a variable name"
1250 let clone_too_many_arguments pos =
1252 (Naming.err_code Naming.NamingTooManyArguments)
1254 "__clone method cannot take arguments"
1256 let naming_too_few_arguments pos =
1257 add (Naming.err_code Naming.NamingTooFewArguments) pos "Too few arguments"
1259 let naming_too_many_arguments pos =
1260 add (Naming.err_code Naming.NamingTooManyArguments) pos "Too many arguments"
1262 let expected_collection pos cn =
1264 (Naming.err_code Naming.ExpectedCollection)
1266 ("Unexpected collection type " ^ strip_ns cn)
1268 let illegal_CLASS pos =
1270 (Naming.err_code Naming.IllegalClass)
1272 "Using __CLASS__ outside a class or trait"
1274 let illegal_TRAIT pos =
1276 (Naming.err_code Naming.IllegalTrait)
1278 "Using __TRAIT__ outside a trait"
1280 let lvar_in_obj_get pos =
1282 (Naming.err_code Naming.LvarInObjGet)
1284 "Dynamic method or attribute access is not allowed on a non-dynamic value."
1286 let nullsafe_property_write_context pos =
1288 (Typing.err_code Typing.NullsafePropertyWriteContext)
1290 "?-> syntax not supported here, this function effectively does a write"
1292 let illegal_fun pos =
1293 let msg =
1294 "The argument to fun() must be a single-quoted, constant "
1295 ^ "literal string representing a valid function name."
1297 add (Naming.err_code Naming.IllegalFun) pos msg
1299 let illegal_member_variable_class pos =
1300 let msg =
1301 "Cannot declare a constant named 'class'. The name 'class' is reserved for the class constant that represents the name of the class"
1303 add (Naming.err_code Naming.IllegalMemberVariableClass) pos msg
1305 let illegal_meth_fun pos =
1306 let msg =
1307 "String argument to fun() contains ':';"
1308 ^ " for static class methods, use"
1309 ^ " class_meth(Cls::class, 'method_name'), not fun('Cls::method_name')"
1311 add (Naming.err_code Naming.IllegalMethFun) pos msg
1313 let illegal_inst_meth pos =
1314 let msg =
1315 "The argument to inst_meth() must be an expression and a "
1316 ^ "constant literal string representing a valid method name."
1318 add (Naming.err_code Naming.IllegalInstMeth) pos msg
1320 let illegal_meth_caller pos =
1321 let msg =
1322 "The two arguments to meth_caller() must be:"
1323 ^ "\n - first: ClassOrInterface::class"
1324 ^ "\n - second: a single-quoted string literal containing the name"
1325 ^ " of a non-static method of that class"
1327 add (Naming.err_code Naming.IllegalMethCaller) pos msg
1329 let illegal_class_meth pos =
1330 let msg =
1331 "The two arguments to class_meth() must be:"
1332 ^ "\n - first: ValidClassname::class"
1333 ^ "\n - second: a single-quoted string literal containing the name"
1334 ^ " of a static method of that class"
1336 add (Naming.err_code Naming.IllegalClassMeth) pos msg
1338 let class_meth_non_final_self pos class_name =
1339 let msg =
1340 "`class_meth` with `self::class` does not preserve class calling context.\n"
1341 ^ "Use `static::class`, or `"
1342 ^ strip_ns class_name
1343 ^ "::class` explicitly"
1345 add (Naming.err_code Naming.ClassMethNonFinalSelf) pos msg
1347 let assert_arity pos =
1349 (Naming.err_code Naming.AssertArity)
1351 "assert expects exactly one argument"
1353 let unexpected_ty_in_tast pos ~actual_ty ~expected_ty =
1355 (Typing.err_code Typing.UnexpectedTy)
1357 ("Unexpected type in TAST: expected " ^ expected_ty ^ ", got " ^ actual_ty)
1359 let uninstantiable_class usage_pos decl_pos name reason_msgl =
1360 let name = strip_ns name in
1361 let msgl =
1363 (usage_pos, name ^ " is uninstantiable"); (decl_pos, "Declaration is here");
1366 let msgl =
1367 match reason_msgl with
1368 | (reason_pos, reason_str) :: tail ->
1369 ((reason_pos, reason_str ^ " which must be instantiable") :: tail) @ msgl
1370 | _ -> msgl
1372 add_list (Typing.err_code Typing.UninstantiableClass) msgl
1374 let new_abstract_record (pos, name) =
1375 let name = strip_ns name in
1377 (Typing.err_code Typing.NewAbstractRecord)
1379 (Printf.sprintf "Cannot create instance of abstract record `%s`" name)
1381 let abstract_const_usage usage_pos decl_pos name =
1382 let name = strip_ns name in
1383 add_list
1384 (Typing.err_code Typing.AbstractConstUsage)
1386 (usage_pos, "Cannot reference abstract constant " ^ name ^ " directly");
1387 (decl_pos, "Declaration is here");
1390 let concrete_const_interface_override
1391 child_pos parent_pos parent_origin name (on_error : typing_error_callback) =
1392 let parent_origin = strip_ns parent_origin in
1393 on_error
1394 ~code:(Typing.err_code Typing.ConcreteConstInterfaceOverride)
1396 ( child_pos,
1397 "Non-abstract constants defined in an interface cannot be overridden when implementing or extending that interface."
1399 ( parent_pos,
1400 "You could make " ^ name ^ " abstract in " ^ parent_origin ^ "." );
1403 let const_without_typehint sid =
1404 let (pos, name) = sid in
1405 let msg =
1406 Printf.sprintf
1407 "Please add a type hint 'const SomeType %s'"
1408 (Utils.strip_all_ns name)
1410 add (Naming.err_code Naming.AddATypehint) pos msg
1412 let prop_without_typehint visibility sid =
1413 let (pos, name) = sid in
1414 let msg =
1415 Printf.sprintf "Please add a type hint '%s SomeType %s'" visibility name
1417 add (Naming.err_code Naming.AddATypehint) pos msg
1419 let illegal_constant pos =
1420 add (Naming.err_code Naming.IllegalConstant) pos "Illegal constant value"
1422 let invalid_req_implements pos =
1424 (Naming.err_code Naming.InvalidReqImplements)
1426 "Only traits may use 'require implements'"
1428 let invalid_req_extends pos =
1430 (Naming.err_code Naming.InvalidReqExtends)
1432 "Only traits and interfaces may use 'require extends'"
1434 let did_you_mean_naming pos name suggest_pos suggest_name =
1435 add_list
1436 (Naming.err_code Naming.DidYouMeanNaming)
1438 (pos, "Could not find " ^ strip_ns name);
1439 (suggest_pos, "Did you mean " ^ strip_ns suggest_name ^ "?");
1442 let using_internal_class pos name =
1444 (Naming.err_code Naming.UsingInternalClass)
1446 (name ^ " is an implementation internal class that cannot be used directly")
1448 let too_few_type_arguments p =
1450 (Naming.err_code Naming.TooFewTypeArguments)
1452 "Too few type arguments for this type"
1454 let goto_label_already_defined
1455 label_name redeclaration_pos original_delcaration_pos =
1456 add_list
1457 (Naming.err_code Naming.GotoLabelAlreadyDefined)
1459 (redeclaration_pos, "Cannot redeclare the goto label '" ^ label_name ^ "'");
1460 (original_delcaration_pos, "Declaration is here");
1463 let goto_label_undefined pos label_name =
1465 (Naming.err_code Naming.GotoLabelUndefined)
1467 ("Undefined goto label: " ^ label_name)
1469 let goto_label_defined_in_finally pos =
1471 (Naming.err_code Naming.GotoLabelDefinedInFinally)
1473 "It is illegal to define a goto label within a finally block."
1475 let goto_invoked_in_finally pos =
1477 (Naming.err_code Naming.GotoInvokedInFinally)
1479 "It is illegal to invoke goto within a finally block."
1481 let mk_method_needs_visibility pos =
1482 ( Naming.err_code Naming.MethodNeedsVisibility,
1483 [(pos, "Methods need to be marked public, private, or protected.")] )
1485 let method_needs_visibility pos =
1486 add_error_with_check (mk_method_needs_visibility pos)
1488 let dynamic_class_name_in_strict_mode pos =
1490 (Naming.err_code Naming.DynamicClassNameInStrictMode)
1492 "Cannot use dynamic class name in strict mode"
1494 let xhp_optional_required_attr pos id =
1496 (Naming.err_code Naming.XhpOptionalRequiredAttr)
1498 ("XHP attribute " ^ id ^ " cannot be marked as nullable and required")
1500 let xhp_required_with_default pos id =
1502 (Naming.err_code Naming.XhpRequiredWithDefault)
1504 ( "XHP attribute "
1505 ^ id
1506 ^ " cannot be marked as required and provide a default" )
1508 let array_typehints_disallowed pos =
1510 (Naming.err_code Naming.ArrayTypehintsDisallowed)
1512 "Array typehints are no longer legal; use varray or darray instead"
1514 let array_literals_disallowed pos =
1516 (Naming.err_code Naming.ArrayLiteralsDisallowed)
1518 "Array literals are no longer legal; use varray or darray instead"
1520 let wildcard_disallowed pos =
1522 (Naming.err_code Naming.WildcardDisallowed)
1524 "Wildcard typehints are not allowed in this position"
1526 let misplaced_mutability_hint pos =
1528 (Naming.err_code Naming.MisplacedMutabilityHint)
1530 "Setting mutability via type hints is only allowed for parameters of reactive function types. For other cases consider using attributes."
1532 let mutability_hint_in_non_rx_function pos =
1534 (Naming.err_code Naming.MutabilityHintInNonRx)
1536 "Parameter with mutability hint cannot appear in non-reactive function type."
1538 let invalid_mutability_in_return_type_hint pos =
1540 (Naming.err_code Naming.InvalidReturnMutableHint)
1542 "OwnedMutable is the only mutability related hint allowed in return type annotation for reactive function types."
1544 let pu_case_in_trait pos kind =
1546 (Naming.err_code Naming.PocketUniversesNotInClass)
1548 (sprintf "Case %s is not allowed in traits" kind)
1550 let pu_duplication pos kind name seen =
1551 let name = strip_ns name in
1552 let seen = strip_ns seen in
1554 (Naming.err_code Naming.PocketUniversesDuplication)
1556 (sprintf "Pocket Universe %s %s is already declared in %s" kind name seen)
1558 let pu_duplication_in_instance pos kind name seen =
1559 let name = strip_ns name in
1560 let seen = strip_ns seen in
1562 (Naming.err_code Naming.PocketUniversesDuplication)
1564 (sprintf "%s %s is already assigned in %s" kind name seen)
1566 let pu_not_in_class pos name loc =
1567 let name = strip_ns name in
1568 let loc = strip_ns loc in
1570 (Naming.err_code Naming.PocketUniversesNotInClass)
1572 (sprintf "Pocket Universe %s is defined outside a class (%s)" name loc)
1574 let pu_atom_missing pos name kind loc missing =
1575 let name = strip_ns name in
1576 let loc = strip_ns loc in
1578 (Naming.err_code Naming.PocketUniversesAtomMissing)
1580 (sprintf
1581 "In Pocket Universe %s, atom %s is missing %s %s"
1583 name
1584 kind
1585 missing)
1587 let pu_atom_unknown pos name kind loc unk =
1588 let name = strip_ns name in
1589 let loc = strip_ns loc in
1591 (Naming.err_code Naming.PocketUniversesAtomUnknown)
1593 (sprintf
1594 "In Pocket Universe %s, atom %s declares unknown %s %s"
1596 name
1597 kind
1598 unk)
1600 let pu_localize pos pu dep_ty =
1601 let pu = strip_ns pu in
1602 let dep_ty = strip_ns dep_ty in
1604 (Naming.err_code Naming.PocketUniversesLocalization)
1606 (sprintf "In the context of %s, cannot expand %s" pu dep_ty)
1608 let pu_invalid_access pos msg =
1610 (Naming.err_code Naming.PocketUniversesLocalization)
1612 ("Invalid Pocket Universe invocation" ^ msg)
1614 let pu_attribute_invalid pos =
1616 (Typing.err_code Typing.PocketUniversesAttributes)
1618 "Invalid __Pu attribute"
1620 let pu_attribute_dup pos kind s =
1621 let s = strip_ns s in
1623 (Typing.err_code Typing.PocketUniversesAttributes)
1625 (sprintf "Duplicated %s '%s' in __Pu attribute" kind s)
1627 let pu_attribute_err pos kind class_name enum_name attr_name =
1628 let class_name = strip_ns class_name in
1630 (Typing.err_code Typing.PocketUniversesAttributes)
1632 (sprintf
1633 "Class/Trait %s has a %s attribute '%s' for enumeration %s"
1634 class_name
1635 kind
1636 attr_name
1637 enum_name)
1639 let pu_attribute_suggestion pos class_name content =
1640 let class_name = strip_ns class_name in
1642 (Typing.err_code Typing.PocketUniversesAttributes)
1644 (sprintf
1645 "Class/Trait %s should have the attribute:\n__Pu(%s)"
1646 class_name
1647 content)
1649 let pu_attribute_not_necessary pos class_name =
1650 let class_name = strip_ns class_name in
1652 (Typing.err_code Typing.PocketUniversesAttributes)
1654 (sprintf "Class/Trait %s does not need any __Pu attribute" class_name)
1656 let pu_reserved_syntax pos =
1658 (Typing.err_code Typing.PocketUniversesReservedSyntax)
1660 ( "This syntax is reserved for the Pocket Universes prototype.\n"
1661 ^ "It can only be used in the directories specified by the\n"
1662 ^ " pocket_universe_enabled_paths = nowhere|everywhere|dir1,..,dirn\noption in .hhconfig"
1665 let illegal_use_of_dynamically_callable attr_pos meth_pos visibility =
1666 add_list
1667 (Naming.err_code Naming.IllegalUseOfDynamicallyCallable)
1669 (attr_pos, "__DynamicallyCallable can only be used on public methods");
1670 (meth_pos, sprintf "But this method is %s" visibility);
1673 (*****************************************************************************)
1674 (* Init check errors *)
1675 (*****************************************************************************)
1677 let no_construct_parent pos =
1679 (NastCheck.err_code NastCheck.NoConstructParent)
1681 (Utils.sl
1683 "You are extending a class that needs to be initialized\n";
1684 "Make sure you call parent::__construct.\n";
1687 let nonstatic_method_in_abstract_final_class pos =
1689 (NastCheck.err_code NastCheck.NonstaticMethodInAbstractFinalClass)
1691 "Abstract final classes cannot have nonstatic methods or constructors."
1693 let constructor_required (pos, name) prop_names =
1694 let name = strip_ns name in
1695 let props_str = String.concat prop_names ~sep:" " in
1697 (NastCheck.err_code NastCheck.ConstructorRequired)
1699 ( "Lacking __construct, class "
1700 ^ name
1701 ^ " does not initialize its private member(s): "
1702 ^ props_str )
1704 let not_initialized (pos, cname) prop_names =
1705 let cname = strip_ns cname in
1706 let props_str =
1707 List.fold_right prop_names ~f:(fun x acc -> x ^ " " ^ acc) ~init:""
1709 let (members, verb) =
1710 if 1 = List.length prop_names then
1711 ("member", "is")
1712 else
1713 ("members", "are")
1715 let setters_str =
1716 List.fold_right
1717 prop_names
1718 ~f:(fun x acc -> "$this->" ^ x ^ " " ^ acc)
1719 ~init:""
1722 (NastCheck.err_code NastCheck.NotInitialized)
1724 (Utils.sl
1726 "Class ";
1727 cname;
1728 " does not initialize all of its members; ";
1729 props_str;
1730 verb;
1731 " not always initialized.";
1732 "\nMake sure you systematically set ";
1733 setters_str;
1734 "when the method __construct is called.";
1735 "\nAlternatively, you can define the ";
1736 members;
1737 " as nullable (?...)\n";
1740 let call_before_init pos cv =
1742 (NastCheck.err_code NastCheck.CallBeforeInit)
1744 (Utils.sl
1746 "Until the initialization of $this is over,";
1747 " you can only call private methods\n";
1748 "The initialization is not over because ";
1751 if String.equal cv "parent::__construct" then
1752 ["you forgot to call parent::__construct"]
1753 else
1754 ["$this->"; cv; " can still potentially be null"] ))
1756 (*****************************************************************************)
1757 (* Nast errors check *)
1758 (*****************************************************************************)
1760 let type_arity use_pos def_pos ~expected ~actual =
1761 add_list
1762 (Typing.err_code Typing.TypeArityMismatch)
1764 ( use_pos,
1765 Printf.sprintf
1766 "Wrong number of type arguments (expected %d, got %d)"
1767 expected
1768 actual );
1769 (def_pos, "Definition is here");
1772 let abstract_with_body (p, _) =
1774 (NastCheck.err_code NastCheck.AbstractWithBody)
1776 "This method is declared as abstract, but has a body"
1778 let not_abstract_without_body (p, _) =
1780 (NastCheck.err_code NastCheck.NotAbstractWithoutBody)
1782 "This method is not declared as abstract, it must have a body"
1784 let mk_not_abstract_without_typeconst (p, _) =
1785 ( NastCheck.err_code NastCheck.NotAbstractWithoutTypeconst,
1787 ( p,
1788 "This type constant is not declared as abstract, it must have"
1789 ^ " an assigned type" );
1792 let not_abstract_without_typeconst node =
1793 add_error_with_check (mk_not_abstract_without_typeconst node)
1795 let typeconst_depends_on_external_tparam pos ext_pos ext_name =
1796 add_list
1797 (NastCheck.err_code NastCheck.TypeconstDependsOnExternalTparam)
1799 ( pos,
1800 "A type constant can only use type parameters declared in its own"
1801 ^ " type parameter list" );
1802 (ext_pos, ext_name ^ " was declared as a type parameter here");
1805 let interface_with_partial_typeconst tconst_pos =
1807 (NastCheck.err_code NastCheck.InterfaceWithPartialTypeconst)
1808 tconst_pos
1809 "An interface cannot contain a partially abstract type constant"
1811 let mk_multiple_xhp_category pos =
1812 ( NastCheck.err_code NastCheck.MultipleXhpCategory,
1813 [(pos, "XHP classes can only contain one category declaration")] )
1815 let multiple_xhp_category pos =
1816 add_error_with_check (mk_multiple_xhp_category pos)
1818 let return_in_gen p =
1820 (NastCheck.err_code NastCheck.ReturnInGen)
1822 ( "You cannot return a value in a generator (a generator"
1823 ^ " is a function that uses yield)" )
1825 let return_in_finally p =
1827 (NastCheck.err_code NastCheck.ReturnInFinally)
1829 ( "Don't use return in a finally block;"
1830 ^ " there's nothing to receive the return value" )
1832 let toplevel_break p =
1834 (NastCheck.err_code NastCheck.ToplevelBreak)
1836 "break can only be used inside loops or switch statements"
1838 let toplevel_continue p =
1840 (NastCheck.err_code NastCheck.ToplevelContinue)
1842 "continue can only be used inside loops"
1844 let continue_in_switch p =
1846 (NastCheck.err_code NastCheck.ContinueInSwitch)
1848 ( "In PHP, 'continue;' inside a switch statement is equivalent to 'break;'."
1849 ^ " Hack does not support this; use 'break' if that is what you meant." )
1851 let await_in_sync_function p =
1853 (NastCheck.err_code NastCheck.AwaitInSyncFunction)
1855 "await can only be used inside async functions"
1857 let interface_use_trait p =
1859 (NastCheck.err_code NastCheck.InterfaceUsesTrait)
1861 "Interfaces cannot use traits"
1863 let await_in_coroutine p =
1865 (NastCheck.err_code NastCheck.AwaitInCoroutine)
1867 "await is not allowed in coroutines."
1869 let yield_in_coroutine p =
1871 (NastCheck.err_code NastCheck.YieldInCoroutine)
1873 "yield is not allowed in coroutines."
1875 let suspend_outside_of_coroutine p =
1877 (NastCheck.err_code NastCheck.SuspendOutsideOfCoroutine)
1879 "suspend is only allowed in coroutines."
1881 let suspend_in_finally p =
1883 (NastCheck.err_code NastCheck.SuspendInFinally)
1885 "suspend is not allowed inside finally blocks."
1887 let static_memoized_function p =
1889 (NastCheck.err_code NastCheck.StaticMemoizedFunction)
1891 "memoize is not allowed on static methods in classes that aren't final "
1893 let magic (p, s) =
1895 (NastCheck.err_code NastCheck.Magic)
1897 (s ^ " is a magic method and cannot be called directly")
1899 let non_interface (p : Pos.t) (c2 : string) (verb : string) : 'a =
1901 (NastCheck.err_code NastCheck.NonInterface)
1903 ("Cannot " ^ verb ^ " " ^ strip_ns c2 ^ " - it is not an interface")
1905 let toString_returns_string pos =
1907 (NastCheck.err_code NastCheck.ToStringReturnsString)
1909 "__toString should return a string"
1911 let toString_visibility pos =
1913 (NastCheck.err_code NastCheck.ToStringVisibility)
1915 "__toString must have public visibility and cannot be static"
1917 let uses_non_trait (p : Pos.t) (n : string) (t : string) =
1919 (NastCheck.err_code NastCheck.UsesNonTrait)
1921 (strip_ns n ^ " is not a trait. It is " ^ t ^ ".")
1923 let requires_non_class (p : Pos.t) (n : string) (t : string) =
1925 (NastCheck.err_code NastCheck.RequiresNonClass)
1927 (strip_ns n ^ " is not a class. It is " ^ t ^ ".")
1929 let requires_final_class (p : Pos.t) (n : string) =
1931 (NastCheck.err_code NastCheck.RequiresFinalClass)
1933 (strip_ns n ^ " is not an extendable class.")
1935 let abstract_body pos =
1937 (NastCheck.err_code NastCheck.AbstractBody)
1939 "This method shouldn't have a body"
1941 let interface_with_member_variable pos =
1943 (NastCheck.err_code NastCheck.InterfaceWithMemberVariable)
1945 "Interfaces cannot have member variables"
1947 let interface_with_static_member_variable pos =
1949 (NastCheck.err_code NastCheck.InterfaceWithStaticMemberVariable)
1951 "Interfaces cannot have static variables"
1953 let illegal_function_name pos mname =
1955 (NastCheck.err_code NastCheck.IllegalFunctionName)
1957 ("Illegal function name: " ^ strip_ns mname)
1959 let inout_params_in_coroutine pos =
1961 (NastCheck.err_code NastCheck.InoutParamsInCoroutine)
1963 "Inout parameters cannot be defined on coroutines."
1965 let mutable_attribute_on_function pos =
1967 (NastCheck.err_code NastCheck.MutableAttributeOnFunction)
1969 "<<__Mutable>> only makes sense on methods, or parameters on functions or methods."
1971 let maybe_mutable_attribute_on_function pos =
1973 (NastCheck.err_code NastCheck.MaybeMutableAttributeOnFunction)
1975 "<<__MaybeMutable>> only makes sense on methods, or parameters on functions or methods."
1977 let conflicting_mutable_and_maybe_mutable_attributes pos =
1979 (NastCheck.err_code NastCheck.ConflictingMutableAndMaybeMutableAttributes)
1981 "Declaration cannot have both <<__Mutable>> and <<__MaybeMutable>> attributtes."
1983 let mutable_methods_must_be_reactive pos name =
1985 (NastCheck.err_code NastCheck.MutableMethodsMustBeReactive)
1987 ( "The method "
1988 ^ strip_ns name
1989 ^ " has a mutable parameter"
1990 ^ " (or mutable this), so it must be marked reactive with <<__Rx>>." )
1992 let mutable_return_annotated_decls_must_be_reactive kind pos name =
1994 (NastCheck.err_code NastCheck.MutableReturnAnnotatedDeclsMustBeReactive)
1996 ( "The "
1997 ^ kind
1998 ^ " "
1999 ^ strip_ns name
2000 ^ " is annotated with <<__MutableReturn>>, "
2001 ^ " so it must be marked reactive with <<__Rx>>." )
2003 let maybe_mutable_methods_must_be_reactive pos name =
2005 (NastCheck.err_code NastCheck.MaybeMutableMethodsMustBeReactive)
2007 ( "The method "
2008 ^ strip_ns name
2009 ^ " is annotated with <<__MaybeMutable> attribute, or has this attribute on one of parameters so it must be marked reactive."
2012 let entrypoint_arguments pos =
2014 (NastCheck.err_code NastCheck.EntryPointArguments)
2016 "__EntryPoint functions cannot take arguments."
2018 let variadic_memoize pos =
2020 (NastCheck.err_code NastCheck.VariadicMemoize)
2022 "Memoized functions cannot be variadic."
2024 let abstract_method_memoize pos =
2026 (NastCheck.err_code NastCheck.AbstractMethodMemoize)
2028 "Abstract methods cannot be memoized."
2030 let inout_params_special pos =
2032 (NastCheck.err_code NastCheck.InoutParamsSpecial)
2034 "Methods with special semantics cannot have inout parameters."
2036 let inout_params_memoize fpos pos =
2037 let msg1 = (fpos, "Functions with inout parameters cannot be memoized") in
2038 let msg2 = (pos, "This is an inout parameter") in
2039 add_list (NastCheck.err_code NastCheck.InoutParamsMemoize) [msg1; msg2]
2041 let reading_from_append pos =
2043 (NastCheck.err_code NastCheck.ReadingFromAppend)
2045 "Cannot use [] for reading"
2047 let inout_argument_bad_expr pos =
2049 (NastCheck.err_code NastCheck.InoutArgumentBadExpr)
2051 ( "Arguments for inout parameters must be local variables or simple "
2052 ^ "subscript expressions on vecs, dicts, keysets, or arrays" )
2054 let illegal_destructor pos =
2056 (NastCheck.err_code NastCheck.IllegalDestructor)
2058 ( "Destructors are not supported in Hack; use other patterns like "
2059 ^ "IDisposable/using or try/catch instead." )
2061 let multiple_conditionally_reactive_annotations pos name =
2063 (NastCheck.err_code NastCheck.MultipleConditionallyReactiveAnnotations)
2065 ("Method '" ^ name ^ "' has multiple <<__OnlyRxIfImpl>> annotations.")
2067 let rx_is_enabled_invalid_location pos =
2069 (NastCheck.err_code NastCheck.RxIsEnabledInvalidLocation)
2071 ( "HH\\Rx\\IS_ENABLED must be the only condition in an if-statement, "
2072 ^ "and that if-statement must be the only statement in the function body."
2075 let atmost_rx_as_rxfunc_invalid_location pos =
2077 (NastCheck.err_code NastCheck.MaybeRxInvalidLocation)
2079 "<<__AtMostRxAsFunc>> attribute can only be put on parameters of conditionally reactive function or method annotated with <<__AtMostRxAsArgs>> attribute."
2081 let no_atmost_rx_as_rxfunc_for_rx_if_args pos =
2083 (NastCheck.err_code NastCheck.NoOnlyrxIfRxfuncForRxIfArgs)
2085 "Function or method annotated with <<__AtMostRxAsArgs>> attribute should have at least one parameter with <<__AtMostRxAsFunc>> or <<__OnlyRxIfImpl>> annotations."
2087 let conditionally_reactive_annotation_invalid_arguments ~is_method pos =
2088 let loc =
2089 if is_method then
2090 "Method"
2091 else
2092 "Parameter"
2095 (NastCheck.err_code
2096 NastCheck.ConditionallyReactiveAnnotationInvalidArguments)
2098 ( loc
2099 ^ " is marked with <<__OnlyRxIfImpl>> attribute that have "
2100 ^ "invalid arguments. This attribute must have one argument and it should be "
2101 ^ "'::class' class constant." )
2103 let coroutine_in_constructor pos =
2105 (NastCheck.err_code NastCheck.CoroutineInConstructor)
2107 "A class constructor may not be a coroutine"
2109 let switch_non_terminal_default pos =
2111 (NastCheck.err_code NastCheck.SwitchNonTerminalDefault)
2113 "Default case in switch must be terminal"
2115 let switch_multiple_default pos =
2117 (NastCheck.err_code NastCheck.SwitchMultipleDefault)
2119 "There can be only one default case in switch"
2121 (*****************************************************************************)
2122 (* Nast terminality *)
2123 (*****************************************************************************)
2125 let case_fallthrough pos1 pos2 =
2126 add_list
2127 (NastCheck.err_code NastCheck.CaseFallthrough)
2129 ( pos1,
2130 "This switch has a case that implicitly falls through and is "
2131 ^ "not annotated with // FALLTHROUGH" );
2132 (pos2, "This case implicitly falls through");
2135 let default_fallthrough pos =
2137 (NastCheck.err_code NastCheck.DefaultFallthrough)
2139 ( "This switch has a default case that implicitly falls "
2140 ^ "through and is not annotated with // FALLTHROUGH" )
2142 (*****************************************************************************)
2143 (* Typing errors *)
2144 (*****************************************************************************)
2146 let visibility_extends
2147 vis pos parent_pos parent_vis (on_error : typing_error_callback) =
2148 let msg1 = (pos, "This member visibility is: " ^ vis) in
2149 let msg2 = (parent_pos, parent_vis ^ " was expected") in
2150 on_error ~code:(Typing.err_code Typing.VisibilityExtends) [msg1; msg2]
2152 let member_not_implemented member_name parent_pos pos defn_pos =
2153 let msg1 = (pos, "This type doesn't implement the method " ^ member_name) in
2154 let msg2 = (parent_pos, "Which is required by this interface") in
2155 let msg3 = (defn_pos, "As defined here") in
2156 add_list (Typing.err_code Typing.MemberNotImplemented) [msg1; msg2; msg3]
2158 let bad_decl_override parent_pos parent_name pos name msgl =
2159 let msg1 =
2160 ( pos,
2161 "Class "
2162 ^ strip_ns name
2163 ^ " does not correctly implement all required members " )
2165 let msg2 =
2166 ( parent_pos,
2167 "Some members are incompatible with those declared in type "
2168 ^ strip_ns parent_name )
2170 (* This is a cascading error message *)
2171 add_list (Typing.err_code Typing.BadDeclOverride) (msg1 :: msg2 :: msgl)
2173 let bad_method_override pos member_name msgl (on_error : typing_error_callback)
2175 let msg =
2176 (pos, "The method " ^ strip_ns member_name ^ " has the wrong type")
2178 (* This is a cascading error message *)
2179 on_error ~code:(Typing.err_code Typing.BadMethodOverride) (msg :: msgl)
2181 let bad_prop_override pos member_name msgl (on_error : typing_error_callback) =
2182 let msg =
2183 (pos, "The property " ^ strip_ns member_name ^ " has the wrong type")
2185 (* This is a cascading error message *)
2186 on_error ~code:(Typing.err_code Typing.BadMethodOverride) (msg :: msgl)
2188 let bad_enum_decl pos msgl =
2189 let msg = (pos, "This enum declaration is invalid.") in
2190 (* This is a cascading error message *)
2191 add_list (Typing.err_code Typing.BadEnumExtends) (msg :: msgl)
2193 let missing_constructor pos (on_error : typing_error_callback) =
2194 on_error
2195 ~code:(Typing.err_code Typing.MissingConstructor)
2196 [(pos, "The constructor is not implemented")]
2198 let typedef_trail_entry pos = (pos, "Typedef definition comes from here")
2200 let abstract_tconst_not_allowed pos (p, tconst_name) =
2201 add_list
2202 (Typing.err_code Typing.AbstractTconstNotAllowed)
2204 (pos, "An abstract type constant is not allowed in this position.");
2205 (p, Printf.sprintf "%s is abstract here." tconst_name);
2208 let add_with_trail code errs trail =
2209 add_list code (errs @ List.map trail typedef_trail_entry)
2211 let enum_constant_type_bad pos ty_pos ty trail =
2212 add_with_trail
2213 (Typing.err_code Typing.EnumConstantTypeBad)
2214 [(pos, "Enum constants must be an int or string"); (ty_pos, "Not " ^ ty)]
2215 trail
2217 let enum_type_bad pos ty trail =
2218 add_with_trail
2219 (Typing.err_code Typing.EnumTypeBad)
2220 [(pos, "Enums must be int or string or arraykey, not " ^ ty)]
2221 trail
2223 let enum_type_typedef_nonnull pos =
2225 (Typing.err_code Typing.EnumTypeTypedefNonnull)
2227 "Can't use typedef that resolves to nonnull in enum"
2229 let enum_switch_redundant const first_pos second_pos =
2230 add_list
2231 (Typing.err_code Typing.EnumSwitchRedundant)
2233 (second_pos, "Redundant case statement");
2234 (first_pos, const ^ " already handled here");
2237 let enum_switch_nonexhaustive pos missing enum_pos =
2238 add_list
2239 (Typing.err_code Typing.EnumSwitchNonexhaustive)
2241 ( pos,
2242 "Switch statement nonexhaustive; the following cases are missing: "
2243 ^ String.concat ~sep:", " missing );
2244 (enum_pos, "Enum declared here");
2247 let enum_switch_redundant_default pos enum_pos =
2248 add_list
2249 (Typing.err_code Typing.EnumSwitchRedundantDefault)
2251 ( pos,
2252 "All cases already covered; a redundant default case prevents "
2253 ^ "detecting future errors. If your goal is to guard against "
2254 ^ "invalid values for this type, do an `is` check before the switch." );
2255 (enum_pos, "Enum declared here");
2258 let enum_switch_not_const pos =
2260 (Typing.err_code Typing.EnumSwitchNotConst)
2262 "Case in switch on enum is not an enum constant"
2264 let enum_switch_wrong_class pos expected got =
2266 (Typing.err_code Typing.EnumSwitchWrongClass)
2268 ("Switching on enum " ^ expected ^ " but using constant from " ^ got)
2270 let invalid_shape_field_name p =
2272 (Typing.err_code Typing.InvalidShapeFieldName)
2274 "Was expecting a constant string, class constant, or int (for shape access)"
2276 let invalid_shape_field_name_empty p =
2278 (Typing.err_code Typing.InvalidShapeFieldNameEmpty)
2280 "A shape field name cannot be an empty string"
2282 let invalid_shape_field_type pos ty_pos ty trail =
2283 add_with_trail
2284 (Typing.err_code Typing.InvalidShapeFieldType)
2286 (pos, "A shape field name must be an int or string"); (ty_pos, "Not " ^ ty);
2288 trail
2290 let invalid_shape_field_literal key_pos witness_pos =
2291 add_list
2292 (Typing.err_code Typing.InvalidShapeFieldLiteral)
2294 (key_pos, "Shape uses literal string as field name");
2295 (witness_pos, "But expected a class constant");
2298 let invalid_shape_field_const key_pos witness_pos =
2299 add_list
2300 (Typing.err_code Typing.InvalidShapeFieldConst)
2302 (key_pos, "Shape uses class constant as field name");
2303 (witness_pos, "But expected a literal string");
2306 let shape_field_class_mismatch key_pos witness_pos key_class witness_class =
2307 add_list
2308 (Typing.err_code Typing.ShapeFieldClassMismatch)
2310 (key_pos, "Shape field name is class constant from " ^ key_class);
2311 (witness_pos, "But expected constant from " ^ witness_class);
2314 let shape_field_type_mismatch key_pos witness_pos key_ty witness_ty =
2315 add_list
2316 (Typing.err_code Typing.ShapeFieldTypeMismatch)
2318 (key_pos, "Shape field name is " ^ key_ty ^ " class constant");
2319 (witness_pos, "But expected " ^ witness_ty);
2322 let missing_field pos1 pos2 name (on_error : typing_error_callback) =
2323 on_error
2324 ~code:(Typing.err_code Typing.MissingField)
2326 (pos1, "The field '" ^ name ^ "' is missing");
2327 (pos2, "The field '" ^ name ^ "' is defined");
2330 let shape_fields_unknown pos1 pos2 (on_error : typing_error_callback) =
2331 on_error
2332 ~code:(Typing.err_code Typing.ShapeFieldsUnknown)
2334 ( pos1,
2335 "This shape type allows unknown fields, and so it may contain fields other than those explicitly declared in its declaration."
2337 ( pos2,
2338 "It is incompatible with a shape that does not allow unknown fields." );
2341 let invalid_shape_remove_key p =
2343 (Typing.err_code Typing.InvalidShapeRemoveKey)
2345 "You can only unset fields of local variables"
2347 let unification_cycle pos ty =
2348 add_list
2349 (Typing.err_code Typing.UnificationCycle)
2351 ( pos,
2352 "Type circularity: in order to type-check this expression it "
2353 ^ "is necessary for a type [rec] to be equal to type "
2354 ^ ty );
2357 let violated_constraint
2358 p_cstr (p_tparam, tparam) left right (on_error : typing_error_callback) =
2359 on_error
2360 ~code:(Typing.err_code Typing.TypeConstraintViolation)
2362 (p_cstr, "Some type constraint(s) are violated here");
2363 (p_tparam, Printf.sprintf "%s is a constrained type parameter" tparam);
2365 @ left
2366 @ right )
2368 let method_variance pos =
2370 (Typing.err_code Typing.MethodVariance)
2372 "Covariance or contravariance is not allowed in type parameter of method or function."
2374 let explain_constraint ~use_pos ~definition_pos ~param_name msgl =
2375 let inst_msg = "Some type constraint(s) here are violated" in
2376 (* There may be multiple constraints instantiated at one spot; avoid
2377 * duplicating the instantiation message *)
2378 let msgl =
2379 match msgl with
2380 | (p, x) :: rest when String.equal x inst_msg && Pos.equal p use_pos -> rest
2381 | _ -> msgl
2383 let name = strip_ns param_name in
2384 add_list
2385 (Typing.err_code Typing.TypeConstraintViolation)
2387 (use_pos, inst_msg);
2388 (definition_pos, "'" ^ name ^ "' is a constrained type parameter");
2390 @ msgl )
2392 let explain_where_constraint ~in_class ~use_pos ~definition_pos msgl =
2393 let callsite_ty =
2394 if in_class then
2395 "class"
2396 else
2397 "method"
2399 let definition_head =
2400 Printf.sprintf "This is the %s with 'where' type constraints" callsite_ty
2402 let inst_msg = "A 'where' type constraint is violated here" in
2403 add_list
2404 (Typing.err_code Typing.TypeConstraintViolation)
2405 ([(use_pos, inst_msg); (definition_pos, definition_head)] @ msgl)
2407 let explain_tconst_where_constraint ~use_pos ~definition_pos msgl =
2408 let inst_msg = "A 'where' type constraint is violated here" in
2409 add_list
2410 (Typing.err_code Typing.TypeConstraintViolation)
2412 (use_pos, inst_msg);
2413 ( definition_pos,
2414 "This method's where constraints contain a generic type access" );
2416 @ msgl )
2418 let format_string pos snippet s class_pos fname class_suggest =
2419 add_list
2420 (Typing.err_code Typing.FormatString)
2422 (pos, "Invalid format string " ^ snippet ^ " in \"" ^ s ^ "\"");
2423 ( class_pos,
2424 "You can add a new format specifier by adding "
2425 ^ fname
2426 ^ "() to "
2427 ^ class_suggest );
2430 let expected_literal_format_string pos =
2432 (Typing.err_code Typing.ExpectedLiteralFormatString)
2434 "This argument must be a literal format string"
2436 let re_prefixed_non_string pos non_strings =
2438 (Typing.err_code Typing.RePrefixedNonString)
2440 (non_strings ^ " are not allowed to be to be `re`-prefixed")
2442 let bad_regex_pattern pos s =
2444 (Typing.err_code Typing.BadRegexPattern)
2446 ("Bad regex pattern; " ^ s ^ ".")
2448 let generic_array_strict p =
2450 (Typing.err_code Typing.GenericArrayStrict)
2452 "You cannot have an array without generics in strict mode"
2454 let option_return_only_typehint p kind =
2455 let (typehint, reason) =
2456 match kind with
2457 | `void -> ("?void", "only return implicitly")
2458 | `noreturn -> ("?noreturn", "never return")
2461 (Typing.err_code Typing.OptionReturnOnlyTypehint)
2463 ( typehint
2464 ^ " is a nonsensical typehint; a function cannot both "
2465 ^ reason
2466 ^ " and return null." )
2468 let tuple_syntax p =
2470 (Typing.err_code Typing.TupleSyntax)
2472 "Did you want a tuple? Try (X,Y), not tuple<X,Y>"
2474 let redeclaring_missing_method p trait_method =
2476 (Typing.err_code Typing.RedeclaringMissingMethod)
2478 ( "Attempting to redeclare a trait method "
2479 ^ trait_method
2480 ^ " which was never inherited. "
2481 ^ "You might be trying to redeclare a non-static method as static or vice-versa."
2484 let expecting_type_hint p =
2485 add (Typing.err_code Typing.ExpectingTypeHint) p "Was expecting a type hint"
2487 let expecting_type_hint_variadic p =
2489 (Typing.err_code Typing.ExpectingTypeHintVariadic)
2491 "Was expecting a type hint on this variadic parameter"
2493 let expecting_return_type_hint p =
2495 (Typing.err_code Typing.ExpectingReturnTypeHint)
2497 "Was expecting a return type hint"
2499 let expecting_awaitable_return_type_hint p =
2501 (Typing.err_code Typing.ExpectingAwaitableReturnTypeHint)
2503 "Was expecting an Awaitable return type hint"
2505 let duplicate_using_var pos =
2507 (Typing.err_code Typing.DuplicateUsingVar)
2509 "Local variable already used in 'using' statement"
2511 let illegal_disposable pos verb =
2513 (Typing.err_code Typing.IllegalDisposable)
2515 ("Disposable objects must only be " ^ verb ^ " in a 'using' statement")
2517 let escaping_disposable pos =
2519 (Typing.err_code Typing.EscapingDisposable)
2521 "Variable from 'using' clause may only be used as receiver in method invocation or passed to function with <<__AcceptDisposable>> parameter attribute"
2523 let escaping_disposable_parameter pos =
2525 (Typing.err_code Typing.EscapingDisposableParameter)
2527 "Parameter with <<__AcceptDisposable>> attribute may only be used as receiver in method invocation or passed to another function with <<__AcceptDisposable>> parameter attribute"
2529 let escaping_this pos =
2531 (Typing.err_code Typing.EscapingThis)
2533 "$this implementing IDisposable or IAsyncDisposable may only be used as receiver in method invocation or passed to another function with <<__AcceptDisposable>> parameter attribute"
2535 let escaping_mutable_object pos =
2537 (Typing.err_code Typing.EscapingMutableObject)
2539 "Neither a Mutable nor MaybeMutable object may be captured by an anonymous function."
2541 let must_extend_disposable pos =
2543 (Typing.err_code Typing.MustExtendDisposable)
2545 "A disposable type may not extend a class or use a trait that is not disposable"
2547 let accept_disposable_invariant pos1 pos2 (on_error : typing_error_callback) =
2548 let msg1 = (pos1, "This parameter is marked <<__AcceptDisposable>>") in
2549 let msg2 = (pos2, "This parameter is not marked <<__AcceptDisposable>>") in
2550 on_error ~code:(Typing.err_code Typing.AcceptDisposableInvariant) [msg1; msg2]
2552 let field_kinds pos1 pos2 =
2553 add_list
2554 (Typing.err_code Typing.FieldKinds)
2556 (pos1, "You cannot use this kind of field (value)");
2557 (pos2, "Mixed with this kind of field (key => value)");
2560 let unbound_name_typing pos name =
2562 (Typing.err_code Typing.UnboundNameTyping)
2564 ("Unbound name (typing): " ^ strip_ns name)
2566 let previous_default p =
2568 (Typing.err_code Typing.PreviousDefault)
2570 ( "A previous parameter has a default value.\n"
2571 ^ "Remove all the default values for the preceding parameters,\n"
2572 ^ "or add a default value to this one." )
2574 let return_only_typehint p kind =
2575 let msg =
2576 match kind with
2577 | `void -> "void"
2578 | `noreturn -> "noreturn"
2581 (Naming.err_code Naming.ReturnOnlyTypehint)
2583 ( "The "
2584 ^ msg
2585 ^ " typehint can only be used to describe a function return type" )
2587 let unexpected_type_arguments p =
2589 (Naming.err_code Naming.UnexpectedTypeArguments)
2591 "Type arguments are not expected for this type"
2593 let too_many_type_arguments p =
2595 (Naming.err_code Naming.TooManyTypeArguments)
2597 "Too many type arguments for this type"
2599 let return_in_void pos1 pos2 =
2600 add_list
2601 (Typing.err_code Typing.ReturnInVoid)
2602 [(pos1, "You cannot return a value"); (pos2, "This is a void function")]
2604 let this_var_outside_class p =
2606 (Typing.err_code Typing.ThisVarOutsideClass)
2608 "Can't use $this outside of a class"
2610 let unbound_global cst_pos =
2612 (Typing.err_code Typing.UnboundGlobal)
2613 cst_pos
2614 "Unbound global constant (Typing)"
2616 let private_inst_meth ~def_pos ~use_pos =
2617 add_list
2618 (Typing.err_code Typing.PrivateInstMeth)
2620 ( use_pos,
2621 "You cannot use this method with inst_meth (whether you are in the same class or not)."
2623 (def_pos, "It is declared as private here");
2626 let protected_inst_meth ~def_pos ~use_pos =
2627 add_list
2628 (Typing.err_code Typing.ProtectedInstMeth)
2630 ( use_pos,
2631 "You cannot use this method with inst_meth (whether you are in the same class hierarchy or not)."
2633 (def_pos, "It is declared as protected here");
2636 let private_class_meth ~def_pos ~use_pos =
2637 add_list
2638 (Typing.err_code Typing.PrivateClassMeth)
2640 ( use_pos,
2641 "You cannot use this method with class_meth (whether you are in the same class or not)."
2643 (def_pos, "It is declared as private here");
2646 let protected_class_meth ~def_pos ~use_pos =
2647 add_list
2648 (Typing.err_code Typing.ProtectedClassMeth)
2650 ( use_pos,
2651 "You cannot use this method with class_meth (whether you are in the same class hierarchy or not)."
2653 (def_pos, "It is declared as protected here");
2656 let array_cast pos =
2658 (Typing.err_code Typing.ArrayCast)
2660 "(array) cast forbidden; arrays with unspecified key and value types are not allowed"
2662 let string_cast pos ty =
2663 add (Typing.err_code Typing.StringCast) pos
2664 @@ Printf.sprintf
2665 "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."
2668 let nullable_cast pos ty ty_pos =
2669 add_list
2670 (Typing.err_code Typing.NullableCast)
2672 (pos, "Casting from a nullable type is forbidden");
2673 (ty_pos, "This is " ^ ty);
2676 let static_outside_class pos =
2678 (Typing.err_code Typing.StaticOutsideClass)
2680 "'static' is undefined outside of a class"
2682 let self_outside_class pos =
2684 (Typing.err_code Typing.SelfOutsideClass)
2686 "'self' is undefined outside of a class"
2688 let new_inconsistent_construct new_pos (cpos, cname) kind =
2689 let name = strip_ns cname in
2690 let preamble =
2691 match kind with
2692 | `static -> "Can't use new static() for " ^ name
2693 | `classname -> "Can't use new on classname<" ^ name ^ ">"
2695 add_list
2696 (Typing.err_code Typing.NewStaticInconsistent)
2698 ( new_pos,
2699 preamble
2700 ^ "; __construct arguments are not guaranteed to be consistent in child classes"
2702 ( cpos,
2703 "This declaration is neither final nor uses the <<__ConsistentConstruct>> attribute"
2707 let undefined_parent pos =
2709 (Typing.err_code Typing.UndefinedParent)
2711 "The parent class is undefined"
2713 let parent_outside_class pos =
2715 (Typing.err_code Typing.ParentOutsideClass)
2717 "'parent' is undefined outside of a class"
2719 let parent_abstract_call meth_name call_pos decl_pos =
2720 add_list
2721 (Typing.err_code Typing.AbstractCall)
2723 (call_pos, "Cannot call parent::" ^ meth_name ^ "(); it is abstract");
2724 (decl_pos, "Declaration is here");
2727 let self_abstract_call meth_name call_pos decl_pos =
2728 add_list
2729 (Typing.err_code Typing.AbstractCall)
2731 ( call_pos,
2732 "Cannot call self::"
2733 ^ meth_name
2734 ^ "(); it is abstract. Did you mean static::"
2735 ^ meth_name
2736 ^ "()?" );
2737 (decl_pos, "Declaration is here");
2740 let classname_abstract_call cname meth_name call_pos decl_pos =
2741 let cname = strip_ns cname in
2742 add_list
2743 (Typing.err_code Typing.AbstractCall)
2745 ( call_pos,
2746 "Cannot call " ^ cname ^ "::" ^ meth_name ^ "(); it is abstract" );
2747 (decl_pos, "Declaration is here");
2750 let static_synthetic_method cname meth_name call_pos decl_pos =
2751 let cname = strip_ns cname in
2752 add_list
2753 (Typing.err_code Typing.StaticSyntheticMethod)
2755 ( call_pos,
2756 "Cannot call "
2757 ^ cname
2758 ^ "::"
2759 ^ meth_name
2760 ^ "(); "
2761 ^ meth_name
2762 ^ " is not defined in "
2763 ^ cname );
2764 (decl_pos, "Declaration is here");
2767 let isset_in_strict pos =
2769 (Typing.err_code Typing.IssetEmptyInStrict)
2771 ( "isset tends to hide errors due to variable typos and so is limited to dynamic checks in "
2772 ^ "strict mode" )
2774 let unset_nonidx_in_strict pos msgs =
2775 add_list
2776 (Typing.err_code Typing.UnsetNonidxInStrict)
2778 ( pos,
2779 "In strict mode, unset is banned except on dynamic, "
2780 ^ "darray, keyset, or dict indexing" );
2782 @ msgs )
2784 let unpacking_disallowed_builtin_function pos name =
2785 let name = strip_ns name in
2787 (Typing.err_code Typing.UnpackingDisallowed)
2789 ("Arg unpacking is disallowed for " ^ name)
2791 let invalid_destructure pos1 pos2 ty (on_error : typing_error_callback) =
2792 on_error
2793 ~code:(Typing.err_code Typing.InvalidDestructure)
2795 ( pos1,
2796 "This expression cannot be destructured with a list(...) expression" );
2797 (pos2, "This is " ^ ty);
2800 let unpack_array_required_argument p fp (on_error : typing_error_callback) =
2801 on_error
2802 ~code:(Typing.err_code Typing.SplatArrayRequired)
2804 ( p,
2805 "An array cannot be unpacked into the required arguments of a function"
2807 (fp, "Definition is here");
2810 let unpack_array_variadic_argument p fp (on_error : typing_error_callback) =
2811 on_error
2812 ~code:(Typing.err_code Typing.SplatArrayRequired)
2814 ( p,
2815 "A function that receives an unpacked array as an argument must have a variadic parameter to accept the elements of the array"
2817 (fp, "Definition is here");
2820 let array_get_arity pos1 name pos2 =
2821 add_list
2822 (Typing.err_code Typing.ArrayGetArity)
2824 (pos1, "You cannot use this " ^ strip_ns name);
2825 (pos2, "It is missing its type parameters");
2828 let typing_error pos msg = add (Typing.err_code Typing.GenericUnify) pos msg
2830 let undefined_field ~use_pos ~name ~shape_type_pos =
2831 add_list
2832 (Typing.err_code Typing.UndefinedField)
2834 (use_pos, "The field " ^ name ^ " is undefined");
2835 (shape_type_pos, "Definition is here");
2838 let array_access code pos1 pos2 ty =
2839 add_list
2840 (Typing.err_code code)
2841 ( (pos1, "This is not an object of type KeyedContainer, this is " ^ ty)
2843 ( if not (phys_equal pos2 Pos.none) then
2844 [(pos2, "Definition is here")]
2845 else
2846 [] ) )
2848 let array_access_read = array_access Typing.ArrayAccessRead
2850 let array_access_write = array_access Typing.ArrayAccessWrite
2852 let keyset_set pos1 pos2 =
2853 add_list
2854 (Typing.err_code Typing.KeysetSet)
2855 ( (pos1, "Elements in a keyset cannot be assigned, use append instead.")
2857 ( if not (phys_equal pos2 Pos.none) then
2858 [(pos2, "Definition is here")]
2859 else
2860 [] ) )
2862 let array_append pos1 pos2 ty =
2863 add_list
2864 (Typing.err_code Typing.ArrayAppend)
2865 ( (pos1, ty ^ " does not allow array append")
2867 ( if not (phys_equal pos2 Pos.none) then
2868 [(pos2, "Definition is here")]
2869 else
2870 [] ) )
2872 let const_mutation pos1 pos2 ty =
2873 add_list
2874 (Typing.err_code Typing.ConstMutation)
2875 ( (pos1, "You cannot mutate this")
2877 ( if not (phys_equal pos2 Pos.none) then
2878 [(pos2, "This is " ^ ty)]
2879 else
2880 [] ) )
2882 let expected_class ?(suffix = "") pos =
2884 (Typing.err_code Typing.ExpectedClass)
2886 ("Was expecting a class" ^ suffix)
2888 let unknown_type description pos r =
2889 let msg = "Was expecting " ^ description ^ " but type is unknown" in
2890 add_list (Typing.err_code Typing.UnknownType) ([(pos, msg)] @ r)
2892 let not_found_hint = function
2893 | `no_hint -> ""
2894 | `closest (_pos, v) -> Printf.sprintf " (did you mean static method '%s'?)" v
2895 | `did_you_mean (_pos, v) -> Printf.sprintf " (did you mean '%s'?)" v
2897 let snot_found_hint = function
2898 | `no_hint -> ""
2899 | `closest (_pos, v) ->
2900 Printf.sprintf " (did you mean instance method '%s'?)" v
2901 | `did_you_mean (_pos, v) -> Printf.sprintf " (did you mean '%s'?)" v
2903 let string_of_class_member_kind = function
2904 | `class_constant -> "class constant"
2905 | `static_method -> "static method"
2906 | `class_variable -> "class variable"
2907 | `class_typeconst -> "type constant"
2909 let smember_not_found
2910 kind
2912 (cpos, class_name)
2913 member_name
2914 hint
2915 (on_error : typing_error_callback) =
2916 let kind = string_of_class_member_kind kind in
2917 let class_name = strip_ns class_name in
2918 let msg = Printf.sprintf "No %s '%s' in %s" kind member_name class_name in
2919 on_error
2920 ~code:(Typing.err_code Typing.SmemberNotFound)
2922 (pos, msg ^ snot_found_hint hint);
2923 (cpos, "Declaration of " ^ class_name ^ " is here");
2926 let member_not_found
2927 kind
2929 (cpos, type_name)
2930 member_name
2931 hint
2932 reason
2933 (on_error : typing_error_callback) =
2934 let type_name = strip_ns type_name in
2935 let kind =
2936 match kind with
2937 | `method_ -> "method"
2938 | `property -> "property"
2940 let msg = Printf.sprintf "No %s '%s' in %s" kind member_name type_name in
2941 on_error
2942 ~code:(Typing.err_code Typing.MemberNotFound)
2943 ( (pos, msg ^ not_found_hint hint)
2944 :: (reason @ [(cpos, "Declaration of " ^ type_name ^ " is here")]) )
2946 let parent_in_trait pos =
2948 (Typing.err_code Typing.ParentInTrait)
2950 ( "parent:: inside a trait is undefined"
2951 ^ " without 'require extends' of a class defined in <?hh" )
2953 let parent_undefined pos =
2954 add (Typing.err_code Typing.ParentUndefined) pos "parent is undefined"
2956 let constructor_no_args pos =
2958 (Typing.err_code Typing.ConstructorNoArgs)
2960 "This constructor expects no argument"
2962 let visibility p msg1 p_vis msg2 =
2963 add_list (Typing.err_code Typing.Visibility) [(p, msg1); (p_vis, msg2)]
2965 let typing_too_many_args expected actual pos pos_def on_error =
2966 on_error_or_add
2967 on_error
2968 (Typing.err_code Typing.TypingTooManyArgs)
2970 ( pos,
2971 Printf.sprintf
2972 "Too many arguments (expected %d but got %d)"
2973 expected
2974 actual );
2975 (pos_def, "Definition is here");
2978 let typing_too_few_args required actual pos pos_def on_error =
2979 on_error_or_add
2980 on_error
2981 (Typing.err_code Typing.TypingTooFewArgs)
2983 ( pos,
2984 Printf.sprintf
2985 "Too few arguments (required %d but got %d)"
2986 required
2987 actual );
2988 (pos_def, "Definition is here");
2991 let bad_call pos ty =
2993 (Typing.err_code Typing.BadCall)
2995 ("This call is invalid, this is not a function, it is " ^ ty)
2997 let extend_final extend_pos decl_pos name =
2998 let name = strip_ns name in
2999 add_list
3000 (Typing.err_code Typing.ExtendFinal)
3002 (extend_pos, "You cannot extend final class " ^ name);
3003 (decl_pos, "Declaration is here");
3006 let extend_non_abstract_record name extend_pos decl_pos =
3007 let name = strip_ns name in
3008 let msg =
3009 Printf.sprintf "Cannot extend record `%s` because it isn't abstract" name
3011 add_list
3012 (Typing.err_code Typing.ExtendFinal)
3013 [(extend_pos, msg); (decl_pos, "Declaration is here")]
3015 let extend_sealed child_pos parent_pos parent_name parent_kind verb =
3016 let name = strip_ns parent_name in
3017 add_list
3018 (Typing.err_code Typing.ExtendSealed)
3020 (child_pos, "You cannot " ^ verb ^ " sealed " ^ parent_kind ^ " " ^ name);
3021 (parent_pos, "Declaration is here");
3024 let trait_prop_const_class pos x =
3026 (Typing.err_code Typing.TraitPropConstClass)
3028 ( "Trait declaration of non-const property "
3030 ^ " is incompatible with a const class" )
3032 let extend_ppl
3033 child_pos
3034 child_class_type
3035 child_is_ppl
3036 parent_pos
3037 parent_class_type
3038 parent_name
3039 verb =
3040 let name = strip_ns parent_name in
3041 let warning =
3042 if child_is_ppl then
3043 child_class_type
3044 ^ " annotated with <<__PPL>> cannot "
3045 ^ verb
3046 ^ " non <<__PPL>> "
3047 ^ parent_class_type
3048 ^ ": "
3049 ^ name
3050 else
3051 child_class_type
3052 ^ " must be annotated with <<__PPL>> to "
3053 ^ verb
3054 ^ " <<__PPL>> "
3055 ^ parent_class_type
3056 ^ ": "
3057 ^ name
3059 add_list
3060 (Typing.err_code Typing.ExtendPPL)
3061 [(child_pos, warning); (parent_pos, "Declaration is here")]
3063 let read_before_write (pos, v) =
3065 (Typing.err_code Typing.ReadBeforeWrite)
3067 (Utils.sl ["Read access to $this->"; v; " before initialization"])
3069 let final_property pos =
3071 (Typing.err_code Typing.FinalProperty)
3073 "Properties cannot be declared final"
3075 let implement_abstract ~is_final pos1 pos2 kind x =
3076 let name = "abstract " ^ kind ^ " '" ^ x ^ "'" in
3077 let msg1 =
3078 if is_final then
3079 "This class was declared as final. It must provide an implementation for the "
3080 ^ name
3081 else
3082 "This class must be declared abstract, or provide an implementation for the "
3083 ^ name
3085 add_list
3086 (Typing.err_code Typing.ImplementAbstract)
3087 [(pos1, msg1); (pos2, "Declaration is here")]
3089 let generic_static pos x =
3091 (Typing.err_code Typing.GenericStatic)
3093 ("This static variable cannot use the type parameter " ^ x ^ ".")
3095 let fun_too_many_args pos1 pos2 (on_error : typing_error_callback) =
3096 on_error
3097 ~code:(Typing.err_code Typing.FunTooManyArgs)
3099 (pos1, "Too many mandatory arguments");
3100 (pos2, "Because of this definition");
3103 let fun_too_few_args pos1 pos2 (on_error : typing_error_callback) =
3104 on_error
3105 ~code:(Typing.err_code Typing.FunTooFewArgs)
3106 [(pos1, "Too few arguments"); (pos2, "Because of this definition")]
3108 let fun_unexpected_nonvariadic pos1 pos2 (on_error : typing_error_callback) =
3109 on_error
3110 ~code:(Typing.err_code Typing.FunUnexpectedNonvariadic)
3112 (pos1, "Should have a variadic argument");
3113 (pos2, "Because of this definition");
3116 let fun_variadicity_hh_vs_php56 pos1 pos2 (on_error : typing_error_callback) =
3117 on_error
3118 ~code:(Typing.err_code Typing.FunVariadicityHhVsPhp56)
3120 (pos1, "Variadic arguments: ...-style is not a subtype of ...$args");
3121 (pos2, "Because of this definition");
3124 let ellipsis_strict_mode ~require pos =
3125 let msg =
3126 match require with
3127 | `Type ->
3128 "Cannot use ... without a type hint in strict mode. Please add a type hint."
3129 | `Param_name ->
3130 "Cannot use ... without a parameter name in strict mode. Please add a parameter name."
3131 | `Type_and_param_name ->
3132 "Cannot use ... without a type hint and parameter name in strict mode. Please add a type hint and parameter name."
3134 add (Typing.err_code Typing.EllipsisStrictMode) pos msg
3136 let untyped_lambda_strict_mode pos =
3137 let msg =
3138 "Cannot determine types of lambda parameters in strict mode. Please add type hints on parameters."
3140 add (Typing.err_code Typing.UntypedLambdaStrictMode) pos msg
3142 let echo_in_reactive_context pos =
3144 (Typing.err_code Typing.EchoInReactiveContext)
3146 "'echo' or 'print' are not allowed in reactive functions."
3148 let expected_tparam
3149 ~use_pos ~definition_pos n (on_error : typing_error_callback option) =
3150 let errl =
3152 ( use_pos,
3153 "Expected "
3155 match n with
3156 | 0 -> "no type parameter"
3157 | 1 -> "a type parameter"
3158 | n -> string_of_int n ^ " type parameters" );
3159 (definition_pos, "Definition is here");
3162 on_error_or_add on_error (Typing.err_code Typing.ExpectedTparam) errl
3164 let object_string pos1 pos2 =
3165 add_list
3166 (Typing.err_code Typing.ObjectString)
3168 (pos1, "You cannot use this object as a string");
3169 (pos2, "This object doesn't implement __toString");
3172 let object_string_deprecated pos =
3174 (Typing.err_code Typing.ObjectString)
3176 "You cannot use this object as a string\nImplicit conversions of Stringish objects to string are deprecated."
3178 let cyclic_typedef def_pos use_pos =
3179 add_list
3180 (Typing.err_code Typing.CyclicTypedef)
3181 [(def_pos, "Cyclic type definition"); (use_pos, "Cyclic use is here")]
3183 let type_arity_mismatch pos1 n1 pos2 n2 (on_error : typing_error_callback) =
3184 on_error
3185 ~code:(Typing.err_code Typing.TypeArityMismatch)
3186 [(pos1, "This type has " ^ n1 ^ " arguments"); (pos2, "This one has " ^ n2)]
3188 let this_final id pos2 =
3189 let n = strip_ns (snd id) in
3190 let message1 = "Since " ^ n ^ " is not final" in
3191 let message2 = "this might not be a " ^ n in
3192 [(fst id, message1); (pos2, message2)]
3194 let exact_class_final id pos2 =
3195 let n = strip_ns (snd id) in
3196 let message1 = "This requires the late-bound type to be exactly " ^ n in
3197 let message2 =
3198 "Since " ^ n ^ " is not final this might be an instance of a child class"
3200 [(fst id, message1); (pos2, message2)]
3202 let fun_arity_mismatch pos1 pos2 (on_error : typing_error_callback) =
3203 on_error
3204 ~code:(Typing.err_code Typing.FunArityMismatch)
3206 (pos1, "Number of arguments doesn't match");
3207 (pos2, "Because of this definition");
3210 let fun_reactivity_mismatch
3211 pos1 kind1 pos2 kind2 (on_error : typing_error_callback) =
3212 let f k = "This function is " ^ k ^ "." in
3213 on_error
3214 ~code:(Typing.err_code Typing.FunReactivityMismatch)
3215 [(pos1, f kind1); (pos2, f kind2)]
3217 let inconsistent_mutability pos1 mut1 p2_opt =
3218 match p2_opt with
3219 | Some (pos2, mut2) ->
3220 add_list
3221 (Typing.err_code Typing.InconsistentMutability)
3223 ( pos1,
3224 "Inconsistent mutability of local variable, here local is " ^ mut1 );
3225 (pos2, "But here it is " ^ mut2);
3227 | None ->
3229 (Typing.err_code Typing.InconsistentMutability)
3230 pos1
3231 ("Local is " ^ mut1 ^ " in one scope and immutable in another.")
3233 let inconsistent_mutability_for_conditional p_mut p_other =
3234 add_list
3235 (Typing.err_code Typing.InconsistentMutability)
3237 ( p_mut,
3238 "Inconsistent mutability of conditional expression, this branch returns owned mutable value"
3240 (p_other, "But this one does not.");
3243 let invalid_mutability_flavor pos mut1 mut2 =
3245 (Typing.err_code Typing.InvalidMutabilityFlavorInAssignment)
3247 ( "Cannot assign "
3248 ^ mut2
3249 ^ " value to "
3250 ^ mut1
3251 ^ " local variable. Mutability flavor of local variable cannot be altered."
3254 let reassign_mutable_var ~in_collection pos1 =
3255 let msg =
3256 if in_collection then
3257 "This variable is mutable. You cannot create a new reference to it by putting it into the collection."
3258 else
3259 "This variable is mutable. You cannot create a new reference to it."
3261 add (Typing.err_code Typing.ReassignMutableVar) pos1 msg
3263 let reassign_mutable_this ~in_collection ~is_maybe_mutable pos1 =
3264 let kind =
3265 if is_maybe_mutable then
3266 "maybe mutable"
3267 else
3268 "mutable"
3270 let msg =
3271 if in_collection then
3272 "$this here is "
3273 ^ kind
3274 ^ ". You cannot create a new reference to it by putting it into the collection."
3275 else
3276 "$this here is " ^ kind ^ ". You cannot create a new reference to it."
3278 add (Typing.err_code Typing.ReassignMutableThis) pos1 msg
3280 let mutable_expression_as_multiple_mutable_arguments
3281 pos param_kind prev_pos prev_param_kind =
3282 add_list
3283 (Typing.err_code Typing.MutableExpressionAsMultipleMutableArguments)
3285 ( pos,
3286 "A mutable expression may not be passed as multiple arguments where at least one matching parameter is mutable. Matching parameter here is "
3287 ^ param_kind );
3288 ( prev_pos,
3289 "This is where it was used before, being passed as " ^ prev_param_kind
3293 let reassign_maybe_mutable_var ~in_collection pos1 =
3294 let msg =
3295 if in_collection then
3296 "This variable is maybe mutable. You cannot create a new reference to it by putting it into the collection."
3297 else
3298 "This variable is maybe mutable. You cannot create a new reference to it."
3300 add (Typing.err_code Typing.ReassignMaybeMutableVar) pos1 msg
3302 let mutable_call_on_immutable fpos pos1 rx_mutable_hint_pos =
3303 let l =
3304 match rx_mutable_hint_pos with
3305 | Some p ->
3307 ( p,
3308 "Consider wrapping this expression with Rx\\mutable to forward mutability."
3311 | None -> []
3313 let l =
3314 (pos1, "Cannot call mutable function on immutable expression")
3315 :: ( fpos,
3316 "This function is marked <<__Mutable>>, so it has a mutable $this." )
3317 :: l
3319 add_list (Typing.err_code Typing.MutableCallOnImmutable) l
3321 let immutable_call_on_mutable fpos pos1 =
3322 add_list
3323 (Typing.err_code Typing.ImmutableCallOnMutable)
3325 (pos1, "Cannot call non-mutable function on mutable expression");
3326 (fpos, "This function is not marked as <<__Mutable>>.");
3329 let mutability_mismatch
3330 ~is_receiver pos1 mut1 pos2 mut2 (on_error : typing_error_callback) =
3331 let msg mut =
3332 let msg =
3333 if is_receiver then
3334 "Receiver of this function"
3335 else
3336 "This parameter"
3338 msg ^ " is " ^ mut
3340 on_error
3341 ~code:(Typing.err_code Typing.MutabilityMismatch)
3342 [(pos1, "Incompatible mutabilities:"); (pos1, msg mut1); (pos2, msg mut2)]
3344 let invalid_call_on_maybe_mutable ~fun_is_mutable pos fpos =
3345 let msg =
3346 "Cannot call "
3347 ^ ( if fun_is_mutable then
3348 "mutable"
3349 else
3350 "non-mutable" )
3351 ^ " function on maybe mutable value."
3353 add_list
3354 (Typing.err_code Typing.InvalidCallMaybeMutable)
3355 [(pos, msg); (fpos, "This function is not marked as <<__MaybeMutable>>.")]
3357 let mutable_argument_mismatch param_pos arg_pos =
3358 add_list
3359 (Typing.err_code Typing.MutableArgumentMismatch)
3361 (arg_pos, "Invalid argument");
3362 (param_pos, "This parameter is marked mutable");
3363 (arg_pos, "But this expression is not");
3366 let immutable_argument_mismatch param_pos arg_pos =
3367 add_list
3368 (Typing.err_code Typing.ImmutableArgumentMismatch)
3370 (arg_pos, "Invalid argument");
3371 (param_pos, "This parameter is not marked as mutable");
3372 (arg_pos, "But this expression is mutable");
3375 let mutably_owned_argument_mismatch ~arg_is_owned_local param_pos arg_pos =
3376 let arg_msg =
3377 if arg_is_owned_local then
3378 "Owned mutable locals used as argument should be passed via Rx\\move function"
3379 else
3380 "But this expression is not owned mutable"
3382 add_list
3383 (Typing.err_code Typing.ImmutableArgumentMismatch)
3385 (arg_pos, "Invalid argument");
3386 (param_pos, "This parameter is marked with <<__OwnedMutable>>");
3387 (arg_pos, arg_msg);
3390 let maybe_mutable_argument_mismatch param_pos arg_pos =
3391 add_list
3392 (Typing.err_code Typing.MaybeMutableArgumentMismatch)
3394 (arg_pos, "Invalid argument");
3395 (param_pos, "This parameter is not marked <<__MaybeMutable>>");
3396 (arg_pos, "But this expression is maybe mutable");
3399 let invalid_mutable_return_result error_pos function_pos value_kind =
3400 add_list
3401 (Typing.err_code Typing.InvalidMutableReturnResult)
3403 ( error_pos,
3404 "Functions marked <<__MutableReturn>> must return mutably owned values: mutably owned local variables and results of calling Rx\\mutable."
3406 (function_pos, "This function is marked <<__MutableReturn>>");
3407 (error_pos, "This expression is " ^ value_kind);
3410 let freeze_in_nonreactive_context pos1 =
3412 (Typing.err_code Typing.FreezeInNonreactiveContext)
3413 pos1
3414 "\\HH\\Rx\\freeze can only be used in reactive functions"
3416 let mutable_in_nonreactive_context pos =
3418 (Typing.err_code Typing.MutableInNonreactiveContext)
3420 "\\HH\\Rx\\mutable can only be used in reactive functions"
3422 let move_in_nonreactive_context pos =
3424 (Typing.err_code Typing.MoveInNonreactiveContext)
3426 "\\HH\\Rx\\move can only be used in reactive functions"
3428 let invalid_argument_type_for_condition_in_rx
3429 ~is_receiver f_pos def_pos arg_pos expected_type actual_type =
3430 let arg_msg =
3431 if is_receiver then
3432 "Receiver type"
3433 else
3434 "Argument type"
3436 let arg_msg =
3437 arg_msg
3438 ^ " must be a subtype of "
3439 ^ expected_type
3440 ^ ", now "
3441 ^ actual_type
3442 ^ "."
3444 add_list
3445 (Typing.err_code Typing.InvalidConditionallyReactiveCall)
3447 ( f_pos,
3448 "Cannot invoke conditionally reactive function in reactive context, because at least one reactivity condition is not met."
3450 (arg_pos, arg_msg);
3451 (def_pos, "This is the function declaration");
3454 let callsite_reactivity_mismatch
3455 f_pos def_pos callee_reactivity cause_pos_opt caller_reactivity =
3456 add_list
3457 (Typing.err_code Typing.CallSiteReactivityMismatch)
3459 ( f_pos,
3460 "Reactivity mismatch: "
3461 ^ caller_reactivity
3462 ^ " function cannot call "
3463 ^ callee_reactivity
3464 ^ " function." );
3465 (def_pos, "This is declaration of the function being called.");
3467 @ Option.value_map cause_pos_opt ~default:[] ~f:(fun cause_pos ->
3469 ( cause_pos,
3470 "Reactivity of this argument was used as reactivity of the callee."
3472 ]) )
3474 let invalid_argument_of_rx_mutable_function pos =
3476 (Typing.err_code Typing.InvalidArgumentOfRxMutableFunction)
3478 "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."
3480 let invalid_freeze_use pos1 =
3482 (Typing.err_code Typing.InvalidFreezeUse)
3483 pos1
3484 "freeze takes a single mutably-owned local variable as an argument"
3486 let invalid_move_use pos1 =
3488 (Typing.err_code Typing.InvalidMoveUse)
3489 pos1
3490 "move takes a single mutably-owned local variable as an argument"
3492 let require_args_reify def_pos arg_pos =
3493 add_list
3494 (Typing.err_code Typing.RequireArgsReify)
3496 ( arg_pos,
3497 "All type arguments must be specified because a type parameter is reified"
3499 (def_pos, "Definition is here");
3502 let require_generic_explicit (def_pos, def_name) arg_pos =
3503 add_list
3504 (Typing.err_code Typing.RequireGenericExplicit)
3506 ( arg_pos,
3507 "Generic type parameter " ^ def_name ^ " must be specified explicitly"
3509 (def_pos, "Definition is here");
3512 let invalid_reified_argument (def_pos, def_name) hint_pos arg_pos arg_kind =
3513 add_list
3514 (Typing.err_code Typing.InvalidReifiedArgument)
3516 (hint_pos, "Invalid reified hint");
3517 ( arg_pos,
3518 "This is " ^ arg_kind ^ ", it cannot be used as a reified type argument"
3520 (def_pos, def_name ^ " is reified");
3523 let invalid_reified_argument_reifiable (def_pos, def_name) arg_pos ty_pos ty_msg
3525 add_list
3526 (Typing.err_code Typing.InvalidReifiedArgument)
3528 (arg_pos, "PHP arrays cannot be used as a reified type argument");
3529 (ty_pos, String.capitalize ty_msg);
3530 (def_pos, def_name ^ " is reified");
3533 let new_static_class_reified pos =
3535 (Typing.err_code Typing.NewStaticClassReified)
3537 "Cannot call new static because the current class has reified generics"
3539 let class_get_reified pos =
3541 (Typing.err_code Typing.ClassGetReified)
3543 "Cannot access static properties on reified generics"
3545 let static_meth_with_class_reified_generic meth_pos generic_pos =
3546 add_list
3547 (Typing.err_code Typing.StaticMethWithClassReifiedGeneric)
3549 ( meth_pos,
3550 "Static methods cannot use generics reified at the class level. Try reifying them at the static method itself."
3552 (generic_pos, "Class-level reified generic used here.");
3555 let consistent_construct_reified pos =
3557 (Typing.err_code Typing.ConsistentConstructReified)
3559 "This class or one of its ancestors is annotated with <<__ConsistentConstruct>>. It cannot have reified generics."
3561 let bad_function_pointer_construction pos =
3563 (Typing.err_code Typing.BadFunctionPointerConstruction)
3565 "Function pointers must be explicitly named"
3567 let reified_generics_not_allowed pos =
3569 (Typing.err_code Typing.InvalidReifiedFunctionPointer)
3571 "Creating function pointers with reified generics is not currently allowed"
3573 let new_without_newable pos name =
3575 (Typing.err_code Typing.NewWithoutNewable)
3577 ( name
3578 ^ " cannot be used with `new` because it does not have the <<__Newable>> attribute"
3581 let invalid_freeze_target pos1 var_pos var_mutability_str =
3582 add_list
3583 (Typing.err_code Typing.InvalidFreezeTarget)
3585 (pos1, "Invalid argument - freeze() takes a single mutable variable");
3586 (var_pos, "This variable is " ^ var_mutability_str);
3589 let invalid_move_target pos1 var_pos var_mutability_str =
3590 add_list
3591 (Typing.err_code Typing.InvalidMoveTarget)
3593 (pos1, "Invalid argument - move() takes a single mutably-owned variable");
3594 (var_pos, "This variable is " ^ var_mutability_str);
3597 let discarded_awaitable pos1 pos2 =
3598 add_list
3599 (Typing.err_code Typing.DiscardedAwaitable)
3601 ( pos1,
3602 "This expression is of type Awaitable, but it's "
3603 ^ "either being discarded or used in a dangerous way before "
3604 ^ "being awaited" );
3605 (pos2, "This is why I think it is Awaitable");
3608 let unify_error ?code errl =
3609 add_list (Option.value code ~default:(Typing.err_code Typing.UnifyError)) errl
3611 let unify_error_at pos ?code errl =
3612 unify_error ?code ((pos, "Typing error") :: errl)
3614 let maybe_unify_error specific_code ?code errl =
3615 add_list (Option.value code ~default:(Typing.err_code specific_code)) errl
3617 let index_type_mismatch = maybe_unify_error Typing.IndexTypeMismatch
3619 let expected_stringlike = maybe_unify_error Typing.ExpectedStringlike
3621 let type_constant_mismatch (on_error : typing_error_callback) ?code errl =
3622 let code =
3623 Option.value code ~default:(Typing.err_code Typing.TypeConstantMismatch)
3625 on_error ~code errl
3627 let class_constant_type_mismatch (on_error : typing_error_callback) ?code errl =
3628 let code =
3629 Option.value
3630 code
3631 ~default:(Typing.err_code Typing.ClassConstantTypeMismatch)
3633 on_error ~code errl
3635 let constant_does_not_match_enum_type =
3636 maybe_unify_error Typing.ConstantDoesNotMatchEnumType
3638 let enum_underlying_type_must_be_arraykey =
3639 maybe_unify_error Typing.EnumUnderlyingTypeMustBeArraykey
3641 let enum_constraint_must_be_arraykey =
3642 maybe_unify_error Typing.EnumConstraintMustBeArraykey
3644 let enum_subtype_must_have_compatible_constraint =
3645 maybe_unify_error Typing.EnumSubtypeMustHaveCompatibleConstraint
3647 let parameter_default_value_wrong_type =
3648 maybe_unify_error Typing.ParameterDefaultValueWrongType
3650 let newtype_alias_must_satisfy_constraint =
3651 maybe_unify_error Typing.NewtypeAliasMustSatisfyConstraint
3653 let bad_function_typevar = maybe_unify_error Typing.BadFunctionTypevar
3655 let bad_class_typevar = maybe_unify_error Typing.BadClassTypevar
3657 let bad_method_typevar = maybe_unify_error Typing.BadMethodTypevar
3659 let missing_return = maybe_unify_error Typing.MissingReturnInNonVoidFunction
3661 let inout_return_type_mismatch =
3662 maybe_unify_error Typing.InoutReturnTypeMismatch
3664 let class_constant_value_does_not_match_hint =
3665 maybe_unify_error Typing.ClassConstantValueDoesNotMatchHint
3667 let class_property_initializer_type_does_not_match_hint =
3668 maybe_unify_error Typing.ClassPropertyInitializerTypeDoesNotMatchHint
3670 let xhp_attribute_does_not_match_hint =
3671 maybe_unify_error Typing.XhpAttributeValueDoesNotMatchHint
3673 let pocket_universes_typing = maybe_unify_error Typing.PocketUniversesTyping
3675 let record_init_value_does_not_match_hint =
3676 maybe_unify_error Typing.RecordInitValueDoesNotMatchHint
3678 let elt_type_to_string = function
3679 | `Method -> "method"
3680 | `Property -> "property"
3682 let static_redeclared_as_dynamic
3683 dyn_position static_position member_name ~elt_type =
3684 let dollar =
3685 match elt_type with
3686 | `Property -> "$"
3687 | _ -> ""
3689 let elt_type = elt_type_to_string elt_type in
3690 let msg_dynamic =
3691 "The "
3692 ^ elt_type
3693 ^ " "
3694 ^ dollar
3695 ^ member_name
3696 ^ " is declared here as non-static"
3698 let msg_static =
3699 "But it conflicts with an inherited static declaration here"
3701 add_list
3702 (Typing.err_code Typing.StaticDynamic)
3703 [(dyn_position, msg_dynamic); (static_position, msg_static)]
3705 let dynamic_redeclared_as_static
3706 static_position dyn_position member_name ~elt_type =
3707 let dollar =
3708 match elt_type with
3709 | `Property -> "$"
3710 | _ -> ""
3712 let elt_type = elt_type_to_string elt_type in
3713 let msg_static =
3714 "The "
3715 ^ elt_type
3716 ^ " "
3717 ^ dollar
3718 ^ member_name
3719 ^ " is declared here as static"
3721 let msg_dynamic =
3722 "But it conflicts with an inherited non-static declaration here"
3724 add_list
3725 (Typing.err_code Typing.StaticDynamic)
3726 [(static_position, msg_static); (dyn_position, msg_dynamic)]
3728 let null_member code ~is_method s pos r =
3729 let msg =
3730 Printf.sprintf
3731 "You are trying to access the %s '%s' but this object can be null."
3732 ( if is_method then
3733 "method"
3734 else
3735 "property" )
3738 add_list (Typing.err_code code) ([(pos, msg)] @ r)
3740 let null_member_read = null_member Typing.NullMemberRead
3742 let null_member_write = null_member Typing.NullMemberWrite
3744 (* Trying to access a member on a mixed or nonnull value. *)
3745 let top_member null_code nonnull_code ~is_method ~is_nullable s pos1 ty pos2 =
3746 let msg =
3747 Printf.sprintf
3748 "You are trying to access the %s '%s' but this is %s. Use a specific class or interface name."
3749 ( if is_method then
3750 "method"
3751 else
3752 "property" )
3756 add_list
3757 (Typing.err_code
3758 ( if is_nullable then
3759 null_code
3760 else
3761 nonnull_code ))
3762 [(pos1, msg); (pos2, "Definition is here")]
3764 let top_member_read =
3765 top_member Typing.NullMemberRead Typing.NonObjectMemberRead
3767 let top_member_write =
3768 top_member Typing.NullMemberWrite Typing.NonObjectMemberWrite
3770 let non_object_member
3771 code ~is_method s pos1 ty pos2 (on_error : typing_error_callback) =
3772 let msg_start =
3773 Printf.sprintf
3774 "You are trying to access the %s '%s' but this is %s"
3775 ( if is_method then
3776 "method"
3777 else
3778 "property" )
3782 let msg =
3783 if String.equal ty "a shape" then
3784 msg_start ^ ". Did you mean $foo['" ^ s ^ "'] instead?"
3785 else
3786 msg_start
3788 on_error
3789 ~code:(Typing.err_code code)
3790 [(pos1, msg); (pos2, "Definition is here")]
3792 let non_object_member_read = non_object_member Typing.NonObjectMemberRead
3794 let non_object_member_write = non_object_member Typing.NonObjectMemberRead
3796 let unknown_object_member ~is_method s pos r =
3797 let msg =
3798 Printf.sprintf
3799 "You are trying to access the %s '%s' on a value whose class is unknown."
3800 ( if is_method then
3801 "method"
3802 else
3803 "property" )
3806 add_list (Typing.err_code Typing.UnknownObjectMember) ([(pos, msg)] @ r)
3808 let non_class_member ~is_method s pos1 ty pos2 =
3809 let msg =
3810 Printf.sprintf
3811 "You are trying to access the static %s '%s' but this is %s"
3812 ( if is_method then
3813 "method"
3814 else
3815 "property" )
3819 add_list
3820 (Typing.err_code Typing.NonClassMember)
3821 [(pos1, msg); (pos2, "Definition is here")]
3823 let ambiguous_member ~is_method s pos1 ty pos2 =
3824 let msg =
3825 Printf.sprintf
3826 "You are trying to access the %s '%s' but there is more than one implementation on %s"
3827 ( if is_method then
3828 "method"
3829 else
3830 "property" )
3834 add_list
3835 (Typing.err_code Typing.AmbiguousMember)
3836 [(pos1, msg); (pos2, "Definition is here")]
3838 let null_container p null_witness =
3839 add_list
3840 (Typing.err_code Typing.NullContainer)
3842 ( p,
3843 "You are trying to access an element of this container"
3844 ^ " but the container could be null. " );
3846 @ null_witness )
3848 let option_mixed pos =
3850 (Typing.err_code Typing.OptionMixed)
3852 "?mixed is a redundant typehint - just use mixed"
3854 let option_null pos =
3856 (Typing.err_code Typing.OptionNull)
3858 "?null is a redundant typehint - just use null"
3860 let declared_covariant pos1 pos2 emsg =
3861 add_list
3862 (Typing.err_code Typing.DeclaredCovariant)
3864 (pos2, "Illegal usage of a covariant type parameter");
3865 (pos1, "This is where the parameter was declared as covariant (+)");
3867 @ emsg )
3869 let declared_contravariant pos1 pos2 emsg =
3870 add_list
3871 (Typing.err_code Typing.DeclaredContravariant)
3873 (pos2, "Illegal usage of a contravariant type parameter");
3874 (pos1, "This is where the parameter was declared as contravariant (-)");
3876 @ emsg )
3878 let static_property_type_generic_param ~class_pos ~var_type_pos ~generic_pos =
3879 add_list
3880 (Typing.err_code Typing.ClassVarTypeGenericParam)
3882 ( generic_pos,
3883 "A generic parameter cannot be used in the type of a static property" );
3884 ( var_type_pos,
3885 "This is where the type of the static property was declared" );
3886 (class_pos, "This is the class containing the static property");
3889 let contravariant_this pos class_name tp =
3891 (Typing.err_code Typing.ContravariantThis)
3893 ( "The \"this\" type cannot be used in this "
3894 ^ "contravariant position because its enclosing class \""
3895 ^ class_name
3896 ^ "\" "
3897 ^ "is final and has a variant type parameter \""
3898 ^ tp
3899 ^ "\"" )
3901 let cyclic_typeconst pos sl =
3902 let sl = List.map sl strip_ns in
3904 (Typing.err_code Typing.CyclicTypeconst)
3906 ("Cyclic type constant:\n " ^ String.concat ~sep:" -> " sl)
3908 let abstract_concrete_override pos parent_pos kind =
3909 let kind_str =
3910 match kind with
3911 | `method_ -> "method"
3912 | `typeconst -> "type constant"
3913 | `constant -> "constant"
3914 | `property -> "property"
3916 add_list
3917 (Typing.err_code Typing.AbstractConcreteOverride)
3919 (pos, "Cannot re-declare this " ^ kind_str ^ " as abstract");
3920 (parent_pos, "Previously defined here");
3923 let required_field_is_optional pos1 pos2 name (on_error : typing_error_callback)
3925 on_error
3926 ~code:(Typing.err_code Typing.RequiredFieldIsOptional)
3928 (pos1, "The field '" ^ name ^ "' is optional");
3929 (pos2, "The field '" ^ name ^ "' is defined as required");
3932 let array_get_with_optional_field pos1 pos2 name =
3933 add_list
3934 (Typing.err_code Typing.ArrayGetWithOptionalField)
3936 ( pos1,
3937 Printf.sprintf
3938 "The field `%s` may not be present in this shape. Use `Shapes::idx()` instead."
3939 name );
3940 (pos2, "This is where the field was declared as optional.");
3943 let non_call_argument_in_suspend pos msgs =
3944 add_list
3945 (Typing.err_code Typing.NonCallArgumentInSuspend)
3946 ( [(pos, "'suspend' operator expects call to a coroutine as an argument.")]
3947 @ msgs )
3949 let non_coroutine_call_in_suspend pos msgs =
3950 add_list
3951 (Typing.err_code Typing.NonCoroutineCallInSuspend)
3953 ( pos,
3954 "Only coroutine functions are allowed to be called in 'suspend' operator."
3957 @ msgs )
3959 let coroutine_call_outside_of_suspend pos =
3960 add_list
3961 (Typing.err_code Typing.CoroutineCallOutsideOfSuspend)
3963 ( pos,
3964 "Coroutine calls are only allowed when they are arguments to 'suspend' operator"
3968 let function_is_not_coroutine pos name =
3969 add_list
3970 (Typing.err_code Typing.FunctionIsNotCoroutine)
3972 ( pos,
3973 "Function '"
3974 ^ name
3975 ^ "' is not a coroutine and cannot be used in as an argument of 'suspend' operator."
3979 let coroutinness_mismatch
3980 pos1_is_coroutine pos1 pos2 (on_error : typing_error_callback) =
3981 let m1 = "This is a coroutine." in
3982 let m2 = "This is not a coroutine." in
3983 on_error
3984 ~code:(Typing.err_code Typing.CoroutinnessMismatch)
3986 ( pos1,
3987 if pos1_is_coroutine then
3989 else
3990 m2 );
3991 ( pos2,
3992 if pos1_is_coroutine then
3994 else
3995 m1 );
3998 let invalid_ppl_call pos context =
3999 let error_msg =
4000 "Cannot call a method on an object of a <<__PPL>> class " ^ context
4002 add (Typing.err_code Typing.InvalidPPLCall) pos error_msg
4004 let invalid_ppl_static_call pos reason =
4005 let error_msg =
4006 "Cannot call a static method on a <<__PPL>> class " ^ reason
4008 add (Typing.err_code Typing.InvalidPPLStaticCall) pos error_msg
4010 let ppl_meth_pointer pos func =
4011 let error_msg = func ^ " cannot be used with a <<__PPL>> class" in
4012 add (Typing.err_code Typing.PPLMethPointer) pos error_msg
4014 let coroutine_outside_experimental pos =
4016 (Typing.err_code Typing.CoroutineOutsideExperimental)
4018 Coroutine_errors.error_message
4020 let return_disposable_mismatch
4021 pos1_return_disposable pos1 pos2 (on_error : typing_error_callback) =
4022 let m1 = "This is marked <<__ReturnDisposable>>." in
4023 let m2 = "This is not marked <<__ReturnDisposable>>." in
4024 on_error
4025 ~code:(Typing.err_code Typing.ReturnDisposableMismatch)
4027 ( pos1,
4028 if pos1_return_disposable then
4030 else
4031 m2 );
4032 ( pos2,
4033 if pos1_return_disposable then
4035 else
4036 m1 );
4039 let return_void_to_rx_mismatch
4040 ~pos1_has_attribute pos1 pos2 (on_error : typing_error_callback) =
4041 let m1 = "This is marked <<__ReturnsVoidToRx>>." in
4042 let m2 = "This is not marked <<__ReturnsVoidToRx>>." in
4043 on_error
4044 ~code:(Typing.err_code Typing.ReturnVoidToRxMismatch)
4046 ( pos1,
4047 if pos1_has_attribute then
4049 else
4050 m2 );
4051 ( pos2,
4052 if pos1_has_attribute then
4054 else
4055 m1 );
4058 let this_as_lexical_variable pos =
4060 (Naming.err_code Naming.ThisAsLexicalVariable)
4062 "Cannot use $this as lexical variable"
4064 let dollardollar_lvalue pos =
4066 (Typing.err_code Typing.DollardollarLvalue)
4068 "Cannot assign a value to the special pipe variable ($$)"
4070 let mutating_const_property pos =
4072 (Typing.err_code Typing.AssigningToConst)
4074 "Cannot mutate a __Const property"
4076 let self_const_parent_not pos =
4078 (Typing.err_code Typing.SelfConstParentNot)
4080 "A __Const class may only extend other __Const classes"
4082 let overriding_prop_const_mismatch
4083 parent_pos
4084 parent_const
4085 child_pos
4086 child_const
4087 (on_error : typing_error_callback) =
4088 let m1 = "This property is __Const" in
4089 let m2 = "This property is not __Const" in
4090 on_error
4091 ~code:(Typing.err_code Typing.OverridingPropConstMismatch)
4093 ( child_pos,
4094 if child_const then
4096 else
4097 m2 );
4098 ( parent_pos,
4099 if parent_const then
4101 else
4102 m2 );
4105 let mutable_return_result_mismatch
4106 pos1_has_mutable_return pos1 pos2 (on_error : typing_error_callback) =
4107 let m1 = "This is marked <<__MutableReturn>>." in
4108 let m2 = "This is not marked <<__MutableReturn>>." in
4109 on_error
4110 ~code:(Typing.err_code Typing.MutableReturnResultMismatch)
4112 ( pos1,
4113 if pos1_has_mutable_return then
4115 else
4116 m2 );
4117 ( pos2,
4118 if pos1_has_mutable_return then
4120 else
4121 m1 );
4124 let pu_expansion pos ty name =
4125 let ty = strip_ns ty in
4127 (Typing.err_code Typing.PocketUniversesExpansion)
4129 (sprintf "Cannot project type %s from %s." name ty)
4131 let pu_typing pos kind msg =
4133 (Typing.err_code Typing.PocketUniversesTyping)
4135 (sprintf "Unexpected Pocket Universes %s %s during typing." kind msg)
4137 let pu_typing_not_supported pos =
4139 (Typing.err_code Typing.PocketUniversesTyping)
4141 "Unsupported Pocket Universes member."
4143 let pu_typing_invalid_upper_bounds pos =
4144 let msg =
4145 "There isn't enough information to infer what pocket universe this atom is from"
4147 add (Typing.err_code Typing.PocketUniversesInvalidUpperBounds) pos msg
4149 let pu_typing_refinement pos =
4151 (Typing.err_code Typing.PocketUniversesRefinement)
4153 "Pocket Universes are not allowed on the right-hand side of is/as"
4155 let php_lambda_disallowed pos =
4157 (NastCheck.err_code NastCheck.PhpLambdaDisallowed)
4159 "PHP style anonymous functions are not allowed."
4161 (*****************************************************************************)
4162 (* Typing decl errors *)
4163 (*****************************************************************************)
4165 let wrong_extend_kind
4166 ~parent_pos ~parent_kind ~parent_name ~child_pos ~child_kind ~child_name =
4167 let parent_kind_str = Ast_defs.string_of_class_kind parent_kind in
4168 let parent_name = strip_ns parent_name in
4169 let child_name = strip_ns child_name in
4170 let use_msg =
4171 Printf.sprintf
4172 " Did you mean to add `use %s;` within the body of %s?"
4173 parent_name
4174 child_name
4176 let child_msg =
4177 match child_kind with
4178 | Ast_defs.Cabstract
4179 | Ast_defs.Cnormal ->
4180 let extends_msg = "Classes can only extend other classes." in
4181 let suggestion =
4182 if Ast_defs.is_c_interface parent_kind then
4183 " Did you mean `implements " ^ parent_name ^ "`?"
4184 else if Ast_defs.is_c_trait parent_kind then
4185 use_msg
4186 else
4189 extends_msg ^ suggestion
4190 | Ast_defs.Cinterface ->
4191 let extends_msg = "Interfaces can only extend other interfaces." in
4192 let suggestion =
4193 if Ast_defs.is_c_trait parent_kind then
4194 use_msg
4195 else
4198 extends_msg ^ suggestion
4199 | Ast_defs.Cenum ->
4200 (* This case should never happen, as the type checker will have already caught
4201 it with EnumTypeBad. But just in case, report this error here too. *)
4202 "Enums can only extend int, string, or arraykey."
4203 | Ast_defs.Ctrait ->
4204 (* This case should never happen, as the parser will have caught it before
4205 we get here. *)
4206 "A trait cannot use `extends`. This is a parser error."
4208 let msg1 = (child_pos, child_msg) in
4209 let msg2 = (parent_pos, "This is " ^ parent_kind_str ^ ".") in
4210 add_list (Typing.err_code Typing.WrongExtendKind) [msg1; msg2]
4212 let unsatisfied_req parent_pos req_name req_pos =
4213 let s1 = "Failure to satisfy requirement: " ^ strip_ns req_name in
4214 let s2 = "Required here" in
4215 if Pos.equal req_pos parent_pos then
4216 add (Typing.err_code Typing.UnsatisfiedReq) parent_pos s1
4217 else
4218 add_list
4219 (Typing.err_code Typing.UnsatisfiedReq)
4220 [(parent_pos, s1); (req_pos, s2)]
4222 let cyclic_class_def stack pos =
4223 let stack = SSet.fold ~f:(fun x y -> strip_ns x ^ " " ^ y) stack ~init:"" in
4225 (Typing.err_code Typing.CyclicClassDef)
4227 ("Cyclic class definition : " ^ stack)
4229 let cyclic_record_def names pos =
4230 let names = List.map ~f:strip_ns names in
4232 (Typing.err_code Typing.CyclicRecordDef)
4234 (Printf.sprintf
4235 "Record inheritance cycle: %s"
4236 (String.concat ~sep:" " names))
4238 let trait_reuse p_pos p_name class_name trait =
4239 let (c_pos, c_name) = class_name in
4240 let c_name = strip_ns c_name in
4241 let trait = strip_ns trait in
4242 let err =
4243 "Class " ^ c_name ^ " reuses trait " ^ trait ^ " in its hierarchy"
4245 let err' = "It is already used through " ^ strip_ns p_name in
4246 add_list (Typing.err_code Typing.TraitReuse) [(c_pos, err); (p_pos, err')]
4248 let trait_reuse_inside_class class_name trait occurrences =
4249 let (c_pos, c_name) = class_name in
4250 let c_name = strip_ns c_name in
4251 let trait = strip_ns trait in
4252 let err = "Class " ^ c_name ^ " uses trait " ^ trait ^ " multiple times" in
4253 add_list
4254 (Typing.err_code Typing.TraitReuseInsideClass)
4255 ([(c_pos, err)] @ List.map ~f:(fun p -> (p, "used here")) occurrences)
4257 let invalid_is_as_expression_hint op hint_pos ty_pos ty_str =
4258 add_list
4259 (Typing.err_code Typing.InvalidIsAsExpressionHint)
4261 (hint_pos, "Invalid \"" ^ op ^ "\" expression hint");
4262 (ty_pos, "The \"" ^ op ^ "\" operator cannot be used with " ^ ty_str);
4265 let invalid_enforceable_type kind_str (tp_pos, tp_name) targ_pos ty_pos ty_str =
4266 add_list
4267 (Typing.err_code Typing.InvalidEnforceableTypeArgument)
4269 (targ_pos, "Invalid type");
4270 ( tp_pos,
4271 "Type " ^ kind_str ^ " " ^ tp_name ^ " was declared __Enforceable here"
4273 (ty_pos, "This type is not enforceable because it has " ^ ty_str);
4276 let reifiable_attr attr_pos decl_kind decl_pos ty_pos ty_msg =
4277 add_list
4278 (Typing.err_code Typing.DisallowPHPArraysAttr)
4280 (decl_pos, "Invalid " ^ decl_kind);
4281 (attr_pos, "This type constant has the __Reifiable attribute");
4282 (ty_pos, "It cannot contain " ^ ty_msg);
4285 let invalid_newable_type_argument (tp_pos, tp_name) ta_pos =
4286 add_list
4287 (Typing.err_code Typing.InvalidNewableTypeArgument)
4289 ( ta_pos,
4290 "A newable type argument must be a concrete class or a newable type parameter."
4292 (tp_pos, "Type parameter " ^ tp_name ^ " was declared __Newable here");
4295 let invalid_newable_type_param_constraints
4296 (tparam_pos, tparam_name) constraint_list =
4297 let partial =
4298 if List.is_empty constraint_list then
4299 "No constraints"
4300 else
4301 "The constraints "
4302 ^ String.concat ~sep:", " (List.map ~f:strip_ns constraint_list)
4304 let msg =
4305 "The type parameter "
4306 ^ tparam_name
4307 ^ " 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. "
4308 ^ partial
4309 ^ " are valid newable classes"
4311 add (Typing.err_code Typing.InvalidNewableTypeParamConstraints) tparam_pos msg
4313 let override_final ~parent ~child ~(on_error : typing_error_callback option) =
4314 let msg1 = (child, "You cannot override this method") in
4315 let msg2 = (parent, "It was declared as final") in
4316 on_error_or_add on_error (Typing.err_code Typing.OverrideFinal) [msg1; msg2]
4318 let override_memoizelsb ~parent ~child (on_error : typing_error_callback) =
4319 on_error
4320 ~code:(Typing.err_code Typing.OverrideMemoizeLSB)
4322 ( child,
4323 "__MemoizeLSB method may not be an override (temporary due to HHVM bug)"
4325 (parent, "This method is being overridden");
4328 let override_lsb ~member_name ~parent ~child (on_error : typing_error_callback)
4330 on_error
4331 ~code:(Typing.err_code Typing.OverrideLSB)
4333 ( child,
4334 "Member " ^ member_name ^ " may not override __LSB member of parent" );
4335 (parent, "This is being overridden");
4338 let should_be_override pos class_id id =
4340 (Typing.err_code Typing.ShouldBeOverride)
4342 (Printf.sprintf
4343 "%s has no parent class with a method `%s` to override"
4344 (strip_ns class_id)
4347 let override_per_trait class_name id m_pos =
4348 let (c_pos, c_name) = class_name in
4349 let err_msg =
4350 "Method "
4351 ^ strip_ns c_name
4352 ^ "::"
4353 ^ id
4354 ^ " should be an override per the declaring trait; no non-private parent definition found or overridden parent is defined in non-<?hh code"
4356 add_list
4357 (Typing.err_code Typing.OverridePerTrait)
4358 [(c_pos, err_msg); (m_pos, "Declaration of " ^ id ^ "() is here")]
4360 let missing_assign pos =
4361 add (Typing.err_code Typing.MissingAssign) pos "Please assign a value"
4363 let private_override pos class_id id =
4365 (Typing.err_code Typing.PrivateOverride)
4367 ( strip_ns class_id
4368 ^ "::"
4369 ^ id
4370 ^ ": combining private and override is nonsensical" )
4372 let invalid_memoized_param pos ty_reason_msg =
4373 add_list
4374 (Typing.err_code Typing.InvalidMemoizedParam)
4375 ( ( pos,
4376 "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"
4378 :: ty_reason_msg )
4380 let invalid_disposable_hint pos class_name =
4382 (Typing.err_code Typing.InvalidDisposableHint)
4384 ( "Parameter with type '"
4385 ^ class_name
4386 ^ "' must not implement IDisposable or IAsyncDisposable. Please use <<__AcceptDisposable>> attribute or create disposable object with 'using' statement instead."
4389 let invalid_disposable_return_hint pos class_name =
4391 (Typing.err_code Typing.InvalidDisposableReturnHint)
4393 ( "Return type '"
4394 ^ class_name
4395 ^ "' must not implement IDisposable or IAsyncDisposable. Please add <<__ReturnDisposable>> attribute."
4398 let xhp_required pos why_xhp ty_reason_msg =
4399 let msg = "An XHP instance was expected" in
4400 add_list
4401 (Typing.err_code Typing.XhpRequired)
4402 ((pos, msg) :: (pos, why_xhp) :: ty_reason_msg)
4404 let illegal_xhp_child pos ty_reason_msg =
4405 let msg = "XHP children must be compatible with XHPChild" in
4406 add_list (Typing.err_code Typing.IllegalXhpChild) ((pos, msg) :: ty_reason_msg)
4408 let missing_xhp_required_attr pos attr ty_reason_msg =
4409 let msg = "Required attribute " ^ attr ^ " is missing." in
4410 add_list
4411 (Typing.err_code Typing.MissingXhpRequiredAttr)
4412 ((pos, msg) :: ty_reason_msg)
4414 let nullsafe_not_needed p nonnull_witness =
4415 add_list
4416 (Typing.err_code Typing.NullsafeNotNeeded)
4417 ( [(p, "You are using the ?-> operator but this object cannot be null. ")]
4418 @ nonnull_witness )
4420 let generic_at_runtime p prefix =
4422 (Typing.err_code Typing.ErasedGenericAtRuntime)
4424 ( prefix
4425 ^ " generics can only be used in type hints because they do not exist at runtime."
4428 let generics_not_allowed p =
4430 (Typing.err_code Typing.GenericsNotAllowed)
4432 "Generics are not allowed in this position."
4434 let trivial_strict_eq p b left right left_trail right_trail =
4435 let msg = "This expression is always " ^ b in
4436 let left_trail = List.map left_trail typedef_trail_entry in
4437 let right_trail = List.map right_trail typedef_trail_entry in
4438 add_list
4439 (Typing.err_code Typing.TrivialStrictEq)
4440 (((p, msg) :: left) @ left_trail @ right @ right_trail)
4442 let trivial_strict_not_nullable_compare_null p result type_reason =
4443 let msg = "This expression is always " ^ result in
4444 add_list
4445 (Typing.err_code Typing.NotNullableCompareNullTrivial)
4446 ((p, msg) :: type_reason)
4448 let eq_incompatible_types p left right =
4449 let msg = "This equality test has incompatible types" in
4450 add_list
4451 (Typing.err_code Typing.EqIncompatibleTypes)
4452 (((p, msg) :: left) @ right)
4454 let comparison_invalid_types p left right =
4455 let msg =
4456 "This comparison has invalid types. Only comparisons in which both arguments are strings, nums, DateTime, or DateTimeImmutable are allowed"
4458 add_list
4459 (Typing.err_code Typing.ComparisonInvalidTypes)
4460 (((p, msg) :: left) @ right)
4462 let void_usage p void_witness =
4463 let msg = "You are using the return value of a void function" in
4464 add_list (Typing.err_code Typing.VoidUsage) ((p, msg) :: void_witness)
4466 let noreturn_usage p noreturn_witness =
4467 let msg = "You are using the return value of a noreturn function" in
4468 add_list (Typing.err_code Typing.NoreturnUsage) ((p, msg) :: noreturn_witness)
4470 let attribute_too_few_arguments pos x n =
4471 let n = string_of_int n in
4473 (Typing.err_code Typing.AttributeTooFewArguments)
4475 ("The attribute " ^ x ^ " expects at least " ^ n ^ " arguments")
4477 let attribute_too_many_arguments pos x n =
4478 let n = string_of_int n in
4480 (Typing.err_code Typing.AttributeTooManyArguments)
4482 ("The attribute " ^ x ^ " expects at most " ^ n ^ " arguments")
4484 let attribute_param_type pos x =
4486 (Typing.err_code Typing.AttributeParamType)
4488 ("This attribute parameter should be " ^ x)
4490 let deprecated_use pos pos_def msg =
4491 add_list
4492 (Typing.err_code Typing.DeprecatedUse)
4493 [(pos, msg); (pos_def, "Definition is here")]
4495 let cannot_declare_constant kind pos (class_pos, class_name) =
4496 let kind_str =
4497 match kind with
4498 | `enum -> "an enum"
4499 | `trait -> "a trait"
4500 | `record -> "a record"
4502 add_list
4503 (Typing.err_code Typing.CannotDeclareConstant)
4505 (pos, "Cannot declare a constant in " ^ kind_str);
4506 (class_pos, strip_ns class_name ^ " was defined as " ^ kind_str ^ " here");
4509 let ambiguous_inheritance
4510 pos class_ origin (error : error) (on_error : typing_error_callback) =
4511 let origin = strip_ns origin in
4512 let class_ = strip_ns class_ in
4513 let message =
4514 "This declaration was inherited from an object of type "
4515 ^ origin
4516 ^ ". Redeclare this member in "
4517 ^ class_
4518 ^ " with a compatible signature."
4520 let (code, msgl) = (get_code error, to_list error) in
4521 on_error ~code (msgl @ [(pos, message)])
4523 let multiple_concrete_defs
4524 child_pos
4525 parent_pos
4526 child_origin
4527 parent_origin
4528 name
4529 class_
4530 (on_error : typing_error_callback) =
4531 let child_origin = strip_ns child_origin in
4532 let parent_origin = strip_ns parent_origin in
4533 let class_ = strip_ns class_ in
4534 on_error
4535 ~code:(Typing.err_code Typing.MultipleConcreteDefs)
4537 ( child_pos,
4538 child_origin
4539 ^ " and "
4540 ^ parent_origin
4541 ^ " both declare ambiguous implementations of "
4542 ^ name
4543 ^ "." );
4544 (child_pos, child_origin ^ "'s definition is here.");
4545 (parent_pos, parent_origin ^ "'s definition is here.");
4546 ( child_pos,
4547 "Redeclare " ^ name ^ " in " ^ class_ ^ " with a compatible signature."
4551 let local_variable_modified_and_used pos_modified pos_used_l =
4552 let used_msg p = (p, "And accessed here") in
4553 add_list
4554 (Typing.err_code Typing.LocalVariableModifedAndUsed)
4555 ( ( pos_modified,
4556 "Unsequenced modification and access to local variable. Modified here"
4558 :: List.map pos_used_l used_msg )
4560 let local_variable_modified_twice pos_modified pos_modified_l =
4561 let modified_msg p = (p, "And also modified here") in
4562 add_list
4563 (Typing.err_code Typing.LocalVariableModifedTwice)
4564 ( ( pos_modified,
4565 "Unsequenced modifications to local variable. Modified here" )
4566 :: List.map pos_modified_l modified_msg )
4568 let assign_during_case p =
4570 (Typing.err_code Typing.AssignDuringCase)
4572 "Don't assign to variables inside of case labels"
4574 let cyclic_enum_constraint pos =
4575 add (Typing.err_code Typing.CyclicEnumConstraint) pos "Cyclic enum constraint"
4577 let invalid_classname p =
4578 add (Typing.err_code Typing.InvalidClassname) p "Not a valid class name"
4580 let illegal_type_structure pos errmsg =
4581 let msg =
4582 "The two arguments to type_structure() must be:"
4583 ^ "\n - first: ValidClassname::class or an object of that class"
4584 ^ "\n - second: a single-quoted string literal containing the name"
4585 ^ " of a type constant of that class"
4586 ^ "\n"
4587 ^ errmsg
4589 add (Typing.err_code Typing.IllegalTypeStructure) pos msg
4591 let illegal_typeconst_direct_access pos =
4592 let msg =
4593 "Type constants cannot be directly accessed. "
4594 ^ "Use type_structure(ValidClassname::class, 'TypeConstName') instead"
4596 add (Typing.err_code Typing.IllegalTypeStructure) pos msg
4598 let override_no_default_typeconst pos_child pos_parent =
4599 add_list
4600 (Typing.err_code Typing.OverrideNoDefaultTypeconst)
4602 (pos_child, "This abstract type constant does not have a default type");
4603 ( pos_parent,
4604 "It cannot override an abstract type constant that has a default type"
4608 let inout_annotation_missing pos1 pos2 =
4609 let msg1 = (pos1, "This argument should be annotated with 'inout'") in
4610 let msg2 = (pos2, "Because this is an inout parameter") in
4611 add_list (Typing.err_code Typing.InoutAnnotationMissing) [msg1; msg2]
4613 let inout_annotation_unexpected pos1 pos2 pos2_is_variadic =
4614 let msg1 = (pos1, "Unexpected inout annotation for argument") in
4615 let msg2 =
4616 ( pos2,
4617 if pos2_is_variadic then
4618 "A variadic parameter can never be inout"
4619 else
4620 "This is a normal parameter (does not have 'inout')" )
4622 add_list (Typing.err_code Typing.InoutAnnotationUnexpected) [msg1; msg2]
4624 let inoutness_mismatch pos1 pos2 (on_error : typing_error_callback) =
4625 let msg1 = (pos1, "This is an inout parameter") in
4626 let msg2 = (pos2, "It is incompatible with a normal parameter") in
4627 on_error ~code:(Typing.err_code Typing.InoutnessMismatch) [msg1; msg2]
4629 let invalid_new_disposable pos =
4630 let msg =
4631 "Disposable objects may only be created in a 'using' statement or 'return' from function marked <<__ReturnDisposable>>"
4633 add (Typing.err_code Typing.InvalidNewDisposable) pos msg
4635 let invalid_return_disposable pos =
4636 let msg =
4637 "Return expression must be new disposable in function marked <<__ReturnDisposable>>"
4639 add (Typing.err_code Typing.InvalidReturnDisposable) pos msg
4641 let nonreactive_function_call pos decl_pos callee_reactivity cause_pos_opt =
4642 add_list
4643 (Typing.err_code Typing.NonreactiveFunctionCall)
4645 (pos, "Reactive functions can only call other reactive functions.");
4646 (decl_pos, "This function is " ^ callee_reactivity ^ ".");
4648 @ Option.value_map cause_pos_opt ~default:[] ~f:(fun cause_pos ->
4650 ( cause_pos,
4651 "This argument caused function to be " ^ callee_reactivity ^ "."
4653 ]) )
4655 let nonreactive_call_from_shallow pos decl_pos callee_reactivity cause_pos_opt =
4656 add_list
4657 (Typing.err_code Typing.NonreactiveCallFromShallow)
4659 (pos, "Shallow reactive functions cannot call non-reactive functions.");
4660 (decl_pos, "This function is " ^ callee_reactivity ^ ".");
4662 @ Option.value_map cause_pos_opt ~default:[] ~f:(fun cause_pos ->
4664 ( cause_pos,
4665 "This argument caused function to be " ^ callee_reactivity ^ "."
4667 ]) )
4669 let rx_enabled_in_non_rx_context pos =
4671 (Typing.err_code Typing.RxEnabledInNonRxContext)
4673 "\\HH\\Rx\\IS_ENABLED can only be used in reactive functions."
4675 let rx_parameter_condition_mismatch
4676 cond pos def_pos (on_error : typing_error_callback) =
4677 on_error
4678 ~code:(Typing.err_code Typing.RxParameterConditionMismatch)
4680 ( pos,
4681 "This parameter does not satisfy "
4682 ^ cond
4683 ^ " condition defined on matching parameter in function super type." );
4684 (def_pos, "This is parameter declaration from the function super type.");
4687 let nonreactive_indexing is_append pos =
4688 let msg =
4689 if is_append then
4690 "Cannot append to a Hack Collection object in a reactive context. Instead, use the 'add' method."
4691 else
4692 "Cannot assign to element of Hack Collection object via [] in a reactive context. Instead, use the 'set' method."
4694 add (Typing.err_code Typing.NonreactiveIndexing) pos msg
4696 let obj_set_reactive pos =
4697 let msg =
4698 "This object's property is being mutated(used as an lvalue)"
4699 ^ "\nYou cannot set non-mutable object properties in reactive functions"
4701 add (Typing.err_code Typing.ObjSetReactive) pos msg
4703 let invalid_unset_target_rx pos =
4705 (Typing.err_code Typing.InvalidUnsetTargetInRx)
4707 "Non-mutable argument for 'unset' is not allowed in reactive functions."
4709 let inout_argument_bad_type pos msgl =
4710 let msg =
4711 "Expected argument marked inout to be contained in a local or "
4712 ^ "a value-typed container (e.g. vec, dict, keyset, array). "
4713 ^ "To use inout here, assign to/from a temporary local variable."
4715 add_list (Typing.err_code Typing.InoutArgumentBadType) ((pos, msg) :: msgl)
4717 let ambiguous_lambda pos uses =
4718 let msg1 =
4719 "Lambda has parameter types that could not be determined at definition site."
4721 let msg2 =
4722 Printf.sprintf
4723 "%d distinct use types were determined: please add type hints to lambda parameters."
4724 (List.length uses)
4726 add_list
4727 (Typing.err_code Typing.AmbiguousLambda)
4728 ( [(pos, msg1); (pos, msg2)]
4729 @ List.map uses (fun (pos, ty) -> (pos, "This use has type " ^ ty)) )
4731 let wrong_expression_kind_attribute
4732 expr_kind pos attr attr_class_pos attr_class_name intf_name =
4733 let msg1 =
4734 Printf.sprintf
4735 "The %s attribute cannot be used on %s."
4736 (strip_ns attr)
4737 expr_kind
4739 let msg2 =
4740 Printf.sprintf
4741 "The attribute's class is defined here. To be available for use on %s, the %s class must implement %s."
4742 expr_kind
4743 (strip_ns attr_class_name)
4744 (strip_ns intf_name)
4746 add_list
4747 (Typing.err_code Typing.WrongExpressionKindAttribute)
4748 [(pos, msg1); (attr_class_pos, msg2)]
4750 let wrong_expression_kind_builtin_attribute expr_kind pos attr =
4751 let msg1 =
4752 Printf.sprintf
4753 "The %s attribute cannot be used on %s."
4754 (strip_ns attr)
4755 expr_kind
4757 add_list (Typing.err_code Typing.WrongExpressionKindAttribute) [(pos, msg1)]
4759 let cannot_return_borrowed_value_as_immutable fun_pos value_pos =
4760 add_list
4761 (Typing.err_code Typing.CannotReturnBorrowedValueAsImmutable)
4763 ( fun_pos,
4764 "Values returned from reactive function by default are treated as immutable."
4766 ( value_pos,
4767 "This value is mutably borrowed and cannot be returned as immutable" );
4770 let decl_override_missing_hint pos (on_error : typing_error_callback) =
4771 on_error
4772 ~code:(Typing.err_code Typing.DeclOverrideMissingHint)
4774 ( pos,
4775 "When redeclaring class members, both declarations must have a typehint"
4779 let invalid_type_for_atmost_rx_as_rxfunc_parameter pos type_str =
4781 (Typing.err_code Typing.InvalidTypeForOnlyrxIfRxfuncParameter)
4783 ( "Parameter annotated with <<__AtMostRxAsFunc>> attribute must be function, now '"
4784 ^ type_str
4785 ^ "'." )
4787 let missing_annotation_for_atmost_rx_as_rxfunc_parameter pos =
4789 (Typing.err_code Typing.MissingAnnotationForOnlyrxIfRxfuncParameter)
4791 "Missing function type annotation on parameter marked with <<__AtMostRxAsFunc>> attribute."
4793 let superglobal_in_reactive_context pos name =
4795 (Typing.err_code Typing.SuperglobalInReactiveContext)
4797 ("Superglobal " ^ name ^ " cannot be used in a reactive context.")
4799 let static_property_in_reactive_context pos =
4801 (Typing.err_code Typing.StaticPropertyInReactiveContext)
4803 "Static property cannot be used in a reactive context."
4805 let returns_void_to_rx_function_as_non_expression_statement pos fpos =
4806 add_list
4807 (Typing.err_code Typing.ReturnsVoidToRxAsNonExpressionStatement)
4809 ( pos,
4810 "Cannot use result of function annotated with <<__ReturnsVoidToRx>> in reactive context"
4812 (fpos, "This is function declaration.");
4815 let non_awaited_awaitable_in_rx pos =
4817 (Typing.err_code Typing.NonawaitedAwaitableInReactiveContext)
4819 "This value has Awaitable type. Awaitable typed values in reactive code must be immediately await'ed."
4821 let shapes_key_exists_always_true pos1 name pos2 =
4822 add_list
4823 (Typing.err_code Typing.ShapesKeyExistsAlwaysTrue)
4825 (pos1, "This Shapes::keyExists() check is always true");
4826 (pos2, "The field '" ^ name ^ "' exists because of this definition");
4829 let shape_field_non_existence_reason pos name = function
4830 | `Undefined ->
4831 [(pos, "The field '" ^ name ^ "' is not defined in this shape")]
4832 | `Nothing reason ->
4833 ( pos,
4834 "The type of the field '"
4835 ^ name
4836 ^ "' in this shape doesn't allow any values" )
4837 :: reason
4839 let shapes_key_exists_always_false pos1 name pos2 reason =
4840 add_list (Typing.err_code Typing.ShapesKeyExistsAlwaysFalse)
4841 @@ (pos1, "This Shapes::keyExists() check is always false")
4842 :: shape_field_non_existence_reason pos2 name reason
4844 let shapes_method_access_with_non_existent_field
4845 pos1 name pos2 method_name reason =
4846 add_list (Typing.err_code Typing.ShapesMethodAccessWithNonExistentField)
4847 @@ ( pos1,
4848 "You are calling Shapes::"
4849 ^ method_name
4850 ^ "() on a field known to not exist" )
4851 :: shape_field_non_existence_reason pos2 name reason
4853 let shape_access_with_non_existent_field pos1 name pos2 reason =
4854 add_list (Typing.err_code Typing.ShapeAccessWithNonExistentField)
4855 @@ (pos1, "You are accessing a field known to not exist")
4856 :: shape_field_non_existence_reason pos2 name reason
4858 let ambiguous_object_access
4859 pos name self_pos vis subclass_pos class_self class_subclass =
4860 let class_self = strip_ns class_self in
4861 let class_subclass = strip_ns class_subclass in
4862 add_list
4863 (Typing.err_code Typing.AmbiguousObjectAccess)
4865 (pos, "This object access to " ^ name ^ " is ambiguous");
4866 ( self_pos,
4867 "You will access the private instance declared in " ^ class_self );
4868 ( subclass_pos,
4869 "Instead of the " ^ vis ^ " instance declared in " ^ class_subclass );
4872 let invalid_traversable_in_rx pos =
4874 (Typing.err_code Typing.InvalidTraversableInRx)
4876 "Cannot traverse over non-reactive traversable in reactive code."
4878 let lateinit_with_default pos =
4880 (Typing.err_code Typing.LateInitWithDefault)
4882 "A late-initialized property cannot have a default value"
4884 let bad_lateinit_override
4885 parent_is_lateinit parent_pos child_pos (on_error : typing_error_callback) =
4886 let verb =
4887 if parent_is_lateinit then
4888 "is"
4889 else
4890 "is not"
4892 on_error
4893 ~code:(Typing.err_code Typing.BadLateInitOverride)
4895 ( child_pos,
4896 "Redeclared properties must be consistently declared __LateInit" );
4897 (parent_pos, "The property " ^ verb ^ " declared __LateInit here");
4900 let bad_xhp_attr_required_override
4901 parent_tag child_tag parent_pos child_pos (on_error : typing_error_callback)
4903 on_error
4904 ~code:(Typing.err_code Typing.BadXhpAttrRequiredOverride)
4906 (child_pos, "Redeclared attribute must not be less strict");
4907 ( parent_pos,
4908 "The attribute is "
4909 ^ parent_tag
4910 ^ ", which is stricter than "
4911 ^ child_tag );
4914 let invalid_switch_case_value_type case_value_p case_value_ty scrutinee_ty =
4915 add (Typing.err_code Typing.InvalidSwitchCaseValueType) case_value_p
4916 @@ Printf.sprintf
4917 "Switch statements use == equality, so comparing values of type %s with %s may not give the desired result."
4918 case_value_ty
4919 scrutinee_ty
4921 let unserializable_type pos message =
4923 (Typing.err_code Typing.UnserializableType)
4925 ( "Unserializable type (could not be converted to JSON and back again): "
4926 ^ message )
4928 let redundant_rx_condition pos =
4930 (Typing.err_code Typing.RedundantRxCondition)
4932 "Reactivity condition for this method is always true, consider removing it."
4934 let invalid_arraykey code pos (cpos, ctype) (kpos, ktype) =
4935 add_list
4936 (Typing.err_code code)
4938 (pos, "This value is not a valid key type for this container");
4939 (cpos, "This container is " ^ ctype);
4940 (kpos, String.capitalize ktype ^ " cannot be used as a key for " ^ ctype);
4943 let invalid_arraykey_read = invalid_arraykey Typing.InvalidArrayKeyRead
4945 let invalid_arraykey_write = invalid_arraykey Typing.InvalidArrayKeyWrite
4947 let invalid_sub_string pos ty =
4948 add (Typing.err_code Typing.InvalidSubString) pos
4949 @@ "Expected an object convertible to string but got "
4950 ^ ty
4952 let typechecker_timeout (pos, fun_name) seconds =
4954 (Typing.err_code Typing.TypecheckerTimeout)
4956 (Printf.sprintf
4957 "Type checker timed out after %d seconds whilst checking function %s"
4958 seconds
4959 fun_name)
4961 let unresolved_type_variable pos =
4963 (Typing.err_code Typing.UnresolvedTypeVariable)
4965 "The type of this expression contains an unresolved type variable"
4967 let invalid_arraykey_constraint pos t =
4969 (Typing.err_code Typing.InvalidArrayKeyConstraint)
4971 ( "This type is "
4973 ^ ", which cannot be used as an arraykey (string | int)" )
4975 let exception_occurred pos e =
4976 let pos_str = pos |> Pos.to_absolute |> Pos.string in
4977 HackEventLogger.type_check_exn_bug ~path:(Pos.filename pos) ~pos:pos_str ~e;
4978 Hh_logger.error
4979 "Exception while typechecking at position %s\n%s"
4980 pos_str
4981 (Exception.to_string e);
4983 (Typing.err_code Typing.ExceptionOccurred)
4985 (Printf.sprintf
4986 "An exception occurred while typechecking this. %s"
4987 Error_message_sentinel.please_file_a_bug_message)
4989 let redundant_covariant pos msg suggest =
4991 (Typing.err_code Typing.RedundantGeneric)
4993 ( "This generic parameter is redundant because it only appears in a covariant (output) position"
4994 ^ msg
4995 ^ ". Consider replacing uses of generic parameter with `"
4996 ^ suggest
4997 ^ "` or specifying <<__Explicit>> on the generic parameter" )
4999 let meth_caller_trait pos trait_name =
5001 (Typing.err_code Typing.MethCallerTrait)
5003 ( strip_ns trait_name
5004 ^ " is a trait which cannot be used with meth_caller. Use a class instead."
5007 let duplicate_interface pos name others =
5008 add_list
5009 (Typing.err_code Typing.DuplicateInterface)
5010 ( ( pos,
5011 Printf.sprintf
5012 "Interface %s is used more than once in this declaration."
5013 (strip_ns name) )
5014 :: List.map others (fun pos -> (pos, "Here is another occurrence")) )
5016 (*****************************************************************************)
5017 (* Printing *)
5018 (*****************************************************************************)
5020 let to_json (error : Pos.absolute error_) =
5021 let (error_code, msgl) = (get_code error, to_list error) in
5022 let elts =
5023 List.map msgl (fun (p, w) ->
5024 let (line, scol, ecol) = Pos.info_pos p in
5025 Hh_json.JSON_Object
5027 ("descr", Hh_json.JSON_String w);
5028 ("path", Hh_json.JSON_String (Pos.filename p));
5029 ("line", Hh_json.int_ line);
5030 ("start", Hh_json.int_ scol);
5031 ("end", Hh_json.int_ ecol);
5032 ("code", Hh_json.int_ error_code);
5035 Hh_json.JSON_Object [("message", Hh_json.JSON_Array elts)]
5037 let convert_errors_to_string ?(include_filename = false) (errors : error list) :
5038 string list =
5039 List.fold_right
5040 ~init:[]
5041 ~f:(fun err acc_out ->
5042 List.fold_right
5043 ~init:acc_out
5044 ~f:(fun (pos, msg) acc_in ->
5045 let result = Format.asprintf "%a %s" Pos.pp pos msg in
5046 if include_filename then
5047 let full_result =
5048 Printf.sprintf
5049 "%s %s"
5050 (Pos.to_absolute pos |> Pos.filename)
5051 result
5053 full_result :: acc_in
5054 else
5055 result :: acc_in)
5056 (to_list err))
5057 errors
5059 (*****************************************************************************)
5060 (* Try if errors. *)
5061 (*****************************************************************************)
5063 let try_ f1 f2 = try_with_result f1 (fun _ l -> f2 l)
5065 let try_with_error f1 f2 =
5066 try_ f1 (fun err ->
5067 let (error_code, l) = (get_code err, to_list err) in
5068 add_list error_code l;
5069 f2 ())
5071 let has_no_errors f =
5072 try_
5073 (fun () ->
5074 let _ = f () in
5075 true)
5076 (fun _ -> false)
5078 (*****************************************************************************)
5079 (* Do. *)
5080 (*****************************************************************************)
5082 let ignore_ f =
5083 let allow_errors_in_default_path_copy = !allow_errors_in_default_path in
5084 set_allow_errors_in_default_path true;
5085 let (_, result) = do_ f in
5086 set_allow_errors_in_default_path allow_errors_in_default_path_copy;
5087 result
5089 let try_when f ~when_ ~do_ =
5090 try_with_result f (fun result (error : error) ->
5091 if when_ () then
5092 do_ error
5093 else
5094 add_error error;
5095 result)