[nullsafe] Rename nullability variants

Summary:
Rename DeclaredNonnull -> UncheckedNonnull, Nonnull -> StrictNonnull.
This is a preparatory step to introduce one more nullability option,
specifically CheckedNonnull to support local nullsafe mode.

Reviewed By: ngorogiannis, mityal

Differential Revision: D19619289

fbshipit-source-id: 12a3ff814
master
Artem Pianykh 5 years ago committed by Facebook Github Bot
parent c0a990c47c
commit ea3cbae757

@ -56,12 +56,12 @@ let get tenv field_name class_typ =
in in
let corrected_nullability = let corrected_nullability =
match nullability with match nullability with
| AnnotatedNullability.DeclaredNonnull _ when is_enum_value -> | AnnotatedNullability.UncheckedNonnull _ when is_enum_value ->
(* Enum values are the special case - they can not be null. So we can strengten nullability. (* Enum values are the special case - they can not be null. So we can strengten nullability.
Note that if it is nullable, we do NOT change nullability: in this case this is probably Note that if it is nullable, we do NOT change nullability: in this case this is probably
not an enum value, but just a static field annotated as nullable. not an enum value, but just a static field annotated as nullable.
*) *)
AnnotatedNullability.Nonnull EnumValue AnnotatedNullability.StrictNonnull EnumValue
| _ -> | _ ->
nullability nullability
in in

@ -16,8 +16,8 @@ module F = Format
type t = type t =
| Nullable of nullable_origin | Nullable of nullable_origin
| DeclaredNonnull of declared_nonnull_origin (** See {!Nullability.t} for explanation *) | UncheckedNonnull of unchecked_nonnull_origin (** See {!Nullability.t} for explanation *)
| Nonnull of nonnull_origin | StrictNonnull of strict_nonnull_origin
[@@deriving compare] [@@deriving compare]
and nullable_origin = and nullable_origin =
@ -31,7 +31,7 @@ and nullable_origin =
| ModelledNullable (** nullsafe knows it is nullable via its internal models *) | ModelledNullable (** nullsafe knows it is nullable via its internal models *)
[@@deriving compare] [@@deriving compare]
and declared_nonnull_origin = and unchecked_nonnull_origin =
| AnnotatedNonnull | AnnotatedNonnull
(** The type is explicitly annotated as non nullable via one of nonnull annotations Nullsafe (** The type is explicitly annotated as non nullable via one of nonnull annotations Nullsafe
recognizes *) recognizes *)
@ -39,7 +39,7 @@ and declared_nonnull_origin =
(** Infer was run in mode where all not annotated (non local) types are treated as non (** Infer was run in mode where all not annotated (non local) types are treated as non
nullable *) nullable *)
and nonnull_origin = and strict_nonnull_origin =
| ModelledNonnull (** nullsafe knows it is non-nullable via its internal models *) | ModelledNonnull (** nullsafe knows it is non-nullable via its internal models *)
| StrictMode (** under strict mode we consider non-null declarations to be trusted *) | StrictMode (** under strict mode we consider non-null declarations to be trusted *)
| PrimitiveType (** Primitive types are non-nullable by language design *) | PrimitiveType (** Primitive types are non-nullable by language design *)
@ -50,10 +50,10 @@ and nonnull_origin =
let get_nullability = function let get_nullability = function
| Nullable _ -> | Nullable _ ->
Nullability.Nullable Nullability.Nullable
| DeclaredNonnull _ -> | UncheckedNonnull _ ->
Nullability.DeclaredNonnull Nullability.UncheckedNonnull
| Nonnull _ -> | StrictNonnull _ ->
Nullability.Nonnull Nullability.StrictNonnull
let pp fmt t = let pp fmt t =
@ -85,21 +85,21 @@ let pp fmt t =
match t with match t with
| Nullable origin -> | Nullable origin ->
F.fprintf fmt "Nullable[%s]" (string_of_nullable_origin origin) F.fprintf fmt "Nullable[%s]" (string_of_nullable_origin origin)
| DeclaredNonnull origin -> | UncheckedNonnull origin ->
F.fprintf fmt "DeclaredNonnull[%s]" (string_of_declared_nonnull_origin origin) F.fprintf fmt "UncheckedNonnull[%s]" (string_of_declared_nonnull_origin origin)
| Nonnull origin -> | StrictNonnull origin ->
F.fprintf fmt "Nonnull[%s]" (string_of_nonnull_origin origin) F.fprintf fmt "StrictNonnull[%s]" (string_of_nonnull_origin origin)
let of_type_and_annotation ~is_strict_mode typ annotations = let of_type_and_annotation ~is_strict_mode typ annotations =
if not (PatternMatch.type_is_class typ) then Nonnull PrimitiveType if not (PatternMatch.type_is_class typ) then StrictNonnull PrimitiveType
else if Annotations.ia_is_nullable annotations then else if Annotations.ia_is_nullable annotations then
let nullable_origin = let nullable_origin =
if Annotations.ia_is_propagates_nullable annotations then AnnotatedPropagatesNullable if Annotations.ia_is_propagates_nullable annotations then AnnotatedPropagatesNullable
else AnnotatedNullable else AnnotatedNullable
in in
Nullable nullable_origin Nullable nullable_origin
else if is_strict_mode then Nonnull StrictMode else if is_strict_mode then StrictNonnull StrictMode
else if Annotations.ia_is_nonnull annotations then DeclaredNonnull AnnotatedNonnull else if Annotations.ia_is_nonnull annotations then UncheckedNonnull AnnotatedNonnull
(* Currently, we treat not annotated types as nonnull *) (* Currently, we treat not annotated types as nonnull *)
else DeclaredNonnull ImplicitlyNonnull else UncheckedNonnull ImplicitlyNonnull

