Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
- 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
- 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
- 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
- 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

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Require binding before migrating expression arguments

When the argument is not already a variable—such as the deleted regression case Int.Ref.increment(mkRef())—the advertised substitution becomes mkRef().contents = mkRef().contents + 1, which invokes mkRef() twice and can read from and write to different references. Document that expression receivers must first be bound once, and retain an end-to-end regression test for this migration pattern.

AGENTS.md reference: AGENTS.md:L41-L41

Useful? React with 👍 / 👎.


#### :eyeglasses: Spec Compliance

Expand Down
36 changes: 0 additions & 36 deletions compiler/ml/lambda.ml
Original file line number Diff line number Diff line change
Expand Up @@ -351,9 +351,6 @@ type builtin =
| Primitive of primitive
| Eliminated of eliminated
| Constant of structured_constant
| Offset_ref of int
(** [%incr] / [%decr]: an assignment through the reference, expanded here
so the caller's own IR carries the form its escape analysis reads. *)

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

(* [r := r.contents + delta]. The reference is mentioned twice, so bind it
unless it is already a variable. *)
let offset_ref ~delta r loc =
let assign r =
Lprim
{
primitive = Psetfield (0, ref_field_set_info);
args =
[
r;
Lprim
{
primitive = Paddint;
args =
[
Lprim
{primitive = Pfield (0, ref_field_info); args = [r]; loc};
Lconst (const_int delta);
];
loc;
};
];
loc;
}
in
match r with
| Lvar _ -> assign r
| _ ->
let id = Ident.create "ref" in
Llet (Strict, id, r, assign (Lvar id))

let eq_comparison (p : comparison) (p1 : comparison) = p = p1

let eq_field_dbg_info (x : field_dbg_info) (y : field_dbg_info) = x = y
Expand Down Expand Up @@ -1269,10 +1237,6 @@ let mk_builtin b args loc =
match args with
| [] -> Lconst c
| _ -> assert false)
| Offset_ref delta -> (
match args with
| [r] -> offset_ref ~delta r loc
| _ -> assert false)
| Eliminated Identity -> (
match args with
| [arg] -> arg
Expand Down
3 changes: 0 additions & 3 deletions compiler/ml/lambda.mli
Original file line number Diff line number Diff line change
Expand Up @@ -321,9 +321,6 @@ type builtin =
| Primitive of primitive
| Eliminated of eliminated
| Constant of structured_constant
| Offset_ref of int
(** [%incr] / [%decr]: an assignment through the reference, expanded here
so the caller's own IR carries the form its escape analysis reads. *)

type inline_attribute =
| Always_inline (* [@inline] or [@inline always] *)
Expand Down
3 changes: 0 additions & 3 deletions compiler/ml/translcore.ml
Original file line number Diff line number Diff line change
Expand Up @@ -252,8 +252,6 @@ let erased_builtins : (string * Lambda.builtin) array =
("%identity", Eliminated Identity);
("%component_identity", Eliminated Identity);
("%ignore", Eliminated Ignore);
("%incr", Offset_ref 1);
("%decr", Offset_ref (-1));
("%null", Constant Const_js_null);
("%undefined", Constant (Const_js_undefined {is_unit = false}));
(* FIXME: Core compatibility *)
Expand All @@ -268,7 +266,6 @@ let primitive_builtins : (string * Lambda.builtin) array =
(* BEGIN Triples for ref data type *)
("%makeref", Pmakeblock Lambda.ref_tag_info);
("%refset", Psetfield (0, Lambda.ref_field_set_info));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Update the remaining legacy primitive fixture

When make test builds the tests/tests project in scripts/test.js:81-84, tests/tests/src/test_per.res:158-161 is included by that project's recursive src configuration and still declares %refget, %incr, and %decr. With these table entries removed, translation raises Unknown builtin primitive "%refget" before the test suite can run; remove or migrate these declarations, or move them into an explicit negative-error fixture.

AGENTS.md reference: AGENTS.md:L41-L43

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed those three declarations in the same commit — thanks, they were stale and nothing else in the repo declares them.

One correction on the predicted failure, so the same finding doesn't get raised at P1 again: test_per.res compiles fine with them. Declaring an external whose primitive no longer exists is not an error — the external is optimized away when unused — and this file only declares %refget, %incr and %decr, never uses them. Unknown builtin primitive is raised at the use site, which is why make test passes on the branch as it stood. Verified directly:

type ref<'a> = {mutable contents: 'a}
external incr: ref<int> => unit = "%incr"
// compiles; adding `let f = r => incr(r)` is what errors

The neighbouring %makeref and %refset declarations stay, since those primitives still exist.

("%refget", Pfield (0, Lambda.ref_field_info));
(* Finish Triples for ref data type *)
("%field0", Pfield (0, Fld_tuple));
("%field1", Pfield (1, Fld_tuple));
Expand Down
7 changes: 0 additions & 7 deletions packages/@rescript/runtime/Stdlib_Int.res
Original file line number Diff line number Diff line change
Expand Up @@ -127,10 +127,3 @@ module Bitwise = {
}

external ignore: int => unit = "%ignore"

module Ref = {
type t = ref<int>

external increment: ref<int> => unit = "%incr"
external decrement: ref<int> => unit = "%decr"
}
30 changes: 0 additions & 30 deletions packages/@rescript/runtime/Stdlib_Int.resi
Original file line number Diff line number Diff line change
Expand Up @@ -520,33 +520,3 @@ module Bitwise: {
without having to store or process it further.
*/
external ignore: int => unit = "%ignore"

module Ref: {
type t = ref<int>

/**
`increment(intRef)` increments the value of the provided reference by 1.

## Examples

```rescript
let myRef = ref(4)
Int.Ref.increment(myRef)
myRef.contents == 5
```
*/
external increment: ref<int> => unit = "%incr"

/**
`decrement(intRef)` decrements the value of the provided reference by 1.

## Examples

```rescript
let myRef = ref(4)
Int.Ref.decrement(myRef)
myRef.contents == 3
```
*/
external decrement: ref<int> => unit = "%decr"
}
3 changes: 0 additions & 3 deletions packages/@rescript/runtime/lib/es6/Stdlib_Int.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,6 @@ let Bitwise = {
lnot: lnot
};

let Ref = {};

let Constants = {
minValue: -2147483648,
maxValue: 2147483647
Expand All @@ -89,6 +87,5 @@ export {
rangeWithOptions,
clamp,
Bitwise,
Ref,
}
/* No side effect */
3 changes: 0 additions & 3 deletions packages/@rescript/runtime/lib/js/Stdlib_Int.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,6 @@ let Bitwise = {
lnot: lnot
};

let Ref = {};

let Constants = {
minValue: -2147483648,
maxValue: 2147483647
Expand All @@ -88,5 +86,4 @@ exports.range = range;
exports.rangeWithOptions = rangeWithOptions;
exports.clamp = clamp;
exports.Bitwise = Bitwise;
exports.Ref = Ref;
/* No side effect */
2 changes: 1 addition & 1 deletion tests/belt_tests/src/bs_queue_test.res
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ describe(__MODULE__, () => {
q,
j => {
assert(i.contents == j)
Stdlib.Int.Ref.increment(i)
i.contents = i.contents + 1
},
)
})
Expand Down
2 changes: 1 addition & 1 deletion tests/tests/src/ari_regress_test.res
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ let gg = (x, y) => {

let g1 = (x, y) => {
let u = x + y
let () = Int.Ref.increment(h)
let () = h.contents = h.contents + 1
(xx, yy) => xx + yy + u
}
let x = gg(3, 5)(6)
Expand Down
6 changes: 3 additions & 3 deletions tests/tests/src/bdd.res
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ let resize = newSize => {
let rec insert = (idl, idh, v, ind, bucket, newNode) =>
if n_items.contents <= sz_1.contents {
htab.contents->Array.setUnsafe(ind, list{newNode, ...bucket})
Int.Ref.increment(n_items)
n_items.contents = n_items.contents + 1
} else {
resize(sz_1.contents + sz_1.contents + 2)
let ind = Int.bitwiseAnd(hashVal(idl, idh, v), sz_1.contents)
Expand Down Expand Up @@ -102,7 +102,7 @@ let mkNode = (low, v, high) => {
low,
v,
{
Int.Ref.increment(nodeC)
nodeC.contents = nodeC.contents + 1
nodeC.contents
},
high,
Expand Down Expand Up @@ -276,7 +276,7 @@ let test_hwb = (bdd, vars) => {
let ntrue = ref(0)
for i in 0 to Array.length(vars) - 1 {
if vars->Array.getUnsafe(i) {
Int.Ref.increment(ntrue)
ntrue.contents = ntrue.contents + 1
}
}
bool_equal(
Expand Down
4 changes: 2 additions & 2 deletions tests/tests/src/bs_ignore_effect.res
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ let v = ref(0)

@obj external config: (~hi: int, ~lo: int, unit) => _ = ""

let h = config(~hi=2, ~lo=0, ignore(Int.Ref.increment(v)))
let h = config(~hi=2, ~lo=0, ignore(v.contents = v.contents + 1))
let z = add(
{
Int.Ref.increment(v)
v.contents = v.contents + 1
Float
},
3.0,
Expand Down
2 changes: 1 addition & 1 deletion tests/tests/src/complex_while_loop.res
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ let f = () => {
fib(n.contents) > 10
} {
n.contents->Int.toString->Console.log
Int.Ref.increment(n)
n.contents = n.contents + 1
}
}

Expand Down
2 changes: 1 addition & 1 deletion tests/tests/src/condition_compilation_test.res
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ let vv = 3
let v = ref(1)

let a = {
let () = Int.Ref.increment(v)
let () = v.contents = v.contents + 1
v.contents
}

Expand Down
8 changes: 4 additions & 4 deletions tests/tests/src/earger_curry_test.res
Original file line number Diff line number Diff line change
Expand Up @@ -96,11 +96,11 @@ let f = x =>
/* let u = */ add5(
x,
{
Int.Ref.increment(v)
v.contents = v.contents + 1
1
},
{
Int.Ref.increment(v)
v.contents = v.contents + 1
2
},
...
Expand All @@ -113,11 +113,11 @@ let g = x => {
add5(
x,
{
Int.Ref.increment(v)
v.contents = v.contents + 1
1
},
{
Int.Ref.increment(v)
v.contents = v.contents + 1
2
},
a,
Expand Down
2 changes: 1 addition & 1 deletion tests/tests/src/ffi_arity_test.res
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ let fff = () => {
/* No inline */
Console.log("x")
Console.log("x")
Int.Ref.increment(vvv)
vvv.contents = vvv.contents + 1
}

let g = () => fff()
Expand Down
2 changes: 1 addition & 1 deletion tests/tests/src/ffi_js_test.res
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ describe(__MODULE__, () => {
let u = ref(3)
let side_effect_config = config(
~kind={
Int.Ref.increment(u)
u.contents = u.contents + 1
Int
},
~hi=3,
Expand Down
8 changes: 4 additions & 4 deletions tests/tests/src/for_loop_test.res
Original file line number Diff line number Diff line change
Expand Up @@ -53,16 +53,16 @@ describe(__MODULE__, () => {
let v4 = ref(0)
let v5 = ref(0)
let inspect_3 = ref(-1)
Int.Ref.increment(v4)
v4.contents = v4.contents + 1
for j in 0 to 1 {
Int.Ref.increment(v5)
v5.contents = v5.contents + 1
let v2 = ref(0)
let v3 = u
for i in 0 to Array.length(x) - 1 {
let _j = i * 2
let k = 2 * u * u
let h = 2 * v5.contents
Int.Ref.increment(v2)
v2.contents = v2.contents + 1
arr[i] = _ => v := v.contents + k + v2.contents + v4.contents + v5.contents + h + v3
/* v2 should not be captured */
}
Expand Down Expand Up @@ -128,7 +128,7 @@ describe(__MODULE__, () => {
/* incr v ; */
v := v.contents + i
for j in 0 to j_len - 1 {
Int.Ref.increment(v)
v.contents = v.contents + 1
collect(v.contents)
arr[i * j_len + j] = _ => vv := vv.contents + v.contents
/* v should not be captured inside,
Expand Down
2 changes: 1 addition & 1 deletion tests/tests/src/functor_def.res
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
let v = ref(0)

let f = (x, x) => {
Int.Ref.increment(v)
v.contents = v.contents + 1
x + x
}

Expand Down
12 changes: 6 additions & 6 deletions tests/tests/src/global_module_alias_test.res
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,18 @@ let v = ref(0)

module Make = (U: S) => {
let () = {
Int.Ref.increment(v)
Int.Ref.increment(v)
Int.Ref.increment(v)
v.contents = v.contents + 1
v.contents = v.contents + 1
v.contents = v.contents + 1
}
include U
}

let f = () => {
let () = {
Int.Ref.increment(v)
Int.Ref.increment(v)
Int.Ref.increment(v)
v.contents = v.contents + 1
v.contents = v.contents + 1
v.contents = v.contents + 1
}
module G = F /* local module is not module alias */
module H = G
Expand Down
10 changes: 5 additions & 5 deletions tests/tests/src/gpr_1072.res
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ let () = {
again4(~y=(), __LINE__, ())
again4(
~x={
Int.Ref.increment(side_effect)
side_effect.contents = side_effect.contents + 1
()
},
~y=(),
Expand All @@ -162,25 +162,25 @@ let () = {
)
again4(
~x={
Int.Ref.increment(side_effect)
side_effect.contents = side_effect.contents + 1
()
},
~y={
Int.Ref.decrement(side_effect)
side_effect.contents = side_effect.contents - 1
()
},
__LINE__,
(),
)
again4(
~y={
Int.Ref.decrement(side_effect)
side_effect.contents = side_effect.contents - 1
()
},
__LINE__,
(),
)
again4(~x=Int.Ref.increment(side_effect), ~y=(), __LINE__, ())
again4(~x=side_effect.contents = side_effect.contents + 1, ~y=(), __LINE__, ())
}

/* external again5 : ?x__ignore:([`a of unit -> int | `b of string -> int ] [@string]) */
Expand Down
Loading
Loading