Skip to content

Commit b019e3e

Browse files
cristianocclaude
andcommitted
Remove Int.Ref and the %incr, %decr and %refget builtins
None of these were designed for ReScript. %incr, %decr and %refget arrived with OCaml's Pervasives in the 2016 initial export and were carried unexamined through every stdlib reshuffle since. Int.Ref itself was created in April 2025 (#7371) not because anyone wanted it, but as somewhere for the Pervasives.incr deprecation to point; the primitives it wrapped were removed for v13 two weeks ago. Outside this repository, GitHub code search finds no user of either the externals or the API. What the primitive bought was unboxing: expanding at the call site kept the field write syntactically visible, so Lam_pass_eliminate_ref could still turn a local ref into a mutable variable. A call through an ordinary function cannot - the reference appears as a bare Lvar and the pass gives up. That is not special to increment. Its body is six nodes against a small_inline_size of five, and cross-module inlining is off, so the inliner cannot reach it. Writing the update directly does keep the unboxing, and is shorter than the call it replaces: Int.Ref.increment(v) -> v.contents = v.contents + 1 53 call sites across 30 test files change that way, and their generated JavaScript is byte-identical. Only two outputs move: Stdlib_Int loses an empty Ref object and its export, and test_incr_ref loses onExpression - added to pin that the primitive bound its argument before mentioning it twice, which has nothing left to test now that no expansion happens. Lambda.offset_ref and the Offset_ref builtin go with them. Nothing in lambda.ml now builds a term outside the constructors and the traversals. Int.Ref.t went too. It was a type alias for ref<int> introduced alongside the two functions, and with them gone the module held nothing else. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W8g8qwBARAcvW9MyuKQq8H
1 parent 90af00c commit b019e3e

39 files changed

Lines changed: 54 additions & 153 deletions

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
- Correct the structured function details produced by `rescript-tools doc` and exposed by `RescriptTools.Docgen`: parameters now retain labels and optionality, nested functions, tuples, variables, and generic arguments retain their type structure, return types are identified correctly, and non-function values no longer receive fake function details. This changes the published docgen detail schema. https://github.com/rescript-lang/rescript/pull/8576
2323
- Make object-field mutability part of the type. A property has one type for reading and writing. Assignment requires `@set`, except on an inferred open row, where assignment makes the field settable. Private rows are not inferred open rows, so a field in `type t = private {.."x": int}` is writable only when annotated with `@set`. Coercions never grant or widen write capability. Previously, getter and setter types were tracked independently, allowing a property to be written at a different type than it was read and allowing writes through a value coerced to a type without `@set`. https://github.com/rescript-lang/rescript/pull/8597
2424
- Remove the undocumented object-field attribute forms `@get` (bare or with a `null`/`undefined`/`nullable` payload) and `@set({no_get: ...})` on object types. Only bare `@set` marks a field settable; nullable getter types are written directly (`null<t>`, `undefined<t>`, `nullable<t>`). https://github.com/rescript-lang/rescript/pull/8597
25+
- Remove `Int.Ref` and the `%incr`, `%decr` and `%refget` builtins behind it. Write `r.contents = r.contents + 1` instead; an `external` declared with one of the removed names is now rejected. https://github.com/rescript-lang/rescript/pull/8616
2526

2627
#### :eyeglasses: Spec Compliance
2728

compiler/ml/lambda.ml