@ -18,8 +18,8 @@ open! IStd
type t = type t =
| Nullable of nullable_origin | Nullable of nullable_origin
| DeclaredNonnull of declared_nonnull_origin (** See {!Nullability.t} for explanation *) | UncheckedNonnull of unchecked_nonnull_origin (** See {!Nullability.t} for explanation *)
| Nonnull of nonnull_origin | StrictNonnull of strict_nonnull_origin
[@@deriving compare] [@@deriving compare]
and nullable_origin = and nullable_origin =
@ -33,7 +33,7 @@ and nullable_origin =
| ModelledNullable (** nullsafe knows it is nullable via its internal models *) | ModelledNullable (** nullsafe knows it is nullable via its internal models *)
[@@deriving compare] [@@deriving compare]
and declared_nonnull_origin = and unchecked_nonnull_origin =
| AnnotatedNonnull | AnnotatedNonnull
(** The type is explicitly annotated as non nullable via one of nonnull annotations Nullsafe (** The type is explicitly annotated as non nullable via one of nonnull annotations Nullsafe
recognizes *) recognizes *)
@ -41,7 +41,7 @@ and declared_nonnull_origin =
(** Infer was run in mode where all not annotated (non local) types are treated as non (** Infer was run in mode where all not annotated (non local) types are treated as non
nullable *) nullable *)
and nonnull_origin = and strict_nonnull_origin =
| ModelledNonnull (** nullsafe knows it is non-nullable via its internal models *) | ModelledNonnull (** nullsafe knows it is non-nullable via its internal models *)
| StrictMode (** under strict mode we consider non-null declarations to be trusted *) | StrictMode (** under strict mode we consider non-null declarations to be trusted *)
| PrimitiveType (** Primitive types are non-nullable by language design *) | PrimitiveType (** Primitive types are non-nullable by language design *)

