Skip to content

Commit

Permalink
Make various primitives non_null_value (ocaml-flambda#2604)
Browse files Browse the repository at this point in the history
* `non_null_value_creation_reason`

* Immediates are non-null

* Primitives are non-null

* Extensible variants are non-null

* Boxed variants are non-null

* Boxed records are non-null

* Tuples are non-null

* Polymorphic variants are non-null

* Arrows are non-null

* First-class modules are non-null

* Basic tests

* More tests

* More tests

* Leave `lazy_t` nullable for now

* More basic tests

* More tests

* Format

* Update ocaml/testsuite/tests/typing-layouts-non-null-value/basics.ml

Co-authored-by: Richard Eisenberg <[email protected]>

* stable -> upstream_compatible

* Update comments and tests

* Display `non_null_value` as `value` (ocaml-flambda#2613)

* Naive hack

* Promote tests

* More hacks

* More hacks + promote tests

* Test hiding

* Stub `Or_null` module

* Test sublayot error

* Formatting

---------

Co-authored-by: Diana Kalinichenko <[email protected]>

---------

Co-authored-by: Diana Kalinichenko <[email protected]>
Co-authored-by: Richard Eisenberg <[email protected]>
  • Loading branch information
3 people authored May 29, 2024
1 parent ba58471 commit fd39aec
Show file tree
Hide file tree
Showing 23 changed files with 1,198 additions and 116 deletions.
2 changes: 1 addition & 1 deletion ocaml/otherlibs/alpha/dune
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
(rule
(deps
(glob_files ../stdlib_alpha/*.{ml,mli}))
(targets alpha.ml alpha.mli)
(targets alpha.ml alpha.mli or_null.ml or_null.mli)
(action
(bash
"cp ../stdlib_alpha/*.{ml,mli} .; mv stdlib_alpha.ml alpha.ml; mv stdlib_alpha.mli alpha.mli")))
Expand Down
15 changes: 15 additions & 0 deletions ocaml/otherlibs/stdlib_alpha/or_null.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
(**************************************************************************)
(* *)
(* OCaml *)
(* *)
(* Diana Kalinichenko, Jane Street, New York *)
(* *)
(* Copyright 2024 Jane Street Group LLC *)
(* *)
(* All rights reserved. This file is distributed under the terms of *)
(* the GNU Lesser General Public License version 2.1, with the *)
(* special exception on linking described in the file LICENSE. *)
(* *)
(**************************************************************************)

type ('a : non_null_value) t = 'a option
16 changes: 16 additions & 0 deletions ocaml/otherlibs/stdlib_alpha/or_null.mli
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
(**************************************************************************)
(* *)
(* OCaml *)
(* *)
(* Diana Kalinichenko, Jane Street, New York *)
(* *)
(* Copyright 2024 Jane Street Group LLC *)
(* *)
(* All rights reserved. This file is distributed under the terms of *)
(* the GNU Lesser General Public License version 2.1, with the *)
(* special exception on linking described in the file LICENSE. *)
(* *)
(**************************************************************************)

(** Unboxed option type. Unimplemented. *)
type ('a : non_null_value) t
1 change: 1 addition & 0 deletions ocaml/otherlibs/stdlib_alpha/stdlib_alpha.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module Or_null = Or_null
1 change: 1 addition & 0 deletions ocaml/otherlibs/stdlib_alpha/stdlib_alpha.mli
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module Or_null = Or_null
4 changes: 2 additions & 2 deletions ocaml/testsuite/tests/typing-layouts-err-msg/annots.ml
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ Line 1, characters 9-33:
^^^^^^^^^^^^^^^^^^^^^^^^
Error: This alias is bound to type 'a -> int
but is used as an instance of type ('b : void)
The layout of 'a -> int is value, because
The layout of 'a -> int is non_null_value, because
it's a function type.
But the layout of 'a -> int must be a sublayout of void, because
of the annotation on the type variable 'b.
Expand All @@ -104,7 +104,7 @@ Line 1, characters 27-31:
1 | type t = 'a -> int as (_ : void)
^^^^
Error: Bad layout annotation:
The layout of 'a -> int is value, because
The layout of 'a -> int is non_null_value, because
it's a function type.
But the layout of 'a -> int must be a sublayout of void, because
of the annotation on the wildcard _ at line 1, characters 27-31.
Expand Down
18 changes: 9 additions & 9 deletions ocaml/testsuite/tests/typing-layouts-err-msg/value.ml
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ type r : void = {a:string}
Line 1, characters 0-26:
1 | type r : void = {a:string}
^^^^^^^^^^^^^^^^^^^^^^^^^^
Error: The layout of type r is value, because
Error: The layout of type r is non_null_value, because
it's a boxed record type.
But the layout of type r must be a sublayout of void, because
of the annotation on the declaration of the type r.
Expand All @@ -133,7 +133,7 @@ type v : void = A of t_value
Line 1, characters 0-28:
1 | type v : void = A of t_value
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Error: The layout of type v is value, because
Error: The layout of type v is non_null_value, because
it's a boxed variant type.
But the layout of type v must be a sublayout of void, because
of the annotation on the declaration of the type v.
Expand All @@ -145,7 +145,7 @@ type attr : void = ..
Line 1, characters 0-21:
1 | type attr : void = ..
^^^^^^^^^^^^^^^^^^^^^
Error: The layout of type attr is value, because
Error: The layout of type attr is non_null_value, because
it's an extensible variant type.
But the layout of type attr must be a sublayout of void, because
of the annotation on the declaration of the type attr.
Expand All @@ -159,8 +159,8 @@ Line 1, characters 40-45:
^^^^^
Error: This expression has type string but an expression was expected of type
('a : void)
The layout of string is value, because
it is the primitive value type string.
The layout of string is non_null_value, because
it is the primitive non-null value type string.
But the layout of string must be a sublayout of void, because
of the annotation on the type variable 'a.
|}];;
Expand All @@ -187,7 +187,7 @@ Line 1, characters 40-45:
^^^^^
Error: This expression has type 'b * 'c
but an expression was expected of type ('a : void)
The layout of 'a * 'b is value, because
The layout of 'a * 'b is non_null_value, because
it's a tuple type.
But the layout of 'a * 'b must be a sublayout of void, because
of the annotation on the type variable 'a.
Expand All @@ -206,7 +206,7 @@ Line 2, characters 36-37:
^
Error: This expression has type [ `A of int | `B ]
but an expression was expected of type 'a t = ('a : void)
The layout of [ `A of int | `B ] is value, because
The layout of [ `A of int | `B ] is non_null_value, because
it's a polymorphic variant type.
But the layout of [ `A of int | `B ] must be a sublayout of void, because
of the definition of t at line 1, characters 0-22.
Expand All @@ -222,7 +222,7 @@ Line 2, characters 31-32:
^
Error: This expression has type int -> int
but an expression was expected of type 'a t = ('a : void)
The layout of int -> int is value, because
The layout of int -> int is non_null_value, because
it's a function type.
But the layout of int -> int must be a sublayout of void, because
of the definition of t at line 1, characters 0-22.
Expand All @@ -248,7 +248,7 @@ Line 4, characters 17-39:
^^^^^^^^^^^^^^^^^^^^^^
Error: This expression has type (module X_int)
but an expression was expected of type 'a t = ('a : void)
The layout of (module X_int) is value, because
The layout of (module X_int) is non_null_value, because
it's a first-class module type.
But the layout of (module X_int) must be a sublayout of void, because
of the definition of t at line 1, characters 0-22.
Expand Down
129 changes: 129 additions & 0 deletions ocaml/testsuite/tests/typing-layouts-non-null-value/arguments.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
(* TEST
flags = "-extension-universe alpha";
expect;
*)

module Fake_or_null : sig
type ('a : non_null_value) t : value

val none : 'a t
val some : 'a -> 'a t
end = struct
type ('a : non_null_value) t = 'a option

let none = None
let some x = Some x
end
;;

[%%expect{|
module Fake_or_null :
sig
type ('a : non_null_value) t : value
val none : ('a : non_null_value). 'a t
val some : ('a : non_null_value). 'a -> 'a t
end
|}]

let _ = Fake_or_null.some (Fake_or_null.none)
;;

[%%expect{|
Line 1, characters 26-45:
1 | let _ = Fake_or_null.some (Fake_or_null.none)
^^^^^^^^^^^^^^^^^^^
Error: This expression has type 'a Fake_or_null.t
but an expression was expected of type ('b : non_null_value)
The layout of 'a Fake_or_null.t is value, because
of the definition of t at line 2, characters 2-38.
But the layout of 'a Fake_or_null.t must be a sublayout of non_null_value, because
of the definition of some at line 5, characters 2-23.
|}]


(* Built-in containers accept nullable values: *)

let _ = [ Fake_or_null.none ]

let _ = [| Fake_or_null.some 3 |]

let _ = [: Fake_or_null.some "test " :]

let _ = Some (Fake_or_null.some 4.2)

let _ = lazy (Fake_or_null.none)
;;

[%%expect{|
- : 'a Fake_or_null.t list = [<abstr>]
- : int Fake_or_null.t array = [|<abstr>|]
- : string Fake_or_null.t iarray = [:<abstr>:]
- : float Fake_or_null.t option = Some <abstr>
- : 'a Fake_or_null.t lazy_t = lazy <abstr>
|}]

module M1 : sig
type 'a t

val mk : 'a -> 'a t
end = struct
type 'a t = 'a

let mk x = x
end

(* CR layouts v3.0: abstract types and type parameters to
abstract types should default to non-null: *)

let _ = Fake_or_null.some (M1.mk 2)
;;
[%%expect{|
module M1 : sig type 'a t val mk : 'a -> 'a t end
Line 14, characters 26-35:
14 | let _ = Fake_or_null.some (M1.mk 2)
^^^^^^^^^
Error: This expression has type int M1.t
but an expression was expected of type ('a : non_null_value)
The layout of int M1.t is value, because
of the definition of t at line 2, characters 2-11.
But the layout of int M1.t must be a sublayout of non_null_value, because
of the definition of some at line 5, characters 2-23.
|}]

let _ = M1.mk (Fake_or_null.some 5)
;;

[%%expect{|
- : int Fake_or_null.t M1.t = <abstr>
|}]

let my_id1 x = x
let my_id2 (x : 'a) = x
let my_id3 : 'a . 'a -> 'a = fun x -> x
let my_id4 (type a) (x : a) = x
;;

[%%expect{|
val my_id1 : 'a -> 'a = <fun>
val my_id2 : 'a -> 'a = <fun>
val my_id3 : 'a -> 'a = <fun>
val my_id4 : 'a -> 'a = <fun>
|}]

(* By default, type variables in functions are nullable: *)

let _ = my_id1 (Fake_or_null.some 1)

let _ = my_id2 (Fake_or_null.some 2)

let _ = my_id3 (Fake_or_null.some 3)

let _ = my_id4 (Fake_or_null.some 4)
;;

[%%expect{|
- : int Fake_or_null.t = <abstr>
- : int Fake_or_null.t = <abstr>
- : int Fake_or_null.t = <abstr>
- : int Fake_or_null.t = <abstr>
|}]
Loading

0 comments on commit fd39aec

Please sign in to comment.