Semantic Diff

#9173 Remove dead code found by reanalyze

9 commits

f9f54a631d54b96901425c42ff49c3a4d4a0386a..pr-9173

1fc91f55e · cknitt + Claude · Nov 02, 2026, 20:58 UTC

Remove dead compiler, build system and test code found by reanalyze

Running reanalyze's dead code analysis over the native and browser (playground) builds reports values, constructors and fields that nothing uses: unused exports of Ext_list, Request_local, Misc.Color, Ast_literal, Ast_fixed_arg, Ast_helper and Ctype, Ast_helper0 builders, the narrowed Typedtree_iter.Make_iterator signature, Lam_id_kind's MutableBlock, Exception and boxed Undefined (with Lambda's Pis_undefined and Js_exp_make.is_undef, which only they produced), Bsc_args actions, Includecore.Field_arity, the hash_string_int primitive and its C stub, two rewatch exception aliases that were only matched, and unused ounit helpers. Fields of serialized formats (.cmi/.cmt) and the frozen parsetree0 stay.

077fb6e0c · cknitt + Claude · Nov 02, 2026, 20:58 UTC

Remove dead editor analysis code and reanalyze's write-only file deps

Reanalyze finds unused code in the editor analysis and in reanalyze itself: the Reactive.Registry/Scheduler exports, Shared_types helpers, Completion fields type_arg_context and data (with the parameters that only filled them), package.dependencies, Server.let*, the never-produced Circular issue, and record fields of the reactive pipeline that nothing reads. Two reactive collections, file_deps_map and files, were computed but never consumed; they were the only readers of the per-file File_deps builder, so that module and its ~file_deps/~add_file_reference plumbing go as well. package.rescript_version stays: the ve+ test directives set it.

918f6adb9 · cknitt + Claude · Nov 03, 2026, 06:40 UTC

Remove unused fields of the .cmi and .cmt formats

Reanalyze finds fields of the serialized formats that nothing reads: cmt_comments, cmt_sourcefile, cmt_builddir, cmt_loadpath, cmt_initial_env, cmt_imports and cmt_use_summaries of Cmt_format, deprecated_used.deprecated_text, Types.label_description.lbl_attributes, Typedtree.extension_constructor.ext_name, Primitive.prim_alloc, and the never-built Env_constraints summary. v13 has a new .cmi/.cmt version anyway, and the release bumps the magic numbers. The initial environment only fed cmt_initial_env, so save_cmt and Typemod.save_signature no longer take it.

9405867ab · cknitt + Claude · Nov 03, 2026, 07:21 UTC

Remove optional arguments that no caller passes

Reanalyze reports optional parameters that are never supplied. The largest group is ?comment in Js_exp_make and Js_stmt_make: only three producers remain (the @__PURE__ annotation on exception creation and the [] and assert_false hints on constants) plus the builders that forward to them, so the generated JavaScript is unchanged. The comment of a tuple field access was always None, so Lambda.str_of_field_info goes too.

The rest are parameters whose default is always taken, such as Location.errorf's ?sub and ?if_highlight, Ctype.free_vars' ?env (with the request-local really_closed it set), Js_implementation's ?outputprefix, Bsc_args.parse_exn's ?finish, and Ast_helper builders' ?runtime_tag, ?runtime_name, ?default and ?suffix. The default is now used directly.

fe6c1b8ab · cknitt + Claude · Nov 03, 2026, 07:40 UTC

Make optional arguments that every caller supplies mandatory

Reanalyze reports optional parameters that no call omits. They become labelled arguments, so a default that is never taken no longer suggests otherwise: mostly ~loc and ~attrs of the Ast_helper0 builders used by the frozen-AST mappers (the mk functions included where all builders now pass both), plus a few others such as Location.pp_ksprintf ~before, Parmatch.do_check_partial ~pred and Type_utils.filter_pipeable_functions ~target_type_id, whose None branches were unreachable.

82c2a9e79 · cknitt + Claude · Nov 03, 2026, 08:03 UTC

Remove the last dead code and mark fields reanalyze cannot see as live

The remaining reanalyze findings outside the frozen parsetree0:

- Dead, removed: the playground's int_unsafe_blit; package.rescript_version with Packages.get_rescript_version, the RESCRIPT_VERSION lookup and the ve+/ve- analysis test directives that only set it; and the default enter_expression of Typedtree_iter, which every iterator overrides (Default_iterator_argument now implements IteratorArgumentDefaults, IteratorArgument without enter_expression). - Live, annotated with [@@live] and a comment: Watch_snapshot's file and dependency and Run_config.snapshot, whose fields are only read by structural equality, and Platform_windows.command, read through Platform.command on Windows only.

Also give the playground's Cmt_format_persistence.save_cmt the signature without the initial environment, which the .cmt field removal missed: the call was a partial application, harmless only because the playground writes no .cmt.

23a70a95a · cknitt + Claude · Nov 03, 2026, 08:03 UTC

Add make dead-code to run reanalyze's dead code analysis

scripts/dead_code.sh builds the native and the browser (playground) profiles and runs reanalyze over both, so uses in either count, and fails on any finding. Vendored flow_parser and the frozen parsetree0 are suppressed. It needs a reanalyze with rescript-lang/reanalyze#224, given as REANALYZE.

77c819756 · cknitt + Claude · Nov 03, 2026, 19:05 UTC

Give platform variants distinct source names and mark forward-ref hooks live

The native and playground variants of a platform module were copied to the same name, so their .cmt locations shared one source path and reanalyze could not tell their declarations apart (it now warns about that). The copy rules use copy#, whose line directive makes locations name platform/native/... or platform/playground/... instead.

type_open_, default_error_reporter and record_deprecated_used are called through forward references (Typecore.type_open, error_reporter, Cmt_utils.record_deprecated_used) with optional arguments reanalyze cannot trace, so they are marked [@live] with a comment.

c4bb5029d · cknitt + Claude · Nov 04, 2026, 06:11 UTC

Remove code left unused by in-memory build file writes

Since #9170 writes build files through Build_file_store, nothing writes or reads them through channels any more. make dead-code reported:

- Misc.output_to_bin_file_directly, Ext_buffer.output_buffer and Cmi_format.read_cmi_channel: never used; removed. - File_util.read_build_file: used only inside File_util; no longer exported. - Compiler_process.run_requests: its ?poll and ?on_complete are never passed (the only caller is a test); removed, like the other never-passed optional arguments.