@ -151,7 +151,7 @@ let mark_ia_nullability ia x = if x then mk_ia_nullable ia else ia
let set_modelled_nullability_for_annotated_type annotated_type should_set_nullable = let set_modelled_nullability_for_annotated_type annotated_type should_set_nullable =
let nullability = let nullability =
if should_set_nullable then AnnotatedNullability.Nullable ModelledNullable if should_set_nullable then AnnotatedNullability.Nullable ModelledNullable
else AnnotatedNullability.Nonnull ModelledNonnull else AnnotatedNullability.StrictNonnull ModelledNonnull
in in
AnnotatedType.{annotated_type with nullability} AnnotatedType.{annotated_type with nullability}

@ -23,8 +23,8 @@ and function_info =
let is_whitelisted_assignment ~is_strict_mode ~lhs ~rhs = let is_whitelisted_assignment ~is_strict_mode ~lhs ~rhs =
match (is_strict_mode, lhs, rhs) with match (is_strict_mode, lhs, rhs) with
| false, Nullability.Nonnull, Nullability.DeclaredNonnull -> | false, Nullability.StrictNonnull, Nullability.UncheckedNonnull ->
(* We allow DeclaredNonnull -> Nonnull conversion outside of strict mode for better adoption. (* We allow UncheckedNonnull -> StrictNonnull conversion outside of strict mode for better adoption.
Otherwise using strictified classes in non-strict context becomes a pain because Otherwise using strictified classes in non-strict context becomes a pain because
of extra warnings. of extra warnings.
*) *)
@ -78,7 +78,7 @@ let bad_param_description
"`null`" "`null`"
| Nullability.Nullable -> | Nullability.Nullable ->
"nullable" "nullable"
| Nullability.Nonnull | Nullability.DeclaredNonnull -> | Nullability.StrictNonnull | Nullability.UncheckedNonnull ->
Logging.die InternalError "Invariant violation: unexpected nullability" Logging.die InternalError "Invariant violation: unexpected nullability"
in in
Format.asprintf "%a is %s" MF.pp_monospaced actual_param_expression nullability_descr Format.asprintf "%a is %s" MF.pp_monospaced actual_param_expression nullability_descr
@ -131,7 +131,11 @@ let bad_param_description
let is_declared_nonnull_to_nonnull ~lhs ~rhs = let is_declared_nonnull_to_nonnull ~lhs ~rhs =
match (lhs, rhs) with Nullability.Nonnull, Nullability.DeclaredNonnull -> true | _ -> false match (lhs, rhs) with
| Nullability.StrictNonnull, Nullability.UncheckedNonnull ->
true
| _ ->
false
let get_issue_type = function let get_issue_type = function
@ -171,7 +175,7 @@ let violation_description {is_strict_mode; lhs; rhs} ~assignment_location assign
"`null`" "`null`"
| Nullable -> | Nullable ->
"a nullable" "a nullable"
| Nonnull | DeclaredNonnull -> | StrictNonnull | UncheckedNonnull ->
Logging.die InternalError "Invariant violation: unexpected nullability" Logging.die InternalError "Invariant violation: unexpected nullability"
in in
Format.asprintf "%a is declared non-nullable but is assigned %s%s." MF.pp_monospaced Format.asprintf "%a is declared non-nullable but is assigned %s%s." MF.pp_monospaced
@ -185,7 +189,7 @@ let violation_description {is_strict_mode; lhs; rhs} ~assignment_location assign
"`null`" "`null`"
| Nullable -> | Nullable ->
"a nullable value" "a nullable value"
| Nonnull | DeclaredNonnull -> | StrictNonnull | UncheckedNonnull ->
Logging.die InternalError "Invariant violation: unexpected nullability" Logging.die InternalError "Invariant violation: unexpected nullability"
in in
Format.asprintf "%a: return type is declared non-nullable but the method returns %s%s." Format.asprintf "%a: return type is declared non-nullable but the method returns %s%s."

