Skip to content

Commit

Permalink
Restructure modal and with-bounds (fka baggage) in jkind
Browse files Browse the repository at this point in the history
This commit contains a significant restructuring of the modal upper bounds and
with-bounds (which is the new name for what was previously called "baggage") in
the innards of Jkind.t

Previously, jkinds morally consisted of:

- a layout
- a map from axis, to a pair of upper bound and a list of types (the with-bounds
  for that axis)

now, we instead have, morally:
- a layout
- a map from axis to the upper bound for that axis
- a list of (type, modality) pairs, where the modality is effectively providing
  us the way that the type operates on the axis

This behavior is both much closer to the syntactic representation of jkinds,
making it simpler both to construct and to print, and probably more efficient,
since the usual behavior is that a type appears on the with-bounds for all
axes (this is only not the case in the presence of modalities)

The test changes are mostly innocuous:

1. Printing changed slightly when illegal crossing is used - actually I'm
   reasonably sure that this change *fixed* printing of kind annotations for
   types with illegal crossing
2. We're no longer deduplicating types for printing kinds (we used to do this
   only when constructing outcometrees); this will come back later as we do
   deduplication of with-bounds at construction time.
3. We actually got better at printing kinds in general, eg we're now better at
   figuring out built-in aliases to print under some with-bounds.

Past the actual internals of with-bounds, we frequently /reconstruct/ the
list-of-types-per-axis shape, eg in subsumption - this is mostly done to avoid
this commit getting too large and hairy, and in follow-up I plan on refactoring
to do more algorithms such as bound extension holistically rather than per-axis,
which ought to also realize more performance gains here.
  • Loading branch information
glittershark committed Jan 14, 2025
1 parent 8b74119 commit f0911cc
Show file tree
Hide file tree
Showing 20 changed files with 647 additions and 826 deletions.
12 changes: 4 additions & 8 deletions testsuite/tests/parsetree/source_jane_street.ml
Original file line number Diff line number Diff line change
Expand Up @@ -1066,14 +1066,10 @@ type 'a contended : immutable_data with 'a @@ contended
type 'a contended_with_int : immutable_data with 'a @@ contended with int

[%%expect{|
type 'a list : value mod many uncontended portable with 'a
type ('a, 'b) either : value mod many uncontended portable with 'a * 'b
type 'a contended : value mod many uncontended portable with 'a @@ contended
type 'a contended_with_int
: value mod many uncontended portable
with 'a @@ contended
with int
type 'a list : immutable_data with 'a
type ('a, 'b) either : immutable_data with 'a * 'b
type 'a contended : immutable_data with 'a @@ contended
type 'a contended_with_int : immutable_data with 'a @@ contended with int
|}]

(* not yet supported *)
Expand Down
60 changes: 30 additions & 30 deletions testsuite/tests/typing-jkind-bounds/allow_illegal_crossing.ml
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,21 @@ type a
type b : value mod portable = { a : int; b : int }
[%%expect {|
type a
type b = { a : int; b : int; }
type b : immutable_data = { a : int; b : int; }
|}]

type a
type b : value mod uncontended = Foo of int
[%%expect {|
type a
type b = Foo of int
type b : immutable_data = Foo of int
|}]

type a
type b : value mod uncontended portable = Foo of int | Bar of int
[%%expect {|
type a
type b = Foo of int | Bar of int
type b : immutable_data = Foo of int | Bar of int
|}]

type a
Expand Down Expand Up @@ -59,7 +59,7 @@ Error: The kind of type "a" is value

type t : value mod portable uncontended = { a : int; b : int }
[%%expect {|
type t = { a : int; b : int; }
type t : immutable_data = { a : int; b : int; }
|}]

type ('a, 'b) t : value mod portable uncontended = { a : 'a; b : 'b }
Expand All @@ -69,40 +69,40 @@ type ('a, 'b) t : immutable_data = { a : 'a; b : 'b; }

