|
1 | 1 | (* TEST
|
2 |
| - flags = "-extension layouts_beta"; |
| 2 | + flags = "-extension layouts_alpha"; |
3 | 3 | expect;
|
4 | 4 | *)
|
5 | 5 |
|
| 6 | +let use_as_value : ('a : value) -> 'a = fun x -> x |
| 7 | +let use_uncontended : 'a @ uncontended -> 'a = fun x -> x |
| 8 | + |
6 | 9 | (* Baseline: if the jkind doesn't match, we should get an error. *)
|
7 |
| -module Mismatched_no_attrs : sig |
8 |
| - type t : float64 |
9 |
| -end = struct |
10 |
| - type t = string |
11 |
| -end |
| 10 | +type t : value mod uncontended = { mutable contents : string } |
12 | 11 | [%%expect{|
|
13 |
| -Lines 3-5, characters 6-3: |
14 |
| -3 | ......struct |
15 |
| -4 | type t = string |
16 |
| -5 | end |
17 |
| -Error: Signature mismatch: |
18 |
| - Modules do not match: |
19 |
| - sig type t = string end |
20 |
| - is not included in |
21 |
| - sig type t : float64 end |
22 |
| - Type declarations do not match: |
23 |
| - type t = string |
24 |
| - is not included in |
25 |
| - type t : float64 |
26 |
| - The layout of the first is value |
27 |
| - because it is the primitive type string. |
28 |
| - But the layout of the first must be a sublayout of float64 |
29 |
| - because of the definition of t at line 2, characters 2-18. |
| 12 | +val use_as_value : 'a -> 'a = <fun> |
| 13 | +val use_uncontended : ('a : value_or_null). 'a -> 'a = <fun> |
| 14 | +Line 5, characters 0-62: |
| 15 | +5 | type t : value mod uncontended = { mutable contents : string } |
| 16 | + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| 17 | +Error: The kind of type "t" is value |
| 18 | + because it's a boxed record type. |
| 19 | + But the kind of type "t" must be a subkind of value mod uncontended |
| 20 | + because of the annotation on the declaration of the type t. |
30 | 21 | |}]
|
31 | 22 |
|
32 |
| -(* On the other hand, if we set the correct attributes on both the impl and the intf, we |
33 |
| - shouldn't get an error (though, obviously, this is completely unsound!) *) |
34 |
| -module Mismatched_with_both_attrs : sig |
35 |
| - type t : float64 |
36 |
| - [@@unsafe_allow_any_kind_in_impl "I love segfaults"] |
37 |
| -end = struct |
38 |
| - type t = string |
39 |
| - [@@unsafe_allow_any_kind_in_intf "I love segfaults"] |
40 |
| -end |
| 23 | +(* On the other hand, if we set the attribute, we shouldn't get an error. *) |
| 24 | +type t : value mod uncontended = { mutable contents : string } |
| 25 | +[@@unsafe_allow_any_mode_crossing] |
| 26 | +let f (x : t @@ contended) = use_uncontended x |
41 | 27 | [%%expect{|
|
42 |
| -module Mismatched_with_both_attrs : sig type t : float64 end |
| 28 | +type t : value mod uncontended = { mutable contents : string; } |
| 29 | +val f : t @ contended -> t = <fun> |
43 | 30 | |}]
|
44 | 31 |
|
45 |
| -(* If we set the attributes but *don't* get a kind mismatch, we ought to be fine *) |
46 |
| -module Matching : sig |
47 |
| - type t : value |
48 |
| - [@@unsafe_allow_any_kind_in_impl "I love segfaults"] |
49 |
| -end = struct |
50 |
| - type t = string |
51 |
| - [@@unsafe_allow_any_kind_in_intf "I love segfaults"] |
52 |
| -end |
| 32 | +(* If we set the attribute but *don't* get a kind mismatch, we ought to be fine *) |
| 33 | +type t : value mod many portable uncontended = string |
| 34 | +[@@unsafe_allow_any_mode_crossing] |
53 | 35 | [%%expect{|
|
54 |
| -Lines 2-3, characters 2-54: |
55 |
| -2 | ..type t : value |
56 |
| -3 | [@@unsafe_allow_any_kind_in_impl "I love segfaults"] |
57 |
| -Warning 212 [unnecessary-allow-any-kind]: [@@allow_any_kind_in_intf] and [@@allow_any_kind_in_impl] set on a |
58 |
| -type, but the kind matches. The attributes can be removed. |
59 |
| - |
60 |
| -module Matching : sig type t end |
| 36 | +type t = string |
61 | 37 | |}]
|
62 | 38 |
|
63 |
| -(* If the attr is only on the signature we should get an error *) |
64 |
| -module Mismatched_with_attr_on_intf : sig |
65 |
| - type t : float64 |
66 |
| - [@@unsafe_allow_any_kind_in_impl "I love segfaults"] |
67 |
| -end = struct |
68 |
| - type t = string |
69 |
| -end |
| 39 | +(* The attribute shouldn't allow us to change the layout *) |
| 40 | +type t : float64 mod uncontended = { mutable contents : string } |
| 41 | +[@@unsafe_allow_any_mode_crossing] |
70 | 42 | [%%expect{|
|
71 |
| -Lines 4-6, characters 6-3: |
72 |
| -4 | ......struct |
73 |
| -5 | type t = string |
74 |
| -6 | end |
75 |
| -Error: Signature mismatch: |
76 |
| - Modules do not match: |
77 |
| - sig type t = string end |
78 |
| - is not included in |
79 |
| - sig type t : float64 end |
80 |
| - Type declarations do not match: |
81 |
| - type t = string |
82 |
| - is not included in |
83 |
| - type t : float64 |
84 |
| - The layout of the first is value |
85 |
| - because it is the primitive type string. |
86 |
| - But the layout of the first must be a sublayout of float64 |
87 |
| - because of the definition of t at lines 2-3, characters 2-54. |
| 43 | +Lines 1-2, characters 0-34: |
| 44 | +1 | type t : float64 mod uncontended = { mutable contents : string } |
| 45 | +2 | [@@unsafe_allow_any_mode_crossing] |
| 46 | +Error: The layout of type "t" is value |
| 47 | + because it's a boxed record type. |
| 48 | + But the layout of type "t" must be a sublayout of float64 |
| 49 | + because of the annotation on the declaration of the type t. |
88 | 50 | |}]
|
89 | 51 |
|
90 |
| -(* If the attr is only on the struct we should get an error *) |
91 |
| -module Mismatched_with_attr_on_impl : sig |
92 |
| - type t : float64 |
| 52 | +(* Abstract types in signatures should work with the unsafe kind *) |
| 53 | +module M : sig |
| 54 | + type t : value mod uncontended |
93 | 55 | end = struct
|
94 |
| - type t = string |
95 |
| - [@@unsafe_allow_any_kind_in_intf "I love segfaults"] |
| 56 | + type t : value mod uncontended = { mutable contents : string } |
| 57 | + [@@unsafe_allow_any_mode_crossing] |
| 58 | + |
| 59 | + let f (x : t @@ contended) = use_uncontended x |
96 | 60 | end
|
97 | 61 | [%%expect{|
|
98 |
| -Lines 3-6, characters 6-3: |
99 |
| -3 | ......struct |
100 |
| -4 | type t = string |
101 |
| -5 | [@@unsafe_allow_any_kind_in_intf "I love segfaults"] |
102 |
| -6 | end |
103 |
| -Error: Signature mismatch: |
104 |
| - Modules do not match: |
105 |
| - sig type t = string end |
106 |
| - is not included in |
107 |
| - sig type t : float64 end |
108 |
| - Type declarations do not match: |
109 |
| - type t = string |
110 |
| - is not included in |
111 |
| - type t : float64 |
112 |
| - The layout of the first is value |
113 |
| - because it is the primitive type string. |
114 |
| - But the layout of the first must be a sublayout of float64 |
115 |
| - because of the definition of t at line 2, characters 2-18. |
| 62 | +module M : sig type t : value mod uncontended end |
116 | 63 | |}]
|
117 | 64 |
|
118 |
| -(* Some more complex stuff with functors *) |
119 |
| - |
120 |
| -module type S1 = sig |
121 |
| - type t : value |
122 |
| -end |
| 65 | +module M1 : sig |
| 66 | + type t : value mod uncontended = { mutable contents : string } |
| 67 | + [@@unsafe_allow_any_mode_crossing] |
| 68 | +end = struct |
| 69 | + type t : value mod uncontended = { mutable contents : string } |
| 70 | + [@@unsafe_allow_any_mode_crossing] |
123 | 71 |
|
124 |
| -module type S2 = sig |
125 |
| - type t : float64 |
126 |
| - [@@unsafe_allow_any_kind_in_impl] |
| 72 | + let f (x : t @@ contended) = use_uncontended x |
127 | 73 | end
|
| 74 | +module M2 : sig |
| 75 | + type t : value mod uncontended = M1.t = { mutable contents : string } |
| 76 | + [@@unsafe_allow_any_mode_crossing] |
| 77 | +end = struct |
| 78 | + type t : value mod uncontended = M1.t = { mutable contents : string } |
| 79 | + [@@unsafe_allow_any_mode_crossing] |
128 | 80 |
|
129 |
| -module type S1 = sig |
130 |
| - type t : value |
131 |
| - [@@unsafe_allow_any_kind_in_intf] |
| 81 | + let f (x : t @@ contended) = use_uncontended x |
132 | 82 | end
|
133 |
| - |
134 |
| -module F1 (X : S1) : S2 = X |
135 |
| - |
136 | 83 | [%%expect{|
|
137 |
| -module type S1 = sig type t end |
138 |
| -module type S2 = sig type t : float64 end |
139 |
| -module type S1 = sig type t end |
140 |
| -module F1 : functor (X : S1) -> S2 |
| 84 | +module M1 : |
| 85 | + sig type t : value mod uncontended = { mutable contents : string; } end |
| 86 | +module M2 : |
| 87 | + sig |
| 88 | + type t = M1.t : value mod uncontended = { mutable contents : string; } |
| 89 | + end |
141 | 90 | |}]
|
142 | 91 |
|
143 |
| -module F2 (X : S2) : S1 = X |
| 92 | +(* Private types still require the attribute *) |
| 93 | +module Private : sig |
| 94 | + type t : value mod uncontended = private { mutable contents : string } |
| 95 | + [@@unsafe_allow_any_mode_crossing] |
| 96 | +end = struct |
| 97 | + type t : value mod uncontended = { mutable contents : string } |
| 98 | + [@@unsafe_allow_any_mode_crossing] |
| 99 | + |
| 100 | + let f (x : t @@ contended) = use_uncontended x |
| 101 | +end |
144 | 102 | [%%expect{|
|
145 |
| -Line 1, characters 26-27: |
146 |
| -1 | module F2 (X : S2) : S1 = X |
147 |
| - ^ |
148 |
| -Error: Signature mismatch: |
149 |
| - Modules do not match: sig type t = X.t end is not included in S1 |
150 |
| - Type declarations do not match: type t = X.t is not included in type t |
151 |
| - The layout of the first is float64 |
152 |
| - because of the definition of t at lines 6-7, characters 2-35. |
153 |
| - But the layout of the first must be a sublayout of value |
154 |
| - because of the definition of t at lines 11-12, characters 2-35. |
| 103 | +module Private : |
| 104 | + sig |
| 105 | + type t : value mod uncontended = private { mutable contents : string; } |
| 106 | + end |
155 | 107 | |}]
|
156 | 108 |
|
157 |
| -(* Non-abstract types can be annotated with [@@unsafe_allow_any_kind_in_intf] too, and get |
158 |
| - checked against signatures during inclusion. *) |
| 109 | +(* Non-abstract types in signatures should work as long as they specify the attribute *) |
| 110 | +module M : sig |
| 111 | + type t1 : value mod uncontended = { mutable contents : string } |
| 112 | + [@@unsafe_allow_any_mode_crossing] |
159 | 113 |
|
160 |
| -module M1 : sig |
161 |
| - type t : value = string [@@unsafe_allow_any_kind_in_intf] |
| 114 | + type t2 : value mod uncontended = private { mutable contents : string } |
| 115 | + [@@unsafe_allow_any_mode_crossing] |
| 116 | + |
| 117 | + type t3 : value mod uncontended = |
| 118 | + | Immut of string |
| 119 | + | Mut of { mutable contents : string } |
| 120 | + [@@unsafe_allow_any_mode_crossing] |
162 | 121 | end = struct
|
163 |
| - type t = string |
164 |
| -end |
| 122 | + type t1 : value mod uncontended = { mutable contents : string } |
| 123 | + [@@unsafe_allow_any_mode_crossing] |
| 124 | + |
| 125 | + type t2 : value mod uncontended = { mutable contents : string } |
| 126 | + [@@unsafe_allow_any_mode_crossing] |
165 | 127 |
|
166 |
| -module M2 : S2 = M1 |
| 128 | + type t3 : value mod uncontended = |
| 129 | + | Immut of string |
| 130 | + | Mut of { mutable contents : string } |
| 131 | + [@@unsafe_allow_any_mode_crossing] |
167 | 132 |
|
| 133 | + let f1 (x : t1 @@ contended) = use_uncontended x |
| 134 | + let f2 (x : t2 @@ contended) = use_uncontended x |
| 135 | + let f3 (x : t3 @@ contended) = use_uncontended x |
| 136 | +end |
168 | 137 | [%%expect{|
|
169 |
| -module M1 : sig type t = string end |
170 |
| -module M2 : S2 |
| 138 | +module M : |
| 139 | + sig |
| 140 | + type t1 : value mod uncontended = { mutable contents : string; } |
| 141 | + type t2 : value mod uncontended = private { mutable contents : string; } |
| 142 | + type t3 |
| 143 | + : value mod uncontended = |
| 144 | + Immut of string |
| 145 | + | Mut of { mutable contents : string; } |
| 146 | + end |
171 | 147 | |}]
|
172 | 148 |
|
173 |
| -module type S3 = sig |
174 |
| - type t : value |
175 |
| - [@@unsafe_allow_any_kind_in_impl] |
176 |
| -end |
| 149 | +(* If the kind annotation on a (non-abstract) type has a more general layout than the one |
| 150 | + inferred from the declaration, we should be able to use the type as if it had the |
| 151 | + inferred layout - but also able to use it as if it had the modal bounds on the |
| 152 | + annotation. |
| 153 | +*) |
| 154 | +module Weaker_layout_stronger_modes : sig |
| 155 | + type t : any mod uncontended |
| 156 | +end = struct |
| 157 | + type t : any mod uncontended = { mutable contents : string } |
| 158 | + [@@unsafe_allow_any_mode_crossing] |
177 | 159 |
|
178 |
| -module M3 : S3 = M1 |
179 |
| -(* CR aspsmith: This is somewhat unfortunate, if S3 and M1 are defined far away, but it's |
180 |
| - unclear how to squash the warning *) |
| 160 | + (* The actual kind here looks more like [value mod uncontended] *) |
| 161 | + let f1 (x : t @@ contended) = use_uncontended x |
| 162 | + let _ = use_as_value ({ contents = "foo" } : t) |
| 163 | +end |
181 | 164 | [%%expect{|
|
182 |
| -module type S3 = sig type t end |
183 |
| -Lines 2-3, characters 2-35: |
184 |
| -2 | ..type t : value |
185 |
| -3 | [@@unsafe_allow_any_kind_in_impl] |
186 |
| -Warning 212 [unnecessary-allow-any-kind]: [@@allow_any_kind_in_intf] and [@@allow_any_kind_in_impl] set on a |
187 |
| -type, but the kind matches. The attributes can be removed. |
188 |
| - |
189 |
| -module M3 : S3 |
| 165 | +module Weaker_layout_stronger_modes : sig type t : any mod uncontended end |
190 | 166 | |}]
|
0 commit comments