Semantic Diff

#8876 Add provisional %raw syntax for fixed external arguments

7 commits, rendered from their records.

Summary

RangeCommitsChangelogAreasJS output changesFormatsFailed checks
b3c4184fa5322e6b37b13b5a4620b2fee94c87df..pr-88767๐Ÿš€ New feature0none10

Changelog draft

๐Ÿš€ New feature
  • Add %raw(...) arguments for externals, for example external assign: (%raw("{}"), t) => t = "Object.assign". The string contains the raw JavaScript value supplied by the binding, and the argument is omitted at call sites. The legacy ` @as(json...) _ , @as("...") _, and @as(1) _ forms now emit a deprecation warning and are formatted as %raw(...)`. #8876

Files changed by more than one commit

compiler/frontend/ast_external_process.ml35fbb3f7e, 9c6a5226c
compiler/ml/classify_function.ml35fbb3f7e, 393ccaf43, e37bf0db3, 133fd8e28
tests/ounit_tests/ounit_ast_mapper0_tests.ml35fbb3f7e, 393ccaf43
tests/ounit_tests/ounit_flow_parser_tests.ml35fbb3f7e, 393ccaf43, e37bf0db3, 133fd8e28
tests/syntax_tests/data/printer/typexpr/expected/fixedExternal.res.txt35fbb3f7e, 1bd4f353e
tests/syntax_tests/data/printer/typexpr/fixedExternal.res35fbb3f7e, 1bd4f353e

b3c4184fa5322e6b37b13b5a4620b2fee94c87df..pr-8876

35fbb3f7e ยท Christoph Knittel ยท Oct 16, 2026

Add provisional %raw syntax for fixed external arguments

๐Ÿš€ New feature

%raw("{}") writes a fixed external argument as a JavaScript literal. The @as(value) _ form is deprecated and formats as %raw(...).

๐Ÿš€ New featureAdd %raw(...) arguments for externals, for example external assign: (%raw("{}"), t) => t = "Object.assign". The string contains the raw JavaScript value supplied by the binding, and the argument is omitted at call sites. The legacy ` @as(json...) _ , @as("...") _, and @as(1) _ forms now emit a deprecation warning and are formatted as %raw(...)`. #8876
71 files ยท +936 โˆ’207 ยท changelog 1 ยท compiler 1 ยท frontend 2 ยท typechecker 10 ยท syntax 3 ยท other 3 ยท runtime 9 ยท playground 1 ยท tests 41
Achanges/raw-external-arguments.feature.md+1โˆ’0
Mcompiler/ext/config.ml+2โˆ’2
Mcompiler/frontend/ast_attributes.ml+4โˆ’3
Mcompiler/frontend/ast_external_process.ml+29โˆ’7
Mcompiler/ml/ast_fixed_arg.ml+57โˆ’10
Mcompiler/ml/ast_fixed_arg.mli+7โˆ’3
Mcompiler/ml/ast_iterator.ml+1โˆ’0
Mcompiler/ml/ast_mapper.ml+1โˆ’0
Mcompiler/ml/ast_mapper_to0.ml+19โˆ’8
Mcompiler/ml/classify_function.ml+18โˆ’0
Mcompiler/ml/classify_function.mli+5โˆ’0
Mcompiler/ml/parsetree.ml+5โˆ’3
Mcompiler/ml/pprintast.ml+12โˆ’17
Mcompiler/ml/printast.ml+10โˆ’7
Mcompiler/syntax/src/res_comments_table.ml+3โˆ’4
Mcompiler/syntax/src/res_core.ml+75โˆ’1
Mcompiler/syntax/src/res_printer.ml+23โˆ’22
Mpackages/@rescript/belt/src/Belt_Array.res+1โˆ’1
Mpackages/@rescript/belt/src/Belt_Array.resi+1โˆ’1
Mpackages/@rescript/belt/src/Belt_Int.res+1โˆ’1
Mpackages/@rescript/runtime/Stdlib_Array.res+1โˆ’1
Mpackages/@rescript/runtime/Stdlib_Array.resi+1โˆ’1
Mpackages/@rescript/runtime/Stdlib_Dict.res+4โˆ’4
Mpackages/@rescript/runtime/Stdlib_Dict.resi+4โˆ’4
Mpackages/@rescript/runtime/Stdlib_JSON.res+2โˆ’2
Mpackages/@rescript/runtime/Stdlib_JSON.resi+2โˆ’2
Mpackages/@rescript/runtime/Stdlib_Object.res+3โˆ’3
Mpackages/@rescript/runtime/Stdlib_RegExp.res+2โˆ’2
Mpackages/@rescript/runtime/Stdlib_RegExp.resi+2โˆ’2
Mpackages/dev-playground/src/Bindings.res+6โˆ’3
Mtests/analysis_tests/tests-reanalyze/deadcode/expected/deadcode.txt+1โˆ’1
Mtests/analysis_tests/tests/src/CompletionJsx.res+1โˆ’1
Mtests/build_tests/react_ppx/src/React.res+5โˆ’7
Atests/build_tests/super_errors/expected/raw_external_arg_not_literal.res.expected+8โˆ’0
Atests/build_tests/super_errors/expected/raw_external_arg_optional.res.expected+8โˆ’0
Atests/build_tests/super_errors/fixtures/raw_external_arg_not_literal.res+1โˆ’0
Atests/build_tests/super_errors/fixtures/raw_external_arg_optional.res+1โˆ’0
Mtests/dependencies/rescript-react/src/React.res+7โˆ’8
Mtests/dependencies/rescript-react/src/ReactDOMStyle.res+2โˆ’2
Mtests/dependencies/rescript-react/src/RescriptReactRouter.res+2โˆ’2
Mtests/ounit_tests/ounit_ast_mapper0_tests.ml+2โˆ’0
Mtests/ounit_tests/ounit_flow_parser_tests.ml+32โˆ’0
Mtests/ounit_tests/ounit_string_literal_tests.ml+34โˆ’0
Mtests/syntax_tests/data/ast-mapping/FixedExternal.res+1โˆ’0
Mtests/syntax_tests/data/ast-mapping/expected/FixedExternal.res.txt+93โˆ’5
Mtests/syntax_tests/data/ast-mapping/expected/FunctionsAndArrows.res.txt+14โˆ’1
Atests/syntax_tests/data/parsing/errors/typexpr/expected/fixedExternalDuplicate.res.txt+10โˆ’0
Atests/syntax_tests/data/parsing/errors/typexpr/expected/fixedExternalPosition.res.txt+11โˆ’0
Atests/syntax_tests/data/parsing/errors/typexpr/expected/fixedExternalTyped.res.txt+10โˆ’0
Atests/syntax_tests/data/parsing/errors/typexpr/fixedExternalDuplicate.res+1โˆ’0
Atests/syntax_tests/data/parsing/errors/typexpr/fixedExternalPosition.res+1โˆ’0
Atests/syntax_tests/data/parsing/errors/typexpr/fixedExternalTyped.res+1โˆ’0
Mtests/syntax_tests/data/printer/other/expected/attributes.res.txt+76โˆ’4
Mtests/syntax_tests/data/printer/typexpr/expected/fixedExternal.res.txt+234โˆ’9
Mtests/syntax_tests/data/printer/typexpr/fixedExternal.res+10โˆ’0
Mtests/tests/src/AsInUncurriedExternals.mjs+8โˆ’1
Mtests/tests/src/AsInUncurriedExternals.res+11โˆ’4
Mtests/tests/src/UncurriedExternals.res+1โˆ’1
Mtests/tests/src/braced_attribute_payload.res+1โˆ’1
Mtests/tests/src/bs_auto_uncurry.res+2โˆ’2
Mtests/tests/src/bs_splice_partial.res+2โˆ’2
Mtests/tests/src/external_ppx.mjs+1โˆ’1
Mtests/tests/src/external_ppx.res+4โˆ’4
Mtests/tests/src/external_ppx2.res+1โˆ’1
Mtests/tests/src/ffi_js_test.res+2โˆ’2
Mtests/tests/src/gpr_1170.res+2โˆ’2
Mtests/tests/src/gpr_1484.res+1โˆ’1
Mtests/tests/src/mario_game.res+1โˆ’1
Mtests/tests/src/prepend_data_ffi.mjs+5โˆ’5
Mtests/tests/src/prepend_data_ffi.res+24โˆ’23
Mtests/tests/src/record_name_test.res+2โˆ’2
with Claude Opus 5.5
70da6ea0d ยท Christoph Knittel ยท Sep 04, 2026

