summaryrefslogtreecommitdiff
path: root/testsuite/tests/typing-sigsubst/sigsubst.ml
blob: 20f58f038e4612d7c257e5f59c27ac33a0e76a45 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
(* TEST
 expect;
*)

module type Printable = sig
  type t
  val print : t -> unit
end
[%%expect {|
module type Printable = sig type t val print : t -> unit end
|}]
module type Comparable = sig
  type t
  val compare : t -> t -> int
end
[%%expect {|
module type Comparable = sig type t val compare : t -> t -> int end
|}]
module type PrintableComparable = sig
  include Printable
  include Comparable with type t = t
end
[%%expect {|
Line 3, characters 2-36:
3 |   include Comparable with type t = t
      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Error: Illegal shadowing of included type t/2 by t.
Line 2, characters 2-19:
2 |   include Printable
      ^^^^^^^^^^^^^^^^^
  Type t/2 came from this include.
Line 3, characters 2-23:
3 |   val print : t -> unit
      ^^^^^^^^^^^^^^^^^^^^^
  The value print has no valid type if t/2 is shadowed.
|}]

module type Sunderscore = sig
  type (_, _) t
end with type (_, 'a) t = int * 'a
[%%expect {|
module type Sunderscore = sig type (_, 'a) t = int * 'a end
|}]


(* Valid substitutions in a recursive module used to fail
   due to the ordering of the modules. This is fixed since #9623. *)
module type S0 = sig
  module rec M : sig type t = M2.t end
  and M2 : sig type t = int end
end with type M.t = int
[%%expect {|
module type S0 =
  sig module rec M : sig type t = int end and M2 : sig type t = int end end
|}]


module type PrintableComparable = sig
  type t
  include Printable with type t := t
  include Comparable with type t := t
end
[%%expect {|
module type PrintableComparable =
  sig type t val print : t -> unit val compare : t -> t -> int end
|}]
module type PrintableComparable = sig
  include Printable
  include Comparable with type t := t
end
[%%expect {|
module type PrintableComparable =
  sig type t val print : t -> unit val compare : t -> t -> int end
|}]
module type ComparableInt = Comparable with type t := int
[%%expect {|
module type ComparableInt = sig val compare : int -> int -> int end
|}]
module type S = sig type t val f : t -> t end
[%%expect {|
module type S = sig type t val f : t -> t end
|}]
module type S' = S with type t := int
[%%expect {|
module type S' = sig val f : int -> int end
|}]

module type S = sig type 'a t val map : ('a -> 'b) -> 'a t -> 'b t end
module type S1 = S with type 'a t := 'a list
[%%expect {|
module type S = sig type 'a t val map : ('a -> 'b) -> 'a t -> 'b t end
module type S1 = sig val map : ('a -> 'b) -> 'a list -> 'b list end
|}]
module type S2 = S with type 'a t := (string * 'a) list
[%%expect {|
module type S2 =
  sig val map : ('a -> 'b) -> (string * 'a) list -> (string * 'b) list end
|}]
module type S3 = S with type _ t := int
[%%expect {|
module type S3 = sig val map : ('a -> 'b) -> int -> int end
|}]


module type S =
  sig module T : sig type exp type arg end val f : T.exp -> T.arg end
module M = struct type exp = string type arg = int end
module type S' = S with module T := M
[%%expect {|
module type S =
  sig module T : sig type exp type arg end val f : T.exp -> T.arg end
module M : sig type exp = string type arg = int end
module type S' = sig val f : M.exp -> M.arg end
|}]


module type S = sig type 'a t end with type 'a t := unit
[%%expect {|
module type S = sig end
|}]

module type S = sig
  type t = [ `Foo ]
  type s = private [< t ]
end with type t := [ `Foo ]
[%%expect {|
module type S = sig type s = private [< `Foo ] end
|}]

module type S = sig
  type t = ..
  type t += A
end with type t := exn
[%%expect {|
module type S = sig type exn += A end
|}]

(* We allow type constraints when replacing a path by a path. *)
type 'a t constraint 'a = 'b list
module type S = sig
  type 'a t2 constraint 'a = 'b list
  type 'a mylist = 'a list
  val x : int mylist t2
end with type 'a t2 := 'a t
[%%expect {|
type 'a t constraint 'a = 'b list
module type S = sig type 'a mylist = 'a list val x : int mylist t end
|}]

(* but not when replacing a path by a type expression *)
type 'a t constraint 'a = 'b list
module type S = sig
  type 'a t2 constraint 'a = 'b list
  type 'a mylist = 'a list
  val x : int mylist t2
end with type 'a t2 := 'a t * bool
[%%expect {|
type 'a t constraint 'a = 'b list
Lines 2-6, characters 16-34:
2 | ................sig
3 |   type 'a t2 constraint 'a = 'b list
4 |   type 'a mylist = 'a list
5 |   val x : int mylist t2
6 | end with type 'a t2 := 'a t * bool
Error: Destructive substitutions are not supported for constrained
       types (other than when replacing a type constructor with
       a type constructor with the same arguments).
|}]

(* Issue where the typer weakens an alias, which breaks the typing of the rest
   of the signature. (MPR#7723)*)
module type S = sig
  module M1 : sig type t = int end
  module M2 = M1
  module M3 : sig module M = M2 end
  module F(X : sig module M = M1 end) : sig type t end
  type t = F(M3).t
end with type M2.t = int
[%%expect {|
module type S =
  sig
    module M1 : sig type t = int end
    module M2 = M1
    module M3 : sig module M = M2 end
    module F : functor (X : sig module M = M1 end) -> sig type t end
    type t = F(M3).t
  end
|}]

type (_, _) eq = Refl : ('a, 'a) eq

module Equal (M : Set.OrderedType) (N : Set.OrderedType with type t = M.t) : sig
  val eq : (Set.Make(M).t, Set.Make(N).t) eq
end = struct
  type meq = Eq of (Set.Make(M).t, Set.Make(M).t) eq
  module type S = sig
    module N = M
    type neq = meq = Eq of (Set.Make(M).t, Set.Make(N).t) eq
  end
  module type T = S with type N.t = M.t with module N := N;;
  module rec T : T = T
  let eq =
    let T.Eq eq = Eq Refl in
    eq
end;;
[%%expect {|
type (_, _) eq = Refl : ('a, 'a) eq
Line 11, characters 18-58:
11 |   module type T = S with type N.t = M.t with module N := N;;
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Error: In this `with' constraint, the new definition of N
       does not match its original definition in the constrained signature:
       Modules do not match:
         sig type t = M.t val compare : t -> t -> int end
       is not included in
         (module M)
|}]

(* Checking that the uses of M.t are rewritten regardless of how they
   are named, but we don't rewrite other types by the same name. *)
module type S = sig
  module M : sig type t val x : t end
  val y : M.t
  module A : sig module M : sig type t val z : t -> M.t end end
end with type M.t := float
[%%expect {|
module type S =
  sig
    module M : sig val x : float end
    val y : float
    module A : sig module M : sig type t val z : t -> float end end
  end
|}]

(* Regression test: at some point, expanding S1 twice in the same
   "with type" would result in a signature with duplicate ids, which
   would confuse the rewriting (we would end with (M2.x : int)) and
   only then get refreshened. *)
module type S = sig
  module type S1 = sig type t type a val x : t end
  module M1 : S1
  type a = M1.t
  module M2 : S1
  type b = M2.t
end with type M1.a = int and type M2.a = int and type M1.t := int;;
[%%expect {|
module type S =
  sig
    module type S1 = sig type t type a val x : t end
    module M1 : sig type a = int val x : int end
    type a = int
    module M2 : sig type t type a = int val x : t end
    type b = M2.t
  end
|}]

(* And now some corner cases with aliases: *)

module type S = sig
  module M : sig type t end
  module A = M
end with type M.t := float
[%%expect {|
Lines 1-4, characters 16-26:
1 | ................sig
2 |   module M : sig type t end
3 |   module A = M
4 | end with type M.t := float
Error: This `with' constraint on M.t changes M, which is aliased
       in the constrained signature (as A).
|}]

(* And more corner cases with applicative functors: *)

module type S = sig
  module M : sig type t type u end
  module F(X : sig type t end) : sig type t end
  type t = F(M).t
end
[%%expect {|
module type S =
  sig
    module M : sig type t type u end
    module F : functor (X : sig type t end) -> sig type t end
    type t = F(M).t
  end
|}]

(* This particular substitution cannot be made to work *)
module type S2 = S with type M.t := float
[%%expect {|
Line 1, characters 17-41:
1 | module type S2 = S with type M.t := float
                     ^^^^^^^^^^^^^^^^^^^^^^^^
Error: This `with' constraint on M.t makes the applicative functor
       type F(M).t ill-typed in the constrained signature:
       Modules do not match:
         sig type u = M.u end
       is not included in
         sig type t end
       The type `t' is required but not provided
|}]

(* However if the applicative functor doesn't care about the type
   we're removing, the typer accepts the removal. *)
module type S2 = S with type M.u := float
[%%expect {|
module type S2 =
  sig
    module M : sig type t end
    module F : functor (X : sig type t end) -> sig type t end
    type t = F(M).t
  end
|}]

(* In the presence of recursive modules, the use of a module can come before its
   definition (in the typed tree). *)

module Id(X : sig type t end) = struct type t = X.t end
module type S3 = sig
  module rec M : sig type t = A of Id(M2).t end
  and M2 : sig type t end
end with type M2.t := int
[%%expect {|
module Id : functor (X : sig type t end) -> sig type t = X.t end
Lines 2-5, characters 17-25:
2 | .................sig
3 |   module rec M : sig type t = A of Id(M2).t end
4 |   and M2 : sig type t end
5 | end with type M2.t := int
Error: This `with' constraint on M2.t makes the applicative functor
       type Id(M2).t ill-typed in the constrained signature:
       Modules do not match: sig end is not included in sig type t end
       The type `t' is required but not provided
|}]


(* Deep destructive module substitution: *)

module A = struct module P = struct type t let x = 1 end end
module type S = sig
  module M : sig
    module N : sig
      module P : sig
        type t
      end
    end
  end
  type t = M.N.P.t
end with module M.N := A
[%%expect {|
module A : sig module P : sig type t val x : int end end
module type S = sig module M : sig end type t = A.P.t end
|}]

(* Same as for types, not all substitutions are accepted *)

module type S = sig
  module M : sig
    module N : sig
      module P : sig
        type t
      end
    end
  end
  module Alias = M
end with module M.N := A
[%%expect {|
Lines 1-10, characters 16-24:
 1 | ................sig
 2 |   module M : sig
 3 |     module N : sig
 4 |       module P : sig
 5 |         type t
 6 |       end
 7 |     end
 8 |   end
 9 |   module Alias = M
10 | end with module M.N := A
Error: This `with' constraint on M.N changes M, which is aliased
       in the constrained signature (as Alias).
|}]