@@ -116,3 +116,130 @@ Error: Bad layout annotation:
116
116
(* CR layouts: Bug in Jane_syntax is duplicating the attrs here *)
117
117
118
118
(* Currently it's not possible to attach attributes to Ltyp_poly *)
119
+
120
+ (* *************************************************************** *)
121
+ (* Tests for [@error_message] applied to [Pexp_constraint].
122
+ Seperate implementation from when it's applied to layout annotations. *)
123
+
124
+ (* Needs a string body *)
125
+ let f (x : bool ) = (x : int )[@ error_message]
126
+ [%% expect{|
127
+ Line 1 , characters 28-44 :
128
+ 1 | let f (x : bool ) = (x : int )[@ error_message]
129
+ ^^^^^^^^^^^^^^^^
130
+ Warning 47 [attribute- payload]: illegal payload for attribute 'error_message'.
131
+ Error_message attribute expects a string argument
132
+ Line 1 , characters 20-21 :
133
+ 1 | let f (x : bool ) = (x : int )[@ error_message]
134
+ ^
135
+ Error : This expression has type bool but an expression was expected of type
136
+ int
137
+ | }]
138
+
139
+ (* Can only be applied once *)
140
+ let f (x : bool ) = (x : int )[@ error_message " A" ][@ error_message " B" ]
141
+ [%% expect{|
142
+ Line 1 , characters 48-68 :
143
+ 1 | let f (x : bool ) = (x : int )[@ error_message " A" ][@ error_message " B" ]
144
+ ^^^^^^^^^^^^^^^^^^^^
145
+ Warning 47 [attribute- payload]: illegal payload for attribute 'error_message'.
146
+ More than one error_message attribute present. All of them will be ignored.
147
+ Line 1 , characters 20-21 :
148
+ 1 | let f (x : bool ) = (x : int )[@ error_message " A" ][@ error_message " B" ]
149
+ ^
150
+ Error : This expression has type bool but an expression was expected of type
151
+ int
152
+ | }]
153
+
154
+ (* Simple test case *)
155
+ let f (x : bool ) = (x : int )[@ error_message " custom message" ]
156
+ [%% expect{|
157
+ Line 1 , characters 20-21 :
158
+ 1 | let f (x : bool ) = (x : int )[@ error_message " custom message" ]
159
+ ^
160
+ Error : This expression has type bool but an expression was expected of type
161
+ int
162
+ because [@ error_message]: custom message
163
+ | }]
164
+
165
+ (* Doesn't work when the type mismatch happens later. This differ from
166
+ the layout annotation case. *)
167
+ let f x : bool = (x : int )[@ error_message " custom message" ]
168
+ [%% expect{|
169
+ Line 1 , characters 16-25 :
170
+ 1 | let f x : bool = (x : int )[@ error_message " custom message" ]
171
+ ^^^^^^^^^
172
+ Error : This expression has type int but an expression was expected of type
173
+ bool
174
+ | }]
175
+
176
+ (* Doesn't apply when the type error is from elsewhere within the expression *)
177
+ let g (x : int ) = x
178
+ let f (x : bool ) = (let y = false in g y : int )[@ error_message " custom message" ]
179
+ [%% expect{|
180
+ val g : int -> int = < fun>
181
+ Line 2 , characters 39-40 :
182
+ 2 | let f (x : bool ) = (let y = false in g y : int )[@ error_message "custom message" ]
183
+ ^
184
+ Error : This expression has type bool but an expression was expected of type
185
+ int
186
+ | }]
187
+
188
+ (* Can be used to enforce layouts but not great *)
189
+ let f (x : string ) = (x : (_ : immediate ))[@ error_message " custom message" ]
190
+ [%% expect{|
191
+ Line 1 , characters 22-23 :
192
+ 1 | let f (x : string ) = (x : (_ : immediate ))[@ error_message " custom message" ]
193
+ ^
194
+ Error : This expression has type string but an expression was expected of type
195
+ ('a : immediate )
196
+ because [@ error_message]: custom message
197
+ The layout of string is value, because
198
+ it is the primitive value type string .
199
+ But the layout of string must be a sublayout of immediate, because
200
+ of the annotation on the wildcard _ at line 1 , characters 26 -41.
201
+ | }]
202
+
203
+ (* Doesn't apply when the mismatch is deep *)
204
+ let f () = (fun (x : int ) -> x : string -> string )[@ error_message " custom message" ]
205
+ [%% expect{|
206
+ Line 1 , characters 16-24 :
207
+ 1 | let f () = (fun (x : int ) -> x : string -> string )[@ error_message " custom message" ]
208
+ ^^^^^^^^
209
+ Error : This pattern matches values of type int
210
+ but a pattern was expected which matches values of type string
211
+ |}]
212
+
213
+ let f () = (fun (x : int ) -> x : string )[@ error_message " custom message" ]
214
+ [%% expect{|
215
+ Line 1 , characters 12-29 :
216
+ 1 | let f () = (fun (x : int ) -> x : string )[@ error_message " custom message" ]
217
+ ^^^^^^^^^^^^^^^^^
218
+ Error : This expression should not be a function , the expected type is
219
+ string because [@ error_message]: custom message
220
+ |}]
221
+
222
+ (* Same when the function is not declared inline *)
223
+ let g (x : int ) = x
224
+ let f () = (g : (string -> string) )[@ error_message " custom message" ]
225
+ [%% expect{|
226
+ val g : int -> int = < fun>
227
+ Line 2 , characters 12-13 :
228
+ 2 | let f () = (g : (string -> string ))[@ error_message "custom message" ]
229
+ ^
230
+ Error : This expression has type int -> int
231
+ but an expression was expected of type string -> string
232
+ Type int is not compatible with type string
233
+ | }]
234
+
235
+ let g (x : int ) = x
236
+ let f () = (g : string )[@ error_message " custom message" ]
237
+ [%% expect{|
238
+ val g : int -> int = < fun>
239
+ Line 2 , characters 12-13 :
240
+ 2 | let f () = (g : string )[@ error_message "custom message" ]
241
+ ^
242
+ Error : This expression has type int -> int
243
+ but an expression was expected of type string
244
+ because [@ error_message]: custom message
245
+ | }]
0 commit comments