Allow slow CI builds in watch recompilation test

1 files ยท +3 โˆ’2 ยท tests 1
Mrewatch/tests/watch/01-watch-recompile.sh+3โˆ’2
393ccaf43 ยท Christoph Knittel ยท Oct 16, 2026

Reject computed keys in fixed literals

A computed object key such as [f()] runs code, so it is not a literal. Also test that a %raw fixed argument survives the v0 bridge.

3 files ยท +57 โˆ’1 ยท typechecker 1 ยท tests 2
Mcompiler/ml/classify_function.ml+10โˆ’1
Mtests/ounit_tests/ounit_ast_mapper0_tests.ml+43โˆ’0
Mtests/ounit_tests/ounit_flow_parser_tests.ml+4โˆ’0
with Claude Opus 5.5
e37bf0db3 ยท Christoph Knittel ยท Oct 16, 2026

Validate fixed literals as strict mode JavaScript

The output is strict, so legacy octal literals such as 007 and octal escapes are rejected.

2 files ยท +11 โˆ’1 ยท typechecker 1 ยท tests 1
Mcompiler/ml/classify_function.ml+6โˆ’1
Mtests/ounit_tests/ounit_flow_parser_tests.ml+5โˆ’0
with Claude Opus 5.5
9c6a5226c ยท Christoph Knittel ยท Oct 16, 2026

Report unused attributes on fixed arguments

As for @as(value) _, an attribute such as @ignore next to %raw has no effect.

3 files ยท +35 โˆ’18 ยท frontend 1 ยท tests 2
Mcompiler/frontend/ast_external_process.ml+24โˆ’18
Atests/build_tests/super_errors/expected/raw_external_arg_unused_attribute.res.expected+10โˆ’0
Atests/build_tests/super_errors/fixtures/raw_external_arg_unused_attribute.res+1โˆ’0
with Claude Opus 5.5
1bd4f353e ยท Christoph Knittel ยท Oct 16, 2026

Test migrating fixed values with template syntax

2 files ยท +47 โˆ’0 ยท tests 2
Mtests/syntax_tests/data/printer/typexpr/expected/fixedExternal.res.txt+45โˆ’0
Mtests/syntax_tests/data/printer/typexpr/fixedExternal.res+2โˆ’0
with Claude Opus 5.5
133fd8e28 ยท Christoph Knittel ยท Oct 17, 2026

Allow unary minus only on numbers in fixed literals

Negating an array, object or regexp can run a valueOf method.

2 files ยท +14 โˆ’1 ยท typechecker 1 ยท tests 1
Mcompiler/ml/classify_function.ml+5โˆ’1
Mtests/ounit_tests/ounit_flow_parser_tests.ml+9โˆ’0
with Claude Opus 5.5