type t : value mod portable = private { foo : string }
[%%expect {|
type t = private { foo : string; }
type t : immutable_data = private { foo : string; }
|}]

type a : value mod portable = { foo : string }
type b : value mod portable = a = { foo : string }
[%%expect {|
type a = { foo : string; }
type b = a = { foo : string; }
type a : immutable_data = { foo : string; }
type b = a : immutable_data = { foo : string; }
|}]

type a : value mod uncontended = private { foo : string }
type b : value mod uncontended = a = private { foo : string }
[%%expect {|
type a = private { foo : string; }
type b = a = private { foo : string; }
type a : immutable_data = private { foo : string; }
type b = a : immutable_data = private { foo : string; }
|}]

type t : value mod uncontended = private Foo of int | Bar
[%%expect {|
type t = private Foo of int | Bar
type t : immutable_data = private Foo of int | Bar
|}]

type a : value mod uncontended = Foo of int | Bar
type b : value mod uncontended = a = Foo of int | Bar
[%%expect {|
type a = Foo of int | Bar
type b = a = Foo of int | Bar
type a : immutable_data = Foo of int | Bar
type b = a : immutable_data = Foo of int | Bar
|}]

type a : value mod portable = private Foo of int | Bar
type b : value mod portable = a = private Foo of int | Bar
[%%expect {|
type a = private Foo of int | Bar
type b = a = private Foo of int | Bar
type a : immutable_data = private Foo of int | Bar
type b = a : immutable_data = private Foo of int | Bar
|}]

type t : value mod uncontended = private Foo of int ref | Bar
Expand Down Expand Up @@ -130,7 +130,7 @@ end = struct
type t = { a : string }
end
[%%expect {|
module A : sig type t = { a : string; } end
module A : sig type t : immutable_data = { a : string; } end
|}]

