2 * Copyright (c) 2015, Facebook, Inc.
5 * This source code is licensed under the MIT license found in the
6 * LICENSE file in the "hack" directory of this source tree.
11 open Reordered_argument_collections
14 type error_code
= int [@@deriving eq
]
16 (** We use `Pos.t message` on the server and convert to `Pos.absolute message`
17 * before sending it to the client *)
18 type 'a message
= 'a
* string [@@deriving eq
]
20 let get_message_pos (msg
: 'a message
) = fst msg
22 let get_message_str (msg
: 'a message
) = snd msg
41 type typing_error_callback
=
42 ?code
:int -> Pos.t
* string -> (Pos.t
* string) list
-> unit
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
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
73 let compare x y
= rank x
- rank y
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
->
93 Option.value (Relative_path.Map.find_opt
y k
) ~default
:PhaseMap.empty
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
:[]
104 let list_to_files_t = function
105 | [] -> Relative_path.Map.empty
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
=
116 = Error_codes.Init.err_code
Error_codes.Init.ForwardCompatibilityNotCurrent
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
129 | Some
(_
, phase_map
) ->
131 PhaseMap.max_binding_opt phase_map
|> Option.value_map ~f
:snd ~default
:[]
133 (match List.rev
error_list with
140 reasons
: 'a message list
;
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)
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 =
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
) =
181 let result = f1
() in
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
194 | Some
{ code
; claim
; reasons
} ->
195 (* Remove bad position sentinel if present: we might be about to add a new primary
198 let (_
, msg
) = claim
in
199 if String.equal msg
badpos_message || String.equal msg
badpos_message_2
201 if List.is_empty reasons
then
202 failwith
"in try_with_result"
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. *)
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
) =
225 (result, !error_map
, !applied_fixmes)
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";
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
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 =
290 | Parsing
-> "Parsing"
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
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
315 let rec compare (x_code
, x_messages
) (y_code
, y_messages
) =
316 match (x_messages
, y_messages
) with
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 *)
323 Relative_path.compare
324 (fst x_message
|> Pos.filename
)
325 (fst y_message
|> Pos.filename
)
327 (* Then within each file, sort by phase *)
329 if comparison = 0 then
330 Int.compare (x_code
/ 1000) (y_code
/ 1000)
334 (* If the error codes are the same, sort by position *)
336 if comparison = 0 then
337 Pos.compare (fst x_message
) (fst y_message
)
341 (* If the error codes are also the same, sort by message text *)
343 if comparison = 0 then
344 String.compare (snd x_message
) (snd y_message
)
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
)
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
378 Relative_path.Map.add
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 (*****************************************************************************)
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_
=
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
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
=
433 (match String.Map.find grouped
key with
435 let grouped = String.Map.set
grouped ~
key ~data
:(members
@ [x
]) in
436 build_map xs
grouped keys
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 =
450 let total = List.length errors
+ dropped_count
in
451 let formatted_total =
461 match max_errors
with
462 | Some max_errors
when dropped_count
> 0 ->
464 " (only showing first %d, dropped %d).\n"
469 Some
(formatted_total ^
truncated)
472 let to_absolute_for_test { code
; claim; reasons } =
474 let path = Pos.filename p
in
475 let path_without_prefix = Relative_path.suffix
path in
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
495 let error_code = error_code_to_string code
in
497 if !report_pos_from_reason && Pos.get_from_reason pos1
then
498 " [FROM REASON INFO]"
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);
514 let add_error_impl error
=
515 if !accumulate_errors then
517 match !current_context with
519 when Relative_path.equal path Relative_path.default
520 && not
!allow_errors_in_default_path ->
522 "WARNING: adding an error in default path\n%s\n"
523 (Caml.Printexc.raw_backtrace_to_string
524 (Caml.Printexc.get_callstack
100))
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)
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 (*****************************************************************************)
549 (*****************************************************************************)
551 type t
= error files_t
* applied_fixme files_t
[@@deriving eq
]
553 module type Error_category
= sig
560 val of_enum
: int -> t
option
562 val show
: t
-> string
564 val err_code
: t
-> int
567 (*****************************************************************************)
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 =
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
631 let pos_msg_l = claim :: pos_msg_l in
634 |> List.map ~
f:(fun (pos, msg) ->
635 Pos.print_verbose_relative
pos ^
": " ^
msg)
638 Exception.get_current_callstack_string
99 |> Exception.clean_stack
640 HackEventLogger.type_check_primary_position_bug
645 if Pos.equal current_span Pos.none
then
646 (Pos.make_from
current_file, badpos_message)
648 (current_span, badpos_message_2)
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)
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
685 "You cannot use `HH_FIXME` or `HH_IGNORE_ERROR` comments to suppress error %d, and this cannot be enabled by configuration"
688 add_error_with_fixme_error error explanation
692 is_not_raised_partial code
&& Relative_path.is_partial
(Pos.filename
pos)
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 *)
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
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
711 "You cannot use `HH_FIXME` or `HH_IGNORE_ERROR` comments to suppress error %d in declarations"
714 add_error_with_fixme_error error explanation
718 (not
(ISet.is_empty
!allowed_fixme_codes_partial))
719 && Relative_path.is_partial
(Pos.filename
pos)
721 is_allowed_code_partial
723 is_allowed_code_strict
725 if whitelist code
then
726 add_applied_fixme code
pos
730 "You cannot use `HH_FIXME` or `HH_IGNORE_ERROR` comments to suppress error %d"
733 add_error_with_fixme_error error explanation
735 and merge
(err'
, fixmes'
) (err, fixmes
) =
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 *)
754 ((* function folding over paths of rechecked files *)
756 (Relative_path.t
-> a files_t
-> 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
=
765 match Relative_path.Map.find_opt acc
path with
768 let new_phase_map = PhaseMap.remove phase_map phase
in
769 if PhaseMap.is_empty
new_phase_map then
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 *)
780 files_t_merge new_ old ~
f:(fun phase
path new_ old
->
781 ( if Relative_path.equal path Relative_path.default
then
785 | Parsing
-> "Parsing"
790 Utils.assert_false_log_backtrace
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`."
798 | Some new_
-> Some
(List.rev new_
)
801 (* For files that were rechecked, but had no errors - remove them from maps *)
802 fold
res (fun path acc
->
804 match Relative_path.Map.find_opt new_
path with
806 | Some phase_map
-> PhaseMap.mem phase_map
phase
811 remove path phase acc
)
813 and incremental_update_set ~old ~new_ ~rechecked
phase =
815 Relative_path.Set.fold
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 =
829 Relative_path.Map.fold
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 =
863 files_t_fold (fst
err) ~init ~
f:(fun source _ errors acc
->
864 List.fold_right errors ~init
:acc ~
f:(f source
))
866 Relative_path.Map.fold (fst
err) ~init ~
f:(fun source phases acc
->
867 match PhaseMap.find_opt phases
phase with
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
->
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
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
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
;
929 "Aliasing with `as` within a trait `use` is a PHP feature that is unsupported in Hack"
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");
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");
952 let invalid_trait_use_as_visibility pos =
953 add_error
(mk_invalid_trait_use_as_visibility pos)
955 (*****************************************************************************)
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 `$$` "
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
1016 Markdown_lite.md_highlight
s)
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),
1027 if String.equal name name_prev then
1028 "Previous definition is here"
1030 "Previous definition "
1031 ^
(highlight_differences name name_prev |> Markdown_lite.md_codify
)
1032 ^
" differs only by case " );
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."
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)]
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) =
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
=
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
=
1089 (not
(String.equal orig hint
))
1090 && String.equal (String.lowercase orig
) (String.lowercase hint
)
1093 "Did you mean %s%s instead (which only differs by case)?"
1095 (highlight_differences orig hint
|> Markdown_lite.md_codify
)
1098 "Did you mean %s%s instead?"
1100 (Markdown_lite.md_codify hint
)
1104 let undefined pos var_name did_you_mean
=
1107 "Variable %s is undefined, or not always defined."
1108 (Markdown_lite.md_codify var_name
)
1111 match did_you_mean
with
1112 | Some
(did_you_mean
, pos) -> [hint_message var_name did_you_mean
pos]
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
1138 (Naming.err_code
Naming.UnexpectedTypedef
)
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");
1152 let fd_name_already_bound pos = add_error
(mk_fd_name_already_bound pos)
1154 let repeated_record_field name pos prev_pos
=
1156 Printf.sprintf
"Duplicate record field %s" (Markdown_lite.md_codify
name)
1159 (NastCheck.err_code
NastCheck.RepeatedRecordFieldName
)
1161 [(prev_pos
, "Previous field is here")]
1163 let unexpected_record_field_name ~field_name ~field_pos ~record_name ~decl_pos
=
1166 "Record %s has no field %s"
1167 (strip_ns record_name
|> Markdown_lite.md_codify
)
1168 (Markdown_lite.md_codify field_name
)
1171 (Typing.err_code
Typing.RecordUnknownField
)
1173 [(decl_pos
, "Definition is here")]
1175 let missing_record_field_name ~field_name ~new_pos ~record_name ~field_decl_pos
1179 "Mising required field %s in %s"
1180 (Markdown_lite.md_codify field_name
)
1181 (strip_ns record_name
|> Markdown_lite.md_codify
)
1184 (Typing.err_code
Typing.RecordMissingRequiredField
)
1186 [(field_decl_pos
, "Field definition is here")]
1188 let type_not_record id
pos =
1190 (Typing.err_code
Typing.NotARecord
)
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
=
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 =
1236 if string_starts_with
name "__" then
1237 "starts with __ but is not a standard attribute"
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
)
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
)
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 =
1306 | _
-> Markdown_lite.md_codify
x ^
" is a type parameter. "
1309 (Naming.err_code
Naming.HigherKindedTypesUnsupportedFeature
)
1312 "%sType parameters cannot themselves have type parameters"
1315 let shadowed_type_param p pos name =
1317 (Naming.err_code
Naming.ShadowedTypeParam
)
1320 "You cannot re-bind the type parameter %s"
1321 (Markdown_lite.md_codify
name) )
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 =
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 =
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 =
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 =
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 =
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 =
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
=
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
=
1436 if not is_trait
then
1437 "Use `" ^
strip_ns class_name ^
"::class` explicitly"
1442 "`class_meth` with `__CLASS__` in non-final classes is not allowed.\n"
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
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
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
)
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
1490 (Typing.err_code
Typing.AbstractConstUsage
)
1492 "Cannot reference abstract constant "
1493 ^
Markdown_lite.md_codify
name
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
1501 ~code
:(Typing.err_code
Typing.ConcreteConstInterfaceOverride
)
1503 "Non-abstract constants defined in an interface cannot be overridden when implementing or extending that interface."
1508 ^
Markdown_lite.md_codify
name
1510 ^
Markdown_lite.md_codify
parent_origin
1514 let interface_const_multiple_defs
1520 (on_error
: typing_error_callback
) =
1521 let parent_origin = strip_ns parent_origin in
1522 let child_origin = strip_ns child_origin in
1524 ~code
:(Typing.err_code
Typing.ConcreteConstInterfaceOverride
)
1526 "Non-abstract constants defined in an interface cannot conflict with other inherited constants."
1530 Markdown_lite.md_codify
name
1531 ^
" inherited from "
1532 ^
Markdown_lite.md_codify
parent_origin );
1534 "conflicts with constant "
1535 ^
Markdown_lite.md_codify
name
1536 ^
" inherited from "
1537 ^
Markdown_lite.md_codify
child_origin
1541 let interface_typeconst_multiple_defs
1548 (on_error
: typing_error_callback
) =
1549 let parent_origin = strip_ns parent_origin in
1550 let child_origin = strip_ns child_origin in
1552 if child_is_abstract
then
1553 "abstract type constant with default value"
1555 "concrete type constant"
1558 ~code
:(Typing.err_code
Typing.ConcreteConstInterfaceOverride
)
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." )
1564 Markdown_lite.md_codify
name
1565 ^
" inherited from "
1566 ^
Markdown_lite.md_codify
parent_origin );
1569 ^
Markdown_lite.md_codify
child
1571 ^
Markdown_lite.md_codify
name
1572 ^
" inherited from "
1573 ^
Markdown_lite.md_codify
child_origin
1577 let const_without_typehint sid
=
1578 let (pos, name) = sid
in
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
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
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
;
1633 (pos, "Methods need to be marked `public`, `private`, or `protected`.");
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
)
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
)
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
=
1681 (Naming.err_code
Naming.IllegalUseOfDynamicallyCallable
)
1682 (attr_pos
, "`__DynamicallyCallable` can only be used on public methods")
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
)
1692 "`__DynamicallyCallable` cannot be used on reified functions or methods"
1694 let parent_in_function_pointer pos parento meth_name
=
1697 | None
-> "Consider using the name of the parent class explicitly."
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. "
1708 let self_in_non_final_function_pointer pos cido meth_name
=
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. "
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
)
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
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): "
1761 let not_initialized (pos, cname
) props
=
1762 let cname = strip_ns cname in
1764 List.map props ~
f:(fun (pos, prop
) ->
1766 Markdown_lite.md_codify
("$this->" ^ prop
) ^
" is not initialized." ))
1769 (NastCheck.err_code
NastCheck.NotInitialized
)
1772 ^
Markdown_lite.md_codify
cname
1773 ^
" has properties that cannot be null and aren't always set in `__construct`."
1777 let call_before_init pos cv
=
1779 (NastCheck.err_code
NastCheck.CallBeforeInit
)
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`"]
1792 Markdown_lite.md_codify
("$this->" ^ cv
);
1793 " can still potentially be null";
1796 (*****************************************************************************)
1797 (* Nast errors check *)
1798 (*****************************************************************************)
1800 let type_arity use_pos def_pos ~expected ~actual
=
1802 (Typing.err_code
Typing.TypeArityMismatch
)
1805 "Wrong number of type arguments (expected %d, got %d)"
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
;
1827 "This type constant is not declared as abstract, it must have"
1828 ^
" an assigned type" );
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
=
1837 (NastCheck.err_code
NastCheck.TypeconstDependsOnExternalTparam
)
1839 "A type constant can only use type parameters declared in its own"
1840 ^
" type parameter list" )
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
)
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");
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 "
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
)
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 "
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 "
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 () =
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
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
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 =
2079 NastCheck.(err_code IllegalContext
)
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
=
2093 (NastCheck.err_code
NastCheck.CaseFallthrough
)
2095 "This `switch` has a `case` that implicitly falls through and is "
2096 ^
"not annotated with `// FALLTHROUGH`" )
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 (*****************************************************************************)
2112 (*****************************************************************************)
2114 let visibility_extends
2115 vis
pos parent_pos parent_vis
(on_error
: typing_error_callback
) =
2117 (pos, "This member visibility is: " ^
Markdown_lite.md_codify vis
)
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
=
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
=
2138 ^
(strip_ns name |> Markdown_lite.md_codify
)
2139 ^
" does not correctly implement all required members " )
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
)
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
) =
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
) =
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
) =
2185 (Typing.err_code
Typing.AbstractTconstNotAllowed
)
2186 (pos, "An abstract type constant is not allowed in this position.")
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
=
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
)]
2204 let enum_type_bad pos ty_dependent ty trail
=
2205 let ty = Markdown_lite.md_codify
ty in
2207 if ty_dependent
then
2208 "Invalid base type for an enum class: "
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
=
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
=
2228 (Typing.err_code
Typing.EnumSwitchNonexhaustive
)
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
=
2237 (Typing.err_code
Typing.EnumSwitchRedundantDefault
)
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
=
2273 (Typing.err_code
Typing.InvalidShapeFieldType
)
2274 (pos, "A shape field name must be an `int` or `string`")
2275 [(ty_pos
, "Not " ^
ty)]
2278 let invalid_shape_field_literal key_pos witness_pos
=
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
=
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
=
2292 (Typing.err_code
Typing.ShapeFieldClassMismatch
)
2294 "Shape field name is class constant from "
2295 ^
Markdown_lite.md_codify key_class
)
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
=
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
) =
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
) =
2315 ~code
:(Typing.err_code
Typing.ShapeFieldsUnknown
)
2317 "This shape type allows unknown fields, and so it may contain fields other than those explicitly declared in its declaration."
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 =
2332 (Typing.err_code
Typing.UnificationCycle
)
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
) =
2342 ~code
:(Typing.err_code
Typing.TypeConstraintViolation
)
2343 (p_cstr
, "Some type constraint(s) are violated here")
2347 "%s is a constrained type parameter"
2348 (Markdown_lite.md_codify tparam
) );
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
2365 if String.equal msg inst_msg && Pos.equal p use_pos
then
2370 let name = strip_ns param_name
in
2372 (Typing.err_code
Typing.TypeConstraintViolation
)
2375 Markdown_lite.md_codify
name ^
" is a constrained type parameter" )
2378 let explain_where_constraint ~in_class ~use_pos ~definition_pos
claim reasons =
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
2390 (Typing.err_code
Typing.TypeConstraintViolation
)
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
2397 (Typing.err_code
Typing.TypeConstraintViolation
)
2401 "This method's `where` constraints contain a generic type access" );
2405 let format_string pos snippet
s class_pos fname class_suggest
=
2407 (Typing.err_code
Typing.FormatString
)
2409 "Invalid format string "
2410 ^
Markdown_lite.md_codify snippet
2412 ^
Markdown_lite.md_codify
("\"" ^
s ^
"\"") )
2415 "You can add a new format specifier by adding "
2416 ^
Markdown_lite.md_codify
(fname ^
"()")
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) =
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 "
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
) =
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
=
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 =
2560 (Typing.err_code
Typing.UnboundNameTypeConstantAccess
)
2563 ^
Markdown_lite.md_codify
(strip_ns name)
2564 ^
" in type constant access" )
2567 if Pos.equal name_pos access_pos
then
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
=
2584 | `noreturn
-> "noreturn"
2587 (Naming.err_code
Naming.ReturnOnlyTypehint
)
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
=
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
)
2621 "Unbound global constant (Typing)"
2623 let private_inst_meth ~def_pos ~use_pos
=
2625 (Typing.err_code
Typing.PrivateInstMeth
)
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
=
2633 (Typing.err_code
Typing.ProtectedInstMeth
)
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
=
2641 (Typing.err_code
Typing.PrivateClassMeth
)
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
=
2649 (Typing.err_code
Typing.ProtectedClassMeth
)
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
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
=
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
2689 | `static
-> "Can't use `new static()` for " ^
Markdown_lite.md_codify
name
2691 "Can't use `new` on " ^
Markdown_lite.md_codify
("classname<" ^
name ^
">")
2694 (Typing.err_code
Typing.NewStaticInconsistent
)
2697 ^
"; `__construct` arguments are not guaranteed to be consistent in child classes"
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
=
2719 (Typing.err_code
Typing.AbstractCall
)
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
=
2728 (Typing.err_code
Typing.AbstractCall
)
2731 ^
Markdown_lite.md_codify
("self::" ^ meth_name ^
"()")
2732 ^
"; it is abstract. Did you mean "
2733 ^
Markdown_lite.md_codify
("static::" ^ meth_name ^
"()")
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
2740 (Typing.err_code
Typing.AbstractCall
)
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
2750 (Typing.err_code
Typing.StaticSyntheticMethod
)
2753 ^
Markdown_lite.md_codify
(cname ^
"::" ^ meth_name ^
"()")
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 "
2767 let unset_nonidx_in_strict pos msgs
=
2769 (Typing.err_code
Typing.UnsetNonidxInStrict
)
2771 "In `strict` mode, `unset` is banned except on dynamic, "
2772 ^
"darray, keyset, or dict indexing" )
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
) =
2784 ~code
:(Typing.err_code
Typing.InvalidDestructure
)
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
) =
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
) =
2797 ~code
:(Typing.err_code
Typing.SplatArrayRequired
)
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
=
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
=
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 =
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")]
2826 let array_access_read = array_access Typing.ArrayAccessRead
2828 let array_access_write = array_access Typing.ArrayAccessWrite
2830 let keyset_set pos1 pos2
=
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")]
2839 let array_append pos1 pos2
ty =
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")]
2848 let const_mutation pos1 pos2
ty =
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)]
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
=
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
=
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
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
2902 (Markdown_lite.md_codify member_name
)
2903 (Markdown_lite.md_codify
class_name)
2906 ~code
:(Typing.err_code
Typing.SmemberNotFound
)
2909 match snot_found_hint member_name
hint with
2911 | Some
hint -> [hint]
2916 "Declaration of " ^
Markdown_lite.md_codify
class_name ^
" is here"
2920 let member_not_found
2927 (on_error
: typing_error_callback
) =
2928 let type_name = strip_ns type_name |> Markdown_lite.md_codify
in
2931 | `method_
-> "instance method"
2932 | `property
-> "property"
2938 (Markdown_lite.md_codify member_name
)
2942 ~code
:(Typing.err_code
Typing.MemberNotFound
)
2945 match not_found_hint member_name
hint with
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
=
2953 match String.chop_prefix meth_name ~prefix
:"__to" with
2955 (* Complain about usage like `if ($not_bool)` that's virtualized to
2956 `if ($not_bool->__toBool())`.
2959 "`%s` cannot be used in a %s position (it has no %s method named `%s`)"
2961 (String.lowercase
type_name)
2968 (* Complain about usage like `$not_int +` that's virtualized to
2969 `$not_int->__plus(...)`.
2972 "`%s` does not support this operator (it has no %s method named `%s`)"
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
=
3003 (Typing.err_code
Typing.TypingTooManyArgs
)
3006 "Too many arguments (expected %d but got %d)"
3009 [(pos_def
, "Definition is here")]
3011 let typing_too_few_args required actual
pos pos_def on_error
=
3014 (Typing.err_code
Typing.TypingTooFewArgs
)
3017 "Too few arguments (required %d but got %d)"
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
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
3039 "Cannot extend record %s because it isn't abstract"
3040 (Markdown_lite.md_codify
name)
3043 (Typing.err_code
Typing.ExtendFinal
)
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
3050 (Typing.err_code
Typing.ExtendSealed
)
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
)
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
3083 "This class was declared as `final`. It must provide an implementation for the "
3086 "This class must be declared `abstract`, or provide an implementation for the "
3090 (Typing.err_code
Typing.ImplementAbstract
)
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
3102 let fun_too_many_args
3103 required actual pos1 pos2
(on_error
: typing_error_callback
) =
3105 ~code
:(Typing.err_code
Typing.FunTooManyArgs
)
3108 "Too many mandatory arguments (expected %d but got %d)"
3111 [(pos2
, "Because of this definition")]
3113 let fun_too_few_args
3114 required actual pos1 pos2
(on_error
: typing_error_callback
) =
3116 ~code
:(Typing.err_code
Typing.FunTooFewArgs
)
3119 "Too few arguments (required %d but got %d)"
3122 [(pos2
, "Because of this definition")]
3124 let fun_unexpected_nonvariadic pos1 pos2
(on_error
: typing_error_callback
) =
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
) =
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 =
3139 | `Type
-> "Cannot use `...` without a **type hint** in strict mode."
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 =
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
3154 ~use_pos ~definition_pos n
(on_error
: typing_error_callback
option) =
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
=
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
=
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
) =
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
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
) =
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
=
3213 (Typing.err_code
Typing.RequireArgsReify
)
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
=
3221 (Typing.err_code
Typing.RequireGenericExplicit
)
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
3231 (Typing.err_code
Typing.InvalidReifiedArgument
)
3232 (hint_pos
, "Invalid reified hint")
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
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
=
3252 match suggested_class
with
3254 let s = strip_ns s in
3255 sprintf
". Try `new %s` instead." s
3259 (Typing.err_code
Typing.NewClassReified
)
3262 "Cannot call `new %s` because the current class has reified generics%s"
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
=
3274 (Typing.err_code
Typing.StaticMethWithClassReifiedGeneric
)
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
=
3308 (Typing.err_code
Typing.DiscardedAwaitable
)
3310 "This expression is of type `Awaitable`, but it's "
3311 ^
"either being discarded or used in a dangerous way before "
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
=
3331 Option.value code ~default
:(Typing.err_code
Typing.TypeConstantMismatch
)
3335 let class_constant_type_mismatch (on_error
: typing_error_callback
) ?
code errl
=
3339 ~default
:(Typing.err_code
Typing.ClassConstantTypeMismatch
)
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
=
3393 (" with await", Naming_special_names.Classes.cIAsyncDisposable
)
3395 ("", Naming_special_names.Classes.cIDisposable
)
3398 (Typing.err_code
Typing.UnifyError
)
3401 "This expression is used in a `using` clause%s so it must have type `%s`"
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
=
3417 let elt_type = elt_type_to_string elt_type in
3422 ^
Markdown_lite.md_codify
(dollar ^ member_name
)
3423 ^
" is declared here as non-static"
3426 "But it conflicts with an inherited static declaration here"
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 =
3440 let elt_type = elt_type_to_string elt_type in
3445 ^
Markdown_lite.md_codify
(dollar ^ member_name
)
3446 ^
" is declared here as static"
3449 "But it conflicts with an inherited non-static declaration here"
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
=
3459 "You are trying to access the %s %s but this object can be null."
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
=
3476 "You are trying to access the %s %s but this is %s. Use a **specific** class or interface name."
3481 (Markdown_lite.md_codify
s)
3486 ( if is_nullable
then
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
) =
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)
3509 if String.equal ty "a shape" then
3510 msg_start ^
". Did you mean `$foo['" ^
s ^
"']` instead?"
3515 ~
code:(Typing.err_code
code)
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
=
3526 "You are trying to access the %s %s on a value whose class is unknown."
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
=
3538 "You are trying to access the static %s %s but this is %s"
3543 (Markdown_lite.md_codify
s)
3547 (Typing.err_code
Typing.NonClassMember
)
3549 [(pos2
, "Definition is here")]
3551 let null_container p null_witness
=
3553 (Typing.err_code
Typing.NullContainer
)
3555 "You are trying to access an element of this container"
3556 ^
" but the container could be `null`. " )
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
=
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 `+`")]
3578 let declared_contravariant pos1 pos2 emsg
=
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 `-`")]
3585 let static_property_type_generic_param ~class_pos ~var_type_pos ~generic_pos
=
3587 (Typing.err_code
Typing.ClassVarTypeGenericParam
)
3589 "A generic parameter cannot be used in the type of a static property" )
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
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 =
3617 | `method_
-> "method"
3618 | `typeconst
-> "type constant"
3619 | `constant
-> "constant"
3620 | `property
-> "property"
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
)
3630 ~
code:(Typing.err_code
Typing.RequiredFieldIsOptional
)
3631 (pos1
, "The field " ^
Markdown_lite.md_codify
name ^
" is **optional**")
3635 ^
Markdown_lite.md_codify
name
3636 ^
" is defined as **required**" );
3639 let array_get_with_optional_field pos1 pos2
name =
3641 (Typing.err_code
Typing.ArrayGetWithOptionalField
)
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
3653 ~
code:(Typing.err_code
Typing.ReturnDisposableMismatch
)
3655 if pos1_return_disposable
then
3661 if pos1_return_disposable
then
3667 let ifc_policy_mismatch
3668 pos_sub pos_super policy_sub policy_super
(on_error
: typing_error_callback
)
3671 "IFC policies must be invariant with respect to inheritance. This method is policied with "
3675 "This is incompatible with its inherited policy, which is " ^ policy_super
3678 ~
code:(Typing.err_code
Typing.IFCPolicyMismatch
)
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
3711 (on_error
: typing_error_callback
) =
3712 let m1 = "This property is `__Const`" in
3713 let m2 = "This property is not `__Const`" in
3715 ~
code:(Typing.err_code
Typing.OverridingPropConstMismatch
)
3723 if parent_const
then
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
3743 ~parent_is_enum_class
3747 ~child_is_enum_class
=
3748 let parent_kind_str =
3749 Ast_defs.string_of_class_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
3757 " Did you mean to add `use %s;` within the body of %s?"
3759 (Markdown_lite.md_codify
child_name)
3762 match child_kind
with
3763 | Ast_defs.Cabstract
3764 | Ast_defs.Cnormal
->
3765 let extends_msg = "Classes can only extend other classes." in
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
3774 extends_msg ^
suggestion
3775 | Ast_defs.Cinterface
->
3776 let extends_msg = "Interfaces can only extend other interfaces." in
3778 if Ast_defs.is_c_trait parent_kind
then
3783 extends_msg ^
suggestion
3785 if child_is_enum_class
then
3786 "Enum classes can only extend other enum classes."
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
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
3807 (Typing.err_code
Typing.UnsatisfiedReq
)
3811 let cyclic_class_def stack pos =
3814 ~
f:(fun x y -> (strip_ns x |> Markdown_lite.md_codify
) ^
" " ^
y)
3819 (Typing.err_code
Typing.CyclicClassDef
)
3821 ("Cyclic class definition : " ^
stack)
3823 let cyclic_record_def names
pos =
3825 List.map ~
f:(fun n -> strip_ns n |> Markdown_lite.md_codify
) names
3828 (Typing.err_code
Typing.CyclicRecordDef
)
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
=
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
3848 "Class " ^
c_name ^
" reuses trait " ^
trait ^
" in its hierarchy"
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
3861 (Typing.err_code
Typing.TraitReuseInsideClass
)
3863 (List.map ~
f:(fun p -> (p, "used here")) occurrences
)
3865 let invalid_is_as_expression_hint op hint_pos
reasons =
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
) ->
3872 ^
Markdown_lite.md_codify op
3873 ^
" operator cannot be used with "
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
3879 (Typing.err_code
Typing.InvalidEnforceableTypeArgument
)
3880 (targ_pos
, "Invalid type")
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
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
=
3903 (Typing.err_code
Typing.InvalidNewableTypeArgument
)
3905 "A newable type argument must be a concrete class or a newable 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
=
3917 if List.is_empty constraint_list
then
3921 ^
String.concat ~sep
:", " (List.map ~
f:strip_ns constraint_list
)
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. "
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
)
3942 ~
code:(Typing.err_code
Typing.OverrideLSB
)
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
)
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
3962 "`%s::%s` is marked `__Override` but `%s` does not define or inherit a `%s` method."
3963 (strip_ns trait_name
)
3969 (Typing.err_code
Typing.OverridePerTrait
)
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
=
3980 (Typing.err_code
Typing.InvalidMemoizedParam
)
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"
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
)
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
4014 (Typing.err_code
Typing.XhpRequired
)
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
=
4024 "Required attribute " ^
Markdown_lite.md_codify attr ^
" is missing."
4027 (Typing.err_code
Typing.MissingXhpRequiredAttr
)
4031 let nullsafe_not_needed p nonnull_witness
=
4033 (Typing.err_code
Typing.NullsafeNotNeeded
)
4034 (p, "You are using the `?->` operator but this object cannot be null. ")
4037 let generic_at_runtime p prefix
=
4039 (Typing.err_code
Typing.ErasedGenericAtRuntime
)
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
4056 (Typing.err_code
Typing.TrivialStrictEq
)
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
4063 (Typing.err_code
Typing.NotNullableCompareNullTrivial
)
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
=
4073 "This comparison has invalid types. Only comparisons in which both arguments are strings, nums, DateTime, or DateTimeImmutable are allowed"
4076 (Typing.err_code
Typing.ComparisonInvalidTypes
)
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
)
4094 ^
Markdown_lite.md_codify
x
4095 ^
" expects at least "
4099 let attribute_too_many_arguments pos x n =
4100 let n = string_of_int
n in
4102 (Typing.err_code
Typing.AttributeTooManyArguments
)
4105 ^
Markdown_lite.md_codify
x
4106 ^
" expects at most "
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 =
4119 | Some pos_def
-> [(pos_def
, "Definition is here")]
4122 add_list
(Typing.err_code
Typing.DeprecatedUse
) (pos, msg) def_message
4124 let cannot_declare_constant kind pos (class_pos
, class_name) =
4127 | `enum
-> "an enum"
4128 | `record
-> "a record"
4131 (Typing.err_code
Typing.CannotDeclareConstant
)
4132 (pos, "Cannot declare a constant in " ^
kind_str)
4135 (strip_ns class_name |> Markdown_lite.md_codify
)
4136 ^
" was defined as "
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
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
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
4167 ~
code:(Typing.err_code
Typing.MultipleConcreteDefs
)
4169 Markdown_lite.md_codify
child_origin
4171 ^
Markdown_lite.md_codify
parent_origin
4172 ^
" both declare ambiguous implementations of "
4173 ^
Markdown_lite.md_codify
name
4177 Markdown_lite.md_codify
child_origin ^
"'s definition is here." );
4179 Markdown_lite.md_codify
parent_origin ^
"'s definition is here." );
4182 ^
Markdown_lite.md_codify
name
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
4191 (Typing.err_code
Typing.LocalVariableModifedAndUsed
)
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
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
=
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"
4224 add
(Typing.err_code
Typing.IllegalTypeStructure
) pos msg
4226 let illegal_typeconst_direct_access pos =
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
=
4235 (Typing.err_code
Typing.OverrideNoDefaultTypeconst
)
4236 (pos_child
, "This abstract type constant does not have a default type")
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
4252 if pos2_is_variadic
then
4253 "A variadic parameter can never be `inout`"
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 =
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 =
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 =
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
=
4286 "Lambda has parameter types that could not be determined at definition site."
4290 "%d distinct use types were determined: please add type hints to lambda parameters."
4294 (Typing.err_code
Typing.AmbiguousLambda
)
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
=
4304 "The %s attribute cannot be used on %s."
4305 (strip_ns attr
|> Markdown_lite.md_codify
)
4310 "The attribute's class is defined here. To be available for use on %s, the %s class must implement %s."
4312 (strip_ns attr_class_name
|> Markdown_lite.md_codify
)
4313 (strip_ns intf_name
|> Markdown_lite.md_codify
)
4316 (Typing.err_code
Typing.WrongExpressionKindAttribute
)
4318 [(attr_class_pos
, msg2)]
4320 let wrong_expression_kind_builtin_attribute expr_kind
pos attr
=
4323 "The %s attribute cannot be used on %s."
4324 (strip_ns attr
|> Markdown_lite.md_codify
)
4327 add_list
(Typing.err_code
Typing.WrongExpressionKindAttribute
) (pos, msg1) []
4329 let decl_override_missing_hint pos (on_error
: typing_error_callback
) =
4331 ~
code:(Typing.err_code
Typing.DeclOverrideMissingHint
)
4333 "When redeclaring class members, both declarations must have a typehint"
4337 let shapes_key_exists_always_true pos1
name pos2
=
4339 (Typing.err_code
Typing.ShapesKeyExistsAlwaysTrue
)
4340 (pos1
, "This `Shapes::keyExists()` check is always true")
4344 ^
Markdown_lite.md_codify
name
4345 ^
" exists because of this definition" );
4348 let shape_field_non_existence_reason pos name = function
4353 ^
Markdown_lite.md_codify
name
4354 ^
" is not defined in this shape" );
4356 | `Nothing
reason ->
4358 "The type of the field "
4359 ^
Markdown_lite.md_codify
name
4360 ^
" in this shape doesn't allow any values" )
4363 let shapes_key_exists_always_false pos1
name pos2
reason =
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 =
4372 (Typing.err_code
Typing.ShapesMethodAccessWithNonExistentField
)
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 =
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
4390 (Typing.err_code
Typing.AmbiguousObjectAccess
)
4392 "This object access to " ^
Markdown_lite.md_codify
name ^
" is ambiguous"
4396 "You will access the private instance declared in "
4397 ^
Markdown_lite.md_codify
class_self );
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
) =
4414 if parent_is_lateinit
then
4420 ~
code:(Typing.err_code
Typing.BadLateInitOverride
)
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
)
4429 ~
code:(Typing.err_code
Typing.BadXhpAttrRequiredOverride
)
4430 (child_pos
, "Redeclared attribute must not be less strict")
4435 ^
", which is stricter than "
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
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): "
4453 let invalid_arraykey code pos (cpos
, ctype
) (kpos
, ktype
) =
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 "
4471 let typechecker_timeout (pos, fun_name
) seconds
=
4473 (Typing.err_code
Typing.TypecheckerTimeout
)
4476 "Type checker timed out after %d seconds whilst checking function %s"
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
)
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
;
4498 "Exception while typechecking at position %s\n%s"
4500 (Exception.to_string e
);
4502 (Typing.err_code
Typing.ExceptionOccurred
)
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"
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
=
4529 (Typing.err_code
Typing.DuplicateInterface
)
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. "
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
)
4550 ^
"We don't support "
4551 ^ feature_description
4552 ^
" parameters like "
4553 ^
Markdown_lite.md_codify var_name
4556 let tparam_non_shadowing_reuse pos var_name
=
4558 (Typing.err_code
Typing.TypeParameterNameAlreadyUsedNonShadow
)
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
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
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
4601 "Context-implicit policy leaks into %s via %s."
4602 (Markdown_lite.md_codify
sink)
4603 (Markdown_lite.md_codify
source) )
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
)
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
4627 (Typing.err_code
Typing.ClassMethAbstractCall
)
4629 "Cannot create a class_meth of "
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
=
4655 (* This should be Naming_special_names.Typehints.wildcard, but its not available in this
4657 if String.equal param_name
"_" then
4658 "the anonymous generic parameter"
4660 "the generic parameter " ^ param_name
4663 (Naming.err_code
Naming.HigherKindedTypesUnsupportedFeature
)
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 "
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 * *)
4675 ~use_pos ~def_pos ~tparam_name ~expected_kind_repr ~actual_kind_repr
=
4677 (Typing.err_code
Typing.KindMismatch
)
4682 ^ expected_kind_repr
4683 ^
" was expected here." )
4687 ^ expected_kind_repr
4688 ^
" due to the definition of "
4693 let class_with_constraints_used_as_hk_type use_pos
class_name =
4695 (Naming.err_code
Naming.HigherKindedTypesUnsupportedFeature
)
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
4705 ~used_class_in_def_pos
4707 ~typedef_tparam_name
4708 ~used_class_in_def_name
4709 ~used_class_tparam_name
=
4711 (Naming.err_code
Naming.HigherKindedTypesUnsupportedFeature
)
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
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
4731 ^
strip_ns typedef_name
4735 let reinheriting_classish_const
4740 existing_const_origin
4743 (Typing.err_code
Typing.RedeclaringClassishConstant
)
4745 strip_ns dest_classish_name
4746 ^
" cannot re-inherit constant "
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
4760 existing_const_origin
4763 (Typing.err_code
Typing.RedeclaringClassishConstant
)
4764 ( redeclaration_pos
,
4765 strip_ns classish_name ^
" cannot re-declare constant " ^ const_name
)
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
=
4775 (Typing.err_code
Typing.IncompatibleEnumInclusion
)
4776 ( dest_classish_pos
,
4778 ^
strip_ns dest_classish_name
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
=
4787 (Typing.err_code
Typing.IncompatibleEnumInclusion
)
4788 ( dest_classish_pos
,
4790 ^
strip_ns dest_classish_name
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
=
4799 (Typing.err_code
Typing.IncompatibleEnumInclusion
)
4800 ( dest_classish_pos
,
4802 ^
strip_ns dest_classish_name
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
)
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
=
4821 (Typing.err_code
Typing.CallCoeffects
)
4823 "This call is not allowed because its coeffects are incompatible with the context"
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
=
4838 op ^
" requires " ^ required ^
", which is not provided by the context."
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
4849 (Typing.err_code
Typing.AbstractFunctionPointer
)
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
4860 match suggestion with
4861 | None
-> "Try deleting this attribute"
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
4881 ^
Markdown_lite.md_codify
name_prev
4882 ^
" which differs from this one ("
4884 ^
") only by case." )
4889 "It was inherited from "
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 "
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
4910 Markdown_lite.md_codify
child_class
4911 ^
" inherited two versions of the "
4914 ^
Markdown_lite.md_codify
name1
4915 ^
" that differ only by case." )
4921 ^
Markdown_lite.md_codify
name1
4927 ^
Markdown_lite.md_codify
name2
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 =
4937 (Typing.err_code
Typing.AtomInvalidParameter
)
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 =
4947 (Typing.err_code
Typing.AtomInvalidParameter
)
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 =
4958 (Typing.err_code
Typing.AtomInvalidParameter
)
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
4970 (Typing.err_code
Typing.AtomUnknown
)
4971 (pos, "Unknown constant " ^ atom_name ^
" in " ^
class_name)
4974 let atom_as_expr pos =
4976 (Typing.err_code
Typing.AtomAsExpression
)
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 =
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: "
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
) ->
5016 | (_
, Ast_defs.Ctrait
) -> "uses "
5017 | (Ast_defs.Cinterface
, Ast_defs.Cinterface
) -> "extends "
5018 | (_
, Ast_defs.Cinterface
) -> "implements "
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
5030 ^
( if child_implements_dynamic
then
5035 ^
"dynamic because it "
5036 ^
kinds_to_use child_kind parent_kind
5041 if child_implements_dynamic
then
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
)
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
)
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
)
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
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 =
5119 | Some
(rpos
, rmsg
) ->
5121 (Typing.err_code
Typing.ReadonlyValueModified
)
5122 (pos, "This value is readonly, its properties cannot be modified")
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
=
5132 (Typing.err_code
Typing.ReadonlyVarMismatch
)
5133 (pos, "This variable is " ^ var_ro
)
5136 "But it's being assigned to an expression which is "
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
=
5145 (Typing.err_code
Typing.ReadonlyMismatch
)
5147 (reason_sub
@ reason_super
)
5149 let readonly_mismatch_on_error
5150 prefix
pos ~reason_sub ~reason_super
(on_error
: typing_error_callback
) =
5152 ~
code:(Typing.err_code
Typing.ReadonlyMismatch
)
5154 (reason_sub
@ reason_super
)
5156 let explicit_readonly_cast kind pos origin_pos
=
5158 (Typing.err_code
Typing.ExplicitReadonlyCast
)
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
=
5168 (Typing.err_code
Typing.ReadonlyMethodCall
)
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
=
5175 (Typing.err_code
Typing.InvalidMethCallerCallingConvention
)
5177 "`meth_caller` does not support methods with the "
5179 ^
" calling convention" )
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 (*****************************************************************************)
5193 (*****************************************************************************)
5195 let to_json (error : Pos.absolute error_
) =
5196 let (error_code, msgl) = (get_code
error, to_list error) in
5198 List.map
msgl (fun (p, w
) ->
5199 let (line
, scol
, ecol
) = Pos.info_pos
p in
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
) :
5216 ~
f:(fun err 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
5225 (Pos.to_absolute pos |> Pos.filename
)
5228 full_result :: acc_in
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 ->
5245 let has_no_errors (f : unit -> 'a
) : bool =
5252 (*****************************************************************************)
5254 (*****************************************************************************)
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;
5263 let try_when f ~when_ ~
do_ =
5264 try_with_result f (fun result error ->