diff --git a/driver/main_args.ml b/driver/main_args.ml index 4bb52a82494..142f0d65bf2 100644 --- a/driver/main_args.ml +++ b/driver/main_args.ml @@ -728,6 +728,10 @@ in \ allows a set of extensions, and every successive universe includes \n\ \ the previous one." +let mk_allow_illegal_crossing f = + "-allow-illegal-crossing", Arg.Unit f, + "Type declarations will not be checked along the portability or contention axes" + let mk_dump_dir f = "-dump-dir", Arg.String f, " dump output like -dlambda into /.dump" @@ -920,6 +924,7 @@ module type Common_options = sig val _extension : string -> unit val _no_extension : string -> unit val _extension_universe : string -> unit + val _allow_illegal_crossing : unit -> unit val _noassert : unit -> unit val _nolabels : unit -> unit val _nostdlib : unit -> unit @@ -1201,6 +1206,7 @@ struct mk_extension F._extension; mk_no_extension F._no_extension; mk_extension_universe F._extension_universe; + mk_allow_illegal_crossing F._allow_illegal_crossing; mk_for_pack_byt F._for_pack; mk_g_byt F._g; mk_no_g F._no_g; @@ -1328,6 +1334,7 @@ struct mk_extension F._extension; mk_no_extension F._no_extension; mk_extension_universe F._extension_universe; + mk_allow_illegal_crossing F._allow_illegal_crossing; mk_noassert F._noassert; mk_noinit F._noinit; mk_nolabels F._nolabels; @@ -1421,6 +1428,7 @@ struct mk_extension F._extension; mk_no_extension F._no_extension; mk_extension_universe F._extension_universe; + mk_allow_illegal_crossing F._allow_illegal_crossing; mk_for_pack_opt F._for_pack; mk_g_opt F._g; mk_no_g F._no_g; @@ -1607,6 +1615,7 @@ module Make_opttop_options (F : Opttop_options) = struct mk_extension F._extension; mk_no_extension F._no_extension; mk_extension_universe F._extension_universe; + mk_allow_illegal_crossing F._allow_illegal_crossing; mk_no_float_const_prop F._no_float_const_prop; mk_noassert F._noassert; mk_noinit F._noinit; @@ -1714,6 +1723,7 @@ struct mk_extension F._extension; mk_no_extension F._no_extension; mk_extension_universe F._extension_universe; + mk_allow_illegal_crossing F._allow_illegal_crossing; mk_noassert F._noassert; mk_nolabels F._nolabels; mk_nostdlib F._nostdlib; @@ -1825,6 +1835,7 @@ module Default = struct let _no_extension s = Language_extension.(disable_of_string_exn s) let _extension_universe s = Language_extension.(set_universe_and_enable_all_of_string_exn s) + let _allow_illegal_crossing = set Clflags.allow_illegal_crossing let _noassert = set noassert let _nolabels = set classic let _nostdlib = set no_std_include diff --git a/driver/main_args.mli b/driver/main_args.mli index 59817e3bf26..992ef1f392a 100644 --- a/driver/main_args.mli +++ b/driver/main_args.mli @@ -34,6 +34,7 @@ module type Common_options = sig val _extension : string -> unit val _no_extension : string -> unit val _extension_universe : string -> unit + val _allow_illegal_crossing : unit -> unit val _noassert : unit -> unit val _nolabels : unit -> unit val _nostdlib : unit -> unit diff --git a/testsuite/tests/typing-layouts/allow_illegal_crossing.ml b/testsuite/tests/typing-layouts/allow_illegal_crossing.ml new file mode 100644 index 00000000000..d22d69b75c0 --- /dev/null +++ b/testsuite/tests/typing-layouts/allow_illegal_crossing.ml @@ -0,0 +1,961 @@ +(* TEST + { + flags = "-allow-illegal-crossing"; + expect; + } +*) + +(*************************************************************************************) +(* Test 1: nominative types can cross portability and contention axes when annotated *) + +type a +type b : value mod portable = { a : int; b : int } +[%%expect {| +type a +type b : value mod portable = { a : int; b : int; } +|}] + +type a +type b : value mod uncontended = Foo of int +[%%expect {| +type a +type b : value mod uncontended = Foo of int +|}] + +type a +type b : value mod uncontended portable = Foo of int | Bar of int +[%%expect {| +type a +type b : value mod uncontended portable = Foo of int | Bar of int +|}] + +module _ = struct + type a + type b : value mod uncontended = private a +end +[%%expect {| +Line 3, characters 2-44: +3 | type b : value mod uncontended = private a + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: The layout of type a is value, because + of the definition of a at line 2, characters 2-8. + But the layout of type a must be a sublayout of value, because + of the definition of b at line 3, characters 2-44. +|}] + +type t : value mod portable uncontended = { a : int; b : int } +[%%expect {| +type t : value mod portable uncontended = { a : int; b : int; } +|}] + +type ('a, 'b) t : value mod portable uncontended = { a : 'a; b : 'b } +[%%expect {| +type ('a, 'b) t : value mod portable uncontended = { a : 'a; b : 'b; } +|}] + +type t : value mod portable = private { foo : string } +[%%expect {| +type t : value mod portable = private { foo : string; } +|}] + +type a : value mod portable = { foo : string } +type b : value mod portable = a = { foo : string } +[%%expect {| +type a : value mod portable = { foo : string; } +type b = a : value mod portable = { foo : string; } +|}] + +type a : value mod uncontended = private { foo : string } +type b : value mod uncontended = a = private { foo : string } +[%%expect {| +type a : value mod uncontended = private { foo : string; } +type b = a : value mod uncontended = private { foo : string; } +|}] + +type t : value mod uncontended = private Foo of int | Bar +[%%expect {| +type t : value mod uncontended = 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 : value mod uncontended = Foo of int | Bar +type b = a : value mod uncontended = 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 : value mod portable = private Foo of int | Bar +type b = a : value mod portable = private Foo of int | Bar +|}] + +module A : sig + type t : value mod portable = { a : string } +end = struct + type t = { a : string } +end +[%%expect {| +module A : sig type t : value mod portable = { a : string; } end +|}] + +(********************************************) +(* Test 2: illegal mode crossing propogates *) + +type a : value mod portable uncontended = Foo of string +type ('a : value mod portable uncontended) b +type c = a b +[%%expect {| +type a : value mod portable uncontended = Foo of string +type ('a : value mod uncontended portable) b +type c = a b +|}] + +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 : value mod portable uncontended = { a : string; b : int; } +val f : ('a : value mod uncontended portable). 'a -> 'a = +val g : t -> t = +|}] + +type t : value mod portable uncontended = { a : int; b : int } +let x : _ as (_ : value mod portable uncontended) = { a = 5; b = 5 } +[%%expect {| +type t : value mod portable uncontended = { a : int; b : int; } +val x : t = {a = 5; b = 5} +|}] + +type ('a, 'b) t : value mod portable uncontended = { a : 'a; b : 'b } +let x : _ as (_ : value mod portable uncontended) = { a = 5; b = 5 } +[%%expect {| +type ('a, 'b) t : value mod portable uncontended = { a : 'a; b : 'b; } +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 : value mod portable uncontended = Foo of string | Bar of int +val x : t = Foo "hello world" +|}] + +module A : sig + type t : value mod portable = { a : string } +end = struct + type t = { a : string } +end +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 : value mod portable = { a : string; } end +type ('a : value mod portable) u = 'a +type v = A.t u +val x : A.t = {A.a = "hello"} +|}] + +type t : value mod portable = { a : string } +let my_str : string @@ nonportable = "" +let y = ({ a = my_str } : t @@ portable) +[%%expect {| +type t : value mod portable = { a : string; } +val my_str : string = "" +val y : t = {a = ""} +|}] + +type t : value mod portable = { a : string } +let my_str : string @@ nonportable = "" +let y : t @@ portable = { a = my_str } +[%%expect {| +type t : value mod portable = { a : string; } +val my_str : string = "" +Line 3, characters 30-36: +3 | let y : t @@ portable = { a = my_str } + ^^^^^^ +Error: This value is nonportable but expected to be portable. +|}] +(* CR layouts v2.8: this is unfortunate that this isn't accepted, but it is fine + since pushing the annotation to the right hand side resolves the issue, and + -allow-illegal-crossing is a short-term solution *) + +type t : value mod uncontended = { a : string } +let make_str () : string = failwith "" +let f () = + let _ = ({ a = make_str () } : t @@ uncontended) in + () +[%%expect {| +type t : value mod uncontended = { a : string; } +val make_str : unit -> string = +val f : unit -> unit = +|}] + +type t : value mod uncontended = { a : string } +let make_str () : string = failwith "" +let f () = + let _ : t @@ uncontended = { a = make_str () } in + () +[%%expect {| +type t : value mod uncontended = { a : string; } +val make_str : unit -> string = +val f : unit -> unit = +|}] +(* CR layouts v2.8: this is unfortunate that this isn't accepted, but it is fine + since pushing the annotation to the right hand side resolves the issue, and + -allow-illegal-crossing is a short-term solution *) + +type t_value : value +type t : value mod portable uncontended = Foo of t_value +let make_value () : t_value = failwith "" +let f () = + let _ = (Foo (make_value ()) : t @@ portable uncontended) in + () +[%%expect {| +type t_value : value +type t : value mod portable uncontended = Foo of t_value +val make_value : unit -> t_value = +val f : unit -> unit = +|}] + +type t : value mod portable = { a : string } +let my_str : string @@ nonportable = "" +let y = ({ a = my_str } : _ @@ portable) +[%%expect {| +type t : value mod portable = { a : string; } +val my_str : string = "" +Line 3, characters 15-21: +3 | let y = ({ a = my_str } : _ @@ portable) + ^^^^^^ +Error: This value is nonportable but expected to be portable. +|}] +(* CR layouts v2.8: this is unfortunate that this isn't accepted, but it is fine + since adding the type to the annotation resolves the issue, and + -allow-illegal-crossing is a short-term solution *) + +let f (_x : _ @@ portable uncontended) = () +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 = +type t : value mod portable uncontended = Foo of string | Bar of int +val g : t @ contended -> unit = +|}] + +(* Demonstrate that -allow-illegal-crossing allows for unsound mode-crossing *) +module Unsound : sig + val cross : 'a @ nonportable contended -> 'a @ portable uncontended +end = struct + type 'a box : value mod portable uncontended = { value : 'a } + let cross x = + let box = { value = x } in + box.value +end + +module Value : sig + type t + val value : t +end = struct + type t = Foo + let value = Foo +end + +let x : Value.t @@ portable uncontended = Unsound.cross Value.value +[%%expect {| +module Unsound : sig val cross : 'a @ contended -> 'a @ portable end +module Value : sig type t val value : t end +val x : Value.t = +|}] + +(* Validate above testing technique *) +let x : Value.t @@ portable uncontended = Value.value +[%%expect {| +Line 1, characters 42-53: +1 | let x : Value.t @@ portable uncontended = Value.value + ^^^^^^^^^^^ +Error: This value is nonportable but expected to be portable. +|}] +(********************************************************) +(* Test 3: types cannot cross other axes when annotated *) + +type a +type b : value mod global = private a +[%%expect {| +type a +Line 2, characters 0-37: +2 | type b : value mod global = private a + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: The layout of type a is value, because + of the definition of a at line 1, characters 0-6. + But the layout of type a must be a sublayout of value, because + of the definition of b at line 2, characters 0-37. +|}] + +type a +type b : value mod many = private a +[%%expect {| +type a +Line 2, characters 0-35: +2 | type b : value mod many = private a + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: The layout of type a is value, because + of the definition of a at line 1, characters 0-6. + But the layout of type a must be a sublayout of value, because + of the definition of b at line 2, characters 0-35. +|}] + +type a +type b : value mod unique = private a +[%%expect {| +type a +Line 2, characters 0-37: +2 | type b : value mod unique = private a + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: The layout of type a is value, because + of the definition of a at line 1, characters 0-6. + But the layout of type a must be a sublayout of value, because + of the definition of b at line 2, characters 0-37. +|}] + +type a +type b : immediate = private a +[%%expect {| +type a +Line 2, characters 0-30: +2 | type b : immediate = private a + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: The layout of type a is value, because + of the definition of a at line 1, characters 0-6. + But the layout of type a must be a sublayout of immediate, because + of the definition of b at line 2, characters 0-30. +|}] + +module _ = struct + type a + type b : value mod global = private a +end +[%%expect {| +Line 3, characters 2-39: +3 | type b : value mod global = private a + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: The layout of type a/2 is value, because + of the definition of a at line 2, characters 2-8. + But the layout of type a/2 must be a sublayout of value, because + of the definition of b at line 3, characters 2-39. +|}] + +module A : sig + type t +end = struct + type t : value mod many = private string +end +[%%expect {| +Line 4, characters 2-42: +4 | type t : value mod many = private string + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: The layout of type string is value, because + it is the primitive value type string. + But the layout of type string must be a sublayout of value, because + of the definition of t at line 4, characters 2-42. +|}] + +type t : value mod external_ = private string +[%%expect {| +Line 1, characters 0-45: +1 | type t : value mod external_ = private string + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: The layout of type string is value, because + it is the primitive value type string. + But the layout of type string must be a sublayout of immediate, because + of the definition of t at line 1, characters 0-45. +|}] + +type t : value mod global = { a : int; b : int } +[%%expect {| +Line 1, characters 0-48: +1 | type t : value mod global = { a : int; b : int } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: The layout of type t is value, because + it's a boxed record type. + But the layout of type t must be a sublayout of value, because + of the annotation on the declaration of the type t. +|}] + +type ('a, 'b) t : value mod many = { a : 'a; b : 'b } +[%%expect {| +Line 1, characters 0-53: +1 | type ('a, 'b) t : value mod many = { a : 'a; b : 'b } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: The layout of type t is value, because + it's a boxed record type. + But the layout of type t must be a sublayout of value, because + of the annotation on the declaration of the type t. +|}] + +type a : value mod unique = private b +and b +[%%expect {| +Line 1, characters 0-37: +1 | type a : value mod unique = private b + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: The layout of type b is value, because + an abstract type has the value layout by default. + But the layout of type b must be a sublayout of value, because + of the definition of a at line 1, characters 0-37. +|}] + +type a +and b : value mod global = private a +[%%expect {| +Line 2, characters 0-36: +2 | and b : value mod global = private a + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: The layout of type a/3 is value, because + an abstract type has the value layout by default. + But the layout of type a/3 must be a sublayout of value, because + of the definition of b at line 2, characters 0-36. +|}] + +module rec A : sig + type t : value mod external_ +end = struct + type t : value mod external_ = private B.t +end +and B : sig + type t +end = struct + type t +end +[%%expect {| +Line 4, characters 2-44: +4 | type t : value mod external_ = private B.t + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: The layout of type B.t is value, because + of the definition of t at line 7, characters 2-8. + But the layout of type B.t must be a sublayout of immediate, because + of the definition of t at line 4, characters 2-44. +|}] + +module rec A : sig + type t +end = struct + type t +end +and B : sig + type t : value mod many +end = struct + type t : value mod many = private A.t +end +[%%expect {| +Line 9, characters 2-39: +9 | type t : value mod many = private A.t + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: The layout of type A.t is value, because + of the definition of t at line 2, characters 2-8. + But the layout of type A.t must be a sublayout of value, because + of the definition of t at line 9, characters 2-39. +|}] + +(*********************************************************************************) +(* Test 4: types cannot cross portability and contention axes when not annotated *) + +module A : sig + type t : value mod portable +end = struct + type t = { a : string } +end +[%%expect {| +Lines 3-5, characters 6-3: +3 | ......struct +4 | type t = { a : string } +5 | end +Error: Signature mismatch: + Modules do not match: + sig type t = { a : string; } end + is not included in + sig type t : value mod portable end + Type declarations do not match: + type t = { a : string; } + is not included in + type t : value mod portable + The layout of the first is value, because + of the definition of t at line 4, characters 2-25. + But the layout of the first must be a sublayout of value, because + of the definition of t at line 2, characters 2-29. +|}] + +module A : sig + type t : value mod portable = { a : string } +end = struct + type t = { a : string } + type ('a : value mod portable) u = 'a + type v = t u +end +[%%expect {| +Line 6, characters 11-12: +6 | type v = t u + ^ +Error: This type t should be an instance of type ('a : value mod portable) + The layout of t is value, because + of the definition of t at line 4, characters 2-25. + But the layout of t must be a sublayout of value, because + of the definition of u at line 5, characters 2-39. +|}] + +module A : sig + type t : value mod portable = { a : string } +end = struct + type t = { a : string } + let x : _ as (_ : value mod portable) = { a = "hello" } +end +[%%expect {| +Line 5, characters 42-57: +5 | let x : _ as (_ : value mod portable) = { a = "hello" } + ^^^^^^^^^^^^^^^ +Error: This expression has type t but an expression was expected of type + ('a : value mod portable) + The layout of t is value, because + of the definition of t at line 4, characters 2-25. + But the layout of t must be a sublayout of value, because + of the annotation on the wildcard _ at line 5, characters 20-38. +|}] + +type a +type b : value mod portable = a +[%%expect {| +type a +Line 2, characters 0-31: +2 | type b : value mod portable = a + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: The layout of type a is value, because + of the definition of a at line 1, characters 0-6. + But the layout of type a must be a sublayout of value, because + of the definition of b at line 2, characters 0-31. +|}] + +type a = { foo : int; bar : string } +type b : any mod portable = a +[%%expect {| +type a = { foo : int; bar : string; } +Line 2, characters 0-29: +2 | type b : any mod portable = a + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: The layout of type a is value, because + of the definition of a at line 1, characters 0-36. + But the layout of type a must be a sublayout of any, because + of the definition of b at line 2, characters 0-29. +|}] + +type a = Foo of int | Bar of string +type b : any mod uncontended = a +[%%expect {| +type a = Foo of int | Bar of string +Line 2, characters 0-32: +2 | type b : any mod uncontended = a + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: The layout of type a is value, because + of the definition of a at line 1, characters 0-35. + But the layout of type a must be a sublayout of any, because + of the definition of b at line 2, characters 0-32. +|}] + +module Foo : sig + type t +end = struct + type t : value mod portable = string +end +type t : value mod portable = Foo.t +[%%expect {| +Line 4, characters 2-38: +4 | type t : value mod portable = string + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: The layout of type string is value, because + it is the primitive value type string. + But the layout of type string must be a sublayout of value, because + of the definition of t at line 4, characters 2-38. +|}] + +type a = { foo : string } +type b : value mod portable = a = { foo : string } +[%%expect {| +type a = { foo : string; } +Line 2, characters 0-50: +2 | type b : value mod portable = a = { foo : string } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: The layout of type a is value, because + of the definition of a at line 1, characters 0-25. + But the layout of type a must be a sublayout of value, because + of the definition of b at line 2, characters 0-50. +|}] + +type a = private { foo : string } +type b : value mod uncontended = a = private { foo : string } +[%%expect {| +type a = private { foo : string; } +Line 2, characters 0-61: +2 | type b : value mod uncontended = a = private { foo : string } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: The layout of type a is value, because + of the definition of a at line 1, characters 0-33. + But the layout of type a must be a sublayout of value, because + of the definition of b at line 2, characters 0-61. +|}] + +type a = Foo of string | Bar +type b : value mod uncontended = a = Foo of string | Bar +[%%expect {| +type a = Foo of string | Bar +Line 2, characters 0-56: +2 | type b : value mod uncontended = a = Foo of string | Bar + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: The layout of type a is value, because + of the definition of a at line 1, characters 0-28. + But the layout of type a must be a sublayout of value, because + of the definition of b at line 2, characters 0-56. +|}] + +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 +Line 2, characters 0-61: +2 | type b : value mod portable = a = private Foo of string | Bar + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: The layout of type a is value, because + of the definition of a at line 1, characters 0-36. + But the layout of type a must be a sublayout of value, because + of the definition of b at line 2, characters 0-61. +|}] + +type ('a : value mod uncontended) of_uncontended +type t = string of_uncontended +[%%expect {| +type ('a : value mod uncontended) of_uncontended +Line 2, characters 9-15: +2 | type t = string of_uncontended + ^^^^^^ +Error: This type string should be an instance of type + ('a : value mod uncontended) + The layout of string is value, because + it is the primitive value type string. + But the layout of string must be a sublayout of value, because + of the definition of of_uncontended at line 1, characters 0-48. +|}] + +type ('a : value mod portable) of_portable +type t = { foo : int } +type u = t of_portable +[%%expect {| +type ('a : value mod portable) of_portable +type t = { foo : int; } +Line 3, characters 9-10: +3 | type u = t of_portable + ^ +Error: This type t should be an instance of type ('a : value mod portable) + The layout of t is value, because + of the definition of t at line 2, characters 0-22. + But the layout of t must be a sublayout of value, because + of the definition of of_portable at line 1, characters 0-42. +|}] + +let f : ('a : value mod portable). 'a -> 'a = fun x -> x +let _ = f "hello" +[%%expect {| +val f : ('a : value mod portable). 'a -> 'a = +Line 2, characters 10-17: +2 | let _ = f "hello" + ^^^^^^^ +Error: This expression has type string but an expression was expected of type + ('a : value mod portable) + The layout of string is value, because + it is the primitive value type string. + But the layout of string must be a sublayout of value, because + of the definition of f at line 1, characters 4-5. +|}] + +let f : ('a : value mod uncontended). 'a -> 'a = fun x -> x +let _ = f "hello" +[%%expect {| +val f : ('a : value mod uncontended). 'a -> 'a = +Line 2, characters 10-17: +2 | let _ = f "hello" + ^^^^^^^ +Error: This expression has type string but an expression was expected of type + ('a : value mod uncontended) + The layout of string is value, because + it is the primitive value type string. + But the layout of string must be a sublayout of value, because + of the definition of f at line 1, characters 4-5. +|}] + +(* immediate types can still cross *) +let f : ('a : value mod portable uncontended). 'a -> 'a = fun x -> x +let _ = f 0 +[%%expect {| +val f : ('a : value mod uncontended portable). 'a -> 'a = +- : int = 0 +|}] + +(*****************************************) +(* Test 5: values cannot illegally cross *) + +let x : _ as (_ : value mod portable) = "hello world" +[%%expect {| +Line 1, characters 40-53: +1 | let x : _ as (_ : value mod portable) = "hello world" + ^^^^^^^^^^^^^ +Error: This expression has type string but an expression was expected of type + ('a : value mod portable) + The layout of string is value, because + it is the primitive value type string. + But the layout of string must be a sublayout of value, because + of the annotation on the wildcard _ at line 1, characters 18-36. +|}] + +type t = { str : string } +let f _ : _ as (_ : value mod uncontended) = { str = "hello world" } +[%%expect {| +type t = { str : string; } +Line 2, characters 45-68: +2 | let f _ : _ as (_ : value mod uncontended) = { str = "hello world" } + ^^^^^^^^^^^^^^^^^^^^^^^ +Error: This expression has type t but an expression was expected of type + ('a : value mod uncontended) + The layout of t is value, because + of the definition of t at line 1, characters 0-25. + But the layout of t must be a sublayout of value, because + of the annotation on the wildcard _ at line 2, characters 20-41. +|}] + +type t = Foo of string +let f : ('a : value mod portable). 'a -> 'a = fun _ -> Foo "hello world" +[%%expect {| +type t = Foo of string +Line 2, characters 55-72: +2 | let f : ('a : value mod portable). 'a -> 'a = fun _ -> Foo "hello world" + ^^^^^^^^^^^^^^^^^ +Error: This expression has type t but an expression was expected of type + ('a : value mod portable) + The layout of t is value, because + of the definition of t at line 1, characters 0-22. + But the layout of t must be a sublayout of value, because + of the annotation on the universal variable 'a. +|}] + +type t = string +let x : ('a : value mod uncontended) = ("hello world" : t) +[%%expect {| +type t = string +Line 2, characters 39-58: +2 | let x : ('a : value mod uncontended) = ("hello world" : t) + ^^^^^^^^^^^^^^^^^^^ +Error: This expression has type t = string + but an expression was expected of type ('a : value mod uncontended) + The layout of t is value, because + it is the primitive value type string. + But the layout of t must be a sublayout of value, because + of the annotation on the type variable 'a. +|}] + +(***************************************) +(* Test 6: layout check is not ignored *) + +type a : word +type b : value mod portable = a +[%%expect {| +type a : word +Line 2, characters 0-31: +2 | type b : value mod portable = a + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: The layout of type a is word, because + of the definition of a at line 1, characters 0-13. + But the layout of type a must be a sublayout of value, because + of the definition of b at line 2, characters 0-31. +|}] + +type a : bits64 +type b : float32 mod uncontended = a +[%%expect {| +type a : bits64 +Line 2, characters 0-36: +2 | type b : float32 mod uncontended = a + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: The layout of type a is bits64, because + of the definition of a at line 1, characters 0-15. + But the layout of type a must be a sublayout of float32, because + of the definition of b at line 2, characters 0-36. +|}] + +type a : any +type b : value mod uncontended = a +[%%expect {| +type a : any +Line 2, characters 0-34: +2 | type b : value mod uncontended = a + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: The layout of type a is any, because + of the definition of a at line 1, characters 0-12. + But the layout of type a must be a sublayout of value, because + of the definition of b at line 2, characters 0-34. +|}] + +(****************************************************************) +(* Test 7: Non-nominative types cannot perform illegal crossing *) + +type a +type b : value mod portable = a +[%%expect {| +type a +Line 2, characters 0-31: +2 | type b : value mod portable = a + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: The layout of type a is value, because + of the definition of a at line 1, characters 0-6. + But the layout of type a must be a sublayout of value, because + of the definition of b at line 2, characters 0-31. +|}] + +type a +type b : value mod uncontended = a +[%%expect {| +type a +Line 2, characters 0-34: +2 | type b : value mod uncontended = a + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: The layout of type a is value, because + of the definition of a at line 1, characters 0-6. + But the layout of type a must be a sublayout of value, because + of the definition of b at line 2, characters 0-34. +|}] + +type a +type b : value mod portable = private a +[%%expect {| +type a +Line 2, characters 0-39: +2 | type b : value mod portable = private a + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: The layout of type a is value, because + of the definition of a at line 1, characters 0-6. + But the layout of type a must be a sublayout of value, because + of the definition of b at line 2, characters 0-39. +|}] + +type a +type b : value mod uncontended = private a +[%%expect {| +type a +Line 2, characters 0-42: +2 | type b : value mod uncontended = private a + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: The layout of type a is value, because + of the definition of a at line 1, characters 0-6. + But the layout of type a must be a sublayout of value, because + of the definition of b at line 2, characters 0-42. +|}] + +type a : word +type b : any mod uncontended portable = private a +[%%expect {| +type a : word +Line 2, characters 0-49: +2 | type b : any mod uncontended portable = private a + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: The layout of type a is word, because + of the definition of a at line 1, characters 0-13. + But the layout of type a must be a sublayout of any, because + of the definition of b at line 2, characters 0-49. +|}] + +type a : value mod global many unique external_ +type b : immediate = private a +[%%expect {| +type a : value mod global many unique external_ +Line 2, characters 0-30: +2 | type b : immediate = private a + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: The layout of type a is immediate, because + of the definition of a at line 1, characters 0-47. + But the layout of type a must be a sublayout of immediate, because + of the definition of b at line 2, characters 0-30. +|}] + +module A : sig + type t +end = struct + type t : value mod portable = private string +end +[%%expect {| +Line 4, characters 2-46: +4 | type t : value mod portable = private string + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: The layout of type string is value, because + it is the primitive value type string. + But the layout of type string must be a sublayout of value, because + of the definition of t at line 4, characters 2-46. +|}] + +type a : value mod portable uncontended = private b +and b +[%%expect {| +Line 1, characters 0-51: +1 | type a : value mod portable uncontended = private b + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: The layout of type b is value, because + an abstract type has the value layout by default. + But the layout of type b must be a sublayout of value, because + of the definition of a at line 1, characters 0-51. +|}] + +type a +and b : value mod portable uncontended = a +[%%expect {| +Line 2, characters 0-42: +2 | and b : value mod portable uncontended = a + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: The layout of type a/2 is value, because + an abstract type has the value layout by default. + But the layout of type a/2 must be a sublayout of value, because + of the definition of b at line 2, characters 0-42. +|}] + +module rec A : sig + type t : value mod portable uncontended +end = struct + type t : value mod portable uncontended = B.t +end +and B : sig + type t +end = struct + type t +end +[%%expect {| +Line 4, characters 2-47: +4 | type t : value mod portable uncontended = B.t + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: The layout of type B.t is value, because + of the definition of t at line 7, characters 2-8. + But the layout of type B.t must be a sublayout of value, because + of the definition of t at line 4, characters 2-47. +|}] + +module rec A : sig + type t +end = struct + type t +end +and B : sig + type t : value mod portable uncontended +end = struct + type t : value mod portable uncontended = private A.t +end +[%%expect {| +Line 9, characters 2-55: +9 | type t : value mod portable uncontended = private A.t + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: The layout of type A.t is value, because + of the definition of t at line 2, characters 2-8. + But the layout of type A.t must be a sublayout of value, because + of the definition of t at line 9, characters 2-55. +|}] diff --git a/testsuite/tests/typing-layouts/jkinds.ml b/testsuite/tests/typing-layouts/jkinds.ml index 59cc25fd4b8..c9ff191ab1f 100644 --- a/testsuite/tests/typing-layouts/jkinds.ml +++ b/testsuite/tests/typing-layouts/jkinds.ml @@ -1565,3 +1565,113 @@ Error: This expression has type < > but an expression was expected of type |}] (* CR layouts v2.8: Bad error message. The error message should be about a kind or mode mismatch, not a layout mismatch. *) + +(****************************************) +(* Test 11: Inference of type parameter *) + +type 'a t : any = 'a +[%%expect {| +type 'a t = 'a +|}] + +type 'a t : value = 'a +[%%expect {| +type 'a t = 'a +|}] + +type 'a t : value mod global = 'a +[%%expect {| +Line 1, characters 0-33: +1 | type 'a t : value mod global = 'a + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: The layout of type 'a is value, because + of the definition of t at line 1, characters 0-33. + But the layout of type 'a must be a sublayout of value, because + of the definition of t at line 1, characters 0-33. +|}] +(* CR layouts v2.8: this should be accepted; 'a should be inferred to have kind + value mod global *) + +type 'a t : word = 'a +[%%expect {| +Line 1, characters 0-21: +1 | type 'a t : word = 'a + ^^^^^^^^^^^^^^^^^^^^^ +Error: The layout of type 'a is value, because + of the definition of t at line 1, characters 0-21. + But the layout of type 'a must be a sublayout of word, because + of the definition of t at line 1, characters 0-21. +|}] +(* CR layouts v2.8: this should be accepted; 'a should be inferred to have kind + word *) + +type 'a t : any = private 'a +[%%expect {| +type 'a t = private 'a +|}] + +type 'a t : value = private 'a +[%%expect {| +type 'a t = private 'a +|}] + +type 'a t : value mod global = private 'a +[%%expect {| +Line 1, characters 0-41: +1 | type 'a t : value mod global = private 'a + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: The layout of type 'a is value, because + of the definition of t at line 1, characters 0-41. + But the layout of type 'a must be a sublayout of value, because + of the definition of t at line 1, characters 0-41. +|}] +(* CR layouts v2.8: this should be accepted; 'a should be inferred to have kind + value mod global *) + +type 'a t : word = private 'a +[%%expect {| +Line 1, characters 0-29: +1 | type 'a t : word = private 'a + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: The layout of type 'a is value, because + of the definition of t at line 1, characters 0-29. + But the layout of type 'a must be a sublayout of word, because + of the definition of t at line 1, characters 0-29. +|}] +(* CR layouts v2.8: this should be accepted; 'a should be inferred to have kind + word *) + +type 'a t : value mod global = Foo of 'a [@@unboxed] +[%%expect {| +Line 1, characters 0-52: +1 | type 'a t : value mod global = Foo of 'a [@@unboxed] + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: The layout of type t is value, because + it instantiates an unannotated type parameter of t, defaulted to layout value. + But the layout of type t must be a sublayout of value, because + of the annotation on the declaration of the type t. +|}] +(* CR layouts v2.8: this should be accepted; 'a should be inferred to have kind + value mod global *) + +type 'a t : value mod global = { x : 'a } +[%%expect {| +Line 1, characters 0-41: +1 | type 'a t : value mod global = { x : 'a } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: The layout of type t is value, because + it's a boxed record type. + But the layout of type t must be a sublayout of value, because + of the annotation on the declaration of the type t. +|}] + +type 'a t : value mod many = { x : 'a } +[%%expect {| +Line 1, characters 0-39: +1 | type 'a t : value mod many = { x : 'a } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: The layout of type t is value, because + it's a boxed record type. + But the layout of type t must be a sublayout of value, because + of the annotation on the declaration of the type t. +|}] diff --git a/typing/ctype.ml b/typing/ctype.ml index f1740a7cb80..4a92475cfd9 100644 --- a/typing/ctype.ml +++ b/typing/ctype.ml @@ -1344,6 +1344,7 @@ let new_local_type ?(loc = Location.none) ?manifest_and_scope jkind ~jkind_annot type_attributes = []; type_unboxed_default = false; type_uid = Uid.mk ~current_unit:(Env.get_unit_name ()); + type_has_illegal_crossings = false; } let existential_name cstr ty = @@ -6491,6 +6492,7 @@ let nondep_type_decl env mid is_covariant decl = type_attributes = decl.type_attributes; type_unboxed_default = decl.type_unboxed_default; type_uid = decl.type_uid; + type_has_illegal_crossings = decl.type_has_illegal_crossings; } with Nondep_cannot_erase _ as exn -> clear_hash (); diff --git a/typing/datarepr.ml b/typing/datarepr.ml index f19d23b4b66..a1f6ca2e372 100644 --- a/typing/datarepr.ml +++ b/typing/datarepr.ml @@ -91,6 +91,7 @@ let constructor_args ~current_unit priv cd_args cd_res path rep = type_attributes = []; type_unboxed_default = false; type_uid = Uid.mk ~current_unit; + type_has_illegal_crossings = false; } in existentials, diff --git a/typing/jkind.ml b/typing/jkind.ml index 02e6db420fa..0e7c4baf6ad 100644 --- a/typing/jkind.ml +++ b/typing/jkind.ml @@ -800,6 +800,30 @@ module Jkind_desc = struct externality_upper_bound = Externality.min } + let add_portability_and_contention_crossing ~from t = + let new_portability = + Portability.Const.meet t.modes_upper_bounds.portability + from.modes_upper_bounds.portability + in + let new_contention = + Contention.Const.meet t.modes_upper_bounds.contention + from.modes_upper_bounds.contention + in + let added_crossings = + (not + (Portability.Const.le t.modes_upper_bounds.portability new_portability)) + || not + (Contention.Const.le t.modes_upper_bounds.contention new_contention) + in + ( { t with + modes_upper_bounds = + { t.modes_upper_bounds with + portability = new_portability; + contention = new_contention + } + }, + added_crossings ) + let max = of_const Const.max let equate_or_equal ~allow_mutation @@ -1029,6 +1053,12 @@ end let add_mode_crossing t = { t with jkind = Jkind_desc.add_mode_crossing t.jkind } +let add_portability_and_contention_crossing ~from t = + let jkind, added_crossings = + Jkind_desc.add_portability_and_contention_crossing ~from:from.jkind t.jkind + in + { t with jkind }, added_crossings + (*** extension requirements ***) (* The [annotation_context] parameter can be used to allow annotations / kinds in different contexts to be enabled with different extension settings. diff --git a/typing/jkind.mli b/typing/jkind.mli index 50e37193e15..37266d8cfed 100644 --- a/typing/jkind.mli +++ b/typing/jkind.mli @@ -298,6 +298,11 @@ end (** Take an existing [t] and add an ability to mode-cross along all the axes. *) val add_mode_crossing : t -> t +(** Take an existing [t] and add an ability to mode-cross along the portability and + contention axes, if [from] crosses the respective axes. Return the new jkind, + along with a boolean of whether illegal crossing was added *) +val add_portability_and_contention_crossing : from:t -> t -> t * bool + (******************************) (* construction *) diff --git a/typing/predef.ml b/typing/predef.ml index 288cec7013e..6b3b0b9c9d8 100644 --- a/typing/predef.ml +++ b/typing/predef.ml @@ -231,6 +231,7 @@ let mk_add_type add_type type_attributes = []; type_unboxed_default = false; type_uid = Uid.of_predef_id type_ident; + type_has_illegal_crossings = false; } in add_type type_ident decl env @@ -269,6 +270,7 @@ let build_initial_env add_type add_extension empty_env = type_attributes = []; type_unboxed_default = false; type_uid = Uid.of_predef_id type_ident; + type_has_illegal_crossings = false; } in add_type type_ident decl env diff --git a/typing/printtyp.ml b/typing/printtyp.ml index c50487ee75a..3f6ff717c17 100644 --- a/typing/printtyp.ml +++ b/typing/printtyp.ml @@ -40,7 +40,7 @@ module Sig_component_kind = Shape.Sig_component_kind [type 'a t : <> = ...]. We print the jkind when it cannot be inferred from the rest of what is - printed. Specifically, we print the user-written jkind in both of these + printed. Specifically, we print the user-written jkind in any of these cases: (C1.1) The type declaration is abstract and has no manifest (i.e., @@ -54,6 +54,10 @@ module Sig_component_kind = Shape.Sig_component_kind be impossible to deduce the jkind. We thus defer to the user in determining whether to print the jkind annotation. + (* CR layouts v2.8: remove this case *) + (C1.3) The type has illegal mode crossings. In this case, the jkind is overridden by + the user rather than being inferred from the definition. + Case (C2). The jkind on a type parameter to a type, like [type ('a : <>) t = ...]. @@ -1875,11 +1879,12 @@ let tree_of_type_decl id decl = in (* The algorithm for setting [lay] here is described as Case (C1) in Note [When to print jkind annotations] *) - let jkind_annotation = match ty, unboxed with - | (Otyp_abstract, _) | (_, true) -> + let jkind_annotation = match ty, unboxed, decl.type_has_illegal_crossings with + | (Otyp_abstract, _, _) | (_, true, _) | (_, _, true) -> (* The two cases of (C1) from the Note correspond to Otyp_abstract. Anything but the default must be user-written, so we print the user-written annotation. *) + (* type_has_illegal_crossings corresponds to C1.3 *) decl.type_jkind_annotation | _ -> None (* other cases have no jkind annotation *) in @@ -2338,6 +2343,7 @@ let dummy = type_attributes = []; type_unboxed_default = false; type_uid = Uid.internal_not_actually_unique; + type_has_illegal_crossings = false; } (** we hide items being defined from short-path to avoid shortening diff --git a/typing/subst.ml b/typing/subst.ml index 27d8ccd4b63..8f5c9d5bc2a 100644 --- a/typing/subst.ml +++ b/typing/subst.ml @@ -503,6 +503,7 @@ let type_declaration' copy_scope s decl = type_attributes = attrs s decl.type_attributes; type_unboxed_default = decl.type_unboxed_default; type_uid = decl.type_uid; + type_has_illegal_crossings = decl.type_has_illegal_crossings; } let type_declaration s decl = diff --git a/typing/typeclass.ml b/typing/typeclass.ml index 4caaf005ad0..403a0e6c654 100644 --- a/typing/typeclass.ml +++ b/typing/typeclass.ml @@ -1619,6 +1619,7 @@ let temp_abbrev loc id arity uid = type_attributes = []; (* or keep attrs from the class decl? *) type_unboxed_default = false; type_uid = uid; + type_has_illegal_crossings = false; } in (!params, ty, ty_td) @@ -1850,6 +1851,7 @@ let class_infos define_class kind type_attributes = []; (* or keep attrs from cl? *) type_unboxed_default = false; type_uid = dummy_class.cty_uid; + type_has_illegal_crossings = false; } in let (cl_params, cl_ty) = diff --git a/typing/typedecl.ml b/typing/typedecl.ml index 491f720bf8f..c807f370971 100644 --- a/typing/typedecl.ml +++ b/typing/typedecl.ml @@ -282,6 +282,7 @@ let enter_type ?abstract_abbrevs rec_flag env sdecl (id, uid) = type_attributes = sdecl_attributes; type_unboxed_default = false; type_uid = uid; + type_has_illegal_crossings = false; } in add_type ~check:true id decl env @@ -928,6 +929,7 @@ let transl_declaration env sdecl (id, uid) = type_attributes = sdecl_attributes; type_unboxed_default = unboxed_default; type_uid = uid; + type_has_illegal_crossings = false; } in (* Check constraints *) List.iter @@ -1112,6 +1114,14 @@ let check_coherence env loc dpath decl = match decl with { type_kind = (Type_variant _ | Type_record _| Type_open); type_manifest = Some ty } -> + if !Clflags.allow_illegal_crossing then begin + let jkind' = Ctype.type_jkind_purely env ty in + begin match Jkind.sub_with_history jkind' decl.type_jkind with + | Ok _ -> () + | Error v -> + raise (Error (loc, Jkind_mismatch_of_type (ty,v))) + end + end; begin match get_desc ty with Tconstr(path, args, _) -> begin try @@ -1590,6 +1600,12 @@ let update_decl_jkind env dpath decl = assert false in + let add_crossings jkind = + match !Clflags.allow_illegal_crossing with + | true -> Jkind.add_portability_and_contention_crossing ~from:decl.type_jkind jkind + | false -> jkind, false + in + let new_decl, new_jkind = match decl.type_kind with | Type_abstract _ -> decl, decl.type_jkind | Type_open -> @@ -1597,11 +1613,17 @@ let update_decl_jkind env dpath decl = { decl with type_jkind }, type_jkind | Type_record (lbls, rep) -> let lbls, rep, type_jkind = update_record_kind decl.type_loc lbls rep in - { decl with type_kind = Type_record (lbls, rep); type_jkind }, + let type_jkind, type_has_illegal_crossings = add_crossings type_jkind in + { decl with type_kind = Type_record (lbls, rep); + type_jkind; + type_has_illegal_crossings }, type_jkind | Type_variant (cstrs, rep) -> let cstrs, rep, type_jkind = update_variant_kind cstrs rep in - { decl with type_kind = Type_variant (cstrs, rep); type_jkind }, + let type_jkind, type_has_illegal_crossings = add_crossings type_jkind in + { decl with type_kind = Type_variant (cstrs, rep); + type_jkind; + type_has_illegal_crossings }, type_jkind in @@ -3095,6 +3117,7 @@ let transl_with_constraint id ?fixed_row_path ~sig_env ~sig_decl ~outer_env type_attributes = sdecl.ptype_attributes; type_unboxed_default; type_uid = Uid.mk ~current_unit:(Env.get_unit_name ()); + type_has_illegal_crossings = false; } in Option.iter (fun p -> set_private_row env sdecl.ptype_loc p new_sig_decl) @@ -3135,6 +3158,7 @@ let transl_with_constraint id ?fixed_row_path ~sig_env ~sig_decl ~outer_env type_variance = new_type_variance; type_separability = new_type_separability; + type_has_illegal_crossings = false; } in { typ_id = id; @@ -3173,7 +3197,8 @@ let transl_package_constraint ~loc ty = type_loc = loc; type_attributes = []; type_unboxed_default = false; - type_uid = Uid.mk ~current_unit:(Env.get_unit_name ()) + type_uid = Uid.mk ~current_unit:(Env.get_unit_name ()); + type_has_illegal_crossings = false; } (* Approximate a type declaration: just make all types abstract *) @@ -3197,6 +3222,7 @@ let abstract_type_decl ~injective ~jkind ~jkind_annotation ~params = type_attributes = []; type_unboxed_default = false; type_uid = Uid.internal_not_actually_unique; + type_has_illegal_crossings = false; } end diff --git a/typing/typemod.ml b/typing/typemod.ml index 78a97563491..3637a3bf950 100644 --- a/typing/typemod.ml +++ b/typing/typemod.ml @@ -682,6 +682,7 @@ let merge_constraint initial_env loc sg lid constr = type_attributes = []; type_unboxed_default = false; type_uid = Uid.mk ~current_unit:(Env.get_unit_name ()); + type_has_illegal_crossings = false; } and id_row = Ident.create_local (s^"#row") in let initial_env = diff --git a/typing/types.ml b/typing/types.ml index 2510e87056f..e39162eecda 100644 --- a/typing/types.ml +++ b/typing/types.ml @@ -265,6 +265,7 @@ type type_declaration = type_attributes: Parsetree.attributes; type_unboxed_default: bool; type_uid: Uid.t; + type_has_illegal_crossings: bool; } and type_decl_kind = (label_declaration, constructor_declaration) type_kind diff --git a/typing/types.mli b/typing/types.mli index 42f0950df2b..61c93e5f39b 100644 --- a/typing/types.mli +++ b/typing/types.mli @@ -532,6 +532,10 @@ type type_declaration = type_unboxed_default: bool; (* true if the unboxed-ness of this type was chosen by a compiler flag *) type_uid: Uid.t; + type_has_illegal_crossings: bool; + (* true iff the type definition has illegal crossings of the portability and + contention axes *) + (* CR layouts v2.8: remove type_has_illegal_crossings *) } and type_decl_kind = (label_declaration, constructor_declaration) type_kind diff --git a/utils/clflags.ml b/utils/clflags.ml index fd001b6a896..f8af7531223 100644 --- a/utils/clflags.ml +++ b/utils/clflags.ml @@ -202,6 +202,7 @@ let afl_inst_ratio = ref 100 (* -afl-inst-ratio *) let function_sections = ref false (* -function-sections *) let probes = ref Config.probes (* -probes *) +let allow_illegal_crossing = ref false (* -allow_illegal_crossing *) let simplify_rounds = ref None (* -rounds *) let default_simplify_rounds = ref 1 (* -rounds *) let rounds () = diff --git a/utils/clflags.mli b/utils/clflags.mli index ea7c00116b6..b75d282c959 100644 --- a/utils/clflags.mli +++ b/utils/clflags.mli @@ -218,6 +218,7 @@ val afl_instrument : bool ref val afl_inst_ratio : int ref val function_sections : bool ref val probes : bool ref +val allow_illegal_crossing : bool ref val all_passes : string list ref val dumped_pass : string -> bool