[nullsafe][TypeOrigin refactor] Split TypeOrigin.Const to nullable and non-nullable constants

Summary:
This diff is a part of work teaching Nullsafe to explain decisions it's
making.

Introducing more specific origins will allow us to automatically infer
nullability based on type origin (in follow up diffs).

Reviewed By: ngorogiannis

Differential Revision: D18450165

fbshipit-source-id: 9dc0d25c0
master
Mitya Lyubarskiy 5 years ago committed by Facebook Github Bot
parent a356ef19d7
commit 4a81a69fb3

@ -73,8 +73,6 @@ let create_nullable origin = {origin; nullability= Nullability.Nullable}
let create_nonnull origin = {origin; nullability= Nullability.Nonnull}
let with_origin t o = {t with origin= o}
let of_annotated_nullability annotated_nullability origin =
match annotated_nullability with
| AnnotatedNullability.Nullable _ ->

@ -61,6 +61,3 @@ val join : t -> t -> t
val origin_is_fun_library : t -> bool
val to_string : t -> string
val with_origin : t -> TypeOrigin.t -> t
(** Leave the same nullability, but change the origin *)

@ -111,11 +111,21 @@ type checks = {eradicate: bool; check_ret_type: check_return_type list}
let rec typecheck_expr ~is_strict_mode find_canonical_duplicate visited checks tenv node instr_ref
(curr_pdesc : Procdesc.t) typestate e tr_default loc : TypeState.range =
match e with
(* null literal or 0 *)
| _ when Exp.is_null_literal e ->
let typ, inferred_nullability = tr_default in
let typ, _ = tr_default in
(* 0 is not the same thing as null. They are encoded as the same thing in SIL.
We distinct them by type.
*)
if PatternMatch.type_is_class typ then
(typ, InferredNullability.create_nullable (TypeOrigin.Const loc))
else (typ, InferredNullability.with_origin inferred_nullability (TypeOrigin.Const loc))
(typ, InferredNullability.create_nullable (TypeOrigin.NullConst loc))
else
(* 0 const (this is not the same as null) *)
(typ, InferredNullability.create_nonnull (TypeOrigin.NonnullConst loc))
| Exp.Const _ ->
let typ, _ = tr_default in
(* We already considered case of null literal above, so this is a non-null const. *)
(typ, InferredNullability.create_nonnull (TypeOrigin.NonnullConst loc))
| Exp.Lvar pvar ->
Option.value (TypeState.lookup_pvar pvar typestate) ~default:tr_default
| Exp.Var id ->
@ -123,9 +133,6 @@ let rec typecheck_expr ~is_strict_mode find_canonical_duplicate visited checks t
| Exp.Exn e1 ->
typecheck_expr ~is_strict_mode find_canonical_duplicate visited checks tenv node instr_ref
curr_pdesc typestate e1 tr_default loc
| Exp.Const _ ->
let typ, _ = tr_default in
(typ, InferredNullability.create_nonnull (TypeOrigin.Const loc))
| Exp.Lfield (exp, field_name, typ) ->
let _, _ = tr_default in
let _, inferred_nullability =

@ -17,20 +17,23 @@ type proc_origin =
[@@deriving compare]
type t =
| Const of Location.t
| Field of t * Typ.Fieldname.t * Location.t
| Formal of Mangled.t
| Proc of proc_origin
| New
| ONone
| Undef
| NullConst of Location.t (** A null literal in the source *)
| NonnullConst of Location.t (** A constant (not equal to null) in the source. *)
| Field of t * Typ.Fieldname.t * Location.t (** A field access *)
| Formal of Mangled.t (** A formal parameter *)
| Proc of proc_origin (** A procedure call *)
| New (** A new object creation *)
| ONone (** No origin is known *)
| Undef (** Undefined value before initialization *)
[@@deriving compare]
let equal = [%compare.equal: t]
let rec to_string = function
| Const _ ->
"Const"
| NullConst _ ->
"null"
| NonnullConst _ ->
"Const (nonnull)"
| Field (o, fn, _) ->
"Field " ^ Typ.Fieldname.to_simplified_string fn ^ " (inner: " ^ to_string o ^ ")"
| Formal s ->
@ -48,7 +51,7 @@ let rec to_string = function
let get_description origin =
let atline loc = " at line " ^ string_of_int loc.Location.line in
match origin with
| Const loc ->
| NullConst loc ->
Some ("null constant" ^ atline loc, Some loc, None)
| Field (_, fn, loc) ->
Some ("field " ^ Typ.Fieldname.to_simplified_string fn ^ atline loc, Some loc, None)
@ -67,7 +70,16 @@ let get_description origin =
modelled_in (atline po.loc)
in
Some (description, Some po.loc, Some po.annotated_signature)
| New | ONone | Undef ->
(* These are origins of non-nullable expressions that are result of evaluating of some rvalue.
Because they are non-nullable and they are rvalues, we won't get normal type violations
With them. All we could get is things like condition redundant or overannotated.
But for these issues we currently don't print origins in the error string.
It is a good idea to change this and start printing origins for these origins as well.
*)
| New | NonnullConst _ ->
None
(* Two special cases - should not really occur in normal code *)
| ONone | Undef ->
None
@ -76,7 +88,7 @@ let join o1 o2 =
(* left priority *)
| Undef, _ | _, Undef ->
Undef
| Field _, (Const _ | Formal _ | Proc _ | New) ->
| Field _, (NullConst _ | NonnullConst _ | Formal _ | Proc _ | New) ->
(* low priority to Field, to support field initialization patterns *)
o2
| _ ->

@ -16,7 +16,8 @@ type proc_origin =
[@@deriving compare]
type t =
| Const of Location.t (** A constant in the source *)
| NullConst of Location.t (** A null literal in the source *)
| NonnullConst of Location.t (** A constant (not equal to null) in the source. *)
| Field of t * Typ.Fieldname.t * Location.t (** A field access *)
| Formal of Mangled.t (** A formal parameter *)
| Proc of proc_origin (** A procedure call *)

Loading…
Cancel
Save