@ -19,9 +19,9 @@ let check ~is_strict_mode nullability =
match nullability with match nullability with
| Nullability.Nullable | Nullability.Null -> | Nullability.Nullable | Nullability.Null ->
Error {is_strict_mode; nullability} Error {is_strict_mode; nullability}
| Nullability.DeclaredNonnull -> | Nullability.UncheckedNonnull ->
if is_strict_mode then Error {is_strict_mode; nullability} else Ok () if is_strict_mode then Error {is_strict_mode; nullability} else Ok ()
| Nullability.Nonnull -> | Nullability.StrictNonnull ->
Ok () Ok ()
@ -40,7 +40,7 @@ let violation_description {nullability} ~dereference_location dereference_type
~nullable_object_descr ~nullable_object_origin = ~nullable_object_descr ~nullable_object_origin =
let module MF = MarkupFormatter in let module MF = MarkupFormatter in
match nullability with match nullability with
| Nullability.DeclaredNonnull -> | Nullability.UncheckedNonnull ->
(* This can happen only in strict mode. (* This can happen only in strict mode.
This type of violation is more subtle than the normal case because, so it should be rendered in a special way *) This type of violation is more subtle than the normal case because, so it should be rendered in a special way *)
ErrorRenderingUtils.get_strict_mode_violation_issue ~bad_usage_location:dereference_location ErrorRenderingUtils.get_strict_mode_violation_issue ~bad_usage_location:dereference_location
@ -91,7 +91,7 @@ let violation_description {nullability} ~dereference_location dereference_type
| Nullability.Nullable -> | Nullability.Nullable ->
Format.sprintf "%s is nullable and is not locally checked for null when %s%s" Format.sprintf "%s is nullable and is not locally checked for null when %s%s"
what_is_dereferred_str action_descr suffix what_is_dereferred_str action_descr suffix
| Nullability.DeclaredNonnull | Nullability.Nonnull -> | Nullability.UncheckedNonnull | Nullability.StrictNonnull ->
Logging.die InternalError "Invariant violation: unexpected nullability" Logging.die InternalError "Invariant violation: unexpected nullability"
in in
(description, IssueType.eradicate_nullable_dereference, dereference_location) (description, IssueType.eradicate_nullable_dereference, dereference_location)

@ -15,7 +15,7 @@ val is_object_nullability_self_explanatory : object_expression:string -> TypeOri
val get_strict_mode_violation_issue : val get_strict_mode_violation_issue :
bad_usage_location:Location.t -> TypeOrigin.t -> string * IssueType.t * Location.t bad_usage_location:Location.t -> TypeOrigin.t -> string * IssueType.t * Location.t
(** Situation when we tried to use DeclaredNonnull as Nonnull. This is disallowed only in strict (** Situation when we tried to use UncheckedNonnull as StrictNonnull. This is disallowed only in
mode. Returns a tuple (error message, issue type, error location). NOTE: Location of the error strict mode. Returns a tuple (error message, issue type, error location). NOTE: Location of the
will be NOT in the place when the value is used (that is [bad_usage_location]), but where the error will be NOT in the place when the value is used (that is [bad_usage_location]), but where
value is first obtained from. *) the value is first obtained from. *)

@ -14,7 +14,7 @@ let create origin = {nullability= TypeOrigin.get_nullability origin; origin}
let get_nullability {nullability} = nullability let get_nullability {nullability} = nullability
let is_nonnull_or_declared_nonnull {nullability} = let is_nonnull_or_declared_nonnull {nullability} =
match nullability with Nonnull | DeclaredNonnull -> true | _ -> false match nullability with StrictNonnull | UncheckedNonnull -> true | _ -> false
let to_string {nullability} = Printf.sprintf "[%s]" (Nullability.to_string nullability) let to_string {nullability} = Printf.sprintf "[%s]" (Nullability.to_string nullability)

