Skip to content

DCE cleanup#8

Open
JonoPrest wants to merge 214 commits into
masterfrom
jono/cmt-sourcefile-fallback
Open

DCE cleanup#8
JonoPrest wants to merge 214 commits into
masterfrom
jono/cmt-sourcefile-fallback

Conversation

@JonoPrest

Copy link
Copy Markdown
Owner

No description provided.

JonoPrest added 30 commits June 11, 2026 11:01
Adds scripts/dce/run-dce.sh + README to run reanalyze DCE over the
compiler's own OCaml source.

The vendored rescript-tools reanalyze can't do this: the compiler's
OCaml is built by host OCaml 5.3 (cmt magic Caml1999I035), while the
vendored ml library only reads the 4.06-era ReScript cmt format, so it
dies with Cmi_format.Error. Instead we build the standalone reanalyze
against host compiler-libs, using the OCaml-5.3 support from
rescript-lang/reanalyze#203 (pinned, not yet merged).

It works end-to-end and produces a full report. Raw output is currently
dominated by entry-point false positives (dune emits only .cmti for the
bsc main, and jsoo isn't built in the default profile), so making it
actionable needs root/entry-point fixes — documented in the README along
with the lowest-noise starting categories (redundant/unused optional
args) and the CI-gating proposal.
…ability blocker

Two findings from triaging the DCE output:

1. Roots: a plain `dune build` emits only .cmti for modules with an
   .mli (incl the bsc main), so reanalyze missed the entry-point bodies
   and over-reported. Switch the runner to `dune build @check`, which
   emits impl .cmt for every module. Fixes the Bs_version-class false
   positives (Dead Value ~2740->2130, Dead Module ~203->146).

2. Blocker: even with roots fixed, reanalyze#203 flags obviously-live
   core modules as dead (Ast_helper has 510 in-tree refs; Lam_compile,
   Js_dump, Lam_convert likewise). Per the PR, its 5.3 value-dependency
   tracking is derived 'just based on the type' in cmt_infos and is
   incomplete (rescript-lang/reanalyze#202). So cross-reference-based
   categories aren't trustworthy yet. Documented in the README.
Investigated why obviously-live modules (Ast_helper, Lam_compile,
Js_dump) are flagged dead. reanalyze's DCE is location-keyed, and OCaml
5.3 broke that on two fronts: cmt_declaration_dependencies is uid-based
and carries few edges, and the dominant typedtree-walk reference source
relies on Texp_ident val_loc that no longer matches declaration
registration cross-module.

Confirmed by experiment (local reanalyze branch): a global uid->decl
pre-pass is a necessary foundation but insufficient; resolving
references via val_uid alone regresses (2129->2526 dead values) because
declarations are still keyed by the old location. The real fix keys both
declarations and references by uid - a core refactor, not a patch.

@JonoPrest JonoPrest left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

DCE notes.

| Batch of ('k * 'v option) list

let set k v = (k, Some v)
let remove k = (k, None)

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

DCE-confirmed cleanup: removed unused reactive exports. Covers reactive.mli too.

@JonoPrest JonoPrest left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

DCE notes 1.

(** Emit a delta *)
let emit t delta = t.emit delta

(** Process a file if changed. Emits delta to subscribers. *)

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

DCE: trimmed dead APIs; trimmed reactive interfaces. Covers reactive_file_collection.mli too.


let empty = {issues = []}

let add_issue result issue = {issues = issue :: result.issues}

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

DCE: removed unused result helpers. Covers analysis_result.mli too.

({cd_attributes; cd_loc; cd_args} :
Typedtree.constructor_declaration)
->
let _process_inline_records =

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

DCE: dropped inline record bindings.

val of_reactive : (string, Cross_file_items.t) Reactive.t -> t
(** Wrap reactive collection directly (no intermediate collection) *)

val iter_optional_arg_calls :

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

DCE: hid item store iterators.

@@ -1,4 +0,0 @@
(** Dead code analysis - cmt file processing.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

DCE: removed dead code alias.

Comment thread compiler/core/j.ml

type mutable_flag = Js_op.mutable_flag
type binop = Js_op.binop
type int_op = Js_op.int_op

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

DCE: trimmed js op types.


val eq_expression : J.expression -> J.expression -> bool

val eq_statement : J.statement -> J.statement -> bool

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

DCE: trimmed js debug exports.

close_in ic;
v

let from_file_with_digest name : t * Digest.t =

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

DCE: trimmed cmj readers. Covers js_cmj_format.mli too.

Comment thread compiler/core/js_dump.ml
(fun cxt f s -> statement top cxt f s)
(if top then P.at_least_two_lines else P.newline)

let string_of_block (block : J.block) =

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

DCE: trimmed js debug exports; trimmed js dump literals. Covers js_dump.mli too.


let new_ = "new"

let array = "Array"

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

DCE: trimmed js dump literals.

@JonoPrest JonoPrest left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

DCE notes.

(* let mk ?comment exp : t =
{expression_desc = exp ; comment } *)

let var ?comment id : t = {expression_desc = Var (Id id); comment}

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

DCE: trimmed JS expression helpers and optional comment args. Covers js_exp_make.mli too.

@JonoPrest JonoPrest left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

DCE notes 1.

val set : 'k -> 'v -> 'k * 'v option
(** Create a batch entry that sets a key *)

val remove : 'k -> 'k * 'v option

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

DCE: trimmed dead APIs; trimmed reactive interfaces; removed unused reactive exports.


(** {1 Processing} *)

val process_files : ('raw, 'v) t -> string list -> unit

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

DCE: trimmed dead APIs; trimmed reactive interfaces.

val empty : t
(** Empty result with no issues *)

val add_issue : t -> Issue.t -> t

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

DCE: removed unused result helpers.

val builder_to_list : builder -> (Lexing.position * Decl.t) list
(** Extract all declarations as a list for reactive merge *)

val create_from_hashtbl : Decl.t Pos_hash.t -> t

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

DCE: trimmed reactive exports; removed stale declaration helpers.

val assert_failure : t
val decode_error : t
val division_by_zero : t
val end_of_file : t

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

DCE: removed unused exception names.

x.times <- x0 + y0;
if captured then x.captured <- true

let pp_info fmt (x : used_info) =

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

DCE: trimmed lambda helpers. Covers lam_pass_count.mli too.


let simplify_lets (lam : Lam.t) : Lam.t =
let occ = Lam_pass_count.collect_occurs lam in
(* Ext_log.dwarn ~__POS__ "@[%a@]@." Lam_pass_count.pp_occ_tbl occ ; *)

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

DCE: trimmed lambda helpers.

| Some (Constant (Const_js_false | Const_js_null | Const_js_undefined _)) ->
Eval_false
| Some
( Normal_optional _ | ImmutableBlock _ | MutableBlock _ | Constant _

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

DCE: trimmed dead APIs.


type ident = Ident.t

type record_representation =

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

DCE: trimmed lambda debug API; removed runtime apply primitive; removed undefined primitive. Covers lam_primitive.mli too.

| Pinit_mod -> fprintf ppf "init_mod!"
| Pupdate_mod -> fprintf ppf "update_mod!"
| Pjs_apply -> fprintf ppf "#apply"
| Pjs_runtime_apply -> fprintf ppf "#runtime_apply"

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

DCE: trimmed lambda debug API; removed runtime apply primitive; removed undefined primitive. More of the same in this file. Covers lam_print.mli too.

@JonoPrest JonoPrest left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

DCE notes 2.




let is_function (lam : Lam.t) =

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

DCE: removed lam function helper. Covers lam_util.mli too.


val read_ast_exn : fname:string -> 'a kind -> 'a

val magic_sep_char : char

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

DCE: trimmed lambda helpers.

type error =
| Cmj_not_found of string
| Js_not_found of string
| Bs_cyclic_depends of string list

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

DCE: trimmed bs exception. Covers bs_exception.mli too.

Comment thread compiler/ext/bsc_args.ml

type string_action =
| String_call of (string -> unit)
| String_set of string ref

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

DCE: trimmed arg spec variants; removed unused args finish. Covers bsc_args.mli too.

Comment thread compiler/ext/ext_array.ml
a.!(i + len - 1 - k) <- t
done

let reverse_in_place a = reverse_range a 0 (Array.length a)

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

DCE: trimmed array helpers. Covers ext_array.mli too.


type t = Parsetree.pattern

let is_unit_cont ~yes ~no (p : t) =

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

DCE: trimmed frontend helpers. Covers ast_pat.mli too.

in
List.rev acc

(** Note this is okay with enums, for variants,

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

DCE: trimmed frontend helpers. Covers ast_polyvar.mli too.

Str.include_ ~loc
(Incl.mk ~loc
(Mod.constraint_ ~loc (Mod.structure ~loc stru) (Mty.signature ~loc sign)))

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

DCE: trimmed frontend helpers. Covers ast_structure.mli too.


type exn += Error of int (* offset *) * error

val pp_error : Format.formatter -> error -> unit

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

DCE: rooted utf8 test hook for DCE.

*)

type pos = {
lnum: int;

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

DCE: rooted unicode test helpers for DCE. Covers ast_utf8_string_interp.mli too.

@JonoPrest JonoPrest left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

DCE notes 3.

* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *)

type untagged_variant = OnlyOneUnknown | AtMostOneObject | AtMostOneArray

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

DCE: trimmed frontend constants. Covers bs_syntaxerr.mli too.


val cst_string : string -> delim -> cst

val empty_label : label

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

DCE: trimmed frontend constants.


type constructor_tag = {
cstr_name: Ast_untagged_variants.tag;
const: int;

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

DCE: trimmed frontend constants. Covers lam_constant.mli too.

type bs_version = int * int * int

type t = {
bsb_project_root: string;

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

DCE: trimmed gentype config.

Comment thread compiler/gentype/paths.ml
@@ -1,7 +1,5 @@
open Gentype_common

let concat = Filename.concat

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

DCE: trimmed gentype config.

Comment thread compiler/ml/stypes.ml
interesting in case of errors.
*)

open Annot

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

DCE: trimmed debug helpers; trimmed call annotations. Covers stypes.mli too.

Comment thread compiler/ml/subst.mli
val modtype : t -> module_type -> module_type
val signature : t -> signature -> signature
val modtype_declaration : t -> modtype_declaration -> modtype_declaration
val module_declaration : t -> module_declaration -> module_declaration

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

DCE: trimmed typing exports.

Comment thread compiler/ml/tbl.ml
let c = compare x v in
if c = 0 then d else find_str x (if c < 0 then l else r)

let rec mem x = function

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

DCE: trimmed debug helpers. Covers tbl.mli too.

Comment thread compiler/ml/translcore.ml

and transl_cases_try cases = List.map transl_case_try cases

and transl_apply ?(inlined = Default_inline)

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

DCE: made apply metadata explicit.

Comment thread compiler/ml/translmod.mli

type error
(* exception Error of Location.t * error *)

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

DCE: trimmed ml exports.

@JonoPrest JonoPrest left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

DCE notes 4.

Comment thread compiler/ml/typecore.ml
(* Forward declaration, to be filled in by Typemod.type_open *)

let type_open :
(?used_slot:bool ref ->

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

DCE: narrowed typecore helpers; removed unused open slot; trimmed typing exports. Covers typecore.mli too.

Comment thread compiler/ml/typedecl.ml
open Types
open Typetexp

type native_repr_kind = Unboxed | Untagged

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

DCE: trimmed ml exports; removed free_variables env. Covers typedecl.mli too.

Comment thread compiler/ml/typemod.ml

(* Compute the environment after opening a module *)

let type_open_ ?used_slot ?toplevel ovf env loc lid =

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

DCE: removed unused open slot; trimmed typing exports. Covers typemod.mli too.

Comment thread compiler/ml/types.mli
[Tobject (_, `Some (`A.ct', [t1;...;tn]')] ==> [(t1, ..., tn) A.ct].
where A.ct is the type of some class.

There are also special cases for so-called "class-types", cf. [Typeclass]

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

DCE: trimmed ctype.

*)
module Color = struct
(* use ANSI color codes, see https://en.wikipedia.org/wiki/ANSI_escape_code *)
type[@warning "-37"] color =

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

DCE: trimmed syntax CLI colors.

@@ -1,3 +1,3 @@
(* Interface to print source code to res.
* Takes a filename called "input" and returns the corresponding formatted res syntax *)
val print : ?ignore_parse_errors:bool -> string -> string [@@dead "+print"]

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

DCE: fixed live printer annotation.

* We don't support custom operators. *)
let parenthesized_ident _name = true

(* TODO: better allocation strategy for the buffer *)

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

DCE: trimmed outcome printers.

val has_inline_record_definition_attribute : Parsetree.attributes -> bool
val has_res_pat_variant_spread_attribute : Parsetree.attributes -> bool
val has_dict_pattern_attribute : Parsetree.attributes -> bool
val has_dict_spread_attribute : Parsetree.attributes -> bool

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

DCE: trimmed syntax helpers.

in
skip_whitespace_and_check scanner.offset

let peek_minus scanner = peek_char scanner '-'

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

DCE: trimmed syntax helpers. Covers res_scanner.mli too.

@@ -1,4 +1,4 @@
type input = Filename of string | Source of string

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

DCE: trimmed syntax print engine.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant