Rip out legacy reactivity from the typechecker and HackC
[hiphop-php.git] / hphp / hack / src / errors / errors.ml
blobd7226f648bb6c8cb135c1b897a6e17193fbbf866
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 =
42 ?code:int -> Pos.t * string -> (Pos.t * string) list -> unit
44 type name_context =
45 | FunctionNamespace
46 | ConstantNamespace
47 | TypeNamespace (** Classes, interfaces, traits, records and type aliases.*)
48 (* The following are all subsets of TypeNamespace, used when we can
49 give a more specific naming error. E.g. `use Foo;` only allows
50 traits. *)
51 | TraitContext
52 | ClassContext
53 | RecordContext
55 (* The file and phase of analysis being currently performed *)
56 let current_context : (Relative_path.t * phase) ref =
57 ref (Relative_path.default, Typing)
59 let current_span : Pos.t ref = ref Pos.none
61 let allow_errors_in_default_path = ref true
63 module PhaseMap = Reordered_argument_map (WrappedMap.Make (struct
64 type t = phase
66 let rank = function
67 | Init -> 0
68 | Parsing -> 1
69 | Naming -> 2
70 | Decl -> 3
71 | Typing -> 4
73 let compare x y = rank x - rank y
74 end))
76 (** Results of single file analysis. *)
77 type 'a file_t = 'a list PhaseMap.t [@@deriving eq]
79 (** Results of multi-file analysis. *)
80 type 'a files_t = 'a file_t Relative_path.Map.t [@@deriving eq]
82 let files_t_fold v ~f ~init =
83 Relative_path.Map.fold v ~init ~f:(fun path v acc ->
84 PhaseMap.fold v ~init:acc ~f:(fun phase v acc -> f path phase v acc))
86 let files_t_map v ~f = Relative_path.Map.map v ~f:(fun v -> PhaseMap.map v ~f)
88 let files_t_merge ~f x y =
89 (* Using fold instead of merge to make the runtime proportional to the size
90 * of first argument (like List.rev_append ) *)
91 Relative_path.Map.fold x ~init:y ~f:(fun k x acc ->
92 let y =
93 Option.value (Relative_path.Map.find_opt y k) ~default:PhaseMap.empty
95 Relative_path.Map.add
96 acc
98 (PhaseMap.merge x y ~f:(fun phase x y -> f phase k x y)))
100 let files_t_to_list x =
101 files_t_fold x ~f:(fun _ _ x acc -> List.rev_append x acc) ~init:[]
102 |> List.rev
104 let list_to_files_t = function
105 | [] -> Relative_path.Map.empty
106 | x ->
107 (* Values constructed here should not be used with incremental mode.
108 * See assert in incremental_update. *)
109 Relative_path.Map.singleton
110 Relative_path.default
111 (PhaseMap.singleton Typing x)
113 let get_code_severity code =
115 code
116 = Error_codes.Init.err_code Error_codes.Init.ForwardCompatibilityNotCurrent
117 then
118 Warning
119 else
120 Error
122 (* Get most recently-ish added error. *)
123 let get_last error_map =
124 (* If this map has more than one element, we pick an arbitrary file. Because
125 * of that, we might not end up with the most recent error and generate a
126 * less-specific error message. This should be rare. *)
127 match Relative_path.Map.max_binding_opt error_map with
128 | None -> None
129 | Some (_, phase_map) ->
130 let error_list =
131 PhaseMap.max_binding_opt phase_map |> Option.value_map ~f:snd ~default:[]
133 (match List.rev error_list with
134 | [] -> None
135 | e :: _ -> Some e)
137 type 'a error_ = {
138 code: error_code;
139 claim: 'a message;
140 reasons: 'a message list;
142 [@@deriving eq]
144 type error = Pos.t error_ [@@deriving eq]
146 type applied_fixme = Pos.t * int [@@deriving eq]
148 let applied_fixmes : applied_fixme files_t ref = ref Relative_path.Map.empty
150 let (error_map : error files_t ref) = ref Relative_path.Map.empty
152 let accumulate_errors = ref false
154 (* Some filename when declaring *)
155 let in_lazy_decl = ref None
157 let (is_hh_fixme : (Pos.t -> error_code -> bool) ref) = ref (fun _ _ -> false)
159 let badpos_message =
160 Printf.sprintf
161 "There is an error somewhere in this file. However the type checker reports that the error is in another file. %s"
162 Error_message_sentinel.please_file_a_bug_message
164 let badpos_message_2 =
165 Printf.sprintf
166 "There is an error somewhere in this definition. However the type checker reports that the error is elsewhere. %s"
167 Error_message_sentinel.please_file_a_bug_message
169 let try_with_result f1 f2 =
170 let error_map_copy = !error_map in
171 let accumulate_errors_copy = !accumulate_errors in
172 let is_hh_fixme_copy = !is_hh_fixme in
173 (is_hh_fixme := (fun _ _ -> false));
174 error_map := Relative_path.Map.empty;
175 accumulate_errors := true;
176 let (result, errors) =
177 Utils.try_finally
179 begin
180 fun () ->
181 let result = f1 () in
182 (result, !error_map)
184 ~finally:
185 begin
186 fun () ->
187 error_map := error_map_copy;
188 accumulate_errors := accumulate_errors_copy;
189 is_hh_fixme := is_hh_fixme_copy
192 match get_last errors with
193 | None -> result
194 | Some { code; claim; reasons } ->
195 (* Remove bad position sentinel if present: we might be about to add a new primary
196 * error position*)
197 let l =
198 let (_, msg) = claim in
199 if String.equal msg badpos_message || String.equal msg badpos_message_2
200 then
201 if List.is_empty reasons then
202 failwith "in try_with_result"
203 else
204 reasons
205 else
206 claim :: reasons
208 f2 result { code; claim = List.hd_exn l; reasons = List.tl_exn l }
210 (* Reset errors before running [f] so that we can return the errors
211 * caused by f. These errors are not added in the global list of errors. *)
212 let do_ f =
213 let error_map_copy = !error_map in
214 let applied_fixmes_copy = !applied_fixmes in
215 let accumulate_errors_copy = !accumulate_errors in
216 error_map := Relative_path.Map.empty;
217 applied_fixmes := Relative_path.Map.empty;
218 accumulate_errors := true;
219 let (result, out_errors, out_applied_fixmes) =
220 Utils.try_finally
222 begin
223 fun () ->
224 let result = f () in
225 (result, !error_map, !applied_fixmes)
227 ~finally:
228 begin
229 fun () ->
230 error_map := error_map_copy;
231 applied_fixmes := applied_fixmes_copy;
232 accumulate_errors := accumulate_errors_copy
235 let out_errors = files_t_map ~f:List.rev out_errors in
236 ((out_errors, out_applied_fixmes), result)
238 let run_in_context path phase f =
239 let context_copy = !current_context in
240 current_context := (path, phase);
241 Utils.try_finally ~f ~finally:(fun () -> current_context := context_copy)
243 let run_with_span span f =
244 let old_span = !current_span in
245 current_span := span;
246 Utils.try_finally ~f ~finally:(fun () -> current_span := old_span)
248 (* Log important data if lazy_decl triggers a crash *)
249 let lazy_decl_error_logging error error_map to_absolute to_string =
250 let error_list = files_t_to_list !error_map in
251 (* Print the current error list, which should be empty *)
252 Printf.eprintf "%s" "Error list(should be empty):\n";
253 List.iter error_list ~f:(fun err ->
254 let msg = err |> to_absolute |> to_string in
255 Printf.eprintf "%s\n" msg);
256 Printf.eprintf "%s" "Offending error:\n";
257 Printf.eprintf "%s" error;
259 (* Print out a larger stack trace *)
260 Printf.eprintf "%s" "Callstack:\n";
261 Printf.eprintf
262 "%s"
263 (Caml.Printexc.raw_backtrace_to_string (Caml.Printexc.get_callstack 500));
265 (* Exit with special error code so we can see the log after *)
266 Exit.exit Exit_status.Lazy_decl_bug
268 (*****************************************************************************)
269 (* Error code printing. *)
270 (*****************************************************************************)
272 let error_kind error_code =
273 match error_code / 1000 with
274 | 1 -> "Parsing"
275 | 2 -> "Naming"
276 | 3 -> "NastCheck"
277 | 4 -> "Typing"
278 | 5 -> "Lint"
279 | 8 -> "Init"
280 | _ -> "Other"
282 let error_code_to_string error_code =
283 let error_kind = error_kind error_code in
284 let error_number = Printf.sprintf "%04d" error_code in
285 error_kind ^ "[" ^ error_number ^ "]"
287 let phase_to_string (phase : phase) : string =
288 match phase with
289 | Init -> "Init"
290 | Parsing -> "Parsing"
291 | Naming -> "Naming"
292 | Decl -> "Decl"
293 | Typing -> "Typing"
295 let phase_of_string (value : string) : phase option =
296 match Caml.String.lowercase_ascii value with
297 | "init" -> Some Init
298 | "parsing" -> Some Parsing
299 | "naming" -> Some Naming
300 | "decl" -> Some Decl
301 | "typing" -> Some Typing
302 | _ -> None
304 let (name_context_to_string : name_context -> string) = function
305 | FunctionNamespace -> "function"
306 | ConstantNamespace -> "constant"
307 | TypeNamespace -> "type"
308 | TraitContext -> "trait"
309 | ClassContext -> "class"
310 | RecordContext -> "record"
312 let get_pos { claim; _ } = fst claim
314 let sort err =
315 let rec compare (x_code, x_messages) (y_code, y_messages) =
316 match (x_messages, y_messages) with
317 | ([], []) -> 0
318 | (_x_messages, []) -> -1
319 | ([], _y_messages) -> 1
320 | (x_message :: x_messages, y_message :: y_messages) ->
321 (* The primary sort order is by file *)
322 let comparison =
323 Relative_path.compare
324 (fst x_message |> Pos.filename)
325 (fst y_message |> Pos.filename)
327 (* Then within each file, sort by phase *)
328 let comparison =
329 if comparison = 0 then
330 Int.compare (x_code / 1000) (y_code / 1000)
331 else
332 comparison
334 (* If the error codes are the same, sort by position *)
335 let comparison =
336 if comparison = 0 then
337 Pos.compare (fst x_message) (fst y_message)
338 else
339 comparison
341 (* If the error codes are also the same, sort by message text *)
342 let comparison =
343 if comparison = 0 then
344 String.compare (snd x_message) (snd y_message)
345 else
346 comparison
348 (* Finally, if the message text is also the same, then continue comparing
349 the reason messages (which indicate the reason why Hack believes
350 there is an error reported in the claim message) *)
351 if comparison = 0 then
352 compare (x_code, x_messages) (y_code, y_messages)
353 else
354 comparison
356 let equal x y = compare x y = 0 in
357 let coalesce { code; claim; reasons } = (code, claim :: reasons) in
358 List.sort ~compare:(fun x y -> compare (coalesce x) (coalesce y)) err
359 |> List.remove_consecutive_duplicates ~equal:(fun x y ->
360 equal (coalesce x) (coalesce y))
362 let get_sorted_error_list (err, _) = sort (files_t_to_list err)
364 (* Getters and setter for passed-in map, based on current context *)
365 let get_current_file_t file_t_map =
366 let current_file = fst !current_context in
367 Relative_path.Map.find_opt file_t_map current_file
368 |> Option.value ~default:PhaseMap.empty
370 let get_current_list file_t_map =
371 let current_phase = snd !current_context in
372 get_current_file_t file_t_map |> fun x ->
373 PhaseMap.find_opt x current_phase |> Option.value ~default:[]
375 let set_current_list file_t_map new_list =
376 let (current_file, current_phase) = !current_context in
377 file_t_map :=
378 Relative_path.Map.add
379 !file_t_map
380 current_file
381 (PhaseMap.add (get_current_file_t !file_t_map) current_phase new_list)
383 let do_with_context path phase f = run_in_context path phase (fun () -> do_ f)
385 (** Turn on lazy decl mode for the duration of the closure.
386 This runs without returning the original state,
387 since we collect it later in do_with_lazy_decls_ *)
388 let run_in_decl_mode filename f =
389 let old_in_lazy_decl = !in_lazy_decl in
390 in_lazy_decl := Some filename;
391 Utils.try_finally ~f ~finally:(fun () -> in_lazy_decl := old_in_lazy_decl)
393 and make_error code claim reasons : error = { code; claim; reasons }
395 (*****************************************************************************)
396 (* Accessors. *)
397 (*****************************************************************************)
398 and get_code ({ code; _ } : 'a error_) = (code : error_code)
400 let get_severity (error : 'a error_) = get_code_severity (get_code error)
402 let to_list ({ claim; reasons; _ } : 'a error_) = claim :: reasons
404 let to_absolute { code; claim; reasons } =
405 let claim = (fst claim |> Pos.to_absolute, snd claim) in
406 let reasons = List.map reasons (fun (p, s) -> (Pos.to_absolute p, s)) in
407 { code; claim; reasons }
409 let make_absolute_error code (x : (Pos.absolute * string) list) :
410 Pos.absolute error_ =
411 match x with
412 | [] -> failwith "an error must have at least one message"
413 | claim :: reasons -> { code; claim; reasons }
415 let get_messages ({ claim; reasons; _ } : 'a error_) = claim :: reasons
417 let read_lines path =
418 try In_channel.read_lines path
419 with Sys_error _ ->
420 (try Multifile.read_file_from_multifile path with Sys_error _ -> [])
422 let num_digits x = int_of_float (Float.log10 (float_of_int x)) + 1
424 (* Sort [xs] such that all the values that return the same
425 value for (f x) are consecutive. For any two elements
426 x1 and x2 in xs where (f x1) = (f x2), if x1 occurs before x2 in
427 xs, then x1 also occurs before x2 in the returned list. *)
428 let combining_sort (xs : 'a list) ~(f : 'a -> string) : 'a list =
429 let rec build_map xs grouped keys =
430 match xs with
431 | x :: xs ->
432 let key = f x in
433 (match String.Map.find grouped key with
434 | Some members ->
435 let grouped = String.Map.set grouped ~key ~data:(members @ [x]) in
436 build_map xs grouped keys
437 | None ->
438 let grouped = String.Map.set grouped ~key ~data:[x] in
439 build_map xs grouped (key :: keys))
440 | [] -> (grouped, keys)
442 let (grouped, keys) = build_map xs String.Map.empty [] in
443 List.concat_map (List.rev keys) ~f:(fun fn -> String.Map.find_exn grouped fn)
445 (* E.g. "10 errors found." *)
446 let format_summary format errors dropped_count max_errors : string option =
447 match format with
448 | Context
449 | Highlighted ->
450 let total = List.length errors + dropped_count in
451 let formatted_total =
452 Printf.sprintf
453 "%d error%s found"
454 total
455 ( if total = 1 then
457 else
458 "s" )
460 let truncated =
461 match max_errors with
462 | Some max_errors when dropped_count > 0 ->
463 Printf.sprintf
464 " (only showing first %d, dropped %d).\n"
465 max_errors
466 dropped_count
467 | _ -> ".\n"
469 Some (formatted_total ^ truncated)
470 | Raw -> None
472 let to_absolute_for_test { code; claim; reasons } =
473 let f (p, s) =
474 let path = Pos.filename p in
475 let path_without_prefix = Relative_path.suffix path in
476 let p =
477 Pos.set_file
478 (Relative_path.create Relative_path.Dummy path_without_prefix)
481 (Pos.to_absolute p, s)
483 let claim = f claim in
484 let reasons = List.map ~f reasons in
485 { code; claim; reasons }
487 let report_pos_from_reason = ref false
489 let to_string ({ code; claim; reasons } : Pos.absolute error_) : string =
490 let buf = Buffer.create 50 in
491 let (pos1, msg1) = claim in
492 Buffer.add_string
494 begin
495 let error_code = error_code_to_string code in
496 let reason_msg =
497 if !report_pos_from_reason && Pos.get_from_reason pos1 then
498 " [FROM REASON INFO]"
499 else
502 Printf.sprintf
503 "%s\n%s (%s)%s\n"
504 (Pos.string pos1)
505 msg1
506 error_code
507 reason_msg
508 end;
509 List.iter reasons (fun (p, w) ->
510 let msg = Printf.sprintf " %s\n %s\n" (Pos.string p) w in
511 Buffer.add_string buf msg);
512 Buffer.contents buf
514 let add_error_impl error =
515 if !accumulate_errors then
516 let () =
517 match !current_context with
518 | (path, _)
519 when Relative_path.equal path Relative_path.default
520 && not !allow_errors_in_default_path ->
521 Hh_logger.log
522 "WARNING: adding an error in default path\n%s\n"
523 (Caml.Printexc.raw_backtrace_to_string
524 (Caml.Printexc.get_callstack 100))
525 | _ -> ()
527 (* Cheap test to avoid duplicating most recent error *)
528 let error_list = get_current_list !error_map in
529 match error_list with
530 | old_error :: _ when equal_error error old_error -> ()
531 | _ -> set_current_list error_map (error :: error_list)
532 else
533 (* We have an error, but haven't handled it in any way *)
534 let msg = error |> to_absolute |> to_string in
535 match !in_lazy_decl with
536 | Some _ -> lazy_decl_error_logging msg error_map to_absolute to_string
537 | None -> Utils.assert_false_log_backtrace (Some msg)
539 (* Whether we've found at least one error *)
540 let currently_has_errors () = not (List.is_empty (get_current_list !error_map))
542 module Parsing = Error_codes.Parsing
543 module Naming = Error_codes.Naming
544 module NastCheck = Error_codes.NastCheck
545 module Typing = Error_codes.Typing
547 (*****************************************************************************)
548 (* Types *)
549 (*****************************************************************************)
551 type t = error files_t * applied_fixme files_t [@@deriving eq]
553 module type Error_category = sig
554 type t
556 val min : int
558 val max : int
560 val of_enum : int -> t option
562 val show : t -> string
564 val err_code : t -> int
567 (*****************************************************************************)
568 (* HH_FIXMEs hook *)
569 (*****************************************************************************)
571 let error_codes_treated_strictly = ref (ISet.of_list [])
573 let is_strict_code code = ISet.mem code !error_codes_treated_strictly
575 (* The 'phps FixmeAllHackErrors' tool must be kept in sync with this list *)
576 let hard_banned_codes =
577 ISet.of_list
579 Typing.err_code Typing.InvalidIsAsExpressionHint;
580 Typing.err_code Typing.InvalidEnforceableTypeArgument;
581 Typing.err_code Typing.RequireArgsReify;
582 Typing.err_code Typing.InvalidReifiedArgument;
583 Typing.err_code Typing.GenericsNotAllowed;
584 Typing.err_code Typing.InvalidNewableTypeArgument;
585 Typing.err_code Typing.InvalidNewableTypeParamConstraints;
586 Typing.err_code Typing.NewWithoutNewable;
587 Typing.err_code Typing.NewClassReified;
588 Typing.err_code Typing.MemoizeReified;
589 Typing.err_code Typing.ClassGetReified;
592 let allowed_fixme_codes_strict = ref ISet.empty
594 let allowed_fixme_codes_partial = ref ISet.empty
596 let codes_not_raised_partial = ref ISet.empty
598 let set_allow_errors_in_default_path x = allow_errors_in_default_path := x
600 let is_allowed_code_strict code = ISet.mem code !allowed_fixme_codes_strict
602 let is_allowed_code_partial code = ISet.mem code !allowed_fixme_codes_partial
604 let is_not_raised_partial code = ISet.mem code !codes_not_raised_partial
606 let (get_hh_fixme_pos : (Pos.t -> error_code -> Pos.t option) ref) =
607 ref (fun _ _ -> None)
609 let (is_hh_fixme_disallowed : (Pos.t -> error_code -> bool) ref) =
610 ref (fun _ _ -> false)
612 (*****************************************************************************)
613 (* Errors accumulator. *)
614 (*****************************************************************************)
616 (* If primary position in error list isn't in current file, wrap with a sentinel error *)
617 let check_pos_msg (claim, pos_msg_l) =
618 let pos = fst claim in
619 let current_file = fst !current_context in
620 let current_span = !current_span in
621 (* If error is reported inside the current span, or no span has been set but the error
622 * is reported in the current file, then accept the error *)
624 Pos.contains current_span pos
625 || Pos.equal current_span Pos.none
626 && Relative_path.equal (Pos.filename pos) current_file
627 || Relative_path.equal current_file Relative_path.default
628 then
629 (claim, pos_msg_l)
630 else
631 let pos_msg_l = claim :: pos_msg_l in
632 let message =
633 pos_msg_l
634 |> List.map ~f:(fun (pos, msg) ->
635 Pos.print_verbose_relative pos ^ ": " ^ msg)
637 let stack =
638 Exception.get_current_callstack_string 99 |> Exception.clean_stack
640 HackEventLogger.type_check_primary_position_bug
641 ~current_file
642 ~message
643 ~stack;
644 let err =
645 if Pos.equal current_span Pos.none then
646 (Pos.make_from current_file, badpos_message)
647 else
648 (current_span, badpos_message_2)
650 (err, pos_msg_l)
652 let add_error_with_fixme_error error explanation =
653 let { code; claim; reasons = _ } = error in
654 let (pos, _) = claim in
655 let pos = Option.value (!get_hh_fixme_pos pos code) ~default:pos in
656 add_error_impl error;
657 add_error_impl { code; claim = (pos, explanation); reasons = [] }
659 let rec add_applied_fixme code pos =
660 if ServerLoadFlag.get_no_load () then
661 let applied_fixmes_list = get_current_list !applied_fixmes in
662 set_current_list applied_fixmes ((pos, code) :: applied_fixmes_list)
663 else
666 and add code pos msg = add_list code (pos, msg) []
668 and fixme_present pos code =
669 !is_hh_fixme pos code || !is_hh_fixme_disallowed pos code
671 and add_list code (claim : _ message) reasons =
672 add_error { code; claim; reasons }
674 and add_error error =
675 let { code; claim; reasons } = error in
676 let (claim, reasons) = check_pos_msg (claim, reasons) in
677 let error = { code; claim; reasons } in
679 let pos = fst claim in
681 if ISet.mem code hard_banned_codes then
682 if fixme_present pos code then
683 let explanation =
684 Printf.sprintf
685 "You cannot use `HH_FIXME` or `HH_IGNORE_ERROR` comments to suppress error %d, and this cannot be enabled by configuration"
686 code
688 add_error_with_fixme_error error explanation
689 else
690 add_error_impl error
691 else if
692 is_not_raised_partial code && Relative_path.is_partial (Pos.filename pos)
693 then
695 else if not (fixme_present pos code) then
696 (* Fixmes and banned decl fixmes are separated by the parser because Errors can't recover
697 * the position information after the fact. This is the default case, where an HH_FIXME
698 * comment is not present. Therefore, the remaining cases are variations on behavior when
699 * a fixme is present *)
700 add_error_impl error
701 else if Relative_path.(is_hhi (prefix (Pos.filename pos))) then
702 add_applied_fixme code pos
703 else if !report_pos_from_reason && Pos.get_from_reason pos then
704 let explanation =
705 "You cannot use `HH_FIXME` or `HH_IGNORE_ERROR` comments to suppress an error whose position was derived from reason information"
707 add_error_with_fixme_error error explanation
708 else if !is_hh_fixme_disallowed pos code then
709 let explanation =
710 Printf.sprintf
711 "You cannot use `HH_FIXME` or `HH_IGNORE_ERROR` comments to suppress error %d in declarations"
712 code
714 add_error_with_fixme_error error explanation
715 else
716 let whitelist =
718 (not (ISet.is_empty !allowed_fixme_codes_partial))
719 && Relative_path.is_partial (Pos.filename pos)
720 then
721 is_allowed_code_partial
722 else
723 is_allowed_code_strict
725 if whitelist code then
726 add_applied_fixme code pos
727 else
728 let explanation =
729 Printf.sprintf
730 "You cannot use `HH_FIXME` or `HH_IGNORE_ERROR` comments to suppress error %d"
731 code
733 add_error_with_fixme_error error explanation
735 and merge (err', fixmes') (err, fixmes) =
736 let append _ _ x y =
737 let x = Option.value x ~default:[] in
738 let y = Option.value y ~default:[] in
739 Some (List.rev_append x y)
741 (files_t_merge ~f:append err' err, files_t_merge ~f:append fixmes' fixmes)
743 and merge_into_current errors =
744 let merged = merge errors (!error_map, !applied_fixmes) in
745 error_map := fst merged;
746 applied_fixmes := snd merged
748 and incremental_update :
749 type (* Need to write out the entire ugly type to convince OCaml it's polymorphic
750 * and can update both error_map as well as applied_fixmes map *)
752 a files_t ->
753 a files_t ->
754 ((* function folding over paths of rechecked files *)
755 a files_t ->
756 (Relative_path.t -> a files_t -> a files_t) ->
757 a files_t) ->
758 phase ->
759 a files_t =
760 fun old new_ fold phase ->
761 (* Helper to remove acc[path][phase]. If acc[path] becomes empty afterwards,
762 * remove it too (i.e do not store empty maps or lists ever). *)
763 let remove path phase acc =
764 let new_phase_map =
765 match Relative_path.Map.find_opt acc path with
766 | None -> None
767 | Some phase_map ->
768 let new_phase_map = PhaseMap.remove phase_map phase in
769 if PhaseMap.is_empty new_phase_map then
770 None
771 else
772 Some new_phase_map
774 match new_phase_map with
775 | None -> Relative_path.Map.remove acc path
776 | Some x -> Relative_path.Map.add acc path x
778 (* Replace old errors with new *)
779 let res =
780 files_t_merge new_ old ~f:(fun phase path new_ old ->
781 ( if Relative_path.equal path Relative_path.default then
782 let phase =
783 match phase with
784 | Init -> "Init"
785 | Parsing -> "Parsing"
786 | Naming -> "Naming"
787 | Decl -> "Decl"
788 | Typing -> "Typing"
790 Utils.assert_false_log_backtrace
791 (Some
792 ( "Default (untracked) error sources should not get into incremental "
793 ^ "mode. There might be a missing call to `Errors.do_with_context`/"
794 ^ "`run_in_context` somwhere or incorrectly used `Errors.from_error_list`."
795 ^ "Phase: "
796 ^ phase )) );
797 match new_ with
798 | Some new_ -> Some (List.rev new_)
799 | None -> old)
801 (* For files that were rechecked, but had no errors - remove them from maps *)
802 fold res (fun path acc ->
803 let has_errors =
804 match Relative_path.Map.find_opt new_ path with
805 | None -> false
806 | Some phase_map -> PhaseMap.mem phase_map phase
808 if has_errors then
810 else
811 remove path phase acc)
813 and incremental_update_set ~old ~new_ ~rechecked phase =
814 let fold init g =
815 Relative_path.Set.fold
817 begin
818 fun path acc ->
819 g path acc
821 ~init
822 rechecked
824 ( incremental_update (fst old) (fst new_) fold phase,
825 incremental_update (snd old) (snd new_) fold phase )
827 and incremental_update_map ~old ~new_ ~rechecked phase =
828 let fold init g =
829 Relative_path.Map.fold
831 begin
832 fun path _ acc ->
833 g path acc
835 ~init
836 rechecked
838 ( incremental_update (fst old) (fst new_) fold phase,
839 incremental_update (snd old) (snd new_) fold phase )
841 and empty = (Relative_path.Map.empty, Relative_path.Map.empty)
843 and is_empty (err, _fixmes) = Relative_path.Map.is_empty err
845 and count (err, _fixmes) =
846 files_t_fold err ~f:(fun _ _ x acc -> acc + List.length x) ~init:0
848 and get_error_list (err, _fixmes) = files_t_to_list err
850 and get_applied_fixmes (_err, fixmes) = files_t_to_list fixmes
852 and from_error_list err = (list_to_files_t err, Relative_path.Map.empty)
854 (*****************************************************************************)
855 (* Accessors. (All methods delegated to the parameterized module.) *)
856 (*****************************************************************************)
858 let iter_error_list f err = List.iter ~f (get_sorted_error_list err)
860 let fold_errors ?phase err ~init ~f =
861 match phase with
862 | None ->
863 files_t_fold (fst err) ~init ~f:(fun source _ errors acc ->
864 List.fold_right errors ~init:acc ~f:(f source))
865 | Some phase ->
866 Relative_path.Map.fold (fst err) ~init ~f:(fun source phases acc ->
867 match PhaseMap.find_opt phases phase with
868 | None -> acc
869 | Some errors -> List.fold_right errors ~init:acc ~f:(f source))
871 let fold_errors_in ?phase err ~source ~init ~f =
872 Relative_path.Map.find_opt (fst err) source
873 |> Option.value ~default:PhaseMap.empty
874 |> PhaseMap.fold ~init ~f:(fun p errors acc ->
875 match phase with
876 | Some x when not (equal_phase x p) -> acc
877 | _ -> List.fold_right errors ~init:acc ~f)
879 let get_failed_files err phase =
880 files_t_fold (fst err) ~init:Relative_path.Set.empty ~f:(fun source p _ acc ->
881 if not (equal_phase phase p) then
883 else
884 Relative_path.Set.add acc source)
886 (*****************************************************************************)
887 (* Error code printing. *)
888 (*****************************************************************************)
890 let internal_error pos msg = add 0 pos ("Internal error: " ^ msg)
892 let unimplemented_feature pos msg = add 0 pos ("Feature not implemented: " ^ msg)
894 let experimental_feature pos msg =
895 add 0 pos ("Cannot use experimental feature: " ^ msg)
897 let strip_ns id = id |> Utils.strip_ns |> Hh_autoimport.reverse_type
899 let on_error_or_add (on_error : typing_error_callback option) code claim reasons
901 match on_error with
902 | None -> add_error { code; claim; reasons }
903 | Some f -> f ~code claim reasons
905 (*****************************************************************************)
906 (* Parsing errors. *)
907 (*****************************************************************************)
909 let fixme_format pos =
911 (Parsing.err_code Parsing.FixmeFormat)
913 "`HH_FIXME` wrong format, expected `/* HH_FIXME[ERROR_NUMBER] */`"
915 let parsing_error (p, msg) = add (Parsing.err_code Parsing.ParsingError) p msg
917 let xhp_parsing_error (p, msg) =
918 add (Parsing.err_code Parsing.XhpParsingError) p msg
920 (*****************************************************************************)
921 (* Legacy AST / AAST errors *)
922 (*****************************************************************************)
924 let mk_unsupported_trait_use_as pos =
926 code = Naming.err_code Naming.UnsupportedTraitUseAs;
927 claim =
928 ( pos,
929 "Aliasing with `as` within a trait `use` is a PHP feature that is unsupported in Hack"
931 reasons = [];
934 let unsupported_trait_use_as pos = add_error (mk_unsupported_trait_use_as pos)
936 let mk_unsupported_instead_of pos =
938 code = Naming.err_code Naming.UnsupportedInsteadOf;
939 claim = (pos, "`insteadof` is a PHP feature that is unsupported in Hack");
940 reasons = [];
943 let unsupported_instead_of pos = add_error (mk_unsupported_instead_of pos)
945 let mk_invalid_trait_use_as_visibility pos =
947 code = Naming.err_code Naming.InvalidTraitUseAsVisibility;
948 claim = (pos, "Cannot redeclare trait method's visibility in this manner");
949 reasons = [];
952 let invalid_trait_use_as_visibility pos =
953 add_error (mk_invalid_trait_use_as_visibility pos)
955 (*****************************************************************************)
956 (* Naming errors *)
957 (*****************************************************************************)
959 let unexpected_arrow pos cname =
961 (Naming.err_code Naming.UnexpectedArrow)
963 ( "Keys may not be specified for "
964 ^ Markdown_lite.md_codify cname
965 ^ " initialization" )
967 let missing_arrow pos cname =
969 (Naming.err_code Naming.MissingArrow)
971 ( "Keys must be specified for "
972 ^ Markdown_lite.md_codify cname
973 ^ " initialization" )
975 let disallowed_xhp_type pos name =
977 (Naming.err_code Naming.DisallowedXhpType)
979 ( Markdown_lite.md_codify name
980 ^ " is not a valid type. Use `:xhp` or `XHPChild`." )
982 let name_is_reserved name pos =
983 let name = Utils.strip_all_ns name in
985 (Naming.err_code Naming.NameIsReserved)
987 (Markdown_lite.md_codify name ^ " cannot be used as it is reserved.")
989 let dollardollar_unused pos =
991 (Naming.err_code Naming.DollardollarUnused)
993 ( "This expression does not contain a "
994 ^ "usage of the special pipe variable. Did you forget to use the `$$` "
995 ^ "variable?" )
997 let method_name_already_bound pos name =
999 (Naming.err_code Naming.MethodNameAlreadyBound)
1001 ("Method name already bound: " ^ Markdown_lite.md_codify name)
1003 (* Given two equal-length strings, highlights the characters in
1004 the second that differ from the first *)
1005 let highlight_differences base to_highlight =
1006 match List.zip (String.to_list base) (String.to_list to_highlight) with
1007 | List.Or_unequal_lengths.Ok l ->
1008 List.group l ~break:(fun (o1, s1) (o2, s2) ->
1009 not (Bool.equal (Char.equal o1 s1) (Char.equal o2 s2)))
1010 |> List.map ~f:(fun cs ->
1011 let s = List.map cs ~f:snd |> String.of_char_list in
1012 let (c1, c2) = List.hd_exn cs in
1013 if Char.equal c1 c2 then
1015 else
1016 Markdown_lite.md_highlight s)
1017 |> String.concat
1018 | List.Or_unequal_lengths.Unequal_lengths -> to_highlight
1020 let error_name_already_bound name name_prev p p_prev =
1021 let name = strip_ns name in
1022 let name_prev = strip_ns name_prev in
1023 let (claim, reasons) =
1024 ( (p, "Name already bound: " ^ Markdown_lite.md_codify name),
1026 ( p_prev,
1027 if String.equal name name_prev then
1028 "Previous definition is here"
1029 else
1030 "Previous definition "
1031 ^ (highlight_differences name name_prev |> Markdown_lite.md_codify)
1032 ^ " differs only by case " );
1035 let hhi_msg =
1036 "This appears to be defined in an hhi file included in your project "
1037 ^ "root. The hhi files for the standard library are now a part of the "
1038 ^ "typechecker and must be removed from your project. Typically, you can "
1039 ^ "do this by deleting the \"hhi\" directory you copied into your "
1040 ^ "project when first starting with Hack."
1042 let reasons =
1043 if Relative_path.(is_hhi (prefix (Pos.filename p))) then
1044 reasons @ [(p_prev, hhi_msg)]
1045 else if Relative_path.(is_hhi (prefix (Pos.filename p_prev))) then
1046 reasons @ [(p, hhi_msg)]
1047 else
1048 reasons
1050 add_list (Naming.err_code Naming.ErrorNameAlreadyBound) claim reasons
1052 let error_class_attribute_already_bound name name_prev p p_prev =
1053 let name = strip_ns name in
1054 let name_prev = strip_ns name_prev in
1055 let (claim, reasons) =
1056 ( ( p,
1057 "A class and an attribute class cannot share the same name. Conflicting class: "
1058 ^ Markdown_lite.md_codify name ),
1059 [(p_prev, "Previous definition: " ^ Markdown_lite.md_codify name_prev)] )
1061 add_list (Naming.err_code Naming.AttributeClassNameConflict) claim reasons
1063 let unbound_name pos name kind =
1064 let kind_str =
1065 match kind with
1066 | ConstantNamespace -> " (a global constant)"
1067 | FunctionNamespace -> " (a global function)"
1068 | TypeNamespace -> ""
1069 | ClassContext -> " (an object type)"
1070 | TraitContext -> " (a trait)"
1071 | RecordContext -> " (a record type)"
1074 (Naming.err_code Naming.UnboundName)
1076 ("Unbound name: " ^ Markdown_lite.md_codify (strip_ns name) ^ kind_str)
1078 let invalid_fun_pointer pos name =
1080 (Naming.err_code Naming.InvalidFunPointer)
1082 ( "Unbound global function: "
1083 ^ Markdown_lite.md_codify (strip_ns name)
1084 ^ " is not a valid name for fun()" )
1086 let hint_message ?(modifier = "") orig hint hint_pos =
1087 let s =
1089 (not (String.equal orig hint))
1090 && String.equal (String.lowercase orig) (String.lowercase hint)
1091 then
1092 Printf.sprintf
1093 "Did you mean %s%s instead (which only differs by case)?"
1094 modifier
1095 (highlight_differences orig hint |> Markdown_lite.md_codify)
1096 else
1097 Printf.sprintf
1098 "Did you mean %s%s instead?"
1099 modifier
1100 (Markdown_lite.md_codify hint)
1102 (hint_pos, s)
1104 let undefined pos var_name did_you_mean =
1105 let msg =
1106 Printf.sprintf
1107 "Variable %s is undefined, or not always defined."
1108 (Markdown_lite.md_codify var_name)
1110 let suggestion =
1111 match did_you_mean with
1112 | Some (did_you_mean, pos) -> [hint_message var_name did_you_mean pos]
1113 | None -> []
1115 add_list (Naming.err_code Naming.Undefined) (pos, msg) suggestion
1117 let this_reserved pos =
1119 (Naming.err_code Naming.ThisReserved)
1121 "The type parameter `this` is reserved"
1123 let start_with_T pos =
1125 (Naming.err_code Naming.StartWith_T)
1127 "Please make your type parameter start with the letter `T` (capital)"
1129 let already_bound pos name =
1131 (Naming.err_code Naming.NameAlreadyBound)
1133 ("Argument already bound: " ^ Markdown_lite.md_codify name)
1135 let unexpected_typedef pos def_pos expected_kind =
1136 let expected_type = name_context_to_string expected_kind in
1137 add_list
1138 (Naming.err_code Naming.UnexpectedTypedef)
1139 ( pos,
1140 Printf.sprintf
1141 "Expected a %s but got a type alias."
1142 (Markdown_lite.md_codify expected_type) )
1143 [(def_pos, "Alias definition is here.")]
1145 let mk_fd_name_already_bound pos =
1147 code = Naming.err_code Naming.FdNameAlreadyBound;
1148 claim = (pos, "Field name already bound");
1149 reasons = [];
1152 let fd_name_already_bound pos = add_error (mk_fd_name_already_bound pos)
1154 let repeated_record_field name pos prev_pos =
1155 let msg =
1156 Printf.sprintf "Duplicate record field %s" (Markdown_lite.md_codify name)
1158 add_list
1159 (NastCheck.err_code NastCheck.RepeatedRecordFieldName)
1160 (pos, msg)
1161 [(prev_pos, "Previous field is here")]
1163 let unexpected_record_field_name ~field_name ~field_pos ~record_name ~decl_pos =
1164 let msg =
1165 Printf.sprintf
1166 "Record %s has no field %s"
1167 (strip_ns record_name |> Markdown_lite.md_codify)
1168 (Markdown_lite.md_codify field_name)
1170 add_list
1171 (Typing.err_code Typing.RecordUnknownField)
1172 (field_pos, msg)
1173 [(decl_pos, "Definition is here")]
1175 let missing_record_field_name ~field_name ~new_pos ~record_name ~field_decl_pos
1177 let msg =
1178 Printf.sprintf
1179 "Mising required field %s in %s"
1180 (Markdown_lite.md_codify field_name)
1181 (strip_ns record_name |> Markdown_lite.md_codify)
1183 add_list
1184 (Typing.err_code Typing.RecordMissingRequiredField)
1185 (new_pos, msg)
1186 [(field_decl_pos, "Field definition is here")]
1188 let type_not_record id pos =
1190 (Typing.err_code Typing.NotARecord)
1192 (Printf.sprintf
1193 "Expected a record type, but got %s."
1194 (strip_ns id |> Markdown_lite.md_codify))
1196 let primitive_toplevel pos =
1198 (Naming.err_code Naming.PrimitiveToplevel)
1200 "Primitive type annotations are always available and may no longer be referred to in the toplevel namespace."
1202 let primitive_invalid_alias pos used valid =
1204 (Naming.err_code Naming.PrimitiveInvalidAlias)
1206 ( "Invalid Hack type. Using "
1207 ^ Markdown_lite.md_codify used
1208 ^ " in Hack is considered an error. Use "
1209 ^ Markdown_lite.md_codify valid
1210 ^ " instead, to keep the codebase consistent." )
1212 let dynamic_new_in_strict_mode pos =
1214 (Naming.err_code Naming.DynamicNewInStrictMode)
1216 "Cannot use dynamic `new`."
1218 let invalid_type_access_root (pos, id) =
1220 (Naming.err_code Naming.InvalidTypeAccessRoot)
1222 ( Markdown_lite.md_codify id
1223 ^ " must be an identifier for a class, `self`, or `this`" )
1225 let duplicate_user_attribute (pos, name) existing_attr_pos =
1226 add_list
1227 (Naming.err_code Naming.DuplicateUserAttribute)
1228 (pos, "You cannot reuse the attribute " ^ Markdown_lite.md_codify name)
1230 ( existing_attr_pos,
1231 Markdown_lite.md_codify name ^ " was already used here" );
1234 let unbound_attribute_name pos name =
1235 let reason =
1236 if string_starts_with name "__" then
1237 "starts with __ but is not a standard attribute"
1238 else
1239 "does not have a class. Please declare a class for the attribute."
1242 (Naming.err_code Naming.UnboundName)
1244 ( "Unrecognized user attribute: "
1245 ^ (strip_ns name |> Markdown_lite.md_codify)
1246 ^ " "
1247 ^ reason )
1249 let this_no_argument pos =
1250 add (Naming.err_code Naming.ThisNoArgument) pos "`this` expects no arguments"
1252 let object_cast pos =
1254 (Naming.err_code Naming.ObjectCast)
1256 "Casts are only supported for `bool`, `int`, `float` and `string`."
1258 let this_hint_outside_class pos =
1260 (Naming.err_code Naming.ThisHintOutsideClass)
1262 "Cannot use `this` outside of a class"
1264 let this_type_forbidden pos =
1266 (Naming.err_code Naming.ThisMustBeReturn)
1268 "The type `this` cannot be used as a constraint on a class generic, or as the type of a static member variable"
1270 let nonstatic_property_with_lsb pos =
1272 (Naming.err_code Naming.NonstaticPropertyWithLSB)
1274 "`__LSB` attribute may only be used on static properties"
1276 let lowercase_this pos type_ =
1278 (Naming.err_code Naming.LowercaseThis)
1280 ( "Invalid Hack type "
1281 ^ Markdown_lite.md_codify type_
1282 ^ ". Use `this` instead" )
1284 let classname_param pos =
1286 (Naming.err_code Naming.ClassnameParam)
1288 ( "Missing type parameter to `classname`; `classname` is entirely"
1289 ^ " meaningless without one" )
1291 (** Used if higher-kinded types are disabled *)
1292 let typaram_applied_to_type pos x =
1294 (Naming.err_code Naming.HigherKindedTypesUnsupportedFeature)
1296 (Printf.sprintf
1297 "`%s` is a type parameter. Type parameters cannot take type arguments (e.g. `%s<int>` isn't allowed)"
1301 (** Used if higher-kinded types are disabled *)
1302 let tparam_with_tparam pos x =
1303 let param_desc =
1304 match x with
1305 | "_" -> ""
1306 | _ -> Markdown_lite.md_codify x ^ " is a type parameter. "
1309 (Naming.err_code Naming.HigherKindedTypesUnsupportedFeature)
1311 (Printf.sprintf
1312 "%sType parameters cannot themselves have type parameters"
1313 param_desc)
1315 let shadowed_type_param p pos name =
1316 add_list
1317 (Naming.err_code Naming.ShadowedTypeParam)
1318 ( p,
1319 Printf.sprintf
1320 "You cannot re-bind the type parameter %s"
1321 (Markdown_lite.md_codify name) )
1323 ( pos,
1324 Printf.sprintf "%s is already bound here" (Markdown_lite.md_codify name)
1328 let missing_typehint pos =
1329 add (Naming.err_code Naming.MissingTypehint) pos "Please add a type hint"
1331 let expected_variable pos =
1333 (Naming.err_code Naming.ExpectedVariable)
1335 "Was expecting a variable name"
1337 let clone_too_many_arguments pos =
1339 (Naming.err_code Naming.NamingTooManyArguments)
1341 "`__clone` method cannot take arguments"
1343 let naming_too_few_arguments pos =
1344 add (Naming.err_code Naming.NamingTooFewArguments) pos "Too few arguments"
1346 let naming_too_many_arguments pos =
1347 add (Naming.err_code Naming.NamingTooManyArguments) pos "Too many arguments"
1349 let expected_collection pos cn =
1351 (Naming.err_code Naming.ExpectedCollection)
1353 ("Unexpected collection type " ^ (strip_ns cn |> Markdown_lite.md_codify))
1355 let illegal_CLASS pos =
1357 (Naming.err_code Naming.IllegalClass)
1359 "Using `__CLASS__` outside a class or trait"
1361 let illegal_TRAIT pos =
1363 (Naming.err_code Naming.IllegalTrait)
1365 "Using `__TRAIT__` outside a trait"
1367 let lvar_in_obj_get pos =
1369 (Naming.err_code Naming.LvarInObjGet)
1371 "Dynamic method or attribute access is not allowed on a non-dynamic value."
1373 let nullsafe_property_write_context pos =
1375 (Typing.err_code Typing.NullsafePropertyWriteContext)
1377 "`?->` syntax not supported here, this function effectively does a write"
1379 let illegal_fun pos =
1380 let msg =
1381 "The argument to `fun()` must be a single-quoted, constant "
1382 ^ "literal string representing a valid function name."
1384 add (Naming.err_code Naming.IllegalFun) pos msg
1386 let illegal_member_variable_class pos =
1387 let msg =
1388 "Cannot declare a constant named `class`. The name `class` is reserved for the class constant that represents the name of the class"
1390 add (Naming.err_code Naming.IllegalMemberVariableClass) pos msg
1392 let illegal_meth_fun pos =
1393 let msg =
1394 "String argument to `fun()` contains `:`;"
1395 ^ " for static class methods, use"
1396 ^ " `class_meth(Cls::class, 'method_name')`, not `fun('Cls::method_name')`"
1398 add (Naming.err_code Naming.IllegalMethFun) pos msg
1400 let illegal_inst_meth pos =
1401 let msg =
1402 "The argument to `inst_meth()` must be an expression and a "
1403 ^ "constant literal string representing a valid method name."
1405 add (Naming.err_code Naming.IllegalInstMeth) pos msg
1407 let illegal_meth_caller pos =
1408 let msg =
1409 "The two arguments to `meth_caller()` must be:"
1410 ^ "\n - first: `ClassOrInterface::class`"
1411 ^ "\n - second: a single-quoted string literal containing the name"
1412 ^ " of a non-static method of that class"
1414 add (Naming.err_code Naming.IllegalMethCaller) pos msg
1416 let illegal_class_meth pos =
1417 let msg =
1418 "The two arguments to `class_meth()` must be:"
1419 ^ "\n - first: `ValidClassname::class`"
1420 ^ "\n - second: a single-quoted string literal containing the name"
1421 ^ " of a static method of that class"
1423 add (Naming.err_code Naming.IllegalClassMeth) pos msg
1425 let class_meth_non_final_self pos class_name =
1426 let msg =
1427 "`class_meth` with `self::class` does not preserve class calling context.\n"
1428 ^ "Use `static::class`, or `"
1429 ^ strip_ns class_name
1430 ^ "::class` explicitly"
1432 add (Naming.err_code Naming.ClassMethNonFinalSelf) pos msg
1434 let class_meth_non_final_CLASS pos is_trait class_name =
1435 let suggestion =
1436 if not is_trait then
1437 "Use `" ^ strip_ns class_name ^ "::class` explicitly"
1438 else
1441 let msg =
1442 "`class_meth` with `__CLASS__` in non-final classes is not allowed.\n"
1443 ^ suggestion
1445 add (Naming.err_code Naming.ClassMethNonFinalCLASS) pos msg
1447 let assert_banned pos =
1449 (Naming.err_code Naming.CallingAssert)
1451 "assert() is banned in Hack. Did you mean `invariant()`?"
1453 let unexpected_ty_in_tast pos ~actual_ty ~expected_ty =
1455 (Typing.err_code Typing.UnexpectedTy)
1457 ( "Unexpected type in TAST: expected "
1458 ^ Markdown_lite.md_codify expected_ty
1459 ^ ", got "
1460 ^ Markdown_lite.md_codify actual_ty )
1462 let uninstantiable_class usage_pos decl_pos name reason_msgl =
1463 let name = strip_ns name in
1464 let (claim, reasons) =
1465 ( (usage_pos, Markdown_lite.md_codify name ^ " is uninstantiable"),
1466 [(decl_pos, "Declaration is here")] )
1468 let (claim, reasons) =
1469 match reason_msgl with
1470 | (reason_pos, reason_str) :: tail ->
1471 let reasons = tail @ (claim :: reasons) in
1472 let claim = (reason_pos, reason_str ^ " which must be instantiable") in
1473 (claim, reasons)
1474 | [] -> (claim, reasons)
1476 add_list (Typing.err_code Typing.UninstantiableClass) claim reasons
1478 let new_abstract_record (pos, name) =
1479 let name = strip_ns name in
1481 (Typing.err_code Typing.NewAbstractRecord)
1483 (Printf.sprintf
1484 "Cannot create instance of abstract record %s"
1485 (Markdown_lite.md_codify name))
1487 let abstract_const_usage usage_pos decl_pos name =
1488 let name = strip_ns name in
1489 add_list
1490 (Typing.err_code Typing.AbstractConstUsage)
1491 ( usage_pos,
1492 "Cannot reference abstract constant "
1493 ^ Markdown_lite.md_codify name
1494 ^ " directly" )
1495 [(decl_pos, "Declaration is here")]
1497 let concrete_const_interface_override
1498 child_pos parent_pos parent_origin name (on_error : typing_error_callback) =
1499 let parent_origin = strip_ns parent_origin in
1500 on_error
1501 ~code:(Typing.err_code Typing.ConcreteConstInterfaceOverride)
1502 ( child_pos,
1503 "Non-abstract constants defined in an interface cannot be overridden when implementing or extending that interface."
1506 ( parent_pos,
1507 "You could make "
1508 ^ Markdown_lite.md_codify name
1509 ^ " abstract in "
1510 ^ Markdown_lite.md_codify parent_origin
1511 ^ "." );
1514 let interface_const_multiple_defs
1515 child_pos
1516 parent_pos
1517 child_origin
1518 parent_origin
1519 name
1520 (on_error : typing_error_callback) =
1521 let parent_origin = strip_ns parent_origin in
1522 let child_origin = strip_ns child_origin in
1523 on_error
1524 ~code:(Typing.err_code Typing.ConcreteConstInterfaceOverride)
1525 ( child_pos,
1526 "Non-abstract constants defined in an interface cannot conflict with other inherited constants."
1529 ( parent_pos,
1530 Markdown_lite.md_codify name
1531 ^ " inherited from "
1532 ^ Markdown_lite.md_codify parent_origin );
1533 ( child_pos,
1534 "conflicts with constant "
1535 ^ Markdown_lite.md_codify name
1536 ^ " inherited from "
1537 ^ Markdown_lite.md_codify child_origin
1538 ^ "." );
1541 let interface_typeconst_multiple_defs
1542 child_pos
1543 parent_pos
1544 child_origin
1545 parent_origin
1546 name
1547 child_is_abstract
1548 (on_error : typing_error_callback) =
1549 let parent_origin = strip_ns parent_origin in
1550 let child_origin = strip_ns child_origin in
1551 let child =
1552 if child_is_abstract then
1553 "abstract type constant with default value"
1554 else
1555 "concrete type constant"
1557 on_error
1558 ~code:(Typing.err_code Typing.ConcreteConstInterfaceOverride)
1559 ( child_pos,
1560 "Concrete and abstract type constants with default values in an interface cannot conflict with inherited"
1561 ^ " concrete or abstract type constants with default values." )
1563 ( parent_pos,
1564 Markdown_lite.md_codify name
1565 ^ " inherited from "
1566 ^ Markdown_lite.md_codify parent_origin );
1567 ( child_pos,
1568 "conflicts with "
1569 ^ Markdown_lite.md_codify child
1570 ^ " "
1571 ^ Markdown_lite.md_codify name
1572 ^ " inherited from "
1573 ^ Markdown_lite.md_codify child_origin
1574 ^ "." );
1577 let const_without_typehint sid =
1578 let (pos, name) = sid in
1579 let msg =
1580 Printf.sprintf
1581 "Please add a type hint `const SomeType %s`"
1582 (Utils.strip_all_ns name)
1584 add (Naming.err_code Naming.AddATypehint) pos msg
1586 let prop_without_typehint visibility sid =
1587 let (pos, name) = sid in
1588 let msg =
1589 Printf.sprintf "Please add a type hint `%s SomeType %s`" visibility name
1591 add (Naming.err_code Naming.AddATypehint) pos msg
1593 let illegal_constant pos =
1594 add (Naming.err_code Naming.IllegalConstant) pos "Illegal constant value"
1596 let invalid_req_implements pos =
1598 (Naming.err_code Naming.InvalidReqImplements)
1600 "Only traits may use `require implements`"
1602 let invalid_req_extends pos =
1604 (Naming.err_code Naming.InvalidReqExtends)
1606 "Only traits and interfaces may use `require extends`"
1608 let did_you_mean_naming pos name suggest_pos suggest_name =
1609 let name = strip_ns name in
1610 let suggest_name = strip_ns suggest_name in
1611 add_list
1612 (Naming.err_code Naming.DidYouMeanNaming)
1613 (pos, "Could not find " ^ Markdown_lite.md_codify name ^ ".")
1614 [hint_message name suggest_name suggest_pos]
1616 let using_internal_class pos name =
1618 (Naming.err_code Naming.UsingInternalClass)
1620 ( Markdown_lite.md_codify name
1621 ^ " is an implementation internal class that cannot be used directly" )
1623 let too_few_type_arguments p =
1625 (Naming.err_code Naming.TooFewTypeArguments)
1627 "Too few type arguments for this type"
1629 let mk_method_needs_visibility pos =
1631 code = Naming.err_code Naming.MethodNeedsVisibility;
1632 claim =
1633 (pos, "Methods need to be marked `public`, `private`, or `protected`.");
1634 reasons = [];
1637 let method_needs_visibility pos = add_error (mk_method_needs_visibility pos)
1639 let dynamic_class_name_in_strict_mode pos =
1641 (Naming.err_code Naming.DynamicClassNameInStrictMode)
1643 "Cannot use dynamic class name in strict mode"
1645 let xhp_optional_required_attr pos id =
1647 (Naming.err_code Naming.XhpOptionalRequiredAttr)
1649 ( "XHP attribute "
1650 ^ Markdown_lite.md_codify id
1651 ^ " cannot be marked as nullable and `@required`" )
1653 let xhp_required_with_default pos id =
1655 (Naming.err_code Naming.XhpRequiredWithDefault)
1657 ( "XHP attribute "
1658 ^ Markdown_lite.md_codify id
1659 ^ " cannot be marked `@required` and provide a default" )
1661 let array_typehints_disallowed pos =
1663 (Naming.err_code Naming.ArrayTypehintsDisallowed)
1665 "Array typehints are no longer legal; use `varray` or `darray` instead"
1667 let wildcard_hint_disallowed pos =
1669 (Naming.err_code Naming.WildcardHintDisallowed)
1671 "Wildcard typehints are not allowed in this position"
1673 let wildcard_param_disallowed pos =
1675 (Naming.err_code Naming.WildcardTypeParamDisallowed)
1677 "Cannot use anonymous type parameter in this position."
1679 let illegal_use_of_dynamically_callable attr_pos meth_pos visibility =
1680 add_list
1681 (Naming.err_code Naming.IllegalUseOfDynamicallyCallable)
1682 (attr_pos, "`__DynamicallyCallable` can only be used on public methods")
1684 ( meth_pos,
1685 sprintf "But this method is %s" (Markdown_lite.md_codify visibility) );
1688 let dynamically_callable_reified attr_pos =
1690 (NastCheck.err_code NastCheck.DynamicallyCallableReified)
1691 attr_pos
1692 "`__DynamicallyCallable` cannot be used on reified functions or methods"
1694 let parent_in_function_pointer pos parento meth_name =
1695 let suggestion =
1696 match parento with
1697 | None -> "Consider using the name of the parent class explicitly."
1698 | Some id ->
1699 let name = Markdown_lite.md_codify (strip_ns id ^ "::" ^ meth_name) in
1700 "Consider using " ^ name ^ " instead"
1703 (Naming.err_code Naming.ParentInFunctionPointer)
1705 ( "Cannot use `parent::` in a function pointer due to class context ambiguity. "
1706 ^ suggestion )
1708 let self_in_non_final_function_pointer pos cido meth_name =
1709 let suggestion =
1710 match cido with
1711 | None -> ""
1712 | Some id ->
1713 let name = Markdown_lite.md_codify (strip_ns id ^ "::" ^ meth_name) in
1714 "Consider using " ^ name ^ " instead"
1717 (Naming.err_code Naming.SelfInNonFinalFunctionPointer)
1719 ( "Cannot use `self::` in a function pointer in a non-final class due to class context ambiguity. "
1720 ^ suggestion )
1722 let invalid_wildcard_context pos =
1724 (Naming.err_code Naming.InvalidWildcardContext)
1726 "A wildcard can only be used as a context when it is the sole context of a callable parameter in a higher-order function. The parameter must also be referenced with `ctx` in the higher-order function's context list, e.g. `function hof((function ()[_]: void) $f)[ctx $f]: void {}`"
1728 (*****************************************************************************)
1729 (* Init check errors *)
1730 (*****************************************************************************)
1732 let no_construct_parent pos =
1734 (NastCheck.err_code NastCheck.NoConstructParent)
1736 (Utils.sl
1738 "You are extending a class that needs to be initialized\n";
1739 "Make sure you call `parent::__construct`.\n";
1742 let nonstatic_method_in_abstract_final_class pos =
1744 (NastCheck.err_code NastCheck.NonstaticMethodInAbstractFinalClass)
1746 "Abstract final classes cannot have nonstatic methods or constructors."
1748 let constructor_required (pos, name) prop_names =
1749 let name = strip_ns name in
1750 let props_str =
1751 List.map ~f:Markdown_lite.md_codify prop_names |> String.concat ~sep:" "
1754 (NastCheck.err_code NastCheck.ConstructorRequired)
1756 ( "Lacking `__construct`, class "
1757 ^ Markdown_lite.md_codify name
1758 ^ " does not initialize its private member(s): "
1759 ^ props_str )
1761 let not_initialized (pos, cname) props =
1762 let cname = strip_ns cname in
1763 let prop_msgs =
1764 List.map props ~f:(fun (pos, prop) ->
1765 ( pos,
1766 Markdown_lite.md_codify ("$this->" ^ prop) ^ " is not initialized." ))
1768 add_list
1769 (NastCheck.err_code NastCheck.NotInitialized)
1770 ( pos,
1771 "Class "
1772 ^ Markdown_lite.md_codify cname
1773 ^ " has properties that cannot be null and aren't always set in `__construct`."
1775 prop_msgs
1777 let call_before_init pos cv =
1779 (NastCheck.err_code NastCheck.CallBeforeInit)
1781 (Utils.sl
1783 "Until the initialization of `$this` is over,";
1784 " you can only call private methods\n";
1785 "The initialization is not over because ";
1788 if String.equal cv "parent::__construct" then
1789 ["you forgot to call `parent::__construct`"]
1790 else
1792 Markdown_lite.md_codify ("$this->" ^ cv);
1793 " can still potentially be null";
1794 ] ))
1796 (*****************************************************************************)
1797 (* Nast errors check *)
1798 (*****************************************************************************)
1800 let type_arity use_pos def_pos ~expected ~actual =
1801 add_list
1802 (Typing.err_code Typing.TypeArityMismatch)
1803 ( use_pos,
1804 Printf.sprintf
1805 "Wrong number of type arguments (expected %d, got %d)"
1806 expected
1807 actual )
1808 [(def_pos, "Definition is here")]
1810 let abstract_with_body (p, _) =
1812 (NastCheck.err_code NastCheck.AbstractWithBody)
1814 "This method is declared as abstract, but has a body"
1816 let not_abstract_without_body (p, _) =
1818 (NastCheck.err_code NastCheck.NotAbstractWithoutBody)
1820 "This method is not declared as abstract, it must have a body"
1822 let mk_not_abstract_without_typeconst (p, _) =
1824 code = NastCheck.err_code NastCheck.NotAbstractWithoutTypeconst;
1825 claim =
1826 ( p,
1827 "This type constant is not declared as abstract, it must have"
1828 ^ " an assigned type" );
1829 reasons = [];
1832 let not_abstract_without_typeconst node =
1833 add_error (mk_not_abstract_without_typeconst node)
1835 let typeconst_depends_on_external_tparam pos ext_pos ext_name =
1836 add_list
1837 (NastCheck.err_code NastCheck.TypeconstDependsOnExternalTparam)
1838 ( pos,
1839 "A type constant can only use type parameters declared in its own"
1840 ^ " type parameter list" )
1842 ( ext_pos,
1843 Markdown_lite.md_codify ext_name
1844 ^ " was declared as a type parameter here" );
1847 let interface_with_partial_typeconst tconst_pos =
1849 (NastCheck.err_code NastCheck.InterfaceWithPartialTypeconst)
1850 tconst_pos
1851 "An interface cannot contain a partially abstract type constant"
1853 let mk_multiple_xhp_category pos =
1855 code = NastCheck.err_code NastCheck.MultipleXhpCategory;
1856 claim = (pos, "XHP classes can only contain one category declaration");
1857 reasons = [];
1860 let multiple_xhp_category pos = add_error (mk_multiple_xhp_category pos)
1862 let return_in_gen p =
1864 (NastCheck.err_code NastCheck.ReturnInGen)
1866 ( "You cannot return a value in a generator (a generator"
1867 ^ " is a function that uses `yield`)" )
1869 let return_in_finally p =
1871 (NastCheck.err_code NastCheck.ReturnInFinally)
1873 ( "Don't use `return` in a `finally` block;"
1874 ^ " there's nothing to receive the return value" )
1876 let toplevel_break p =
1878 (NastCheck.err_code NastCheck.ToplevelBreak)
1880 "`break` can only be used inside loops or `switch` statements"
1882 let toplevel_continue p =
1884 (NastCheck.err_code NastCheck.ToplevelContinue)
1886 "`continue` can only be used inside loops"
1888 let continue_in_switch p =
1890 (NastCheck.err_code NastCheck.ContinueInSwitch)
1892 ( "In PHP, `continue;` inside a switch statement is equivalent to `break;`."
1893 ^ " Hack does not support this; use `break` if that is what you meant." )
1895 let await_in_sync_function p =
1897 (NastCheck.err_code NastCheck.AwaitInSyncFunction)
1899 "`await` can only be used inside `async` functions"
1901 let interface_use_trait p =
1903 (NastCheck.err_code NastCheck.InterfaceUsesTrait)
1905 "Interfaces cannot use traits"
1907 let static_memoized_function p =
1909 (NastCheck.err_code NastCheck.StaticMemoizedFunction)
1911 "`memoize` is not allowed on static methods in classes that aren't final "
1913 let magic (p, s) =
1915 (NastCheck.err_code NastCheck.Magic)
1917 ( Markdown_lite.md_codify s
1918 ^ " is a magic method and cannot be called directly" )
1920 let non_interface (p : Pos.t) (c2 : string) (verb : string) : 'a =
1922 (NastCheck.err_code NastCheck.NonInterface)
1924 ( "Cannot "
1925 ^ verb
1926 ^ " "
1927 ^ (strip_ns c2 |> Markdown_lite.md_codify)
1928 ^ " - it is not an interface" )
1930 let toString_returns_string pos =
1932 (NastCheck.err_code NastCheck.ToStringReturnsString)
1934 "`__toString` should return a string"
1936 let toString_visibility pos =
1938 (NastCheck.err_code NastCheck.ToStringVisibility)
1940 "`__toString` must have public visibility and cannot be static"
1942 let uses_non_trait (p : Pos.t) (n : string) (t : string) =
1944 (NastCheck.err_code NastCheck.UsesNonTrait)
1946 ( (strip_ns n |> Markdown_lite.md_codify)
1947 ^ " is not a trait. It is "
1949 ^ "." )
1951 let requires_non_class (p : Pos.t) (n : string) (t : string) =
1953 (NastCheck.err_code NastCheck.RequiresNonClass)
1955 ( (strip_ns n |> Markdown_lite.md_codify)
1956 ^ " is not a class. It is "
1958 ^ "." )
1960 let requires_final_class (p : Pos.t) (n : string) =
1962 (NastCheck.err_code NastCheck.RequiresFinalClass)
1964 ((strip_ns n |> Markdown_lite.md_codify) ^ " is not an extendable class.")
1966 let abstract_body pos =
1968 (NastCheck.err_code NastCheck.AbstractBody)
1970 "This method shouldn't have a body"
1972 let interface_with_member_variable pos =
1974 (NastCheck.err_code NastCheck.InterfaceWithMemberVariable)
1976 "Interfaces cannot have member variables"
1978 let interface_with_static_member_variable pos =
1980 (NastCheck.err_code NastCheck.InterfaceWithStaticMemberVariable)
1982 "Interfaces cannot have static variables"
1984 let illegal_function_name pos mname =
1986 (NastCheck.err_code NastCheck.IllegalFunctionName)
1988 ("Illegal function name: " ^ (strip_ns mname |> Markdown_lite.md_codify))
1990 let entrypoint_arguments pos =
1992 (NastCheck.err_code NastCheck.EntryPointArguments)
1994 "`__EntryPoint` functions cannot take arguments."
1996 let variadic_memoize pos =
1998 (NastCheck.err_code NastCheck.VariadicMemoize)
2000 "Memoized functions cannot be variadic."
2002 let abstract_method_memoize pos =
2004 (NastCheck.err_code NastCheck.AbstractMethodMemoize)
2006 "Abstract methods cannot be memoized."
2008 let instance_property_in_abstract_final_class pos =
2010 (NastCheck.err_code NastCheck.InstancePropertyInAbstractFinalClass)
2012 "Abstract final classes cannot have instance properties."
2014 let inout_params_special pos =
2016 (NastCheck.err_code NastCheck.InoutParamsSpecial)
2018 "Methods with special semantics cannot have `inout` parameters."
2020 let inout_params_memoize fpos pos =
2021 let msg1 = (fpos, "Functions with `inout` parameters cannot be memoized") in
2022 let msg2 = (pos, "This is an `inout` parameter") in
2023 add_list (NastCheck.err_code NastCheck.InoutParamsMemoize) msg1 [msg2]
2025 let reading_from_append pos =
2027 (NastCheck.err_code NastCheck.ReadingFromAppend)
2029 "Cannot use `[]` for reading"
2031 let inout_argument_bad_expr pos =
2033 (NastCheck.err_code NastCheck.InoutArgumentBadExpr)
2035 ( "Arguments for `inout` parameters must be local variables or simple "
2036 ^ "subscript expressions on vecs, dicts, keysets, or arrays" )
2038 let illegal_destructor pos =
2040 (NastCheck.err_code NastCheck.IllegalDestructor)
2042 ( "Destructors are not supported in Hack; use other patterns like "
2043 ^ "`IDisposable`/`using` or `try`/`catch` instead." )
2045 let switch_non_terminal_default pos =
2047 (NastCheck.err_code NastCheck.SwitchNonTerminalDefault)
2049 "Default case in `switch` must be terminal"
2051 let switch_multiple_default pos =
2053 (NastCheck.err_code NastCheck.SwitchMultipleDefault)
2055 "There can be only one `default` case in `switch`"
2057 let context_definitions_msg () =
2058 (* Notes:
2059 * - needs to be a thunk because path_of_prefix resolves a reference that is populated at runtime
2060 * - points to the hh_server tmp hhi directory
2061 * - magic numbers are inteded to provide a nicer IDE experience,
2062 * - a Pos is constructed in order to make the link to contexts.hhi clickable
2064 let path =
2065 Relative_path.(
2066 let path =
2067 Path.concat (Path.make (path_of_prefix Hhi)) "coeffect/contexts.hhi"
2069 create Hhi (Path.to_string path))
2071 ( Pos.make_from_lnum_bol_cnum
2072 ~pos_file:path
2073 ~pos_start:(28, 0, 0)
2074 ~pos_end:(28, 0, 23),
2075 "Hack provides a list of supported contexts here" )
2077 let illegal_context pos name =
2078 add_list
2079 NastCheck.(err_code IllegalContext)
2080 ( pos,
2081 "Illegal context: "
2082 ^ (name |> Markdown_lite.md_codify)
2083 ^ "\nCannot use a context defined outside namespace "
2084 ^ Naming_special_names.Coeffects.contexts )
2085 [context_definitions_msg ()]
2087 (*****************************************************************************)
2088 (* Nast terminality *)
2089 (*****************************************************************************)
2091 let case_fallthrough pos1 pos2 =
2092 add_list
2093 (NastCheck.err_code NastCheck.CaseFallthrough)
2094 ( pos1,
2095 "This `switch` has a `case` that implicitly falls through and is "
2096 ^ "not annotated with `// FALLTHROUGH`" )
2098 ( pos2,
2099 "This `case` implicitly falls through. Did you forget to add `break` or `return`?"
2103 let default_fallthrough pos =
2105 (NastCheck.err_code NastCheck.DefaultFallthrough)
2107 ( "This `switch` has a default case that implicitly falls "
2108 ^ "through and is not annotated with `// FALLTHROUGH`" )
2110 (*****************************************************************************)
2111 (* Typing errors *)
2112 (*****************************************************************************)
2114 let visibility_extends
2115 vis pos parent_pos parent_vis (on_error : typing_error_callback) =
2116 let msg1 =
2117 (pos, "This member visibility is: " ^ Markdown_lite.md_codify vis)
2119 let msg2 =
2120 (parent_pos, Markdown_lite.md_codify parent_vis ^ " was expected")
2122 on_error ~code:(Typing.err_code Typing.VisibilityExtends) msg1 [msg2]
2124 let member_not_implemented member_name parent_pos pos defn_pos =
2125 let msg1 =
2126 ( pos,
2127 "This type doesn't implement the method "
2128 ^ Markdown_lite.md_codify member_name )
2130 let msg2 = (parent_pos, "Which is required by this interface") in
2131 let msg3 = (defn_pos, "As defined here") in
2132 add_list (Typing.err_code Typing.MemberNotImplemented) msg1 [msg2; msg3]
2134 let bad_decl_override parent_pos parent_name pos name msgl =
2135 let msg1 =
2136 ( pos,
2137 "Class "
2138 ^ (strip_ns name |> Markdown_lite.md_codify)
2139 ^ " does not correctly implement all required members " )
2141 let msg2 =
2142 ( parent_pos,
2143 "Some members are incompatible with those declared in type "
2144 ^ (strip_ns parent_name |> Markdown_lite.md_codify) )
2146 (* This is a cascading error message *)
2147 add_list (Typing.err_code Typing.BadDeclOverride) msg1 (msg2 :: msgl)
2149 let bad_method_override pos member_name msgl (on_error : typing_error_callback)
2151 let msg =
2152 ( pos,
2153 "The method "
2154 ^ (strip_ns member_name |> Markdown_lite.md_codify)
2155 ^ " is not compatible with the overridden method" )
2157 (* This is a cascading error message *)
2158 on_error ~code:(Typing.err_code Typing.BadMethodOverride) msg msgl
2160 let bad_prop_override pos member_name msgl (on_error : typing_error_callback) =
2161 let msg =
2162 ( pos,
2163 "The property "
2164 ^ (strip_ns member_name |> Markdown_lite.md_codify)
2165 ^ " has the wrong type" )
2167 (* This is a cascading error message *)
2168 on_error ~code:(Typing.err_code Typing.BadMethodOverride) msg msgl
2170 let bad_enum_decl pos msgl =
2171 let msg = (pos, "This enum declaration is invalid.") in
2172 (* This is a cascading error message *)
2173 add_list (Typing.err_code Typing.BadEnumExtends) msg msgl
2175 let missing_constructor pos (on_error : typing_error_callback) =
2176 on_error
2177 ~code:(Typing.err_code Typing.MissingConstructor)
2178 (pos, "The constructor is not implemented")
2181 let typedef_trail_entry pos = (pos, "Typedef definition comes from here")
2183 let abstract_tconst_not_allowed pos (p, tconst_name) =
2184 add_list
2185 (Typing.err_code Typing.AbstractTconstNotAllowed)
2186 (pos, "An abstract type constant is not allowed in this position.")
2188 ( p,
2189 Printf.sprintf
2190 "%s is abstract here."
2191 (Markdown_lite.md_codify tconst_name) );
2194 let add_with_trail code claim reasons trail =
2195 add_list code claim (reasons @ List.map trail typedef_trail_entry)
2197 let enum_constant_type_bad pos ty_pos ty trail =
2198 add_with_trail
2199 (Typing.err_code Typing.EnumConstantTypeBad)
2200 (pos, "Enum constants must be an `int` or `string`")
2201 [(ty_pos, "Not " ^ Markdown_lite.md_codify ty)]
2202 trail
2204 let enum_type_bad pos ty_dependent ty trail =
2205 let ty = Markdown_lite.md_codify ty in
2206 let msg =
2207 if ty_dependent then
2208 "Invalid base type for an enum class: "
2209 else
2210 "Enums must be `int` or `string` or `arraykey`, not "
2212 add_with_trail (Typing.err_code Typing.EnumTypeBad) (pos, msg ^ ty) [] trail
2214 let enum_type_typedef_nonnull pos =
2216 (Typing.err_code Typing.EnumTypeTypedefNonnull)
2218 "Can't use `typedef` that resolves to nonnull in enum"
2220 let enum_switch_redundant const first_pos second_pos =
2221 add_list
2222 (Typing.err_code Typing.EnumSwitchRedundant)
2223 (second_pos, "Redundant `case` statement")
2224 [(first_pos, Markdown_lite.md_codify const ^ " already handled here")]
2226 let enum_switch_nonexhaustive pos missing enum_pos =
2227 add_list
2228 (Typing.err_code Typing.EnumSwitchNonexhaustive)
2229 ( pos,
2230 "`switch` statement nonexhaustive; the following cases are missing: "
2231 ^ (List.map ~f:Markdown_lite.md_codify missing |> String.concat ~sep:", ")
2233 [(enum_pos, "Enum declared here")]
2235 let enum_switch_redundant_default pos enum_pos =
2236 add_list
2237 (Typing.err_code Typing.EnumSwitchRedundantDefault)
2238 ( pos,
2239 "All cases already covered; a redundant `default` case prevents "
2240 ^ "detecting future errors. If your goal is to guard against "
2241 ^ "invalid values for this type, do an `is` check before the switch." )
2242 [(enum_pos, "Enum declared here")]
2244 let enum_switch_not_const pos =
2246 (Typing.err_code Typing.EnumSwitchNotConst)
2248 "Case in `switch` on enum is not an enum constant"
2250 let enum_switch_wrong_class pos expected got =
2252 (Typing.err_code Typing.EnumSwitchWrongClass)
2254 ( "Switching on enum "
2255 ^ Markdown_lite.md_codify expected
2256 ^ " but using constant from "
2257 ^ Markdown_lite.md_codify got )
2259 let invalid_shape_field_name p =
2261 (Typing.err_code Typing.InvalidShapeFieldName)
2263 "Was expecting a constant string, class constant, or int (for shape access)"
2265 let invalid_shape_field_name_empty p =
2267 (Typing.err_code Typing.InvalidShapeFieldNameEmpty)
2269 "A shape field name cannot be an empty string"
2271 let invalid_shape_field_type pos ty_pos ty trail =
2272 add_with_trail
2273 (Typing.err_code Typing.InvalidShapeFieldType)
2274 (pos, "A shape field name must be an `int` or `string`")
2275 [(ty_pos, "Not " ^ ty)]
2276 trail
2278 let invalid_shape_field_literal key_pos witness_pos =
2279 add_list
2280 (Typing.err_code Typing.InvalidShapeFieldLiteral)
2281 (key_pos, "Shape uses literal string as field name")
2282 [(witness_pos, "But expected a class constant")]
2284 let invalid_shape_field_const key_pos witness_pos =
2285 add_list
2286 (Typing.err_code Typing.InvalidShapeFieldConst)
2287 (key_pos, "Shape uses class constant as field name")
2288 [(witness_pos, "But expected a literal string")]
2290 let shape_field_class_mismatch key_pos witness_pos key_class witness_class =
2291 add_list
2292 (Typing.err_code Typing.ShapeFieldClassMismatch)
2293 ( key_pos,
2294 "Shape field name is class constant from "
2295 ^ Markdown_lite.md_codify key_class )
2297 ( witness_pos,
2298 "But expected constant from " ^ Markdown_lite.md_codify witness_class );
2301 let shape_field_type_mismatch key_pos witness_pos key_ty witness_ty =
2302 add_list
2303 (Typing.err_code Typing.ShapeFieldTypeMismatch)
2304 (key_pos, "Shape field name is " ^ key_ty ^ " class constant")
2305 [(witness_pos, "But expected " ^ witness_ty)]
2307 let missing_field pos1 pos2 name (on_error : typing_error_callback) =
2308 on_error
2309 ~code:(Typing.err_code Typing.MissingField)
2310 (pos1, "The field " ^ Markdown_lite.md_codify name ^ " is missing")
2311 [(pos2, "The field " ^ Markdown_lite.md_codify name ^ " is defined")]
2313 let shape_fields_unknown pos1 pos2 (on_error : typing_error_callback) =
2314 on_error
2315 ~code:(Typing.err_code Typing.ShapeFieldsUnknown)
2316 ( pos1,
2317 "This shape type allows unknown fields, and so it may contain fields other than those explicitly declared in its declaration."
2320 ( pos2,
2321 "It is incompatible with a shape that does not allow unknown fields." );
2324 let invalid_shape_remove_key p =
2326 (Typing.err_code Typing.InvalidShapeRemoveKey)
2328 "You can only unset fields of **local** variables"
2330 let unification_cycle pos ty =
2331 add_list
2332 (Typing.err_code Typing.UnificationCycle)
2333 ( pos,
2334 "Type circularity: in order to type-check this expression it "
2335 ^ "is necessary for a type [rec] to be equal to type "
2336 ^ Markdown_lite.md_codify ty )
2339 let violated_constraint
2340 p_cstr (p_tparam, tparam) left right (on_error : typing_error_callback) =
2341 on_error
2342 ~code:(Typing.err_code Typing.TypeConstraintViolation)
2343 (p_cstr, "Some type constraint(s) are violated here")
2345 ( p_tparam,
2346 Printf.sprintf
2347 "%s is a constrained type parameter"
2348 (Markdown_lite.md_codify tparam) );
2350 @ left
2351 @ right )
2353 let method_variance pos =
2355 (Typing.err_code Typing.MethodVariance)
2357 "Covariance or contravariance is not allowed in type parameter of method or function."
2359 let explain_constraint ~use_pos ~definition_pos ~param_name claim reasons =
2360 let inst_msg = "Some type constraint(s) here are violated" in
2361 (* There may be multiple constraints instantiated at one spot; avoid
2362 * duplicating the instantiation message *)
2363 let (p, msg) = claim in
2364 let msgl =
2365 if String.equal msg inst_msg && Pos.equal p use_pos then
2366 reasons
2367 else
2368 claim :: reasons
2370 let name = strip_ns param_name in
2371 add_list
2372 (Typing.err_code Typing.TypeConstraintViolation)
2373 (use_pos, inst_msg)
2374 ( ( definition_pos,
2375 Markdown_lite.md_codify name ^ " is a constrained type parameter" )
2376 :: msgl )
2378 let explain_where_constraint ~in_class ~use_pos ~definition_pos claim reasons =
2379 let callsite_ty =
2380 if in_class then
2381 "class"
2382 else
2383 "method"
2385 let definition_head =
2386 Printf.sprintf "This is the %s with `where` type constraints" callsite_ty
2388 let inst_msg = "A `where` type constraint is violated here" in
2389 add_list
2390 (Typing.err_code Typing.TypeConstraintViolation)
2391 (use_pos, inst_msg)
2392 ([(definition_pos, definition_head)] @ (claim :: reasons))
2394 let explain_tconst_where_constraint ~use_pos ~definition_pos msgl =
2395 let inst_msg = "A `where` type constraint is violated here" in
2396 add_list
2397 (Typing.err_code Typing.TypeConstraintViolation)
2398 (use_pos, inst_msg)
2400 ( definition_pos,
2401 "This method's `where` constraints contain a generic type access" );
2403 @ msgl )
2405 let format_string pos snippet s class_pos fname class_suggest =
2406 add_list
2407 (Typing.err_code Typing.FormatString)
2408 ( pos,
2409 "Invalid format string "
2410 ^ Markdown_lite.md_codify snippet
2411 ^ " in "
2412 ^ Markdown_lite.md_codify ("\"" ^ s ^ "\"") )
2414 ( class_pos,
2415 "You can add a new format specifier by adding "
2416 ^ Markdown_lite.md_codify (fname ^ "()")
2417 ^ " to "
2418 ^ Markdown_lite.md_codify class_suggest );
2421 let expected_literal_format_string pos =
2423 (Typing.err_code Typing.ExpectedLiteralFormatString)
2425 "This argument must be a literal format string"
2427 let re_prefixed_non_string pos non_strings =
2429 (Typing.err_code Typing.RePrefixedNonString)
2431 (non_strings ^ " are not allowed to be to be `re`-prefixed")
2433 let bad_regex_pattern pos s =
2435 (Typing.err_code Typing.BadRegexPattern)
2437 ("Bad regex pattern; " ^ s ^ ".")
2439 let generic_array_strict p =
2441 (Typing.err_code Typing.GenericArrayStrict)
2443 "You cannot have an array without generics in strict mode"
2445 let option_return_only_typehint p kind =
2446 let (typehint, reason) =
2447 match kind with
2448 | `void -> ("?void", "only return implicitly")
2449 | `noreturn -> ("?noreturn", "never return")
2452 (Typing.err_code Typing.OptionReturnOnlyTypehint)
2454 ( Markdown_lite.md_codify typehint
2455 ^ " is a nonsensical typehint; a function cannot both "
2456 ^ reason
2457 ^ " and return null." )
2459 let tuple_syntax p =
2461 (Typing.err_code Typing.TupleSyntax)
2463 "Did you want a *tuple*? Try `(X,Y)`, not `tuple<X,Y>`"
2465 let redeclaring_missing_method p trait_method =
2467 (Typing.err_code Typing.RedeclaringMissingMethod)
2469 ( "Attempting to redeclare a trait method "
2470 ^ Markdown_lite.md_codify trait_method
2471 ^ " which was never inherited. "
2472 ^ "You might be trying to redeclare a non-static method as `static` or vice-versa."
2475 let expecting_type_hint p =
2476 add (Typing.err_code Typing.ExpectingTypeHint) p "Was expecting a type hint"
2478 let expecting_type_hint_variadic p =
2480 (Typing.err_code Typing.ExpectingTypeHintVariadic)
2482 "Was expecting a type hint on this variadic parameter"
2484 let expecting_return_type_hint p =
2486 (Typing.err_code Typing.ExpectingReturnTypeHint)
2488 "Was expecting a return type hint"
2490 let duplicate_using_var pos =
2492 (Typing.err_code Typing.DuplicateUsingVar)
2494 "Local variable already used in `using` statement"
2496 let illegal_disposable pos verb =
2498 (Typing.err_code Typing.IllegalDisposable)
2500 ("Disposable objects must only be " ^ verb ^ " in a `using` statement")
2502 let escaping_disposable pos =
2504 (Typing.err_code Typing.EscapingDisposable)
2506 ( "Variable from `using` clause may only be used as receiver in method invocation "
2507 ^ "or passed to function with `<<__AcceptDisposable>>` parameter attribute"
2510 let escaping_disposable_parameter pos =
2512 (Typing.err_code Typing.EscapingDisposableParameter)
2514 ( "Parameter with `<<__AcceptDisposable>>` attribute may only be used as receiver in method invocation "
2515 ^ "or passed to another function with `<<__AcceptDisposable>>` parameter attribute"
2518 let escaping_this pos =
2520 (Typing.err_code Typing.EscapingThis)
2522 ( "`$this` implementing `IDisposable` or `IAsyncDisposable` may only be used as receiver in method invocation "
2523 ^ "or passed to another function with `<<__AcceptDisposable>>` parameter attribute"
2526 let must_extend_disposable pos =
2528 (Typing.err_code Typing.MustExtendDisposable)
2530 "A disposable type may not extend a class or use a trait that is not disposable"
2532 let accept_disposable_invariant pos1 pos2 (on_error : typing_error_callback) =
2533 let msg1 = (pos1, "This parameter is marked `<<__AcceptDisposable>>`") in
2534 let msg2 = (pos2, "This parameter is not marked `<<__AcceptDisposable>>`") in
2535 on_error ~code:(Typing.err_code Typing.AcceptDisposableInvariant) msg1 [msg2]
2537 let ifc_external_contravariant pos1 pos2 (on_error : typing_error_callback) =
2538 let msg1 =
2539 ( pos1,
2540 "Parameters with `<<__External>>` must be overridden by other parameters with <<__External>>. This parameter is marked `<<__External>>`"
2543 let msg2 = (pos2, "But this parameter is not marked `<<__External>>`") in
2544 on_error ~code:(Typing.err_code Typing.IFCExternalContravariant) msg1 [msg2]
2546 let field_kinds pos1 pos2 =
2547 add_list
2548 (Typing.err_code Typing.FieldKinds)
2549 (pos1, "You cannot use this kind of field (value)")
2550 [(pos2, "Mixed with this kind of field (key => value)")]
2552 let unbound_name_typing pos name =
2554 (Typing.err_code Typing.UnboundNameTyping)
2556 ("Unbound name (typing): " ^ Markdown_lite.md_codify (strip_ns name))
2558 let unbound_name_type_constant_access ~access_pos ~name_pos name =
2559 add_list
2560 (Typing.err_code Typing.UnboundNameTypeConstantAccess)
2561 ( access_pos,
2562 "Unbound name "
2563 ^ Markdown_lite.md_codify (strip_ns name)
2564 ^ " in type constant access" )
2565 ( []
2567 if Pos.equal name_pos access_pos then
2569 else
2570 [(name_pos, "Unbound name is here")] )
2572 let previous_default p =
2574 (Typing.err_code Typing.PreviousDefault)
2576 ( "A previous parameter has a default value.\n"
2577 ^ "Remove all the default values for the preceding parameters,\n"
2578 ^ "or add a default value to this one." )
2580 let return_only_typehint p kind =
2581 let msg =
2582 match kind with
2583 | `void -> "void"
2584 | `noreturn -> "noreturn"
2587 (Naming.err_code Naming.ReturnOnlyTypehint)
2589 ( "The "
2590 ^ Markdown_lite.md_codify msg
2591 ^ " typehint can only be used to describe a function return type" )
2593 let unexpected_type_arguments p =
2595 (Naming.err_code Naming.UnexpectedTypeArguments)
2597 "Type arguments are not expected for this type"
2599 let too_many_type_arguments p =
2601 (Naming.err_code Naming.TooManyTypeArguments)
2603 "Too many type arguments for this type"
2605 let return_in_void pos1 pos2 =
2606 add_list
2607 (Typing.err_code Typing.ReturnInVoid)
2608 (pos1, "You cannot return a value")
2609 [(pos2, "This is a `void` function")]
2611 let this_var_outside_class p =
2613 (Typing.err_code Typing.ThisVarOutsideClass)
2615 "Can't use `$this` outside of a class"
2617 let unbound_global cst_pos =
2619 (Typing.err_code Typing.UnboundGlobal)
2620 cst_pos
2621 "Unbound global constant (Typing)"
2623 let private_inst_meth ~def_pos ~use_pos =
2624 add_list
2625 (Typing.err_code Typing.PrivateInstMeth)
2626 ( use_pos,
2627 "You cannot use this method with `inst_meth` (whether you are in the same class or not)."
2629 [(def_pos, "It is declared as `private` here")]
2631 let protected_inst_meth ~def_pos ~use_pos =
2632 add_list
2633 (Typing.err_code Typing.ProtectedInstMeth)
2634 ( use_pos,
2635 "You cannot use this method with `inst_meth` (whether you are in the same class hierarchy or not)."
2637 [(def_pos, "It is declared as `protected` here")]
2639 let private_class_meth ~def_pos ~use_pos =
2640 add_list
2641 (Typing.err_code Typing.PrivateClassMeth)
2642 ( use_pos,
2643 "You cannot use this method with `class_meth` (whether you are in the same class or not)."
2645 [(def_pos, "It is declared as `private` here")]
2647 let protected_class_meth ~def_pos ~use_pos =
2648 add_list
2649 (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")]
2655 let array_cast pos =
2657 (Typing.err_code Typing.ArrayCast)
2659 "(array) cast forbidden; arrays with unspecified key and value types are not allowed"
2661 let string_cast pos ty =
2662 add (Typing.err_code Typing.StringCast) pos
2663 @@ Printf.sprintf
2664 "Cannot cast a value of type %s to string. Only primitives may be used in a `(string)` cast."
2665 (Markdown_lite.md_codify ty)
2667 let nullable_cast pos ty ty_pos =
2668 add_list
2669 (Typing.err_code Typing.NullableCast)
2670 (pos, "Casting from a nullable type is forbidden")
2671 [(ty_pos, "This is " ^ Markdown_lite.md_codify ty)]
2673 let static_outside_class pos =
2675 (Typing.err_code Typing.StaticOutsideClass)
2677 "`static` is undefined outside of a class"
2679 let self_outside_class pos =
2681 (Typing.err_code Typing.SelfOutsideClass)
2683 "`self` is undefined outside of a class"
2685 let new_inconsistent_construct new_pos (cpos, cname) kind =
2686 let name = strip_ns cname in
2687 let preamble =
2688 match kind with
2689 | `static -> "Can't use `new static()` for " ^ Markdown_lite.md_codify name
2690 | `classname ->
2691 "Can't use `new` on " ^ Markdown_lite.md_codify ("classname<" ^ name ^ ">")
2693 add_list
2694 (Typing.err_code Typing.NewStaticInconsistent)
2695 ( new_pos,
2696 preamble
2697 ^ "; `__construct` arguments are not guaranteed to be consistent in child classes"
2700 ( cpos,
2701 "This declaration is neither `final` nor uses the `<<__ConsistentConstruct>>` attribute"
2705 let undefined_parent pos =
2707 (Typing.err_code Typing.UndefinedParent)
2709 "The parent class is undefined"
2711 let parent_outside_class pos =
2713 (Typing.err_code Typing.ParentOutsideClass)
2715 "`parent` is undefined outside of a class"
2717 let parent_abstract_call meth_name call_pos decl_pos =
2718 add_list
2719 (Typing.err_code Typing.AbstractCall)
2720 ( call_pos,
2721 "Cannot call "
2722 ^ Markdown_lite.md_codify ("parent::" ^ meth_name ^ "()")
2723 ^ "; it is abstract" )
2724 [(decl_pos, "Declaration is here")]
2726 let self_abstract_call meth_name call_pos decl_pos =
2727 add_list
2728 (Typing.err_code Typing.AbstractCall)
2729 ( call_pos,
2730 "Cannot call "
2731 ^ Markdown_lite.md_codify ("self::" ^ meth_name ^ "()")
2732 ^ "; it is abstract. Did you mean "
2733 ^ Markdown_lite.md_codify ("static::" ^ meth_name ^ "()")
2734 ^ "?" )
2735 [(decl_pos, "Declaration is here")]
2737 let classname_abstract_call cname meth_name call_pos decl_pos =
2738 let cname = strip_ns cname in
2739 add_list
2740 (Typing.err_code Typing.AbstractCall)
2741 ( call_pos,
2742 "Cannot call "
2743 ^ Markdown_lite.md_codify (cname ^ "::" ^ meth_name ^ "()")
2744 ^ "; it is abstract" )
2745 [(decl_pos, "Declaration is here")]
2747 let static_synthetic_method cname meth_name call_pos decl_pos =
2748 let cname = strip_ns cname in
2749 add_list
2750 (Typing.err_code Typing.StaticSyntheticMethod)
2751 ( call_pos,
2752 "Cannot call "
2753 ^ Markdown_lite.md_codify (cname ^ "::" ^ meth_name ^ "()")
2754 ^ "; "
2755 ^ Markdown_lite.md_codify meth_name
2756 ^ " is not defined in "
2757 ^ Markdown_lite.md_codify cname )
2758 [(decl_pos, "Declaration is here")]
2760 let isset_in_strict pos =
2762 (Typing.err_code Typing.IssetEmptyInStrict)
2764 ( "`isset` tends to hide errors due to variable typos and so is limited to dynamic checks in "
2765 ^ "`strict` mode" )
2767 let unset_nonidx_in_strict pos msgs =
2768 add_list
2769 (Typing.err_code Typing.UnsetNonidxInStrict)
2770 ( pos,
2771 "In `strict` mode, `unset` is banned except on dynamic, "
2772 ^ "darray, keyset, or dict indexing" )
2773 msgs
2775 let unpacking_disallowed_builtin_function pos name =
2776 let name = strip_ns name in
2778 (Typing.err_code Typing.UnpackingDisallowed)
2780 ("Arg unpacking is disallowed for " ^ Markdown_lite.md_codify name)
2782 let invalid_destructure pos1 pos2 ty (on_error : typing_error_callback) =
2783 on_error
2784 ~code:(Typing.err_code Typing.InvalidDestructure)
2785 ( pos1,
2786 "This expression cannot be destructured with a `list(...)` expression" )
2787 [(pos2, "This is " ^ Markdown_lite.md_codify ty)]
2789 let unpack_array_required_argument p fp (on_error : typing_error_callback) =
2790 on_error
2791 ~code:(Typing.err_code Typing.SplatArrayRequired)
2792 (p, "An array cannot be unpacked into the required arguments of a function")
2793 [(fp, "Definition is here")]
2795 let unpack_array_variadic_argument p fp (on_error : typing_error_callback) =
2796 on_error
2797 ~code:(Typing.err_code Typing.SplatArrayRequired)
2798 ( p,
2799 "A function that receives an unpacked array as an argument must have a variadic parameter to accept the elements of the array"
2801 [(fp, "Definition is here")]
2803 let array_get_arity pos1 name pos2 =
2804 add_list
2805 (Typing.err_code Typing.ArrayGetArity)
2806 (pos1, "You cannot use this " ^ (strip_ns name |> Markdown_lite.md_codify))
2807 [(pos2, "It is missing its type parameters")]
2809 let typing_error pos msg = add (Typing.err_code Typing.GenericUnify) pos msg
2811 let undefined_field ~use_pos ~name ~shape_type_pos =
2812 add_list
2813 (Typing.err_code Typing.UndefinedField)
2814 (use_pos, "The field " ^ Markdown_lite.md_codify name ^ " is undefined")
2815 [(shape_type_pos, "Definition is here")]
2817 let array_access code pos1 pos2 ty =
2818 add_list
2819 (Typing.err_code code)
2820 (pos1, "This is not an object of type `KeyedContainer`, this is " ^ ty)
2821 ( if not (phys_equal pos2 Pos.none) then
2822 [(pos2, "Definition is here")]
2823 else
2824 [] )
2826 let array_access_read = array_access Typing.ArrayAccessRead
2828 let array_access_write = array_access Typing.ArrayAccessWrite
2830 let keyset_set pos1 pos2 =
2831 add_list
2832 (Typing.err_code Typing.KeysetSet)
2833 (pos1, "Elements in a keyset cannot be assigned, use append instead.")
2834 ( if not (phys_equal pos2 Pos.none) then
2835 [(pos2, "Definition is here")]
2836 else
2837 [] )
2839 let array_append pos1 pos2 ty =
2840 add_list
2841 (Typing.err_code Typing.ArrayAppend)
2842 (pos1, ty ^ " does not allow array append")
2843 ( if not (phys_equal pos2 Pos.none) then
2844 [(pos2, "Definition is here")]
2845 else
2846 [] )
2848 let const_mutation pos1 pos2 ty =
2849 add_list
2850 (Typing.err_code Typing.ConstMutation)
2851 (pos1, "You cannot mutate this")
2852 ( if not (phys_equal pos2 Pos.none) then
2853 [(pos2, "This is " ^ ty)]
2854 else
2855 [] )
2857 let expected_class ?(suffix = "") pos =
2859 (Typing.err_code Typing.ExpectedClass)
2861 ("Was expecting a class" ^ suffix)
2863 let unknown_type description pos r =
2864 let msg = "Was expecting " ^ description ^ " but type is unknown" in
2865 add_list (Typing.err_code Typing.UnknownType) (pos, msg) r
2867 let not_found_hint orig hint =
2868 match hint with
2869 | `no_hint -> None
2870 | `closest (pos, v) ->
2871 Some (hint_message ~modifier:"static method " orig v pos)
2872 | `did_you_mean (pos, v) -> Some (hint_message orig v pos)
2874 let snot_found_hint orig hint =
2875 match hint with
2876 | `no_hint -> None
2877 | `closest (pos, v) ->
2878 Some (hint_message ~modifier:"instance method " orig v pos)
2879 | `did_you_mean (pos, v) -> Some (hint_message orig v pos)
2881 let string_of_class_member_kind = function
2882 | `class_constant -> "class constant"
2883 | `static_method -> "static method"
2884 | `class_variable -> "class variable"
2885 | `class_typeconst -> "type constant"
2886 | `method_ -> "method"
2887 | `property -> "property"
2889 let smember_not_found
2890 kind
2892 (cpos, class_name)
2893 member_name
2894 hint
2895 (on_error : typing_error_callback) =
2896 let kind = string_of_class_member_kind kind in
2897 let class_name = strip_ns class_name in
2898 let msg =
2899 Printf.sprintf
2900 "No %s %s in %s"
2901 kind
2902 (Markdown_lite.md_codify member_name)
2903 (Markdown_lite.md_codify class_name)
2905 on_error
2906 ~code:(Typing.err_code Typing.SmemberNotFound)
2907 (pos, msg)
2908 (let hint =
2909 match snot_found_hint member_name hint with
2910 | None -> []
2911 | Some hint -> [hint]
2913 hint
2915 ( cpos,
2916 "Declaration of " ^ Markdown_lite.md_codify class_name ^ " is here"
2920 let member_not_found
2921 kind
2923 (cpos, type_name)
2924 member_name
2925 hint
2926 reason
2927 (on_error : typing_error_callback) =
2928 let type_name = strip_ns type_name |> Markdown_lite.md_codify in
2929 let kind =
2930 match kind with
2931 | `method_ -> "instance method"
2932 | `property -> "property"
2934 let msg =
2935 Printf.sprintf
2936 "No %s %s in %s"
2937 kind
2938 (Markdown_lite.md_codify member_name)
2939 type_name
2941 on_error
2942 ~code:(Typing.err_code Typing.MemberNotFound)
2943 (pos, msg)
2944 (let hint =
2945 match not_found_hint member_name hint with
2946 | None -> []
2947 | Some hint -> [hint]
2949 hint @ reason @ [(cpos, "Declaration of " ^ type_name ^ " is here")])
2951 let expr_tree_unsupported_operator cls_name meth_name pos ~is_method =
2952 let msg =
2953 match String.chop_prefix meth_name ~prefix:"__to" with
2954 | Some type_name ->
2955 (* Complain about usage like `if ($not_bool)` that's virtualized to
2956 `if ($not_bool->__toBool())`.
2958 Printf.sprintf
2959 "`%s` cannot be used in a %s position (it has no %s method named `%s`)"
2960 cls_name
2961 (String.lowercase type_name)
2962 ( if is_method then
2963 "instance"
2964 else
2965 "static" )
2966 meth_name
2967 | None ->
2968 (* Complain about usage like `$not_int +` that's virtualized to
2969 `$not_int->__plus(...)`.
2971 Printf.sprintf
2972 "`%s` does not support this operator (it has no %s method named `%s`)"
2973 cls_name
2974 ( if is_method then
2975 "instance"
2976 else
2977 "static" )
2978 meth_name
2980 add (Typing.err_code Typing.MemberNotFound) pos msg
2982 let parent_in_trait pos =
2984 (Typing.err_code Typing.ParentInTrait)
2986 "You can only use `parent::` in traits that specify `require extends SomeClass`"
2988 let parent_undefined pos =
2989 add (Typing.err_code Typing.ParentUndefined) pos "parent is undefined"
2991 let constructor_no_args pos =
2993 (Typing.err_code Typing.ConstructorNoArgs)
2995 "This constructor expects no argument"
2997 let visibility p msg1 p_vis msg2 =
2998 add_list (Typing.err_code Typing.Visibility) (p, msg1) [(p_vis, msg2)]
3000 let typing_too_many_args expected actual pos pos_def on_error =
3001 on_error_or_add
3002 on_error
3003 (Typing.err_code Typing.TypingTooManyArgs)
3004 ( pos,
3005 Printf.sprintf
3006 "Too many arguments (expected %d but got %d)"
3007 expected
3008 actual )
3009 [(pos_def, "Definition is here")]
3011 let typing_too_few_args required actual pos pos_def on_error =
3012 on_error_or_add
3013 on_error
3014 (Typing.err_code Typing.TypingTooFewArgs)
3015 ( pos,
3016 Printf.sprintf
3017 "Too few arguments (required %d but got %d)"
3018 required
3019 actual )
3020 [(pos_def, "Definition is here")]
3022 let bad_call pos ty =
3024 (Typing.err_code Typing.BadCall)
3026 ("This call is invalid, this is not a function, it is " ^ ty)
3028 let extend_final extend_pos decl_pos name =
3029 let name = strip_ns name in
3030 add_list
3031 (Typing.err_code Typing.ExtendFinal)
3032 (extend_pos, "You cannot extend final class " ^ Markdown_lite.md_codify name)
3033 [(decl_pos, "Declaration is here")]
3035 let extend_non_abstract_record name extend_pos decl_pos =
3036 let name = strip_ns name in
3037 let msg =
3038 Printf.sprintf
3039 "Cannot extend record %s because it isn't abstract"
3040 (Markdown_lite.md_codify name)
3042 add_list
3043 (Typing.err_code Typing.ExtendFinal)
3044 (extend_pos, msg)
3045 [(decl_pos, "Declaration is here")]
3047 let extend_sealed child_pos parent_pos parent_name parent_kind verb =
3048 let name = strip_ns parent_name in
3049 add_list
3050 (Typing.err_code Typing.ExtendSealed)
3051 ( child_pos,
3052 "You cannot "
3053 ^ verb
3054 ^ " sealed "
3055 ^ parent_kind
3056 ^ " "
3057 ^ Markdown_lite.md_codify name )
3058 [(parent_pos, "Declaration is here")]
3060 let trait_prop_const_class pos x =
3062 (Typing.err_code Typing.TraitPropConstClass)
3064 ( "Trait declaration of non-const property "
3065 ^ Markdown_lite.md_codify x
3066 ^ " is incompatible with a const class" )
3068 let read_before_write (pos, v) =
3070 (Typing.err_code Typing.ReadBeforeWrite)
3072 (Utils.sl
3074 "Read access to ";
3075 Markdown_lite.md_codify ("$this->" ^ v);
3076 " before initialization";
3079 let implement_abstract ~is_final pos1 pos2 kind x =
3080 let name = "abstract " ^ kind ^ " " ^ Markdown_lite.md_codify x in
3081 let msg1 =
3082 if is_final then
3083 "This class was declared as `final`. It must provide an implementation for the "
3084 ^ name
3085 else
3086 "This class must be declared `abstract`, or provide an implementation for the "
3087 ^ name
3089 add_list
3090 (Typing.err_code Typing.ImplementAbstract)
3091 (pos1, msg1)
3092 [(pos2, "Declaration is here")]
3094 let generic_static pos x =
3096 (Typing.err_code Typing.GenericStatic)
3098 ( "This static variable cannot use the type parameter "
3099 ^ Markdown_lite.md_codify x
3100 ^ "." )
3102 let fun_too_many_args
3103 required actual pos1 pos2 (on_error : typing_error_callback) =
3104 on_error
3105 ~code:(Typing.err_code Typing.FunTooManyArgs)
3106 ( pos1,
3107 Printf.sprintf
3108 "Too many mandatory arguments (expected %d but got %d)"
3109 required
3110 actual )
3111 [(pos2, "Because of this definition")]
3113 let fun_too_few_args
3114 required actual pos1 pos2 (on_error : typing_error_callback) =
3115 on_error
3116 ~code:(Typing.err_code Typing.FunTooFewArgs)
3117 ( pos1,
3118 Printf.sprintf
3119 "Too few arguments (required %d but got %d)"
3120 required
3121 actual )
3122 [(pos2, "Because of this definition")]
3124 let fun_unexpected_nonvariadic pos1 pos2 (on_error : typing_error_callback) =
3125 on_error
3126 ~code:(Typing.err_code Typing.FunUnexpectedNonvariadic)
3127 (pos1, "Should have a variadic argument")
3128 [(pos2, "Because of this definition")]
3130 let fun_variadicity_hh_vs_php56 pos1 pos2 (on_error : typing_error_callback) =
3131 on_error
3132 ~code:(Typing.err_code Typing.FunVariadicityHhVsPhp56)
3133 (pos1, "Variadic arguments: `...`-style is not a subtype of `...$args`")
3134 [(pos2, "Because of this definition")]
3136 let ellipsis_strict_mode ~require pos =
3137 let msg =
3138 match require with
3139 | `Type -> "Cannot use `...` without a **type hint** in strict mode."
3140 | `Param_name ->
3141 "Cannot use `...` without a **parameter name** in strict mode."
3142 | `Type_and_param_name ->
3143 "Cannot use `...` without a **type hint** and **parameter name** in strict mode."
3145 add (Typing.err_code Typing.EllipsisStrictMode) pos msg
3147 let untyped_lambda_strict_mode pos =
3148 let msg =
3149 "Cannot determine types of lambda parameters in strict mode. Please add type hints on parameters."
3151 add (Typing.err_code Typing.UntypedLambdaStrictMode) pos msg
3153 let expected_tparam
3154 ~use_pos ~definition_pos n (on_error : typing_error_callback option) =
3155 let claim =
3156 ( use_pos,
3157 "Expected "
3159 match n with
3160 | 0 -> "no type parameters"
3161 | 1 -> "exactly one type parameter"
3162 | n -> string_of_int n ^ " type parameters" )
3164 let reasons = [(definition_pos, "Definition is here")] in
3165 on_error_or_add on_error (Typing.err_code Typing.ExpectedTparam) claim reasons
3167 let object_string pos1 pos2 =
3168 add_list
3169 (Typing.err_code Typing.ObjectString)
3170 (pos1, "You cannot use this object as a string")
3171 [(pos2, "This object doesn't implement `__toString`")]
3173 let object_string_deprecated pos =
3175 (Typing.err_code Typing.ObjectString)
3177 "You cannot use this object as a string\nImplicit conversions of Stringish objects to string are deprecated."
3179 let cyclic_typedef def_pos use_pos =
3180 add_list
3181 (Typing.err_code Typing.CyclicTypedef)
3182 (def_pos, "Cyclic type definition")
3183 [(use_pos, "Cyclic use is here")]
3185 let type_arity_mismatch pos1 n1 pos2 n2 (on_error : typing_error_callback) =
3186 on_error
3187 ~code:(Typing.err_code Typing.TypeArityMismatch)
3188 (pos1, "This type has " ^ n1 ^ " arguments")
3189 [(pos2, "This one has " ^ n2)]
3191 let this_final id pos2 =
3192 let n = strip_ns (snd id) |> Markdown_lite.md_codify in
3193 let message1 = "Since " ^ n ^ " is not final" in
3194 let message2 = "this might not be a " ^ n in
3195 [(fst id, message1); (pos2, message2)]
3197 let exact_class_final id pos2 =
3198 let n = strip_ns (snd id) |> Markdown_lite.md_codify in
3199 let message1 = "This requires the late-bound type to be exactly " ^ n in
3200 let message2 =
3201 "Since " ^ n ^ " is not final this might be an instance of a child class"
3203 [(fst id, message1); (pos2, message2)]
3205 let fun_arity_mismatch pos1 pos2 (on_error : typing_error_callback) =
3206 on_error
3207 ~code:(Typing.err_code Typing.FunArityMismatch)
3208 (pos1, "Number of arguments doesn't match")
3209 [(pos2, "Because of this definition")]
3211 let require_args_reify def_pos arg_pos =
3212 add_list
3213 (Typing.err_code Typing.RequireArgsReify)
3214 ( arg_pos,
3215 "All type arguments must be specified because a type parameter is reified"
3217 [(def_pos, "Definition is here")]
3219 let require_generic_explicit (def_pos, def_name) arg_pos =
3220 add_list
3221 (Typing.err_code Typing.RequireGenericExplicit)
3222 ( arg_pos,
3223 "Generic type parameter "
3224 ^ Markdown_lite.md_codify def_name
3225 ^ " must be specified explicitly" )
3226 [(def_pos, "Definition is here")]
3228 let invalid_reified_argument (def_pos, def_name) hint_pos arg_info =
3229 let (arg_pos, arg_kind) = List.hd_exn arg_info in
3230 add_list
3231 (Typing.err_code Typing.InvalidReifiedArgument)
3232 (hint_pos, "Invalid reified hint")
3234 ( arg_pos,
3235 "This is " ^ arg_kind ^ ", it cannot be used as a reified type argument"
3237 (def_pos, Markdown_lite.md_codify def_name ^ " is reified");
3240 let invalid_reified_argument_reifiable (def_pos, def_name) arg_pos ty_pos ty_msg
3242 add_list
3243 (Typing.err_code Typing.InvalidReifiedArgument)
3244 (arg_pos, "PHP arrays cannot be used as a reified type argument")
3246 (ty_pos, String.capitalize ty_msg);
3247 (def_pos, Markdown_lite.md_codify def_name ^ " is reified");
3250 let new_class_reified pos class_type suggested_class =
3251 let suggestion =
3252 match suggested_class with
3253 | Some s ->
3254 let s = strip_ns s in
3255 sprintf ". Try `new %s` instead." s
3256 | None -> ""
3259 (Typing.err_code Typing.NewClassReified)
3261 (sprintf
3262 "Cannot call `new %s` because the current class has reified generics%s"
3263 class_type
3264 suggestion)
3266 let class_get_reified pos =
3268 (Typing.err_code Typing.ClassGetReified)
3270 "Cannot access static properties on reified generics"
3272 let static_meth_with_class_reified_generic meth_pos generic_pos =
3273 add_list
3274 (Typing.err_code Typing.StaticMethWithClassReifiedGeneric)
3275 ( meth_pos,
3276 "Static methods cannot use generics reified at the class level. Try reifying them at the static method itself."
3278 [(generic_pos, "Class-level reified generic used here.")]
3280 let consistent_construct_reified pos =
3282 (Typing.err_code Typing.ConsistentConstructReified)
3284 "This class or one of its ancestors is annotated with `<<__ConsistentConstruct>>`. It cannot have reified generics."
3286 let bad_function_pointer_construction pos =
3288 (Typing.err_code Typing.BadFunctionPointerConstruction)
3290 "Function pointers must be explicitly named"
3292 let reified_generics_not_allowed pos =
3294 (Typing.err_code Typing.InvalidReifiedFunctionPointer)
3296 "Creating function pointers with reified generics is not currently allowed"
3298 let new_without_newable pos name =
3300 (Typing.err_code Typing.NewWithoutNewable)
3302 ( Markdown_lite.md_codify name
3303 ^ " cannot be used with `new` because it does not have the `<<__Newable>>` attribute"
3306 let discarded_awaitable pos1 pos2 =
3307 add_list
3308 (Typing.err_code Typing.DiscardedAwaitable)
3309 ( pos1,
3310 "This expression is of type `Awaitable`, but it's "
3311 ^ "either being discarded or used in a dangerous way before "
3312 ^ "being awaited" )
3313 [(pos2, "This is why I think it is `Awaitable`")]
3315 let unify_error ?code err =
3316 add_list (Option.value code ~default:(Typing.err_code Typing.UnifyError)) err
3318 let unify_error_at : Pos.t -> typing_error_callback =
3319 fun pos ?code claim reasons ->
3320 unify_error ?code (pos, "Typing error") (claim :: reasons)
3322 let maybe_unify_error specific_code ?code errl =
3323 add_list (Option.value code ~default:(Typing.err_code specific_code)) errl
3325 let index_type_mismatch = maybe_unify_error Typing.IndexTypeMismatch
3327 let expected_stringlike = maybe_unify_error Typing.ExpectedStringlike
3329 let type_constant_mismatch (on_error : typing_error_callback) ?code errl =
3330 let code =
3331 Option.value code ~default:(Typing.err_code Typing.TypeConstantMismatch)
3333 on_error ~code errl
3335 let class_constant_type_mismatch (on_error : typing_error_callback) ?code errl =
3336 let code =
3337 Option.value
3338 code
3339 ~default:(Typing.err_code Typing.ClassConstantTypeMismatch)
3341 on_error ~code errl
3343 let constant_does_not_match_enum_type =
3344 maybe_unify_error Typing.ConstantDoesNotMatchEnumType
3346 let enum_underlying_type_must_be_arraykey =
3347 maybe_unify_error Typing.EnumUnderlyingTypeMustBeArraykey
3349 let enum_constraint_must_be_arraykey =
3350 maybe_unify_error Typing.EnumConstraintMustBeArraykey
3352 let enum_subtype_must_have_compatible_constraint =
3353 maybe_unify_error Typing.EnumSubtypeMustHaveCompatibleConstraint
3355 let parameter_default_value_wrong_type =
3356 maybe_unify_error Typing.ParameterDefaultValueWrongType
3358 let newtype_alias_must_satisfy_constraint =
3359 maybe_unify_error Typing.NewtypeAliasMustSatisfyConstraint
3361 let bad_function_typevar = maybe_unify_error Typing.BadFunctionTypevar
3363 let bad_class_typevar = maybe_unify_error Typing.BadClassTypevar
3365 let bad_method_typevar = maybe_unify_error Typing.BadMethodTypevar
3367 let missing_return = maybe_unify_error Typing.MissingReturnInNonVoidFunction
3369 let inout_return_type_mismatch =
3370 maybe_unify_error Typing.InoutReturnTypeMismatch
3372 let class_constant_value_does_not_match_hint =
3373 maybe_unify_error Typing.ClassConstantValueDoesNotMatchHint
3375 let class_property_initializer_type_does_not_match_hint =
3376 maybe_unify_error Typing.ClassPropertyInitializerTypeDoesNotMatchHint
3378 let xhp_attribute_does_not_match_hint =
3379 maybe_unify_error Typing.XhpAttributeValueDoesNotMatchHint
3381 let record_init_value_does_not_match_hint =
3382 maybe_unify_error Typing.RecordInitValueDoesNotMatchHint
3384 let strict_str_concat_type_mismatch =
3385 maybe_unify_error Typing.StrictStrConcatTypeMismatch
3387 let strict_str_interp_type_mismatch =
3388 maybe_unify_error Typing.StrictStrInterpTypeMismatch
3390 let using_error pos has_await ?code:_ msg _list =
3391 let (note, cls) =
3392 if has_await then
3393 (" with await", Naming_special_names.Classes.cIAsyncDisposable)
3394 else
3395 ("", Naming_special_names.Classes.cIDisposable)
3397 add_list
3398 (Typing.err_code Typing.UnifyError)
3399 ( pos,
3400 Printf.sprintf
3401 "This expression is used in a `using` clause%s so it must have type `%s`"
3402 note
3403 cls )
3404 [msg]
3406 let elt_type_to_string = function
3407 | `Method -> "method"
3408 | `Property -> "property"
3410 let static_redeclared_as_dynamic
3411 dyn_position static_position member_name ~elt_type =
3412 let dollar =
3413 match elt_type with
3414 | `Property -> "$"
3415 | _ -> ""
3417 let elt_type = elt_type_to_string elt_type in
3418 let msg_dynamic =
3419 "The "
3420 ^ elt_type
3421 ^ " "
3422 ^ Markdown_lite.md_codify (dollar ^ member_name)
3423 ^ " is declared here as non-static"
3425 let msg_static =
3426 "But it conflicts with an inherited static declaration here"
3428 add_list
3429 (Typing.err_code Typing.StaticDynamic)
3430 (dyn_position, msg_dynamic)
3431 [(static_position, msg_static)]
3433 let dynamic_redeclared_as_static
3434 static_position dyn_position member_name ~elt_type =
3435 let dollar =
3436 match elt_type with
3437 | `Property -> "$"
3438 | _ -> ""
3440 let elt_type = elt_type_to_string elt_type in
3441 let msg_static =
3442 "The "
3443 ^ elt_type
3444 ^ " "
3445 ^ Markdown_lite.md_codify (dollar ^ member_name)
3446 ^ " is declared here as static"
3448 let msg_dynamic =
3449 "But it conflicts with an inherited non-static declaration here"
3451 add_list
3452 (Typing.err_code Typing.StaticDynamic)
3453 (static_position, msg_static)
3454 [(dyn_position, msg_dynamic)]
3456 let null_member code ~is_method s pos r =
3457 let msg =
3458 Printf.sprintf
3459 "You are trying to access the %s %s but this object can be null."
3460 ( if is_method then
3461 "method"
3462 else
3463 "property" )
3464 (Markdown_lite.md_codify s)
3466 add_list (Typing.err_code code) (pos, msg) r
3468 let null_member_read = null_member Typing.NullMemberRead
3470 let null_member_write = null_member Typing.NullMemberWrite
3472 (* Trying to access a member on a mixed or nonnull value. *)
3473 let top_member null_code nonnull_code ~is_method ~is_nullable s pos1 ty pos2 =
3474 let msg =
3475 Printf.sprintf
3476 "You are trying to access the %s %s but this is %s. Use a **specific** class or interface name."
3477 ( if is_method then
3478 "method"
3479 else
3480 "property" )
3481 (Markdown_lite.md_codify s)
3484 add_list
3485 (Typing.err_code
3486 ( if is_nullable then
3487 null_code
3488 else
3489 nonnull_code ))
3490 (pos1, msg)
3491 [(pos2, "Definition is here")]
3493 let top_member_read =
3494 top_member Typing.NullMemberRead Typing.NonObjectMemberRead
3496 let top_member_write =
3497 top_member Typing.NullMemberWrite Typing.NonObjectMemberWrite
3499 let non_object_member
3500 code ~kind s pos1 ty pos2 (on_error : typing_error_callback) =
3501 let msg_start =
3502 Printf.sprintf
3503 "You are trying to access the %s %s but this is %s"
3504 (string_of_class_member_kind kind)
3505 (Markdown_lite.md_codify s)
3508 let msg =
3509 if String.equal ty "a shape" then
3510 msg_start ^ ". Did you mean `$foo['" ^ s ^ "']` instead?"
3511 else
3512 msg_start
3514 on_error
3515 ~code:(Typing.err_code code)
3516 (pos1, msg)
3517 [(pos2, "Definition is here")]
3519 let non_object_member_read = non_object_member Typing.NonObjectMemberRead
3521 let non_object_member_write = non_object_member Typing.NonObjectMemberRead
3523 let unknown_object_member ~is_method s pos r =
3524 let msg =
3525 Printf.sprintf
3526 "You are trying to access the %s %s on a value whose class is unknown."
3527 ( if is_method then
3528 "method"
3529 else
3530 "property" )
3531 (Markdown_lite.md_codify s)
3533 add_list (Typing.err_code Typing.UnknownObjectMember) (pos, msg) r
3535 let non_class_member ~is_method s pos1 ty pos2 =
3536 let msg =
3537 Printf.sprintf
3538 "You are trying to access the static %s %s but this is %s"
3539 ( if is_method then
3540 "method"
3541 else
3542 "property" )
3543 (Markdown_lite.md_codify s)
3546 add_list
3547 (Typing.err_code Typing.NonClassMember)
3548 (pos1, msg)
3549 [(pos2, "Definition is here")]
3551 let null_container p null_witness =
3552 add_list
3553 (Typing.err_code Typing.NullContainer)
3554 ( p,
3555 "You are trying to access an element of this container"
3556 ^ " but the container could be `null`. " )
3557 null_witness
3559 let option_mixed pos =
3561 (Typing.err_code Typing.OptionMixed)
3563 "`?mixed` is a redundant typehint - just use `mixed`"
3565 let option_null pos =
3567 (Typing.err_code Typing.OptionNull)
3569 "`?null` is a redundant typehint - just use `null`"
3571 let declared_covariant pos1 pos2 emsg =
3572 add_list
3573 (Typing.err_code Typing.DeclaredCovariant)
3574 (pos2, "Illegal usage of a covariant type parameter")
3575 ( [(pos1, "This is where the parameter was declared as covariant `+`")]
3576 @ emsg )
3578 let declared_contravariant pos1 pos2 emsg =
3579 add_list
3580 (Typing.err_code Typing.DeclaredContravariant)
3581 (pos2, "Illegal usage of a contravariant type parameter")
3582 ( [(pos1, "This is where the parameter was declared as contravariant `-`")]
3583 @ emsg )
3585 let static_property_type_generic_param ~class_pos ~var_type_pos ~generic_pos =
3586 add_list
3587 (Typing.err_code Typing.ClassVarTypeGenericParam)
3588 ( generic_pos,
3589 "A generic parameter cannot be used in the type of a static property" )
3591 ( var_type_pos,
3592 "This is where the type of the static property was declared" );
3593 (class_pos, "This is the class containing the static property");
3596 let contravariant_this pos class_name tp =
3598 (Typing.err_code Typing.ContravariantThis)
3600 ( "The `this` type cannot be used in this "
3601 ^ "contravariant position because its enclosing class "
3602 ^ Markdown_lite.md_codify class_name
3603 ^ " "
3604 ^ "is final and has a variant type parameter "
3605 ^ Markdown_lite.md_codify tp )
3607 let cyclic_typeconst pos sl =
3608 let sl = List.map sl ~f:(fun s -> strip_ns s |> Markdown_lite.md_codify) in
3610 (Typing.err_code Typing.CyclicTypeconst)
3612 ("Cyclic type constant:\n " ^ String.concat ~sep:" -> " sl)
3614 let abstract_concrete_override pos parent_pos kind =
3615 let kind_str =
3616 match kind with
3617 | `method_ -> "method"
3618 | `typeconst -> "type constant"
3619 | `constant -> "constant"
3620 | `property -> "property"
3622 add_list
3623 (Typing.err_code Typing.AbstractConcreteOverride)
3624 (pos, "Cannot re-declare this " ^ kind_str ^ " as abstract")
3625 [(parent_pos, "Previously defined here")]
3627 let required_field_is_optional pos1 pos2 name (on_error : typing_error_callback)
3629 on_error
3630 ~code:(Typing.err_code Typing.RequiredFieldIsOptional)
3631 (pos1, "The field " ^ Markdown_lite.md_codify name ^ " is **optional**")
3633 ( pos2,
3634 "The field "
3635 ^ Markdown_lite.md_codify name
3636 ^ " is defined as **required**" );
3639 let array_get_with_optional_field pos1 pos2 name =
3640 add_list
3641 (Typing.err_code Typing.ArrayGetWithOptionalField)
3642 ( pos1,
3643 Printf.sprintf
3644 "The field %s may not be present in this shape. Use `Shapes::idx()` instead."
3645 (Markdown_lite.md_codify name) )
3646 [(pos2, "This is where the field was declared as optional.")]
3648 let return_disposable_mismatch
3649 pos1_return_disposable pos1 pos2 (on_error : typing_error_callback) =
3650 let m1 = "This is marked `<<__ReturnDisposable>>`." in
3651 let m2 = "This is not marked `<<__ReturnDisposable>>`." in
3652 on_error
3653 ~code:(Typing.err_code Typing.ReturnDisposableMismatch)
3654 ( pos1,
3655 if pos1_return_disposable then
3657 else
3658 m2 )
3660 ( pos2,
3661 if pos1_return_disposable then
3663 else
3664 m1 );
3667 let ifc_policy_mismatch
3668 pos_sub pos_super policy_sub policy_super (on_error : typing_error_callback)
3670 let m1 =
3671 "IFC policies must be invariant with respect to inheritance. This method is policied with "
3672 ^ policy_sub
3674 let m2 =
3675 "This is incompatible with its inherited policy, which is " ^ policy_super
3677 on_error
3678 ~code:(Typing.err_code Typing.IFCPolicyMismatch)
3679 (pos_sub, m1)
3680 [(pos_super, m2)]
3682 let this_as_lexical_variable pos =
3684 (Naming.err_code Naming.ThisAsLexicalVariable)
3686 "Cannot use `$this` as lexical variable"
3688 let dollardollar_lvalue pos =
3690 (Typing.err_code Typing.DollardollarLvalue)
3692 "Cannot assign a value to the special pipe variable `$$`"
3694 let mutating_const_property pos =
3696 (Typing.err_code Typing.AssigningToConst)
3698 "Cannot mutate a `__Const` property"
3700 let self_const_parent_not pos =
3702 (Typing.err_code Typing.SelfConstParentNot)
3704 "A `__Const` class may only extend other `__Const` classes"
3706 let overriding_prop_const_mismatch
3707 parent_pos
3708 parent_const
3709 child_pos
3710 child_const
3711 (on_error : typing_error_callback) =
3712 let m1 = "This property is `__Const`" in
3713 let m2 = "This property is not `__Const`" in
3714 on_error
3715 ~code:(Typing.err_code Typing.OverridingPropConstMismatch)
3716 ( child_pos,
3717 if child_const then
3719 else
3720 m2 )
3722 ( parent_pos,
3723 if parent_const then
3725 else
3726 m2 );
3729 let php_lambda_disallowed pos =
3731 (NastCheck.err_code NastCheck.PhpLambdaDisallowed)
3733 "PHP style anonymous functions are not allowed."
3735 (*****************************************************************************)
3736 (* Typing decl errors *)
3737 (*****************************************************************************)
3739 let wrong_extend_kind
3740 ~parent_pos
3741 ~parent_kind
3742 ~parent_name
3743 ~parent_is_enum_class
3744 ~child_pos
3745 ~child_kind
3746 ~child_name
3747 ~child_is_enum_class =
3748 let parent_kind_str =
3749 Ast_defs.string_of_class_kind
3750 parent_kind
3751 ~is_enum_class:parent_is_enum_class
3753 let parent_name = strip_ns parent_name in
3754 let child_name = strip_ns child_name in
3755 let use_msg =
3756 Printf.sprintf
3757 " Did you mean to add `use %s;` within the body of %s?"
3758 parent_name
3759 (Markdown_lite.md_codify child_name)
3761 let child_msg =
3762 match child_kind with
3763 | Ast_defs.Cabstract
3764 | Ast_defs.Cnormal ->
3765 let extends_msg = "Classes can only extend other classes." in
3766 let suggestion =
3767 if Ast_defs.is_c_interface parent_kind then
3768 " Did you mean `implements " ^ parent_name ^ "`?"
3769 else if Ast_defs.is_c_trait parent_kind then
3770 use_msg
3771 else
3774 extends_msg ^ suggestion
3775 | Ast_defs.Cinterface ->
3776 let extends_msg = "Interfaces can only extend other interfaces." in
3777 let suggestion =
3778 if Ast_defs.is_c_trait parent_kind then
3779 use_msg
3780 else
3783 extends_msg ^ suggestion
3784 | Ast_defs.Cenum ->
3785 if child_is_enum_class then
3786 "Enum classes can only extend other enum classes."
3787 else
3788 (* This case should never happen, as the type checker will have already caught
3789 it with EnumTypeBad. But just in case, report this error here too. *)
3790 "Enums can only extend int, string, or arraykey."
3791 | Ast_defs.Ctrait ->
3792 (* This case should never happen, as the parser will have caught it before
3793 we get here. *)
3794 "A trait cannot use `extends`. This is a parser error."
3796 let msg1 = (child_pos, child_msg) in
3797 let msg2 = (parent_pos, "This is " ^ parent_kind_str ^ ".") in
3798 add_list (Typing.err_code Typing.WrongExtendKind) msg1 [msg2]
3800 let unsatisfied_req parent_pos req_name req_pos =
3801 let s1 = "Failure to satisfy requirement: " ^ strip_ns req_name in
3802 let s2 = "Required here" in
3803 if Pos.equal req_pos parent_pos then
3804 add (Typing.err_code Typing.UnsatisfiedReq) parent_pos s1
3805 else
3806 add_list
3807 (Typing.err_code Typing.UnsatisfiedReq)
3808 (parent_pos, s1)
3809 [(req_pos, s2)]
3811 let cyclic_class_def stack pos =
3812 let stack =
3813 SSet.fold
3814 ~f:(fun x y -> (strip_ns x |> Markdown_lite.md_codify) ^ " " ^ y)
3815 stack
3816 ~init:""
3819 (Typing.err_code Typing.CyclicClassDef)
3821 ("Cyclic class definition : " ^ stack)
3823 let cyclic_record_def names pos =
3824 let names =
3825 List.map ~f:(fun n -> strip_ns n |> Markdown_lite.md_codify) names
3828 (Typing.err_code Typing.CyclicRecordDef)
3830 (Printf.sprintf
3831 "Record inheritance cycle: %s"
3832 (String.concat ~sep:" " names))
3834 let trait_reuse_with_final_method use_pos trait_name parent_cls_name trace =
3835 let msg =
3836 Printf.sprintf
3837 "Traits with final methods cannot be reused, and `%s` is already used by `%s`."
3838 (strip_ns trait_name)
3839 (strip_ns parent_cls_name)
3841 add_list (Typing.err_code Typing.TraitReuse) (use_pos, msg) trace
3843 let trait_reuse p_pos p_name class_name trait =
3844 let (c_pos, c_name) = class_name in
3845 let c_name = strip_ns c_name |> Markdown_lite.md_codify in
3846 let trait = strip_ns trait |> Markdown_lite.md_codify in
3847 let err =
3848 "Class " ^ c_name ^ " reuses trait " ^ trait ^ " in its hierarchy"
3850 let err' =
3851 "It is already used through " ^ (strip_ns p_name |> Markdown_lite.md_codify)
3853 add_list (Typing.err_code Typing.TraitReuse) (c_pos, err) [(p_pos, err')]
3855 let trait_reuse_inside_class class_name trait occurrences =
3856 let (c_pos, c_name) = class_name in
3857 let c_name = strip_ns c_name |> Markdown_lite.md_codify in
3858 let trait = strip_ns trait |> Markdown_lite.md_codify in
3859 let err = "Class " ^ c_name ^ " uses trait " ^ trait ^ " multiple times" in
3860 add_list
3861 (Typing.err_code Typing.TraitReuseInsideClass)
3862 (c_pos, err)
3863 (List.map ~f:(fun p -> (p, "used here")) occurrences)
3865 let invalid_is_as_expression_hint op hint_pos reasons =
3866 add_list
3867 (Typing.err_code Typing.InvalidIsAsExpressionHint)
3868 (hint_pos, "Invalid " ^ Markdown_lite.md_codify op ^ " expression hint")
3869 (List.map reasons ~f:(fun (ty_pos, ty_str) ->
3870 ( ty_pos,
3871 "The "
3872 ^ Markdown_lite.md_codify op
3873 ^ " operator cannot be used with "
3874 ^ ty_str )))
3876 let invalid_enforceable_type kind_str (tp_pos, tp_name) targ_pos ty_info =
3877 let (ty_pos, ty_str) = List.hd_exn ty_info in
3878 add_list
3879 (Typing.err_code Typing.InvalidEnforceableTypeArgument)
3880 (targ_pos, "Invalid type")
3882 ( tp_pos,
3883 "Type "
3884 ^ kind_str
3885 ^ " "
3886 ^ Markdown_lite.md_codify tp_name
3887 ^ " was declared `__Enforceable` here" );
3888 (ty_pos, "This type is not enforceable because it has " ^ ty_str);
3891 let reifiable_attr attr_pos decl_kind decl_pos ty_info =
3892 let (ty_pos, ty_msg) = List.hd_exn ty_info in
3893 add_list
3894 (Typing.err_code Typing.DisallowPHPArraysAttr)
3895 (decl_pos, "Invalid " ^ decl_kind)
3897 (attr_pos, "This type constant has the `__Reifiable` attribute");
3898 (ty_pos, "It cannot contain " ^ ty_msg);
3901 let invalid_newable_type_argument (tp_pos, tp_name) ta_pos =
3902 add_list
3903 (Typing.err_code Typing.InvalidNewableTypeArgument)
3904 ( ta_pos,
3905 "A newable type argument must be a concrete class or a newable type parameter."
3908 ( tp_pos,
3909 "Type parameter "
3910 ^ Markdown_lite.md_codify tp_name
3911 ^ " was declared `__Newable` here" );
3914 let invalid_newable_type_param_constraints
3915 (tparam_pos, tparam_name) constraint_list =
3916 let partial =
3917 if List.is_empty constraint_list then
3918 "No constraints"
3919 else
3920 "The constraints "
3921 ^ String.concat ~sep:", " (List.map ~f:strip_ns constraint_list)
3923 let msg =
3924 "The type parameter "
3925 ^ Markdown_lite.md_codify tparam_name
3926 ^ " has the `<<__Newable>>` attribute. "
3927 ^ "Newable type parameters must be constrained with `as`, and exactly one of those constraints must be a valid newable class. "
3928 ^ "The class must either be final, or it must have the `<<__ConsistentConstruct>>` attribute or extend a class that has it. "
3929 ^ partial
3930 ^ " are valid newable classes"
3932 add (Typing.err_code Typing.InvalidNewableTypeParamConstraints) tparam_pos msg
3934 let override_final ~parent ~child ~(on_error : typing_error_callback option) =
3935 let msg1 = (child, "You cannot override this method") in
3936 let msg2 = (parent, "It was declared as final") in
3937 on_error_or_add on_error (Typing.err_code Typing.OverrideFinal) msg1 [msg2]
3939 let override_lsb ~member_name ~parent ~child (on_error : typing_error_callback)
3941 on_error
3942 ~code:(Typing.err_code Typing.OverrideLSB)
3943 ( child,
3944 "Member "
3945 ^ Markdown_lite.md_codify member_name
3946 ^ " may not override `__LSB` member of parent" )
3947 [(parent, "This is being overridden")]
3949 let should_be_override pos class_id id =
3951 (Typing.err_code Typing.ShouldBeOverride)
3953 (Printf.sprintf
3954 "%s has no parent class with a method %s to override"
3955 (strip_ns class_id |> Markdown_lite.md_codify)
3956 (Markdown_lite.md_codify id))
3958 let override_per_trait class_name meth_name trait_name m_pos =
3959 let (c_pos, c_name) = class_name in
3960 let err_msg =
3961 Printf.sprintf
3962 "`%s::%s` is marked `__Override` but `%s` does not define or inherit a `%s` method."
3963 (strip_ns trait_name)
3964 meth_name
3965 (strip_ns c_name)
3966 meth_name
3968 add_list
3969 (Typing.err_code Typing.OverridePerTrait)
3970 (c_pos, err_msg)
3972 (m_pos, "Declaration of " ^ Markdown_lite.md_codify meth_name ^ " is here");
3975 let missing_assign pos =
3976 add (Typing.err_code Typing.MissingAssign) pos "Please assign a value"
3978 let invalid_memoized_param pos ty_reason_msg =
3979 add_list
3980 (Typing.err_code Typing.InvalidMemoizedParam)
3981 ( pos,
3982 "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"
3984 ty_reason_msg
3986 let invalid_disposable_hint pos class_name =
3988 (Typing.err_code Typing.InvalidDisposableHint)
3990 ( "Parameter with type "
3991 ^ Markdown_lite.md_codify class_name
3992 ^ " must not implement `IDisposable` or `IAsyncDisposable`. "
3993 ^ "Please use `<<__AcceptDisposable>>` attribute or create disposable object with `using` statement instead."
3996 let invalid_disposable_return_hint pos class_name =
3998 (Typing.err_code Typing.InvalidDisposableReturnHint)
4000 ( "Return type "
4001 ^ Markdown_lite.md_codify class_name
4002 ^ " must not implement `IDisposable` or `IAsyncDisposable`. Please add `<<__ReturnDisposable>>` attribute."
4005 let invalid_constfun_attribute pos =
4007 (NastCheck.err_code NastCheck.InvalidConstFunAttribute)
4009 "<<__ConstFun>> can only be used on function type hints and functions."
4011 let xhp_required pos why_xhp ty_reason_msg =
4012 let msg = "An XHP instance was expected" in
4013 add_list
4014 (Typing.err_code Typing.XhpRequired)
4015 (pos, msg)
4016 ((pos, why_xhp) :: ty_reason_msg)
4018 let illegal_xhp_child pos ty_reason_msg =
4019 let msg = "XHP children must be compatible with XHPChild" in
4020 add_list (Typing.err_code Typing.IllegalXhpChild) (pos, msg) ty_reason_msg
4022 let missing_xhp_required_attr pos attr ty_reason_msg =
4023 let msg =
4024 "Required attribute " ^ Markdown_lite.md_codify attr ^ " is missing."
4026 add_list
4027 (Typing.err_code Typing.MissingXhpRequiredAttr)
4028 (pos, msg)
4029 ty_reason_msg
4031 let nullsafe_not_needed p nonnull_witness =
4032 add_list
4033 (Typing.err_code Typing.NullsafeNotNeeded)
4034 (p, "You are using the `?->` operator but this object cannot be null. ")
4035 nonnull_witness
4037 let generic_at_runtime p prefix =
4039 (Typing.err_code Typing.ErasedGenericAtRuntime)
4041 ( prefix
4042 ^ " generics can only be used in type hints because they do not exist at runtime."
4045 let generics_not_allowed p =
4047 (Typing.err_code Typing.GenericsNotAllowed)
4049 "Generics are not allowed in this position."
4051 let trivial_strict_eq p b left right left_trail right_trail =
4052 let msg = "This expression is always " ^ b in
4053 let left_trail = List.map left_trail typedef_trail_entry in
4054 let right_trail = List.map right_trail typedef_trail_entry in
4055 add_list
4056 (Typing.err_code Typing.TrivialStrictEq)
4057 (p, msg)
4058 (left @ left_trail @ right @ right_trail)
4060 let trivial_strict_not_nullable_compare_null p result type_reason =
4061 let msg = "This expression is always " ^ result in
4062 add_list
4063 (Typing.err_code Typing.NotNullableCompareNullTrivial)
4064 (p, msg)
4065 type_reason
4067 let eq_incompatible_types p left right =
4068 let msg = "This equality test has incompatible types" in
4069 add_list (Typing.err_code Typing.EqIncompatibleTypes) (p, msg) (left @ right)
4071 let comparison_invalid_types p left right =
4072 let msg =
4073 "This comparison has invalid types. Only comparisons in which both arguments are strings, nums, DateTime, or DateTimeImmutable are allowed"
4075 add_list
4076 (Typing.err_code Typing.ComparisonInvalidTypes)
4077 (p, msg)
4078 (left @ right)
4080 let void_usage p void_witness =
4081 let msg = "You are using the return value of a `void` function" in
4082 add_list (Typing.err_code Typing.VoidUsage) (p, msg) void_witness
4084 let noreturn_usage p noreturn_witness =
4085 let msg = "You are using the return value of a `noreturn` function" in
4086 add_list (Typing.err_code Typing.NoreturnUsage) (p, msg) noreturn_witness
4088 let attribute_too_few_arguments pos x n =
4089 let n = string_of_int n in
4091 (Typing.err_code Typing.AttributeTooFewArguments)
4093 ( "The attribute "
4094 ^ Markdown_lite.md_codify x
4095 ^ " expects at least "
4097 ^ " arguments" )
4099 let attribute_too_many_arguments pos x n =
4100 let n = string_of_int n in
4102 (Typing.err_code Typing.AttributeTooManyArguments)
4104 ( "The attribute "
4105 ^ Markdown_lite.md_codify x
4106 ^ " expects at most "
4108 ^ " arguments" )
4110 let attribute_param_type pos x =
4112 (Typing.err_code Typing.AttributeParamType)
4114 ("This attribute parameter should be " ^ x)
4116 let deprecated_use pos ?(pos_def = None) msg =
4117 let def_message =
4118 match pos_def with
4119 | Some pos_def -> [(pos_def, "Definition is here")]
4120 | None -> []
4122 add_list (Typing.err_code Typing.DeprecatedUse) (pos, msg) def_message
4124 let cannot_declare_constant kind pos (class_pos, class_name) =
4125 let kind_str =
4126 match kind with
4127 | `enum -> "an enum"
4128 | `record -> "a record"
4130 add_list
4131 (Typing.err_code Typing.CannotDeclareConstant)
4132 (pos, "Cannot declare a constant in " ^ kind_str)
4134 ( class_pos,
4135 (strip_ns class_name |> Markdown_lite.md_codify)
4136 ^ " was defined as "
4137 ^ kind_str
4138 ^ " here" );
4141 let ambiguous_inheritance
4142 pos class_ origin error (on_error : typing_error_callback) =
4143 let { code; claim; reasons } = error in
4144 let origin = strip_ns origin in
4145 let class_ = strip_ns class_ in
4146 let message =
4147 "This declaration was inherited from an object of type "
4148 ^ Markdown_lite.md_codify origin
4149 ^ ". Redeclare this member in "
4150 ^ Markdown_lite.md_codify class_
4151 ^ " with a compatible signature."
4153 on_error ~code claim (reasons @ [(pos, message)])
4155 let multiple_concrete_defs
4156 child_pos
4157 parent_pos
4158 child_origin
4159 parent_origin
4160 name
4161 class_
4162 (on_error : typing_error_callback) =
4163 let child_origin = strip_ns child_origin in
4164 let parent_origin = strip_ns parent_origin in
4165 let class_ = strip_ns class_ in
4166 on_error
4167 ~code:(Typing.err_code Typing.MultipleConcreteDefs)
4168 ( child_pos,
4169 Markdown_lite.md_codify child_origin
4170 ^ " and "
4171 ^ Markdown_lite.md_codify parent_origin
4172 ^ " both declare ambiguous implementations of "
4173 ^ Markdown_lite.md_codify name
4174 ^ "." )
4176 ( child_pos,
4177 Markdown_lite.md_codify child_origin ^ "'s definition is here." );
4178 ( parent_pos,
4179 Markdown_lite.md_codify parent_origin ^ "'s definition is here." );
4180 ( child_pos,
4181 "Redeclare "
4182 ^ Markdown_lite.md_codify name
4183 ^ " in "
4184 ^ Markdown_lite.md_codify class_
4185 ^ " with a compatible signature." );
4188 let local_variable_modified_and_used pos_modified pos_used_l =
4189 let used_msg p = (p, "And accessed here") in
4190 add_list
4191 (Typing.err_code Typing.LocalVariableModifedAndUsed)
4192 ( pos_modified,
4193 "Unsequenced modification and access to local variable. Modified here" )
4194 (List.map pos_used_l used_msg)
4196 let local_variable_modified_twice pos_modified pos_modified_l =
4197 let modified_msg p = (p, "And also modified here") in
4198 add_list
4199 (Typing.err_code Typing.LocalVariableModifedTwice)
4200 (pos_modified, "Unsequenced modifications to local variable. Modified here")
4201 (List.map pos_modified_l modified_msg)
4203 let assign_during_case p =
4205 (Typing.err_code Typing.AssignDuringCase)
4207 "Don't assign to variables inside of case labels"
4209 let cyclic_enum_constraint pos =
4210 add (Typing.err_code Typing.CyclicEnumConstraint) pos "Cyclic enum constraint"
4212 let invalid_classname p =
4213 add (Typing.err_code Typing.InvalidClassname) p "Not a valid class name"
4215 let illegal_type_structure pos errmsg =
4216 let msg =
4217 "The two arguments to `type_structure()` must be:"
4218 ^ "\n - first: `ValidClassname::class` or an object of that class"
4219 ^ "\n - second: a single-quoted string literal containing the name"
4220 ^ " of a type constant of that class"
4221 ^ "\n"
4222 ^ errmsg
4224 add (Typing.err_code Typing.IllegalTypeStructure) pos msg
4226 let illegal_typeconst_direct_access pos =
4227 let msg =
4228 "Type constants cannot be directly accessed. "
4229 ^ "Use `type_structure(ValidClassname::class, 'TypeConstName')` instead"
4231 add (Typing.err_code Typing.IllegalTypeStructure) pos msg
4233 let override_no_default_typeconst pos_child pos_parent =
4234 add_list
4235 (Typing.err_code Typing.OverrideNoDefaultTypeconst)
4236 (pos_child, "This abstract type constant does not have a default type")
4238 ( pos_parent,
4239 "It cannot override an abstract type constant that has a default type"
4243 let inout_annotation_missing pos1 pos2 =
4244 let msg1 = (pos1, "This argument should be annotated with `inout`") in
4245 let msg2 = (pos2, "Because this is an `inout` parameter") in
4246 add_list (Typing.err_code Typing.InoutAnnotationMissing) msg1 [msg2]
4248 let inout_annotation_unexpected pos1 pos2 pos2_is_variadic =
4249 let msg1 = (pos1, "Unexpected `inout` annotation for argument") in
4250 let msg2 =
4251 ( pos2,
4252 if pos2_is_variadic then
4253 "A variadic parameter can never be `inout`"
4254 else
4255 "This is a normal parameter (does not have `inout`)" )
4257 add_list (Typing.err_code Typing.InoutAnnotationUnexpected) msg1 [msg2]
4259 let inoutness_mismatch pos1 pos2 (on_error : typing_error_callback) =
4260 let msg1 = (pos1, "This is an `inout` parameter") in
4261 let msg2 = (pos2, "It is incompatible with a normal parameter") in
4262 on_error ~code:(Typing.err_code Typing.InoutnessMismatch) msg1 [msg2]
4264 let invalid_new_disposable pos =
4265 let msg =
4266 "Disposable objects may only be created in a `using` statement or `return` from function marked `<<__ReturnDisposable>>`"
4268 add (Typing.err_code Typing.InvalidNewDisposable) pos msg
4270 let invalid_return_disposable pos =
4271 let msg =
4272 "Return expression must be new disposable in function marked `<<__ReturnDisposable>>`"
4274 add (Typing.err_code Typing.InvalidReturnDisposable) pos msg
4276 let inout_argument_bad_type pos msgl =
4277 let msg =
4278 "Expected argument marked `inout` to be contained in a local or "
4279 ^ "a value-typed container (e.g. vec, dict, keyset, array). "
4280 ^ "To use `inout` here, assign to/from a temporary local variable."
4282 add_list (Typing.err_code Typing.InoutArgumentBadType) (pos, msg) msgl
4284 let ambiguous_lambda pos uses =
4285 let msg1 =
4286 "Lambda has parameter types that could not be determined at definition site."
4288 let msg2 =
4289 Printf.sprintf
4290 "%d distinct use types were determined: please add type hints to lambda parameters."
4291 (List.length uses)
4293 add_list
4294 (Typing.err_code Typing.AmbiguousLambda)
4295 (pos, msg1)
4296 ( (pos, msg2)
4297 :: List.map uses (fun (pos, ty) ->
4298 (pos, "This use has type " ^ Markdown_lite.md_codify ty)) )
4300 let wrong_expression_kind_attribute
4301 expr_kind pos attr attr_class_pos attr_class_name intf_name =
4302 let msg1 =
4303 Printf.sprintf
4304 "The %s attribute cannot be used on %s."
4305 (strip_ns attr |> Markdown_lite.md_codify)
4306 expr_kind
4308 let msg2 =
4309 Printf.sprintf
4310 "The attribute's class is defined here. To be available for use on %s, the %s class must implement %s."
4311 expr_kind
4312 (strip_ns attr_class_name |> Markdown_lite.md_codify)
4313 (strip_ns intf_name |> Markdown_lite.md_codify)
4315 add_list
4316 (Typing.err_code Typing.WrongExpressionKindAttribute)
4317 (pos, msg1)
4318 [(attr_class_pos, msg2)]
4320 let wrong_expression_kind_builtin_attribute expr_kind pos attr =
4321 let msg1 =
4322 Printf.sprintf
4323 "The %s attribute cannot be used on %s."
4324 (strip_ns attr |> Markdown_lite.md_codify)
4325 expr_kind
4327 add_list (Typing.err_code Typing.WrongExpressionKindAttribute) (pos, msg1) []
4329 let decl_override_missing_hint pos (on_error : typing_error_callback) =
4330 on_error
4331 ~code:(Typing.err_code Typing.DeclOverrideMissingHint)
4332 ( pos,
4333 "When redeclaring class members, both declarations must have a typehint"
4337 let shapes_key_exists_always_true pos1 name pos2 =
4338 add_list
4339 (Typing.err_code Typing.ShapesKeyExistsAlwaysTrue)
4340 (pos1, "This `Shapes::keyExists()` check is always true")
4342 ( pos2,
4343 "The field "
4344 ^ Markdown_lite.md_codify name
4345 ^ " exists because of this definition" );
4348 let shape_field_non_existence_reason pos name = function
4349 | `Undefined ->
4351 ( pos,
4352 "The field "
4353 ^ Markdown_lite.md_codify name
4354 ^ " is not defined in this shape" );
4356 | `Nothing reason ->
4357 ( pos,
4358 "The type of the field "
4359 ^ Markdown_lite.md_codify name
4360 ^ " in this shape doesn't allow any values" )
4361 :: reason
4363 let shapes_key_exists_always_false pos1 name pos2 reason =
4364 add_list
4365 (Typing.err_code Typing.ShapesKeyExistsAlwaysFalse)
4366 (pos1, "This `Shapes::keyExists()` check is always false")
4367 @@ shape_field_non_existence_reason pos2 name reason
4369 let shapes_method_access_with_non_existent_field
4370 pos1 name pos2 method_name reason =
4371 add_list
4372 (Typing.err_code Typing.ShapesMethodAccessWithNonExistentField)
4373 ( pos1,
4374 "You are calling "
4375 ^ Markdown_lite.md_codify ("Shapes::" ^ method_name ^ "()")
4376 ^ " on a field known to not exist" )
4377 @@ shape_field_non_existence_reason pos2 name reason
4379 let shape_access_with_non_existent_field pos1 name pos2 reason =
4380 add_list
4381 (Typing.err_code Typing.ShapeAccessWithNonExistentField)
4382 (pos1, "You are accessing a field known to not exist")
4383 @@ shape_field_non_existence_reason pos2 name reason
4385 let ambiguous_object_access
4386 pos name self_pos vis subclass_pos class_self class_subclass =
4387 let class_self = strip_ns class_self in
4388 let class_subclass = strip_ns class_subclass in
4389 add_list
4390 (Typing.err_code Typing.AmbiguousObjectAccess)
4391 ( pos,
4392 "This object access to " ^ Markdown_lite.md_codify name ^ " is ambiguous"
4395 ( self_pos,
4396 "You will access the private instance declared in "
4397 ^ Markdown_lite.md_codify class_self );
4398 ( subclass_pos,
4399 "Instead of the "
4400 ^ vis
4401 ^ " instance declared in "
4402 ^ Markdown_lite.md_codify class_subclass );
4405 let lateinit_with_default pos =
4407 (Typing.err_code Typing.LateInitWithDefault)
4409 "A late-initialized property cannot have a default value"
4411 let bad_lateinit_override
4412 parent_is_lateinit parent_pos child_pos (on_error : typing_error_callback) =
4413 let verb =
4414 if parent_is_lateinit then
4415 "is"
4416 else
4417 "is not"
4419 on_error
4420 ~code:(Typing.err_code Typing.BadLateInitOverride)
4421 ( child_pos,
4422 "Redeclared properties must be consistently declared `__LateInit`" )
4423 [(parent_pos, "The property " ^ verb ^ " declared `__LateInit` here")]
4425 let bad_xhp_attr_required_override
4426 parent_tag child_tag parent_pos child_pos (on_error : typing_error_callback)
4428 on_error
4429 ~code:(Typing.err_code Typing.BadXhpAttrRequiredOverride)
4430 (child_pos, "Redeclared attribute must not be less strict")
4432 ( parent_pos,
4433 "The attribute is "
4434 ^ parent_tag
4435 ^ ", which is stricter than "
4436 ^ child_tag );
4439 let invalid_switch_case_value_type case_value_p case_value_ty scrutinee_ty =
4440 add (Typing.err_code Typing.InvalidSwitchCaseValueType) case_value_p
4441 @@ Printf.sprintf
4442 "Switch statements use `==` equality, so comparing values of type %s with %s may not give the desired result."
4443 (case_value_ty |> Markdown_lite.md_codify)
4444 (scrutinee_ty |> Markdown_lite.md_codify)
4446 let unserializable_type pos message =
4448 (Typing.err_code Typing.UnserializableType)
4450 ( "Unserializable type (could not be converted to JSON and back again): "
4451 ^ message )
4453 let invalid_arraykey code pos (cpos, ctype) (kpos, ktype) =
4454 add_list
4455 (Typing.err_code code)
4456 (pos, "This value is not a valid key type for this container")
4458 (cpos, "This container is " ^ ctype);
4459 (kpos, String.capitalize ktype ^ " cannot be used as a key for " ^ ctype);
4462 let invalid_arraykey_read = invalid_arraykey Typing.InvalidArrayKeyRead
4464 let invalid_arraykey_write = invalid_arraykey Typing.InvalidArrayKeyWrite
4466 let invalid_sub_string pos ty =
4467 add (Typing.err_code Typing.InvalidSubString) pos
4468 @@ "Expected an object convertible to string but got "
4469 ^ ty
4471 let typechecker_timeout (pos, fun_name) seconds =
4473 (Typing.err_code Typing.TypecheckerTimeout)
4475 (Printf.sprintf
4476 "Type checker timed out after %d seconds whilst checking function %s"
4477 seconds
4478 fun_name)
4480 let unresolved_type_variable pos =
4482 (Typing.err_code Typing.UnresolvedTypeVariable)
4484 "The type of this expression contains an unresolved type variable"
4486 let invalid_arraykey_constraint pos t =
4488 (Typing.err_code Typing.InvalidArrayKeyConstraint)
4490 ( "This type is "
4492 ^ ", which cannot be used as an arraykey (string | int)" )
4494 let exception_occurred pos e =
4495 let pos_str = pos |> Pos.to_absolute |> Pos.string in
4496 HackEventLogger.type_check_exn_bug ~path:(Pos.filename pos) ~pos:pos_str ~e;
4497 Hh_logger.error
4498 "Exception while typechecking at position %s\n%s"
4499 pos_str
4500 (Exception.to_string e);
4502 (Typing.err_code Typing.ExceptionOccurred)
4504 (Printf.sprintf
4505 "An exception occurred while typechecking this. Please try %s. %s"
4506 (Markdown_lite.md_codify "hh restart")
4507 Error_message_sentinel.please_file_a_bug_message)
4509 let redundant_covariant pos msg suggest =
4511 (Typing.err_code Typing.RedundantGeneric)
4513 ( "This generic parameter is redundant because it only appears in a covariant (output) position"
4514 ^ msg
4515 ^ ". Consider replacing uses of generic parameter with "
4516 ^ Markdown_lite.md_codify suggest
4517 ^ " or specifying `<<__Explicit>>` on the generic parameter" )
4519 let meth_caller_trait pos trait_name =
4521 (Typing.err_code Typing.MethCallerTrait)
4523 ( (strip_ns trait_name |> Markdown_lite.md_codify)
4524 ^ " is a trait which cannot be used with `meth_caller`. Use a class instead."
4527 let duplicate_interface pos name others =
4528 add_list
4529 (Typing.err_code Typing.DuplicateInterface)
4530 ( pos,
4531 Printf.sprintf
4532 "Interface %s is used more than once in this declaration."
4533 (strip_ns name |> Markdown_lite.md_codify) )
4534 (List.map others (fun pos -> (pos, "Here is another occurrence")))
4536 let hk_var_description because_nested var_name =
4537 if because_nested then
4538 Markdown_lite.md_codify var_name
4539 ^ " is a generic parameter of another (higher-kinded) generic parameter. "
4540 else
4541 Markdown_lite.md_codify var_name
4542 ^ " is a higher-kinded type parameter, standing for a type that has type parameters itself. "
4544 let unsupported_hk_feature ~because_nested pos var_name feature_description =
4545 let var_description = hk_var_description because_nested var_name in
4547 (Naming.err_code Naming.HigherKindedTypesUnsupportedFeature)
4549 ( var_description
4550 ^ "We don't support "
4551 ^ feature_description
4552 ^ " parameters like "
4553 ^ Markdown_lite.md_codify var_name
4554 ^ "." )
4556 let tparam_non_shadowing_reuse pos var_name =
4558 (Typing.err_code Typing.TypeParameterNameAlreadyUsedNonShadow)
4560 ( "The name "
4561 ^ Markdown_lite.md_codify var_name
4562 ^ " was already used for another generic parameter. Please use a different name to avoid confusion."
4565 let illegal_information_flow
4566 primary secondaries (source_poss, source) (sink_poss, sink) =
4567 let explain poss node printer reasons =
4568 let msg = printer node in
4569 List.map ~f:(fun pos -> (pos, msg)) poss @ reasons
4571 let source = Markdown_lite.md_codify source in
4572 let sink = Markdown_lite.md_codify sink in
4573 let sprintf_main = sprintf "Data with policy %s appears in context %s." in
4574 let claim = (primary, sprintf_main source sink) in
4575 let reasons =
4576 let sprintf = Printf.sprintf in
4577 let sprintf_source = sprintf "This may be the data source with policy %s" in
4578 let sprintf_sink = sprintf "This may be the data sink with policy %s" in
4579 let other_occurrences =
4580 let f p = (p, "Another program point contributing to the illegal flow") in
4581 List.map ~f secondaries
4584 |> explain source_poss source sprintf_source
4585 |> explain sink_poss sink sprintf_sink
4586 |> List.append other_occurrences
4587 |> List.rev
4589 add_list (Typing.err_code Typing.IllegalInformationFlow) claim reasons
4591 let context_implicit_policy_leakage
4592 primary secondaries (source_poss, source) (sink_poss, sink) =
4593 let program_point p =
4594 (p, "Another program point contributing to the leakage")
4596 let explain_source p = (p, "Leakage source") in
4597 let explain_sink p = (p, "Leakage sink") in
4598 let claim =
4599 ( primary,
4600 Printf.sprintf
4601 "Context-implicit policy leaks into %s via %s."
4602 (Markdown_lite.md_codify sink)
4603 (Markdown_lite.md_codify source) )
4605 let reasons =
4606 List.map ~f:program_point secondaries
4607 @ List.map ~f:explain_source source_poss
4608 @ List.map ~f:explain_sink sink_poss
4610 add_list (Typing.err_code Typing.ContextImplicitPolicyLeakage) claim reasons
4612 let unknown_information_flow pos str =
4614 (Typing.err_code Typing.UnknownInformationFlow)
4616 ("Unable to analyze information flow for " ^ str ^ ". This might be unsafe.")
4618 let reified_function_reference call_pos =
4620 (Typing.err_code Typing.ReifiedFunctionReference)
4621 call_pos
4622 "Invalid function reference. This function requires reified generics. Prefer using a lambda instead."
4624 let class_meth_abstract_call cname meth_name call_pos decl_pos =
4625 let cname = strip_ns cname in
4626 add_list
4627 (Typing.err_code Typing.ClassMethAbstractCall)
4628 ( call_pos,
4629 "Cannot create a class_meth of "
4630 ^ cname
4631 ^ "::"
4632 ^ meth_name
4633 ^ "; it is abstract." )
4634 [(decl_pos, "Declaration is here")]
4636 let higher_kinded_partial_application pos count =
4638 (Naming.err_code Naming.HigherKindedTypesUnsupportedFeature)
4640 ( "A higher-kinded type is expected here."
4641 ^ " We do not not support partial applications to yield higher-kinded types, but you are providing "
4642 ^ string_of_int count
4643 ^ " type argument(s)." )
4645 let wildcard_for_higher_kinded_type pos =
4647 (Naming.err_code Naming.HigherKindedTypesUnsupportedFeature)
4649 ( "You are supplying _ where a higher-kinded type is expected."
4650 ^ " We cannot infer higher-kinded type arguments at this time, please state the actual type."
4653 let implicit_type_argument_for_higher_kinded_type ~use_pos ~def_pos param_name =
4654 let param_desc =
4655 (* This should be Naming_special_names.Typehints.wildcard, but its not available in this
4656 module *)
4657 if String.equal param_name "_" then
4658 "the anonymous generic parameter"
4659 else
4660 "the generic parameter " ^ param_name
4662 add_list
4663 (Naming.err_code Naming.HigherKindedTypesUnsupportedFeature)
4664 ( use_pos,
4665 "You left out the type arguments here such that they may be inferred."
4666 ^ " However, a higher-kinded type is expected in place of "
4667 ^ param_desc
4668 ^ ", meaning that the type arguments cannot be inferred."
4669 ^ " Please provide the type arguments explicitly." )
4670 [(def_pos, param_desc ^ " was declared to be higher-kinded here.")]
4672 (* This is only to be used in a context where we expect something higher-kinded,
4673 meaning that expected_kind_repr should never just be * *)
4674 let kind_mismatch
4675 ~use_pos ~def_pos ~tparam_name ~expected_kind_repr ~actual_kind_repr =
4676 add_list
4677 (Typing.err_code Typing.KindMismatch)
4678 ( use_pos,
4679 "This is "
4680 ^ actual_kind_repr
4681 ^ ", but "
4682 ^ expected_kind_repr
4683 ^ " was expected here." )
4685 ( def_pos,
4686 "We are expecting "
4687 ^ expected_kind_repr
4688 ^ " due to the definition of "
4689 ^ tparam_name
4690 ^ " here." );
4693 let class_with_constraints_used_as_hk_type use_pos class_name =
4695 (Naming.err_code Naming.HigherKindedTypesUnsupportedFeature)
4696 use_pos
4697 ( "The class "
4698 ^ strip_ns class_name
4699 ^ " imposes constraints on some of its type parameters. Classes that do this cannot be used as higher-kinded types at this time."
4702 let alias_with_implicit_constraints_as_hk_type
4703 ~use_pos
4704 ~typedef_pos
4705 ~used_class_in_def_pos
4706 ~typedef_name
4707 ~typedef_tparam_name
4708 ~used_class_in_def_name
4709 ~used_class_tparam_name =
4710 add_list
4711 (Naming.err_code Naming.HigherKindedTypesUnsupportedFeature)
4712 ( use_pos,
4713 "The type "
4714 ^ strip_ns typedef_name
4715 ^ " implicitly imposes constraints on its type parameters. Therefore, it cannot be used as a higher-kinded type at this time."
4718 (typedef_pos, "The definition of " ^ strip_ns typedef_name ^ " is here.");
4719 ( used_class_in_def_pos,
4720 "The definition of "
4721 ^ strip_ns typedef_name
4722 ^ " relies on "
4723 ^ strip_ns used_class_in_def_name
4724 ^ " and the constraints that "
4725 ^ strip_ns used_class_in_def_name
4726 ^ " imposes on its type parameter "
4727 ^ strip_ns used_class_tparam_name
4728 ^ " then become implicit constraints on the type parameter "
4729 ^ typedef_tparam_name
4730 ^ " of "
4731 ^ strip_ns typedef_name
4732 ^ "." );
4735 let reinheriting_classish_const
4736 dest_classish_pos
4737 dest_classish_name
4738 src_classish_pos
4739 src_classish_name
4740 existing_const_origin
4741 const_name =
4742 add_list
4743 (Typing.err_code Typing.RedeclaringClassishConstant)
4744 ( src_classish_pos,
4745 strip_ns dest_classish_name
4746 ^ " cannot re-inherit constant "
4747 ^ const_name
4748 ^ " from "
4749 ^ src_classish_name )
4751 ( dest_classish_pos,
4752 "because it already inherited it via " ^ strip_ns existing_const_origin
4756 let redeclaring_classish_const
4757 classish_pos
4758 classish_name
4759 redeclaration_pos
4760 existing_const_origin
4761 const_name =
4762 add_list
4763 (Typing.err_code Typing.RedeclaringClassishConstant)
4764 ( redeclaration_pos,
4765 strip_ns classish_name ^ " cannot re-declare constant " ^ const_name )
4767 ( classish_pos,
4768 "because it already inherited it via " ^ strip_ns existing_const_origin
4772 let incompatible_enum_inclusion_base
4773 dest_classish_pos dest_classish_name src_classish_name =
4774 add_list
4775 (Typing.err_code Typing.IncompatibleEnumInclusion)
4776 ( dest_classish_pos,
4777 "Enum "
4778 ^ strip_ns dest_classish_name
4779 ^ " includes enum "
4780 ^ strip_ns src_classish_name
4781 ^ " but their base types are incompatible" )
4784 let incompatible_enum_inclusion_constraint
4785 dest_classish_pos dest_classish_name src_classish_name =
4786 add_list
4787 (Typing.err_code Typing.IncompatibleEnumInclusion)
4788 ( dest_classish_pos,
4789 "Enum "
4790 ^ strip_ns dest_classish_name
4791 ^ " includes enum "
4792 ^ strip_ns src_classish_name
4793 ^ " but their constraints are incompatible" )
4796 let enum_inclusion_not_enum
4797 dest_classish_pos dest_classish_name src_classish_name =
4798 add_list
4799 (Typing.err_code Typing.IncompatibleEnumInclusion)
4800 ( dest_classish_pos,
4801 "Enum "
4802 ^ strip_ns dest_classish_name
4803 ^ " includes "
4804 ^ strip_ns src_classish_name
4805 ^ " which is not an enum" )
4808 (* This is meant for subtyping functions with incompatible coeffects, i.e.
4809 * (function ()[io]: void) </: (function ()[]: void) *)
4810 let coeffect_subtyping_error
4811 pos_expected cap_expected pos_got cap_got (on_error : typing_error_callback)
4813 on_error
4814 ~code:(Typing.err_code Typing.SubtypeCoeffects)
4815 (pos_expected, "Expected a function that requires " ^ cap_expected)
4816 [(pos_got, "But got a function that requires " ^ cap_got)]
4818 let call_coeffect_error
4819 ~available_incl_unsafe ~available_pos ~required ~required_pos call_pos =
4820 add_list
4821 (Typing.err_code Typing.CallCoeffects)
4822 ( call_pos,
4823 "This call is not allowed because its coeffects are incompatible with the context"
4826 ( available_pos,
4827 "From this declaration, the context of this function body provides "
4828 ^ available_incl_unsafe );
4829 (required_pos, "But the function being called requires " ^ required);
4830 context_definitions_msg ();
4833 let op_coeffect_error
4834 ~locally_available ~available_pos ~err_code ~required op op_pos =
4835 add_list
4836 err_code
4837 ( op_pos,
4838 op ^ " requires " ^ required ^ ", which is not provided by the context."
4841 ( available_pos,
4842 "The local (enclosing) context provides " ^ locally_available );
4843 context_definitions_msg ();
4846 let abstract_function_pointer cname meth_name call_pos decl_pos =
4847 let cname = strip_ns cname in
4848 add_list
4849 (Typing.err_code Typing.AbstractFunctionPointer)
4850 ( call_pos,
4851 "Cannot create a function pointer to "
4852 ^ Markdown_lite.md_codify (cname ^ "::" ^ meth_name)
4853 ^ "; it is abstract" )
4854 [(decl_pos, "Declaration is here")]
4856 let unnecessary_attribute pos ~attr ~reason ~suggestion =
4857 let attr = strip_ns attr in
4858 let (reason_pos, reason_msg) = reason in
4859 let suggestion =
4860 match suggestion with
4861 | None -> "Try deleting this attribute"
4862 | Some s -> s
4864 add_list
4865 (Typing.err_code Typing.UnnecessaryAttribute)
4866 (pos, sprintf "The attribute `%s` is unnecessary" attr)
4867 [(reason_pos, "It is unnecessary because " ^ reason_msg); (pos, suggestion)]
4869 let inherited_class_member_with_different_case
4870 member_type name name_prev p child_class prev_class prev_class_pos =
4871 let name = strip_ns name in
4872 let name_prev = strip_ns name_prev in
4873 let child_class = strip_ns child_class in
4874 let prev_class = strip_ns prev_class in
4875 let claim =
4876 ( p,
4877 child_class
4878 ^ " inherits a "
4879 ^ member_type
4880 ^ " named "
4881 ^ Markdown_lite.md_codify name_prev
4882 ^ " which differs from this one ("
4883 ^ name
4884 ^ ") only by case." )
4886 let reasons =
4888 ( prev_class_pos,
4889 "It was inherited from "
4890 ^ prev_class
4891 ^ " as "
4892 ^ (highlight_differences name name_prev |> Markdown_lite.md_codify)
4893 ^ ". If you meant to override it, please use the same casing as the inherited "
4894 ^ member_type
4895 ^ "."
4896 ^ " Otherwise, please choose a different name for the new method." );
4899 add_list (Typing.err_code Typing.InheritedMethodCaseDiffers) claim reasons
4901 let multiple_inherited_class_member_with_different_case
4902 ~member_type ~name1 ~name2 ~class1 ~class2 ~child_class ~child_p ~p1 ~p2 =
4903 let name1 = strip_ns name1 in
4904 let name2 = strip_ns name2 in
4905 let class1 = strip_ns class1 in
4906 let class2 = strip_ns class2 in
4907 let child_class = strip_ns child_class in
4908 let claim =
4909 ( child_p,
4910 Markdown_lite.md_codify child_class
4911 ^ " inherited two versions of the "
4912 ^ member_type
4913 ^ " "
4914 ^ Markdown_lite.md_codify name1
4915 ^ " that differ only by case." )
4917 let reasons =
4919 ( p1,
4920 "It inherited "
4921 ^ Markdown_lite.md_codify name1
4922 ^ " from "
4923 ^ class1
4924 ^ " here." );
4925 ( p2,
4926 "And "
4927 ^ Markdown_lite.md_codify name2
4928 ^ " from "
4929 ^ class2
4930 ^ " here. Please rename these methods to the same casing." );
4933 add_list (Typing.err_code Typing.InheritedMethodCaseDiffers) claim reasons
4935 let atom_invalid_parameter pos =
4936 add_list
4937 (Typing.err_code Typing.AtomInvalidParameter)
4938 ( pos,
4939 "Attribute "
4940 ^ Naming_special_names.UserAttributes.uaAtom
4941 ^ " is only allowed on "
4942 ^ Naming_special_names.Classes.cMemberOf )
4945 let atom_invalid_parameter_in_enum_class pos =
4946 add_list
4947 (Typing.err_code Typing.AtomInvalidParameter)
4948 ( pos,
4949 "When using "
4950 ^ Naming_special_names.UserAttributes.uaAtom
4951 ^ ", only type parameters bounded by enum classes and "
4952 ^ "enum classes are allowed as the first parameters of "
4953 ^ Naming_special_names.Classes.cMemberOf )
4956 let atom_invalid_generic pos name =
4957 add_list
4958 (Typing.err_code Typing.AtomInvalidParameter)
4959 ( pos,
4960 "The type "
4961 ^ name
4962 ^ " must be a type constant or a reified generic "
4963 ^ "in order to be used with "
4964 ^ Naming_special_names.UserAttributes.uaAtom )
4967 let atom_unknown pos atom_name class_name =
4968 let class_name = strip_ns class_name in
4969 add_list
4970 (Typing.err_code Typing.AtomUnknown)
4971 (pos, "Unknown constant " ^ atom_name ^ " in " ^ class_name)
4974 let atom_as_expr pos =
4975 add_list
4976 (Typing.err_code Typing.AtomAsExpression)
4977 ( pos,
4978 "Atoms are not allowed in this position. They are only allowed "
4979 ^ "in function call, if the function parameter is annotated with "
4980 ^ Naming_special_names.UserAttributes.uaAtom )
4983 let atom_invalid_argument pos =
4984 add_list
4985 (Typing.err_code Typing.AtomInvalidArgument)
4986 (pos, "An atom is required here, not a class constant projection")
4989 let ifc_internal_error pos reason =
4991 (Typing.err_code Typing.IFCInternalError)
4993 ( "IFC Internal Error: "
4994 ^ reason
4995 ^ ". If you see this error and aren't expecting it, please `hh rage` and let the Hack team know."
4998 let parent_implements_dynamic
5000 (child_name, child_kind)
5001 (parent_name, parent_kind)
5002 child_implements_dynamic =
5003 let kind_to_strings = function
5004 | Ast_defs.Cabstract
5005 | Ast_defs.Cnormal ->
5006 ("class ", "implement ")
5007 | Ast_defs.Ctrait -> ("trait ", "implement ")
5008 | Ast_defs.Cinterface -> ("interface ", "extend ")
5009 | Ast_defs.Cenum -> (* cannot happen *) ("", "")
5011 let kinds_to_use child_kind parent_kind =
5012 match (child_kind, parent_kind) with
5013 | (_, Ast_defs.Cabstract)
5014 | (_, Ast_defs.Cnormal) ->
5015 "extends "
5016 | (_, Ast_defs.Ctrait) -> "uses "
5017 | (Ast_defs.Cinterface, Ast_defs.Cinterface) -> "extends "
5018 | (_, Ast_defs.Cinterface) -> "implements "
5019 | (_, _) -> ""
5021 let child_name = strip_ns child_name in
5022 let (child_kind_s, action) = kind_to_strings child_kind in
5023 let parent_name = strip_ns parent_name in
5024 let (parent_kind_s, _) = kind_to_strings parent_kind in
5026 (Typing.err_code Typing.ImplementsDynamic)
5028 ( String.capitalize child_kind_s
5029 ^ child_name
5030 ^ ( if child_implements_dynamic then
5031 " cannot "
5032 else
5033 " must " )
5034 ^ action
5035 ^ "dynamic because it "
5036 ^ kinds_to_use child_kind parent_kind
5037 ^ parent_kind_s
5038 ^ parent_name
5039 ^ " which does"
5041 if child_implements_dynamic then
5042 " not"
5043 else
5044 "" )
5046 let method_is_not_dynamically_callable pos method_name class_name =
5047 let class_name = strip_ns class_name in
5049 (Typing.err_code Typing.ImplementsDynamic)
5051 ( "Class "
5052 ^ Markdown_lite.md_codify class_name
5053 ^ " cannot implement dynamic because method "
5054 ^ Markdown_lite.md_codify method_name
5055 ^ " is not dynamically callable" )
5057 let property_is_not_enforceable pos prop_name class_name =
5058 let class_name = strip_ns class_name in
5060 (Typing.err_code Typing.ImplementsDynamic)
5062 ( "Class "
5063 ^ Markdown_lite.md_codify class_name
5064 ^ " cannot implement dynamic because property "
5065 ^ Markdown_lite.md_codify prop_name
5066 ^ " does not have an enforceable type" )
5068 let property_is_not_dynamic pos prop_name class_name =
5069 let class_name = strip_ns class_name in
5071 (Typing.err_code Typing.ImplementsDynamic)
5073 ( "Class "
5074 ^ Markdown_lite.md_codify class_name
5075 ^ " cannot implement dynamic because property "
5076 ^ Markdown_lite.md_codify prop_name
5077 ^ " cannot be assigned to dynamic" )
5079 let immutable_local pos =
5081 (Typing.err_code Typing.ImmutableLocal)
5083 (* TODO: generalize this error message in the future for arbitrary immutable locals *)
5084 "This variable cannot be reassigned because it is used for a dependent context"
5086 let enum_classes_reserved_syntax pos =
5088 (Typing.err_code Typing.EnumClassesReservedSyntax)
5090 ( "This syntax is reserved for the Enum Classes feature.\n"
5091 ^ "Enable it with the enable_enum_classes option in .hhconfig" )
5093 let nonsense_member_selection pos kind =
5095 (Typing.err_code Typing.NonsenseMemberSelection)
5097 ("Dynamic member access requires a local variable, not `" ^ kind ^ "`.")
5099 let consider_meth_caller pos class_name meth_name =
5101 (Typing.err_code Typing.ConsiderMethCaller)
5103 ( "Function pointer syntax requires a static method. "
5104 ^ "Use `meth_caller("
5105 ^ strip_ns class_name
5106 ^ "::class, '"
5107 ^ meth_name
5108 ^ "')` to create a function pointer to the instance method" )
5110 let enum_supertyping_reserved_syntax pos =
5112 (Typing.err_code Typing.EnumSupertypingReservedSyntax)
5114 ( "This Enum uses syntax reserved for the Enum Supertyping feature.\n"
5115 ^ "Enable it with the enable_enum_supertyping option in .hhconfig" )
5117 let readonly_modified ?reason pos =
5118 match reason with
5119 | Some (rpos, rmsg) ->
5120 add_list
5121 (Typing.err_code Typing.ReadonlyValueModified)
5122 (pos, "This value is readonly, its properties cannot be modified")
5123 [(rpos, rmsg)]
5124 | None ->
5126 (Typing.err_code Typing.ReadonlyValueModified)
5128 "This value is readonly, its properties cannot be modified"
5130 let var_readonly_mismatch pos var_ro rval_pos rval_ro =
5131 add_list
5132 (Typing.err_code Typing.ReadonlyVarMismatch)
5133 (pos, "This variable is " ^ var_ro)
5135 ( rval_pos,
5136 "But it's being assigned to an expression which is "
5137 ^ rval_ro
5138 ^ "."
5139 ^ "\n For now, variables can only be assigned the same readonlyness within the body of a function."
5143 let readonly_mismatch prefix pos ~reason_sub ~reason_super =
5144 add_list
5145 (Typing.err_code Typing.ReadonlyMismatch)
5146 (pos, prefix)
5147 (reason_sub @ reason_super)
5149 let readonly_mismatch_on_error
5150 prefix pos ~reason_sub ~reason_super (on_error : typing_error_callback) =
5151 on_error
5152 ~code:(Typing.err_code Typing.ReadonlyMismatch)
5153 (pos, prefix)
5154 (reason_sub @ reason_super)
5156 let explicit_readonly_cast kind pos origin_pos =
5157 add_list
5158 (Typing.err_code Typing.ExplicitReadonlyCast)
5159 ( pos,
5160 "This "
5161 ^ kind
5162 ^ " returns a readonly value. It must be explicitly wrapped in a readonly expression."
5164 [(origin_pos, "The " ^ kind ^ " is defined here.")]
5166 let readonly_method_call receiver_pos method_pos =
5167 add_list
5168 (Typing.err_code Typing.ReadonlyMethodCall)
5169 ( receiver_pos,
5170 "This expression is readonly, so it can only call readonly methods" )
5171 [(method_pos, "This method is not readonly")]
5173 let invalid_meth_caller_calling_convention call_pos param_pos convention =
5174 add_list
5175 (Typing.err_code Typing.InvalidMethCallerCallingConvention)
5176 ( call_pos,
5177 "`meth_caller` does not support methods with the "
5178 ^ convention
5179 ^ " calling convention" )
5181 ( param_pos,
5182 "This is why I think this method uses the `inout` calling convention" );
5185 let unsafe_cast pos =
5187 (Typing.err_code Typing.UnsafeCast)
5189 "This cast violates type safety and may lead to unexpected behavior at runtime."
5191 (*****************************************************************************)
5192 (* Printing *)
5193 (*****************************************************************************)
5195 let to_json (error : Pos.absolute error_) =
5196 let (error_code, msgl) = (get_code error, to_list error) in
5197 let elts =
5198 List.map msgl (fun (p, w) ->
5199 let (line, scol, ecol) = Pos.info_pos p in
5200 Hh_json.JSON_Object
5202 ("descr", Hh_json.JSON_String w);
5203 ("path", Hh_json.JSON_String (Pos.filename p));
5204 ("line", Hh_json.int_ line);
5205 ("start", Hh_json.int_ scol);
5206 ("end", Hh_json.int_ ecol);
5207 ("code", Hh_json.int_ error_code);
5210 Hh_json.JSON_Object [("message", Hh_json.JSON_Array elts)]
5212 let convert_errors_to_string ?(include_filename = false) (errors : error list) :
5213 string list =
5214 List.fold_right
5215 ~init:[]
5216 ~f:(fun err acc_out ->
5217 List.fold_right
5218 ~init:acc_out
5219 ~f:(fun (pos, msg) acc_in ->
5220 let result = Format.asprintf "%a %s" Pos.pp pos msg in
5221 if include_filename then
5222 let full_result =
5223 Printf.sprintf
5224 "%s %s"
5225 (Pos.to_absolute pos |> Pos.filename)
5226 result
5228 full_result :: acc_in
5229 else
5230 result :: acc_in)
5231 (to_list err))
5232 errors
5234 (*****************************************************************************)
5235 (* Try if errors. *)
5236 (*****************************************************************************)
5238 let try_ f1 f2 = try_with_result f1 (fun _ err -> f2 err)
5240 let try_with_error f1 f2 =
5241 try_ f1 (fun error ->
5242 add_error error;
5243 f2 ())
5245 let has_no_errors (f : unit -> 'a) : bool =
5246 try_
5247 (fun () ->
5248 let _ = f () in
5249 true)
5250 (fun _ -> false)
5252 (*****************************************************************************)
5253 (* Do. *)
5254 (*****************************************************************************)
5256 let ignore_ f =
5257 let allow_errors_in_default_path_copy = !allow_errors_in_default_path in
5258 set_allow_errors_in_default_path true;
5259 let (_, result) = do_ f in
5260 set_allow_errors_in_default_path allow_errors_in_default_path_copy;
5261 result
5263 let try_when f ~when_ ~do_ =
5264 try_with_result f (fun result error ->
5265 if when_ () then
5266 do_ error
5267 else
5268 add_error error;
5269 result)