Lines changed: 0 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -351,9 +351,6 @@ type builtin =
351351
| Primitive of primitive
352352
| Eliminated of eliminated
353353
| Constant of structured_constant
354-
| Offset_ref of int
355-
(** [%incr] / [%decr]: an assignment through the reference, expanded here
356-
so the caller's own IR carries the form its escape analysis reads. *)
357354

358355
type inline_attribute =
359356
| Always_inline (* [@inline] or [@inline always] *)
@@ -490,35 +487,6 @@ let lambda_false = Lconst Const_js_false
490487

491488
(* [r := r.contents + delta]. The reference is mentioned twice, so bind it
492489
unless it is already a variable. *)
493-
let offset_ref ~delta r loc =
494-
let assign r =
495-
Lprim
496-
{
497-
primitive = Psetfield (0, ref_field_set_info);
498-
args =
499-
[
500-
r;
501-
Lprim
502-
{
503-
primitive = Paddint;
504-
args =
505-
[
506-
Lprim
507-
{primitive = Pfield (0, ref_field_info); args = [r]; loc};
508-
Lconst (const_int delta);
509-
];
510-
loc;
511-
};
512-
];
513-
loc;
514-
}
515-
in
516-
match r with
517-
| Lvar _ -> assign r
518-
| _ ->
519-
let id = Ident.create "ref" in
520-
Llet (Strict, id, r, assign (Lvar id))
521-
522490
let eq_comparison (p : comparison) (p1 : comparison) = p = p1
523491

524492
let eq_field_dbg_info (x : field_dbg_info) (y : field_dbg_info) = x = y
@@ -1269,10 +1237,6 @@ let mk_builtin b args loc =
12691237
match args with
12701238
| [] -> Lconst c
12711239
| _ -> assert false)
1272-
| Offset_ref delta -> (
1273-
match args with
1274-
| [r] -> offset_ref ~delta r loc
1275-
| _ -> assert false)
12761240
| Eliminated Identity -> (
12771241
match args with
12781242
| [arg] -> arg

compiler/ml/lambda.mli

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -321,9 +321,6 @@ type builtin =
321321
| Primitive of primitive
322322
| Eliminated of eliminated
323323
| Constant of structured_constant
324-
| Offset_ref of int
325-
(** [%incr] / [%decr]: an assignment through the reference, expanded here
326-
so the caller's own IR carries the form its escape analysis reads. *)
327324

328325
type inline_attribute =
329326
| Always_inline (* [@inline] or [@inline always] *)

compiler/ml/translcore.ml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -252,8 +252,6 @@ let erased_builtins : (string * Lambda.builtin) array =
252252
("%identity", Eliminated Identity);
253253
("%component_identity", Eliminated Identity);
254254
("%ignore", Eliminated Ignore);
255-
("%incr", Offset_ref 1);
256-
("%decr", Offset_ref (-1));
257255
("%null", Constant Const_js_null);
258256
("%undefined", Constant (Const_js_undefined {is_unit = false}));
259257
(* FIXME: Core compatibility *)
@@ -268,7 +266,6 @@ let primitive_builtins : (string * Lambda.builtin) array =
268266
(* BEGIN Triples for ref data type *)
269267
("%makeref", Pmakeblock Lambda.ref_tag_info);
270268
("%refset", Psetfield (0, Lambda.ref_field_set_info));
271-
("%refget", Pfield (0, Lambda.ref_field_info));
272269
(* Finish Triples for ref data type *)
273270
("%field0", Pfield (0, Fld_tuple));
274271
("%field1", Pfield (1, Fld_tuple));

packages/@rescript/runtime/Stdlib_Int.res

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -127,10 +127,3 @@ module Bitwise = {
127127
}
128128

129129
external ignore: int => unit = "%ignore"
130-
131-
module Ref = {
132-
type t = ref<int>
133-
134-
external increment: ref<int> => unit = "%incr"
135-
external decrement: ref<int> => unit = "%decr"
136-
}

packages/@rescript/runtime/Stdlib_Int.resi

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -520,33 +520,3 @@ module Bitwise: {
520520
without having to store or process it further.
521521
*/
522522
external ignore: int => unit = "%ignore"
523-
524-
module Ref: {
525-
type t = ref<int>
526-
527-
/**
528-
`increment(intRef)` increments the value of the provided reference by 1.
529-
530-
## Examples
531-
532-
```rescript
533-
let myRef = ref(4)
534-
Int.Ref.increment(myRef)
535-
myRef.contents == 5
536-
```
537-
*/
538-
external increment: ref<int> => unit = "%incr"
539-
540-
/**
541-
`decrement(intRef)` decrements the value of the provided reference by 1.
542-
543-
## Examples
544-
545-
```rescript
546-
let myRef = ref(4)
547-
Int.Ref.decrement(myRef)
548-
myRef.contents == 3
549-
```
550-
*/
551-
external decrement: ref<int> => unit = "%decr"
552-
}

packages/@rescript/runtime/lib/es6/Stdlib_Int.mjs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,6 @@ let Bitwise = {
7575
lnot: lnot
7676
};
7777

78-
let Ref = {};
79-
8078
let Constants = {
8179
minValue: -2147483648,
8280
maxValue: 2147483647
@@ -89,6 +87,5 @@ export {
8987
rangeWithOptions,
9088
clamp,
9189
Bitwise,
92-
Ref,
9390
}
9491
/* No side effect */

packages/@rescript/runtime/lib/js/Stdlib_Int.cjs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,6 @@ let Bitwise = {
7575
lnot: lnot
7676
};
7777

78-
let Ref = {};
79-
8078
let Constants = {
8179
minValue: -2147483648,
8280
maxValue: 2147483647
@@ -88,5 +86,4 @@ exports.range = range;
8886
exports.rangeWithOptions = rangeWithOptions;
8987
exports.clamp = clamp;
9088
exports.Bitwise = Bitwise;
91-
exports.Ref = Ref;
9289
/* No side effect */

tests/belt_tests/src/bs_queue_test.res

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ describe(__MODULE__, () => {
116116
q,
117117
j => {
118118
assert(i.contents == j)
119-
Stdlib.Int.Ref.increment(i)
119+
i.contents = i.contents + 1
120120
},
121121
)
122122
})

tests/tests/src/ari_regress_test.res

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ let gg = (x, y) => {
1313

1414
let g1 = (x, y) => {
1515
let u = x + y
16-
let () = Int.Ref.increment(h)
16+
let () = h.contents = h.contents + 1
1717
(xx, yy) => xx + yy + u
1818
}
1919
let x = gg(3, 5)(6)

0 commit comments

Comments
 (0)