@ -13,7 +13,7 @@ type type_role = Param | Ret
let is_whitelisted_violation ~subtype ~supertype = let is_whitelisted_violation ~subtype ~supertype =
match (subtype, supertype) with match (subtype, supertype) with
| Nullability.DeclaredNonnull, Nullability.Nonnull -> | Nullability.UncheckedNonnull, Nullability.StrictNonnull ->
(* It is a violation that we are currently willing to ignore because (* It is a violation that we are currently willing to ignore because
it is hard to obey in practice. it is hard to obey in practice.
It might lead to unsoundness issues, so this might be reconsidered. It might lead to unsoundness issues, so this might be reconsidered.

@ -10,14 +10,21 @@ open! IStd
type t = type t =
| Null (** The only possible value for that type is null *) | Null (** The only possible value for that type is null *)
| Nullable (** No guarantees on the nullability *) | Nullable (** No guarantees on the nullability *)
| DeclaredNonnull | UncheckedNonnull
(** The type comes from a signature that is annotated (explicitly or implicitly according to (** The type comes from a signature that is annotated (explicitly or implicitly according to
conventions) as non-nullable. Hovewer, it might still contain null since the truthfullness conventions) as non-nullable. However, it might still contain null since the truthfulness
of the declaration was not checked. *) of the declaration was not checked. *)
| Nonnull | StrictNonnull
(** We believe that this value can not be null. If it is not the case, this is an unsoundness (** Non-nullable value with the highest degree of certainty, because it is either:
issue for Nullsafe, and we aim to minimize number of such issues occuring in real-world
programs. *) - 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] [@@deriving compare, equal]
let top = Nullable let top = Nullable
@ -30,10 +37,10 @@ let join x y =
Nullable Nullable
| Nullable, _ | _, Nullable -> | Nullable, _ | _, Nullable ->
Nullable Nullable
| DeclaredNonnull, _ | _, DeclaredNonnull -> | UncheckedNonnull, _ | _, UncheckedNonnull ->
DeclaredNonnull UncheckedNonnull
| Nonnull, Nonnull -> | StrictNonnull, StrictNonnull ->
Nonnull StrictNonnull
let is_subtype ~subtype ~supertype = equal (join subtype supertype) supertype let is_subtype ~subtype ~supertype = equal (join subtype supertype) supertype
@ -43,7 +50,7 @@ let to_string = function
"Null" "Null"
| Nullable -> | Nullable ->
"Nullable" "Nullable"
| DeclaredNonnull -> | UncheckedNonnull ->
"DeclaredNonnull" "UncheckedNonnull"
| Nonnull -> | StrictNonnull ->
"Nonnull" "StrictNonnull"

@ -18,13 +18,15 @@ open! IStd
type t = type t =
| Null (** The only possible value for that type is null *) | Null (** The only possible value for that type is null *)
| Nullable (** No guarantees on the nullability *) | Nullable (** No guarantees on the nullability *)
| DeclaredNonnull | UncheckedNonnull
(** The type comes from a signature that is annotated (explicitly or implicitly according to (** The type comes from a signature that is annotated (explicitly or implicitly according to
conventions) as non-nullable. Hovewer, it might still contain null since the truthfullness conventions) as non-nullable. Hovewer, it might still contain null since the truthfullness
of the declaration was not checked. *) of the declaration was not checked. *)
| Nonnull | StrictNonnull
(** We believe that this value can not be null. If it is not the case, this is an unsoundness (** We believe that this value can not be null because it is either a non-null literal, an
issue for Nullsafe, and we aim to minimize number of such issues occuring in real-world expression that semantically cannot be null, or a non-null value that should not be null
according to typechecking rules. If the latter is not the case, this is an unsoundness
issue for nullsafe, and we aim to minimize number of such issues occuring in real-world
programs. *) programs. *)
[@@deriving compare, equal] [@@deriving compare, equal]

@ -11,9 +11,10 @@ type violation = {declared_nullability: Nullability.t; can_be_narrowed_to: Nulla
let check ~what ~by_rhs_upper_bound = let check ~what ~by_rhs_upper_bound =
match (what, by_rhs_upper_bound) with match (what, by_rhs_upper_bound) with
| Nullability.Nullable, Nullability.Nonnull | Nullability.Nullable, Nullability.DeclaredNonnull -> | Nullability.Nullable, Nullability.StrictNonnull
| Nullability.Nullable, Nullability.UncheckedNonnull ->
Error {declared_nullability= what; can_be_narrowed_to= by_rhs_upper_bound} Error {declared_nullability= what; can_be_narrowed_to= by_rhs_upper_bound}
| Nullability.Null, Nullability.Nonnull | Nullability.Null, Nullability.DeclaredNonnull -> | Nullability.Null, Nullability.StrictNonnull | Nullability.Null, Nullability.UncheckedNonnull ->
(* Null, Nonnull pais is an edge case that we don't expect to arise in practice for two reasons: (* Null, Nonnull pais is an edge case that we don't expect to arise in practice for two reasons:
1. The only way to declare something as Null is to declare it is java.lang.Void, but nullsafe 1. The only way to declare something as Null is to declare it is java.lang.Void, but nullsafe
does not know about it just yet. does not know about it just yet.

@ -183,9 +183,9 @@ let is_declared_nonnull AnnotatedField.{annotated_type} =
match annotated_type.nullability with match annotated_type.nullability with
| AnnotatedNullability.Nullable _ -> | AnnotatedNullability.Nullable _ ->
false false
| AnnotatedNullability.DeclaredNonnull _ -> | AnnotatedNullability.UncheckedNonnull _ ->
true true
| AnnotatedNullability.Nonnull _ -> | AnnotatedNullability.StrictNonnull _ ->
true true
@ -234,7 +234,7 @@ let get_nullability_upper_bound_for_typestate proc_name field_name typestate =
*) *)
let get_nullability_upper_bound field_name typestate_list = let get_nullability_upper_bound field_name typestate_list =
(* Join upper bounds for all typestates in the list *) (* Join upper bounds for all typestates in the list *)
List.fold typestate_list ~init:Nullability.Nonnull ~f:(fun acc (proc_name, typestate) -> List.fold typestate_list ~init:Nullability.StrictNonnull ~f:(fun acc (proc_name, typestate) ->
Nullability.join acc Nullability.join acc
(get_nullability_upper_bound_for_typestate proc_name field_name typestate) ) (get_nullability_upper_bound_for_typestate proc_name field_name typestate) )

@ -63,7 +63,7 @@ let get_nullability = function
| ArrayAccess | ArrayAccess
| OptimisticFallback (* non-null is the most optimistic type *) | OptimisticFallback (* non-null is the most optimistic type *)
| Undef (* This is a very special case, assigning non-null is a technical trick *) -> | Undef (* This is a very special case, assigning non-null is a technical trick *) ->
Nullability.Nonnull Nullability.StrictNonnull
| Field {field_type= {nullability}} -> | Field {field_type= {nullability}} ->
AnnotatedNullability.get_nullability nullability AnnotatedNullability.get_nullability nullability
| MethodParameter {param_annotated_type= {nullability}} -> | MethodParameter {param_annotated_type= {nullability}} ->
@ -116,7 +116,7 @@ let get_method_ret_description pname call_loc
match nullability with match nullability with
| AnnotatedNullability.Nullable _ -> | AnnotatedNullability.Nullable _ ->
"nullable" "nullable"
| AnnotatedNullability.DeclaredNonnull _ | AnnotatedNullability.Nonnull _ -> | AnnotatedNullability.UncheckedNonnull _ | AnnotatedNullability.StrictNonnull _ ->
"non-nullable" "non-nullable"
in in
let model_info = let model_info =

Loading…
Cancel
Save