You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

96 lines
3.3 KiB

(*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*)
open! IStd
module F = Format
type t =
| Null (** The only possible value for that type is null *)
| Nullable (** No guarantees on the nullability *)
| ThirdPartyNonnull
(** Values coming from third-party methods and fields not explictly annotated as [@Nullable].
We still consider those as non-nullable but with the least level of confidence. *)
| UncheckedNonnull
(** The type comes from a signature that is annotated (explicitly or implicitly according to
conventions) as non-nullable. However, it might still contain null since the truthfulness
of the declaration was not checked. *)
| LocallyCheckedNonnull
(** Non-nullable value the comes from a class checked under local mode. Local mode type-checks
files against its dependencies but does not require the dependencies to be transitively
checked. Therefore this type of non-nullable value is differentiated from StrictNonnull. *)
| StrictNonnull
(** Non-nullable value with the highest degree of certainty, because it is either:
- a non-null literal,
- an expression that semantically cannot be null,
- comes from internal code checked under strict mode,
- comes from a third-party method with an appropriate built-in model or user-defined
nullability signature.
The latter two are potential sources of unsoundness issues for nullsafe, but we need to
strike the balance between the strictness of analysis, convenience, and real-world risk. *)
[@@deriving compare, equal]
type pair = t * t [@@deriving compare, equal]
let top = Nullable
let join x y =
match (x, y) with
| Null, Null ->
Null
| Null, _ | _, Null ->
Nullable
| Nullable, _ | _, Nullable ->
Nullable
| ThirdPartyNonnull, _ | _, ThirdPartyNonnull ->
ThirdPartyNonnull
| UncheckedNonnull, _ | _, UncheckedNonnull ->
UncheckedNonnull
| LocallyCheckedNonnull, _ | _, LocallyCheckedNonnull ->
LocallyCheckedNonnull
| StrictNonnull, StrictNonnull ->
StrictNonnull
let is_subtype ~subtype ~supertype = equal (join subtype supertype) supertype
let is_considered_nonnull ~nullsafe_mode nullability =
let least_required =
match nullsafe_mode with
| NullsafeMode.Strict ->
StrictNonnull
| NullsafeMode.Local (NullsafeMode.Trust.Only _classes) ->
(* TODO(T61473665). For now treat trust with specified classes as trust=none. *)
LocallyCheckedNonnull
| NullsafeMode.Local NullsafeMode.Trust.All ->
UncheckedNonnull
| NullsafeMode.Default ->
ThirdPartyNonnull
in
is_subtype ~subtype:nullability ~supertype:least_required
let is_nonnullish t = is_considered_nonnull ~nullsafe_mode:NullsafeMode.Default t
let to_string = function
| Null ->
"Null"
| Nullable ->
"Nullable"
| ThirdPartyNonnull ->
"ThirdPartyNonnull"
| UncheckedNonnull ->
"UncheckedNonnull"
| LocallyCheckedNonnull ->
"LocallyCheckedNonnull"
| StrictNonnull ->
"StrictNonnull"
let pp fmt t = F.fprintf fmt "%s" (to_string t)