(********************************************)
Expand All @@ -140,7 +140,7 @@ type a : value mod portable uncontended = Foo of string
type ('a : value mod portable uncontended) b
type c = a b
[%%expect {|
type a = Foo of string
type a : immutable_data = Foo of string
type ('a : value mod uncontended portable) b
type c = a b
|}]
Expand All @@ -158,15 +158,15 @@ type t : value mod portable uncontended = { a : string; b : int }
let f : ('a : value mod portable uncontended). 'a -> 'a = fun x -> x
let g (x : t) = f x
[%%expect {|
type t = { a : string; b : int; }
type t : immutable_data = { a : string; b : int; }
val f : ('a : value mod uncontended portable). 'a -> 'a = <fun>
val g : t -> t = <fun>
|}]

type t : value mod portable uncontended = { a : int; b : int }
let x : _ as (_ : value mod portable uncontended) = { a = 5; b = 5 }
[%%expect {|
type t = { a : int; b : int; }
type t : immutable_data = { a : int; b : int; }
val x : t = {a = 5; b = 5}
|}]

Expand All @@ -180,7 +180,7 @@ val x : (int, int) t = {a = 5; b = 5}
type t : value mod portable uncontended = Foo of string | Bar of int
let x : _ as (_ : value mod portable uncontended) = Foo "hello world"
[%%expect {|
type t = Foo of string | Bar of int
type t : immutable_data = Foo of string | Bar of int
val x : t = Foo "hello world"
|}]

Expand All @@ -200,7 +200,7 @@ type ('a : value mod portable) u = 'a
type v = A.t u
let x : _ as (_ : value mod portable) = ({ a = "hello" } : A.t)
[%%expect {|
module A : sig type t = { a : string; } end
module A : sig type t : immutable_data = { a : string; } end
type ('a : value mod portable) u = 'a
type v = A.t u
val x : A.t = {A.a = "hello"}
Expand All @@ -210,7 +210,7 @@ type t : value mod portable = { a : string }
let my_str : string @@ nonportable = ""
let y = ({ a = my_str } : t @@ portable)
[%%expect {|
type t = { a : string; }
type t : immutable_data = { a : string; }
val my_str : string = ""
val y : t = {a = ""}
|}]
Expand All @@ -230,7 +230,7 @@ let f () =
let _ = ({ a = make_str () } : t @@ uncontended) in
()
[%%expect {|
type t = { a : string; }
type t : immutable_data = { a : string; }
val make_str : unit -> string = <fun>
val f : unit -> unit = <fun>
|}]
Expand All @@ -241,7 +241,7 @@ let f () =
let _ : t @@ uncontended = { a = make_str () } in
()
[%%expect {|
type t = { a : string; }
type t : immutable_data = { a : string; }
val make_str : unit -> string = <fun>
val f : unit -> unit = <fun>
|}]
Expand Down Expand Up @@ -282,7 +282,7 @@ type t : value mod portable uncontended = Foo of string | Bar of int
let g (x : t @@ nonportable contended) = f x; f (Foo ""); f (Bar 10)
[%%expect {|
val f : 'a @ portable -> unit = <fun>
type t = Foo of string | Bar of int
type t : immutable_data = Foo of string | Bar of int
val g : t @ contended -> unit = <fun>
|}]

Expand Down Expand Up @@ -545,7 +545,7 @@ end = struct
type v = t u
end
[%%expect {|
module A : sig type t = { a : string; } end
module A : sig type t : immutable_data = { a : string; } end
|}, Principal{|
Line 6, characters 11-12:
6 | type v = t u
Expand Down Expand Up @@ -582,7 +582,7 @@ end = struct
let x : _ as (_ : value mod portable) = { a = "hello" }
end
[%%expect {|
module A : sig type t = { a : string; } end
module A : sig type t : immutable_data = { a : string; } end
|}, Principal{|
Line 5, characters 42-57:
5 | let x : _ as (_ : value mod portable) = { a = "hello" }
Expand Down Expand Up @@ -687,14 +687,14 @@ type a = { foo : string }
type b : value mod portable = a = { foo : string }
[%%expect {|
type a = { foo : string; }
type b = a = { foo : string; }
type b = a : immutable_data = { foo : string; }
|}]
type a = private { foo : string }
type b : value mod uncontended = a = private { foo : string }
[%%expect {|
type a = private { foo : string; }
type b = a = private { foo : string; }
type b = a : immutable_data = private { foo : string; }
|}]
type a = { foo : string -> string }
Expand Down Expand Up @@ -727,14 +727,14 @@ type a = Foo of string | Bar
type b : value mod uncontended = a = Foo of string | Bar
[%%expect {|
type a = Foo of string | Bar
type b = a = Foo of string | Bar
type b = a : immutable_data = Foo of string | Bar
|}]
type a = private Foo of string | Bar
type b : value mod portable = a = private Foo of string | Bar
[%%expect {|
type a = private Foo of string | Bar
type b = a = private Foo of string | Bar
type b = a : immutable_data = private Foo of string | Bar
|}]
type a = Foo of { mutable x : int } | Bar
Expand Down
17 changes: 5 additions & 12 deletions testsuite/tests/typing-jkind-bounds/modalities.ml
Original file line number Diff line number Diff line change
Expand Up @@ -96,12 +96,8 @@ Error: This expression has type "string t"
but an expression was expected of type
"('a : value mod global & value mod global)"
The kind of string t is
value_or_null mod global unique many uncontended portable external_
non_null
with string @@ global
& value_or_null mod global unique many uncontended portable
external_ non_null
with string @@ global
immediate with string @@ global with string @@ global & immediate
with string @@ global with string @@ global
because of the definition of t at line 4, characters 0-51.
But the kind of string t must be a subkind of
value mod global & value mod global
Expand All @@ -128,12 +124,9 @@ Line 1, characters 65-66:
Error: This expression has type "(string -> string) t"
but an expression was expected of type "('a : value & value)"
The kind of (string -> string) t is
value_or_null mod global unique many uncontended portable external_
non_null
with string -> string @@ global
& value_or_null mod global unique many uncontended portable
external_ non_null
with string -> string @@ global
immediate with string -> string @@ global
with string -> string @@ global & immediate
with string -> string @@ global with string -> string @@ global
because of the definition of t at line 4, characters 0-51.
But the kind of (string -> string) t must be a subkind of
value & value
Expand Down
4 changes: 2 additions & 2 deletions testsuite/tests/typing-layouts-or-null/reexport.ml
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ Lines 2-4, characters 2-16:
4 | | This of 'a
Error: The kind of type "'a or_null" is value_or_null
because it is the primitive value_or_null type or_null.
But the kind of type "'a or_null" must be a subkind of
value mod many uncontended portable with 'a
But the kind of type "'a or_null" must be a subkind of immutable_data
with 'a
because of the definition of t at lines 2-4, characters 2-16.
|}]

Expand Down
12 changes: 6 additions & 6 deletions testsuite/tests/typing-layouts-products/basics_alpha.ml
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,9 @@ Line 3, characters 0-39:
3 | type t3 : any mod non_null = #(t1 * t2);;
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Error: The kind of type "#(t1 * t2)" is
any mod global unique many uncontended portable external_ non_null
any_non_null mod global unique many uncontended portable external_
with t1 with t2
& any mod global unique many uncontended portable external_ non_null
& any_non_null mod global unique many uncontended portable external_
with t1 with t2
because it is an unboxed tuple.
But the kind of type "#(t1 * t2)" must be a subkind of any_non_null
Expand All @@ -86,9 +86,9 @@ Line 3, characters 0-45:
3 | type t3 : any & any mod non_null = #(t1 * t2);;
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Error: The kind of type "#(t1 * t2)" is
any mod global unique many uncontended portable external_ non_null
any_non_null mod global unique many uncontended portable external_
with t1 with t2
& any mod global unique many uncontended portable external_ non_null
& any_non_null mod global unique many uncontended portable external_
with t1 with t2
because it is an unboxed tuple.
But the kind of type "#(t1 * t2)" must be a subkind of
Expand All @@ -106,9 +106,9 @@ Line 3, characters 0-62:
3 | type t3 : (any mod non_null) & (any mod non_null) = #(t1 * t2);;
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Error: The kind of type "#(t1 * t2)" is
any mod global unique many uncontended portable external_ non_null
any_non_null mod global unique many uncontended portable external_
with t1 with t2
& any mod global unique many uncontended portable external_ non_null
& any_non_null mod global unique many uncontended portable external_
with t1 with t2
because it is an unboxed tuple.
But the kind of type "#(t1 * t2)" must be a subkind of
Expand Down
8 changes: 2 additions & 6 deletions testsuite/tests/typing-layouts-unboxed-records/basics.ml
Original file line number Diff line number Diff line change
Expand Up @@ -760,12 +760,8 @@ Line 1, characters 0-61:
1 | type q : any mod portable = #{ x : int -> int; y : int -> q }
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Error: The kind of type "q" is
value_or_null mod global unique many uncontended portable external_
non_null
with int -> int with int -> q
& value_or_null mod global unique many uncontended portable
external_ non_null
with int -> int with int -> q
immediate with int -> int with int -> q & immediate with int -> int
with int -> q
because it is an unboxed record.
But the kind of type "q" must be a subkind of
value_or_null mod portable & value_or_null mod portable
Expand Down
2 changes: 1 addition & 1 deletion typing/ctype.ml
Original file line number Diff line number Diff line change
Expand Up @@ -2207,7 +2207,7 @@ let rec estimate_type_jkind ~expand_component env ty =
(* Checking [has_baggage] here is needed for correctness, because
intersection types sometimes do not unify with themselves. Removing
this check causes typing-misc/pr7937.ml to fail. *)
if Jkind.has_baggage jkind
if Jkind.has_with_bounds jkind
then
let level = get_level ty in
(* CR layouts v2.8: We could possibly skip this substitution if we're
Expand Down
Loading

0 comments on commit f0911cc

Please sign in to comment.