summaryrefslogtreecommitdiff
path: root/manual/src/refman/extensions/attributes.etex
blob: 19b72f5dde6346597435d4ce3d5835689f3bb974 (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
383
384
385
386
387
388
389
390
391
392
(Introduced in OCaml 4.02,
infix notations for constructs other than expressions added in 4.03)

Attributes are ``decorations'' of the syntax tree which are mostly
ignored by the type-checker but can be used by external tools.  An
attribute is made of an identifier and a payload, which can be a
structure, a type expression (prefixed with ":"), a signature
(prefixed with ":") or a pattern (prefixed with "?") optionally
followed by a "when" clause:


\begin{syntax}
attr-id:
    lowercase-ident
 |  capitalized-ident
 |  attr-id '.' attr-id
;
attr-payload:
    [ module-items ]
 |  ':' typexpr
 |  ':' [ specification ]
 |  '?' pattern ['when' expr]
;
\end{syntax}

The first form of attributes is attached with a postfix notation on
``algebraic'' categories:

\begin{syntax}
attribute:
    '[@' attr-id attr-payload ']'
;
expr: ...
     | expr attribute
;
typexpr: ...
     | typexpr attribute
;
pattern: ...
     | pattern attribute
;
module-expr: ...
     | module-expr attribute
;
module-type: ...
     | module-type attribute
;
class-expr: ...
     | class-expr attribute
;
class-type: ...
     | class-type attribute
;
\end{syntax}

This form of attributes can also be inserted after the @'`'tag-name@
in polymorphic variant type expressions (@tag-spec-first@, @tag-spec@,
@tag-spec-full@) or after the @method-name@ in @method-type@.

The same syntactic form is also used to attach attributes to labels and
constructors in type declarations:

\begin{syntax}
field-decl:
          ['mutable'] field-name ':' poly-typexpr { attribute }
;
constr-decl:
          (constr-name || '()') [ 'of' constr-args ] { attribute }
;
\end{syntax}

Note: when a label declaration is followed by a semi-colon, attributes
can also be put after the semi-colon (in which case they are merged to
those specified before).


The second form of attributes are attached to ``blocks'' such as type
declarations, class fields, etc:

\begin{syntax}
item-attribute:
    '[@@' attr-id attr-payload ']'
;
typedef: ...
   | typedef item-attribute
;
exception-definition:
        'exception' constr-decl
      | 'exception' constr-name '=' constr
;
module-items:
        [';;'] ( definition || expr { item-attribute } ) { [';;'] definition || ';;' expr { item-attribute } } [';;']
;
class-binding: ...
   | class-binding item-attribute
;
class-spec: ...
   | class-spec item-attribute
;
classtype-def: ...
   | classtype-def item-attribute
;
definition:
          'let' ['rec'] let-binding { 'and' let-binding }
        | 'external' value-name ':' typexpr '=' external-declaration { item-attribute }
        | type-definition
        | exception-definition { item-attribute }
        | class-definition
        | classtype-definition
        | 'module' module-name { '(' module-name ':' module-type ')' }
                   [ ':' module-type ] \\ '=' module-expr { item-attribute }
        | 'module' 'type' modtype-name '=' module-type { item-attribute }
        | 'open' module-path { item-attribute }
        | 'include' module-expr { item-attribute }
        | 'module' 'rec' module-name ':' module-type '=' \\
          module-expr { item-attribute } \\
          { 'and' module-name ':' module-type '=' module-expr \\
          { item-attribute } }
;
specification:
          'val' value-name ':' typexpr { item-attribute }
        | 'external' value-name ':' typexpr '=' external-declaration { item-attribute }
        | type-definition
        | 'exception' constr-decl { item-attribute }
        | class-specification
        | classtype-definition
        | 'module' module-name ':' module-type { item-attribute }
        | 'module' module-name { '(' module-name ':' module-type ')' }
          ':' module-type { item-attribute }
        | 'module' 'type' modtype-name { item-attribute }
        | 'module' 'type' modtype-name '=' module-type { item-attribute }
        | 'open' module-path { item-attribute }
        | 'include' module-type { item-attribute }
;
class-field-spec: ...
        | class-field-spec item-attribute
;
class-field: ...
        | class-field item-attribute
;
\end{syntax}

A third form of attributes appears as stand-alone structure or
signature items in the module or class sub-languages.  They are not
attached to any specific node in the syntax tree:

\begin{syntax}
floating-attribute:
    '[@@@' attr-id attr-payload ']'
;
definition: ...
   | floating-attribute
;
specification: ...
   | floating-attribute
;
class-field-spec: ...
   | floating-attribute
;
class-field: ...
   | floating-attribute
;
\end{syntax}

(Note: contrary to what the grammar above describes, @item-attributes@
cannot be attached to these floating attributes in @class-field-spec@
and @class-field@.)


It is also possible to specify attributes using an infix syntax. For instance:

\begin{verbatim}
let[@foo] x = 2 in x + 1          === (let x = 2 [@@foo] in x + 1)
begin[@foo][@bar x] ... end       === (begin ... end)[@foo][@bar x]
module[@foo] M = ...              === module M = ... [@@foo]
type[@foo] t = T                  === type t = T [@@foo]
method[@foo] m = ...              === method m = ... [@@foo]
\end{verbatim}

For "let", the attributes are applied to each bindings:

\begin{verbatim}
let[@foo] x = 2 and y = 3 in x + y === (let x = 2 [@@foo] and y = 3 in x + y)
let[@foo] x = 2
and[@bar] y = 3 in x + y           === (let x = 2 [@@foo] and y = 3 [@@bar] in x + y)
\end{verbatim}


\subsection{ss:builtin-attributes}{Built-in attributes}

Some attributes are understood by the type-checker:
\begin{itemize}
\item
 ``ocaml.warning'' or ``warning'', with a string literal payload.
 This can be used as floating attributes in a
 signature/structure/object/object type.  The string is parsed and has
 the same effect as the "-w" command-line option, in the scope between
 the attribute and the end of the current
 signature/structure/object/object type.  The attribute can also be
 attached to any kind of syntactic item which support attributes
 (such as an expression, or a type expression)
 in which case its scope is limited to that item.
 Note that it is not well-defined which scope is used for a specific
 warning.  This is implementation dependent and can change between versions.
 Some warnings are even completely outside the control of ``ocaml.warning''
 (for instance, warnings 1, 2, 14, 29 and 50).

\item
 ``ocaml.warnerror'' or ``warnerror'', with a string literal payload.
 Same as ``ocaml.warning'', for the "-warn-error" command-line option.

\item
 ``ocaml.alert'' or ``alert'': see section~\ref{s:alerts}.

\item
  ``ocaml.deprecated'' or ``deprecated'': alias for the
  ``deprecated'' alert, see section~\ref{s:alerts}.
\item
  ``ocaml.deprecated_mutable'' or ``deprecated_mutable''.
  Can be applied to a mutable record label.  If the label is later
  used to modify the field (with ``expr.l <- expr''), the ``deprecated'' alert
  will be triggered.  If the payload of the attribute is a string literal,
  the alert message includes this text.
\item
  ``ocaml.ppwarning'' or ``ppwarning'', in any context, with
  a string literal payload.  The text is reported as warning (22)
  by the compiler (currently, the warning location is the location
  of the string payload).  This is mostly useful for preprocessors which
  need to communicate warnings to the user.  This could also be used
  to mark explicitly some code location for further inspection.
\item
  ``ocaml.warn_on_literal_pattern'' or ``warn_on_literal_pattern'' annotate
  constructors in type definition. A warning (52) is then emitted when this
  constructor is pattern matched with a constant literal as argument. This
  attribute denotes constructors whose argument is purely informative and
  may change in the future. Therefore, pattern matching on this argument
  with a constant literal is unreliable. For instance, all built-in exception
  constructors are marked as ``warn_on_literal_pattern''.
  Note that, due to an implementation limitation, this warning (52) is only
  triggered for single argument constructor.
\item
  ``ocaml.tailcall'' or ``tailcall'' can be applied to function
  application in order to check that the call is tailcall optimized.
  If it it not the case, a warning (51) is emitted.
\item
  ``ocaml.inline'' or ``inline'' take either ``never'', ``always''
  or nothing as payload on a function or functor definition. If no payload
  is provided, the default value is ``always''. This payload controls when
  applications of the annotated functions should be inlined.
\item
  ``ocaml.inlined'' or ``inlined'' can be applied to any function or functor
  application to check that the call is inlined by the compiler. If the call
  is not inlined, a warning (55) is emitted.
\item
  ``ocaml.noalloc'', ``ocaml.unboxed''and ``ocaml.untagged'' or
  ``noalloc'', ``unboxed'' and ``untagged'' can be used on external
  definitions to obtain finer control over the C-to-OCaml interface. See
  \ref{s:C-cheaper-call} for more details.
\item
  ``ocaml.immediate'' or ``immediate'' applied on an abstract type mark the type as
  having a non-pointer implementation (e.g. ``int'', ``bool'', ``char'' or
  enumerated types). Mutation of these immediate types does not activate the
  garbage collector's write barrier, which can significantly boost performance in
  programs relying heavily on mutable state.
\item
  ``ocaml.immediate64'' or ``immediate64'' applied on an abstract type mark the
  type as having a non-pointer implementation on 64 bit platforms. No assumption
  is made on other platforms. In order to produce a type with the
  ``immediate64`` attribute, one must use ``Sys.Immediate64.Make`` functor.
\item
  "ocaml.unboxed" or "unboxed" can be used on a type definition if the
  type is a single-field record or a concrete type with a single
  constructor that has a single argument. It tells the compiler to
  optimize the representation of the type by removing the block that
  represents the record or the constructor (i.e. a value of this type
  is physically equal to its argument). In the case of GADTs, an
  additional restriction applies: the argument must not be an
  existential variable, represented by an existential type variable,
  or an abstract type constructor applied to an existential type
  variable.
\item
   "ocaml.boxed" or "boxed" can be used on type definitions to mean
   the opposite of "ocaml.unboxed": keep the unoptimized
   representation of the type. When there is no annotation, the
   default is currently "boxed" but it may change in the future.
 \item
   "ocaml.local" or "local" take either "never", "always", "maybe" or
   nothing as payload on a function definition.  If no payload is
   provided, the default is "always".  The attribute controls an
   optimization which consists in compiling a function into a static
   continuation.  Contrary to inlining, this optimization does not
   duplicate the function's body.  This is possible when all
   references to the function are full applications, all sharing the
   same continuation (for instance, the returned value of several
   branches of a pattern matching). "never" disables the optimization,
   "always" asserts that the optimization applies (otherwise a warning
   55 is emitted) and "maybe" lets the optimization apply when
   possible (this is the default behavior when the attribute is not
   specified).  The optimization is implicitly disabled when using the
   bytecode compiler in debug mode (-g), and for functions marked with
   an "ocaml.inline always" or "ocaml.unrolled" attribute which
   supersede "ocaml.local".
\end{itemize}

\begin{caml_example*}{verbatim}
module X = struct
  [@@@warning "+9"]  (* locally enable warning 9 in this structure *)
  [@@@ellipsis]
end
[@@deprecated "Please use module 'Y' instead."]

let x = begin[@warning "+9"] [()[@ellipsis]] end

type t = A | B
  [@@deprecated "Please use type 's' instead."]
\end{caml_example*}

\begin{caml_example*}{verbatim}[warning=22]
let fires_warning_22 x =
  assert (x >= 0) [@ppwarning "TODO: remove this later"]
\end{caml_example*}

\begin{caml_example*}{verbatim}[warning=51]
let rec is_a_tail_call = function
  | [] -> ()
  | _ :: q -> (is_a_tail_call[@tailcall]) q

let rec not_a_tail_call = function
  | [] -> []
  | x :: q -> x :: (not_a_tail_call[@tailcall]) q
\end{caml_example*}

\begin{caml_example*}{verbatim}
let f x = x [@@inline]

let () = (f[@inlined]) ()
\end{caml_example}

\begin{caml_example*}{verbatim}
type fragile =
  | Int of int [@warn_on_literal_pattern]
  | String of string [@warn_on_literal_pattern]
\end{caml_example*}

\begin{caml_example}{verbatim}[warning=52]
let fragile_match_1 = function
| Int 0 -> ()
| _ -> ()
\end{caml_example}

\begin{caml_example}{verbatim}[warning=52]
let fragile_match_2 = function
| String "constant" -> ()
| _ -> ()
\end{caml_example}

\begin{caml_example*}{verbatim}
module Immediate: sig
  type t [@@immediate]
  val x: t ref
end = struct
  type t = A | B
  let x = ref A
end
\end{caml_example*}

\begin{caml_example*}{verbatim}
module Int_or_int64 : sig
  type t [@@immediate64]
  val zero : t
  val one : t
  val add : t -> t -> t
end = struct

  include Sys.Immediate64.Make(Int)(Int64)

  module type S = sig
    val zero : t
    val one : t
    val add : t -> t -> t
  end

  let impl : (module S) =
    match repr with
    | Immediate ->
        (module Int : S)
    | Non_immediate ->
        (module Int64 : S)

  include (val impl : S)
end
\end{caml_example*}