|
|
|
(*
|
|
|
|
* 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)
|