Skip to content
Open
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
26 changes: 23 additions & 3 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# CLAUDE.md
# AGENTS.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Shared guidance for code agents (Claude, Gemini, Codex, etc.) working in this repository. The files `CLAUDE.md` and `GEMINI.md` are symlinks to this document. For Codex‑specific workflow details also see `CODEX.md`.

## Project Overview

Expand Down Expand Up @@ -136,4 +136,24 @@ The compiler is designed for fast feedback loops and scales to large codebases.
- Avoid introducing meaningless symbols
- Maintain readable JavaScript output
- Consider compilation speed impact
- Use appropriate optimization passes in the Lambda and JS IRs
- Use appropriate optimization passes in the Lambda and JS IRs

## Agent Notes and Gotchas

- **Node version features:** Runtime docstring tests conditionally enable features by Node major version:
- 20+: array `toReversed`/`toSorted`
- 22+: new `Set` APIs and `Promise.withResolvers`
- 24+: `RegExp.escape`
Tests auto‑skip unsupported features based on `process.version`.
- **CPU count in sandboxes:** Some CI/sandboxed environments report `os.cpus().length === 0`.
- Clamp concurrency/batch size to at least 1 when using `os.cpus()`.
- This pattern is used in `tests/docstring_tests/DocTest.res` and `cli/rescript-legacy/format.js`.
- **Formatting in tests:** `make test` checks formatting (OCaml, ReScript, JS, Rust). If it fails locally, run `make format` and re‑run tests.
- **Executables location:** Build copies platform binaries into `packages/@rescript/<platform>/bin/` and convenience folders like `darwinarm64/`.
- **Direct dune usage:** You can use `dune build`/`dune build -w`, but prefer `make` targets which also copy executables.

## References

- `CODEX.md`: detailed setup, build, testing, and workflows for agented development
- `README.md`: high‑level repo overview and usage
- `Makefile`: authoritative list of build/test targets
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
- Fix generation of interfaces for module types containing multiple type constraints. https://github.com/rescript-lang/rescript/pull/7825
- JSX preserve mode: fix "make is not a valid component name". https://github.com/rescript-lang/rescript/pull/7831
- Rewatch: include parser arguments of experimental features. https://github.com/rescript-lang/rescript/pull/7836
- Suppress spurious “constructor … is never used” warnings when constructors are introduced via variant coercions; still warn for constructors only present on the target side. https://github.com/rescript-lang/rescript/pull/7839

#### :memo: Documentation

Expand Down
30 changes: 30 additions & 0 deletions compiler/ml/typecore.ml
Original file line number Diff line number Diff line change
Expand Up @@ -3018,6 +3018,36 @@ and type_expect_ ~context ?in_function ?(recarg = Rejected) env sexp ty_expected
raise (Error (loc, env, Not_subtype (tr1, tr2, ctx))));
(arg, ty', cty')
in
(* After a successful coercion, if we coerced between concrete variant
types, mark the intersection of constructors as positively used for the
target type to avoid spurious "constructor ... is never used" warnings
when values are introduced via coercions. *)
(try
let _p_src, _p_src_conc, src_decl =
Ctype.extract_concrete_typedecl env arg.exp_type
in
let _, p_tgt_conc, tgt_decl = Ctype.extract_concrete_typedecl env ty' in
match (src_decl.type_kind, tgt_decl.type_kind) with
| Type_variant src_cons, Type_variant tgt_cons ->
let module StringSet = Set.Make (String) in
let src_set =
List.fold_left
(fun acc (c : Types.constructor_declaration) ->
StringSet.add (Ident.name c.cd_id) acc)
StringSet.empty src_cons
in
let has_src name = StringSet.mem name src_set in
let tgt_ty_name_conc = Path.last p_tgt_conc in
(* Mark usage for the concrete target decl (implementation view). *)
List.iter
(fun (c : Types.constructor_declaration) ->
let cname = Ident.name c.cd_id in
if has_src cname then
Env.mark_constructor_used Env.Positive env tgt_ty_name_conc
tgt_decl cname)
tgt_cons
| _ -> ()
with Not_found -> ());
rue
{
exp_desc = arg.exp_desc;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@

Warning number 37
/.../fixtures/VariantCoercionWarnOnC.res:9:3-11:7

7 │ let log: a => unit
8 │ } = {
9 │ type b =
10 │  | ...a
11 │  | C
12 │
13 │ let log = (x: a) => Js.log((x :> b))

unused constructor C.
16 changes: 16 additions & 0 deletions tests/build_tests/super_errors/fixtures/VariantCoercionWarnOnC.res
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Ensure unused-constructor warning still fires for new members introduced
// only on the target side of a coercion.

type a = A | B

module M: {
let log: a => unit
} = {
type b =
| ...a
| C

let log = (x: a) => Js.log((x :> b))
}

let _ = M.log(A)
6 changes: 5 additions & 1 deletion tests/docstring_tests/DocTest.res
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,11 @@ let extractDocFromFile = async file => {
}
}

let batchSize = OS.cpus()->Array.length
// Some environments may report 0 CPUs; clamp to at least 1 to avoid zero-sized batches
let batchSize = switch OS.cpus()->Array.length {
| n if n > 0 => n
| _ => 1
}

let runtimePath = Path.join(["packages", "@rescript", "runtime"])

Expand Down
4 changes: 3 additions & 1 deletion tests/docstring_tests/DocTest.res.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 17 additions & 0 deletions tests/tests/src/VariantCoercionConstructUsed.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Generated by ReScript, PLEASE EDIT WITH CARE


function log(x) {
console.log(x);
}

let DoNotWarn = {
log: log
};

console.log("A");

export {
DoNotWarn,
}
/* Not a pure module */
15 changes: 15 additions & 0 deletions tests/tests/src/VariantCoercionConstructUsed.res
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Repro for incorrect "constructor ... is never used" warning with coercions
// This should compile cleanly without warnings when coercing from a -> b.

type a = A | B
module DoNotWarn: {
let log: a => unit
} = {
type b =
| ...a
| C

let log = (x: a) => Js.log((x :> b))
}

let _ = DoNotWarn.log(A)