Skip to content
Draft
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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
- Remove runtime APIs that were deprecated for removal in ReScript 13, including the `Char` module, unsafe `Obj` operations, legacy `Pervasives` helpers, and `Array.unsafe_get`. https://github.com/rescript-lang/rescript/pull/8564
- Remove the deprecated `Js` namespace and its runtime modules. https://github.com/rescript-lang/rescript/pull/8531
- Move Belt into the separately installed `@rescript/belt` package. Projects using Belt must install the package and list it in their `rescript.json` dependencies. https://github.com/rescript-lang/rescript/pull/8554
- 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

#### :eyeglasses: Spec Compliance

Expand All @@ -29,6 +30,8 @@

- Fix argument evaluation order when a function call is inlined: the beta reducer stacked argument bindings in reverse parameter order, so the last argument was evaluated first when arguments could not be substituted directly. https://github.com/rescript-lang/rescript/pull/8572
- Preserve parentheses around multiplication, division, and modulo expressions used as exponents. https://github.com/rescript-lang/rescript/pull/8550
- Make a function's locally abstract types (`(type t, x) => ...`) part of the function AST node instead of a chain of wrapper nodes. Fixes the formatter dropping the association of attributes with their `type` group (`(@attr type t, x, @attr2 type s, y)` used to print as `@attr @attr2` on the function) and comments written next to a type parameter migrating onto the following value parameter. https://github.com/rescript-lang/rescript/pull/8574
- Preserve trailing comments between the type and `=` in locally abstract value constraints (`let f: type a. t /* comment */ = value`). https://github.com/rescript-lang/rescript/pull/8575
- Enforce function arity in interface/module inclusion and type coercion. Previously a curried implementation (e.g. `int => int => int`) could satisfy an uncurried interface (`(int, int) => int`) or be coerced to it, which could miscompile calls made through the interface type. Such mismatches are now compile errors with an explanatory hint. https://github.com/rescript-lang/rescript/pull/8559
- Fix termination-analysis false positives for functions whose progress flows through un-annotated helpers: collecting the callees of a function binding was accidentally disabled in 2024 (the collection guard required a node shape that uncurried code never produces), so helpers calling `@progress` functions were no longer added to the function table. https://github.com/rescript-lang/rescript/pull/8568
- Fix default values of optional parameters being computed at the wrong time for curried functions: in `(~x=default, y) => (~z=default, w) => ...`, `x`'s default was only computed when the *inner* function was applied. Each default is now computed when its own parameter group is applied. https://github.com/rescript-lang/rescript/pull/8568
Expand All @@ -48,6 +51,7 @@

- Sync the platform npm package's compiler binaries (`packages/@rescript/<platform>/bin`) via dune promotion on every `dune build`, instead of Makefile/CI copy steps that only ran when make did: a plain `dune build` can no longer leave `cli/*.js` and the test harnesses running a stale compiler. https://github.com/rescript-lang/rescript/pull/8560
- Remove unused compiler IR definitions, modules, helpers, error variants, and Typedtree fields. https://github.com/rescript-lang/rescript/pull/8551 https://github.com/rescript-lang/rescript/pull/8555
- Make locally abstract value constraints (`let f: type a. t = value`) structural in the parsetree, remove the obsolete `Pexp_newtype` and `Texp_newtype` wrapper metadata, and keep the old encoding confined to the frozen external-PPX bridge. The CMT magic number is bumped to `Caml1999T024`. https://github.com/rescript-lang/rescript/pull/8575
- Eliminate the `Pjs_fn_make`/`Pjs_fn_make_unit` arity-adjustment primitives and the `unsafe_adjust_to_arity` machinery: with structural arity, functions are constructed at their final arity, so the enforcement layer (and the active-pattern currying split it compensated for) is deleted. Generated code improves: no adapter closures for patterns on mutable fields, better constant propagation and name preservation, and recursive modules whose members are plain functions compile statically without the runtime bootstrap. https://github.com/rescript-lang/rescript/pull/8570
- Cleanups enabled by structural arity: remove the unreachable `Too_many_arguments` error and the `?in_function` threading through the type checker that existed only to decorate it; remove the dead `function$`-vs-arrow unification bridge, `Ctype.arity`, and the unused parsetree arity helpers; deduplicate the analysis arrow-flattening helpers. https://github.com/rescript-lang/rescript/pull/8569

Expand Down
14 changes: 10 additions & 4 deletions analysis/src/completion_front_end.ml
Original file line number Diff line number Diff line change
Expand Up @@ -769,7 +769,8 @@ let completion_with_parser1 ~debug ~offset ~pos_cursor ~kind_file
let old_in_jsx_context = !in_jsx_context in
if Utils.is_jsx_component value_binding then in_jsx_context := true;
(match value_binding with
| {pvb_pat = {ppat_desc = Ppat_constraint (_pat, core_type)}; pvb_expr}
| {pvb_pat = {ppat_desc = Ppat_constraint (_, core_type)}; pvb_expr}
| {pvb_constraint = Some {pvc_type = core_type}; pvb_expr}
when loc_has_cursor pvb_expr.pexp_loc -> (
(* Expression with derivable type annotation.
E.g: let x: someRecord = {<com>} *)
Expand Down Expand Up @@ -806,9 +807,14 @@ let completion_with_parser1 ~debug ~offset ~pos_cursor ~kind_file
{context_path = CTypeAtPos loc; prefix; nested = List.rev nested})
| _ -> ())
| {
pvb_pat = {ppat_desc = Ppat_constraint (_pat, core_type); ppat_loc};
pvb_expr;
}
pvb_pat = {ppat_desc = Ppat_constraint (_, core_type); ppat_loc};
pvb_expr;
}
| {
pvb_pat = {ppat_loc};
pvb_expr;
pvb_constraint = Some {pvc_type = core_type};
}
when loc_has_cursor value_binding.pvb_loc
&& loc_has_cursor ppat_loc = false
&& loc_has_cursor pvb_expr.pexp_loc = false
Expand Down
16 changes: 15 additions & 1 deletion analysis/src/dump_ast.ml
Original file line number Diff line number Diff line change
Expand Up @@ -298,11 +298,25 @@ and print_expr_item expr ~pos ~indentation =
| v -> Printf.sprintf "<unimplemented_pexp_desc: %s>" (Utils.identify_pexp v)

let print_value_binding value ~pos ~indentation =
let constraint_ =
match value.Parsetree.pvb_constraint with
| None -> ""
| Some {pvc_newtypes; pvc_type} ->
"\n"
^ add_indentation indentation
^ "constraint: type "
^ (pvc_newtypes
|> List.map (fun ({Location.txt} as name) ->
(name |> print_loc_denominator_loc ~pos) ^ txt)
|> String.concat " ")
^ ". "
^ print_core_type pvc_type ~pos
in
print_attributes value.Parsetree.pvb_attributes
^ "value" ^ ":\n"
^ add_indentation (indentation + 1)
^ (value.pvb_pat |> print_pattern ~pos ~indentation:(indentation + 1))
^ "\n"
^ constraint_ ^ "\n"
^ add_indentation indentation
^ "expr:\n"
^ add_indentation (indentation + 1)
Expand Down
2 changes: 2 additions & 0 deletions analysis/src/hint.ml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ let inlay ~source ~kind_file ~pos ~max_length ~full ~state ~debug =
(match vb with
| {
pvb_pat = {ppat_desc = Ppat_var _};
pvb_constraint = None;
pvb_expr =
{
pexp_desc =
Expand Down Expand Up @@ -125,6 +126,7 @@ let code_lens ~source ~kind_file ~full ~debug =
(match vb with
| {
pvb_pat = {ppat_desc = Ppat_var _; ppat_loc};
pvb_constraint = None;
pvb_expr = {pexp_desc = Pexp_fun _};
} ->
push ppat_loc
Expand Down
1 change: 0 additions & 1 deletion analysis/src/utils.ml
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,6 @@ let identify_pexp pexp =
| Pexp_letmodule _ -> "Pexp_letmodule"
| Pexp_letexception _ -> "Pexp_letexception"
| Pexp_assert _ -> "Pexp_assert"
| Pexp_newtype _ -> "Pexp_newtype"
| Pexp_pack _ -> "Pexp_pack"
| Pexp_extension _ -> "Pexp_extension"
| Pexp_open _ -> "Pexp_open"
Expand Down
11 changes: 7 additions & 4 deletions analysis/src/xform.ml
Original file line number Diff line number Diff line change
Expand Up @@ -322,10 +322,13 @@ module Add_type_annotation = struct
match si.pstr_desc with
| Pstr_value (_recFlag, bindings) ->
let process_binding (vb : Parsetree.value_binding) =
(* Can't add a type annotation to a jsx component, or the compiler crashes *)
let is_jsx_component = Utils.is_jsx_component vb in
if not is_jsx_component then process_pattern vb.pvb_pat;
process_function vb.pvb_expr
match vb.pvb_constraint with
| Some _ -> ()
| None ->
(* Can't add a type annotation to a jsx component, or the compiler crashes *)
let is_jsx_component = Utils.is_jsx_component vb in
if not is_jsx_component then process_pattern vb.pvb_pat;
process_function vb.pvb_expr
in
bindings |> List.iter process_binding;
Ast_iterator.default_iterator.structure_item iterator si
Expand Down
2 changes: 1 addition & 1 deletion compiler/ext/config.ml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@ and ast0_impl_magic_number = "Caml1999M022"

and ast0_intf_magic_number = "Caml1999N022"

and cmt_magic_number = "Caml1999T023"
and cmt_magic_number = "Caml1999T024"

let load_path = ref ([] : string list)
35 changes: 29 additions & 6 deletions compiler/frontend/ast_tuple_pattern_flatten.ml
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,26 @@ let flattern_tuple_pattern_vb (self : Bs_ast_mapper.mapper)
(vb : Parsetree.value_binding) (acc : Parsetree.value_binding list) :
Parsetree.value_binding list =
let pvb_pat = self.pat self vb.pvb_pat in
let pvb_constraint =
Option.map
(fun {Parsetree.pvc_newtypes; pvc_type} ->
{
Parsetree.pvc_newtypes =
List.map
(fun (name : string Asttypes.loc) ->
{name with loc = self.location self name.loc})
pvc_newtypes;
pvc_type = self.typ self pvc_type;
})
vb.pvb_constraint
in
let pvb_expr = self.expr self vb.pvb_expr in
let pvb_attributes = self.attributes self vb.pvb_attributes in
match (pvb_pat.ppat_desc, pvb_expr.pexp_desc) with
| Ppat_tuple xs, _ when List.for_all is_simple_pattern xs -> (
match (pvb_constraint, pvb_pat.ppat_desc, pvb_expr.pexp_desc) with
| Some _, _, _ ->
{pvb_pat; pvb_expr; pvb_constraint; pvb_loc = vb.pvb_loc; pvb_attributes}
:: acc
| None, Ppat_tuple xs, _ when List.for_all is_simple_pattern xs -> (
match Ast_open_cxt.destruct_open_tuple pvb_expr [] with
| Some (wholes, es, tuple_attributes)
when Ext_list.for_all xs is_simple_pattern && Ext_list.same_length es xs
Expand All @@ -59,16 +75,20 @@ let flattern_tuple_pattern_vb (self : Bs_ast_mapper.mapper)
{
pvb_pat = pat;
pvb_expr = Ast_open_cxt.restore_exp exp wholes;
pvb_constraint = None;
pvb_attributes;
pvb_loc = vb.pvb_loc;
}
:: acc)
| _ -> {pvb_pat; pvb_expr; pvb_loc = vb.pvb_loc; pvb_attributes} :: acc)
| Ppat_record (_, _, Some rest), Pexp_pack {pmod_desc = Pmod_ident _} ->
| _ ->
{pvb_pat; pvb_expr; pvb_constraint; pvb_loc = vb.pvb_loc; pvb_attributes}
:: acc)
| None, Ppat_record (_, _, Some rest), Pexp_pack {pmod_desc = Pmod_ident _} ->
Location.raise_errorf ~loc:rest.rest_loc
"Record rest patterns are not supported when destructuring modules. Bind \
the module fields explicitly."
| Ppat_record (lid_pats, _, None), Pexp_pack {pmod_desc = Pmod_ident id} ->
| None, Ppat_record (lid_pats, _, None), Pexp_pack {pmod_desc = Pmod_ident id}
->
Ext_list.map_append lid_pats acc (fun {lid; x = pat} ->
match lid.txt with
| Lident s ->
Expand All @@ -77,13 +97,16 @@ let flattern_tuple_pattern_vb (self : Bs_ast_mapper.mapper)
pvb_expr =
Ast_helper.Exp.ident ~loc:lid.loc
{lid with txt = Ldot (id.txt, s)};
pvb_constraint = None;
pvb_attributes = [];
pvb_loc = pat.ppat_loc;
}
| _ ->
Location.raise_errorf ~loc:lid.loc
"Not supported pattern match on modules")
| _ -> {pvb_pat; pvb_expr; pvb_loc = vb.pvb_loc; pvb_attributes} :: acc
| _ ->
{pvb_pat; pvb_expr; pvb_constraint; pvb_loc = vb.pvb_loc; pvb_attributes}
:: acc

let value_bindings_mapper (self : Bs_ast_mapper.mapper)
(vbs : Parsetree.value_binding list) =
Expand Down
4 changes: 2 additions & 2 deletions compiler/frontend/ast_uncurry_gen.ml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
open Ast_helper

(* Handling `fun [@this]` used in `object [@bs] end` *)
let to_method_callback ~async loc (self : Bs_ast_mapper.mapper)
let to_method_callback ~async ~newtypes loc (self : Bs_ast_mapper.mapper)
(params : Parsetree.fun_param list) body : Parsetree.expression_desc =
match params with
| [] -> assert false
Expand Down Expand Up @@ -53,7 +53,7 @@ let to_method_callback ~async loc (self : Bs_ast_mapper.mapper)
let arity = List.length mapped_params in
let body =
Ast_async.make_function_async ~async
(Ast_helper.Exp.fun_ ~loc ~async mapped_params result)
(Ast_helper.Exp.fun_ ~loc ~async ~newtypes mapped_params result)
in
let arity_s = string_of_int arity in
Stack.pop Js_config.self_stack |> ignore;
Expand Down
1 change: 1 addition & 0 deletions compiler/frontend/ast_uncurry_gen.mli
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

val to_method_callback :
async:bool ->
newtypes:(string Asttypes.loc * Parsetree.attributes) list ->
Location.t ->
Bs_ast_mapper.mapper ->
Parsetree.fun_param list ->
Expand Down
23 changes: 18 additions & 5 deletions compiler/frontend/bs_ast_mapper.ml
Original file line number Diff line number Diff line change
Expand Up @@ -325,8 +325,12 @@ module E = struct
sub vbs)
(sub.expr sub e)
(* #end *)
| Pexp_fun {params; body; async} ->
| Pexp_fun {newtypes; params; body; async} ->
fun_ ~loc ~attrs ~async
~newtypes:
(List.map
(fun (name, attrs) -> (map_loc sub name, sub.attributes sub attrs))
newtypes)
(List.map
(fun (param : Parsetree.fun_param) ->
{
Expand Down Expand Up @@ -384,8 +388,6 @@ module E = struct
(sub.extension_constructor sub cd)
(sub.expr sub e)
| Pexp_assert e -> assert_ ~loc ~attrs (sub.expr sub e)
| Pexp_newtype (s, e) ->
newtype ~loc ~attrs (map_loc sub s) (sub.expr sub e)
| Pexp_pack me -> pack ~loc ~attrs (sub.module_expr sub me)
| Pexp_open (ovf, lid, e) ->
open_ ~loc ~attrs ovf (map_loc sub lid) (sub.expr sub e)
Expand Down Expand Up @@ -534,8 +536,19 @@ let default_mapper =
~loc:(this.location this pincl_loc)
~attrs:(this.attributes this pincl_attributes));
value_binding =
(fun this {pvb_pat; pvb_expr; pvb_attributes; pvb_loc} ->
Vb.mk (this.pat this pvb_pat) (this.expr this pvb_expr)
(fun this {pvb_pat; pvb_expr; pvb_constraint; pvb_attributes; pvb_loc} ->
let pvb_pat = this.pat this pvb_pat in
let constraint_ =
Option.map
(fun {pvc_newtypes; pvc_type} ->
{
pvc_newtypes = List.map (map_loc this) pvc_newtypes;
pvc_type = this.typ this pvc_type;
})
pvb_constraint
in
let pvb_expr = this.expr this pvb_expr in
Vb.mk pvb_pat pvb_expr ?constraint_
~loc:(this.location this pvb_loc)
~attrs:(this.attributes this pvb_attributes));
(* #if true then *)
Expand Down
43 changes: 30 additions & 13 deletions compiler/frontend/bs_builtin_ppx.ml
Original file line number Diff line number Diff line change
Expand Up @@ -92,10 +92,7 @@ let expr_mapper ~async_context ~in_function_def (self : mapper)
| Pexp_constant (Pconst_integer (s, Some 'l')) ->
{e with pexp_desc = Pexp_constant (Pconst_integer (s, None))}
(* End rewriting *)
| Pexp_newtype (s, body) ->
let res = self.expr self body in
{e with pexp_desc = Pexp_newtype (s, res)}
| Pexp_fun {params; body; async} -> (
| Pexp_fun {newtypes; params; body; async} -> (
match Ast_attributes.process_attributes_rev e.pexp_attributes with
| Nothing, _ ->
(* Handle @async x => y => ... is in async context *)
Expand All @@ -116,19 +113,27 @@ let expr_mapper ~async_context ~in_function_def (self : mapper)
mapper did (GH #7974). *)
let body = self.expr self body in
in_function_def := saved_in_function_def;
let newtypes =
Ext_list.map newtypes (fun (name, nt_attrs) ->
(name, self.attributes self nt_attrs))
in
let mapped =
Ast_helper.Exp.fun_ ~loc:e.pexp_loc ~attrs ~async params body
Ast_helper.Exp.fun_ ~loc:e.pexp_loc ~attrs ~async ~newtypes params body
in
Ast_async.make_function_async ~async mapped
| Meth_callback _, pexp_attributes ->
(* FIXME: does it make sense to have a label for [this] ? *)
async_context := false;
{
e with
pexp_desc =
Ast_uncurry_gen.to_method_callback ~async e.pexp_loc self params body;
pexp_attributes;
})
let callback =
{
e with
pexp_desc =
Ast_uncurry_gen.to_method_callback ~async ~newtypes e.pexp_loc self
params body;
pexp_attributes;
}
in
callback)
| Pexp_apply _ -> Ast_exp_apply.app_exp_mapper e self
| Pexp_match
( b,
Expand Down Expand Up @@ -183,6 +188,7 @@ let expr_mapper ~async_context ~in_function_def (self : mapper)
({txt = Lident ("None" as variant_name)}, None) );
} as pvb_pat;
pvb_expr;
pvb_constraint = None;
pvb_attributes;
};
],
Expand Down Expand Up @@ -295,6 +301,7 @@ let expr_mapper ~async_context ~in_function_def (self : mapper)
( {ppat_desc = Ppat_record _}
| {ppat_desc = Ppat_alias ({ppat_desc = Ppat_record _}, _)} ) as p;
pvb_expr;
pvb_constraint = None;
pvb_attributes;
pvb_loc = _;
};
Expand Down Expand Up @@ -509,6 +516,7 @@ let structure_item_mapper (self : mapper) (str : Parsetree.structure_item) :
{
pvb_pat = {ppat_desc = Ppat_var pval_name} as pvb_pat;
pvb_expr;
pvb_constraint = None;
pvb_attributes;
pvb_loc;
};
Expand Down Expand Up @@ -582,7 +590,16 @@ let structure_item_mapper (self : mapper) (str : Parsetree.structure_item) :
str with
pstr_desc =
Pstr_value
(Nonrecursive, [{pvb_pat; pvb_expr; pvb_attributes; pvb_loc}]);
( Nonrecursive,
[
{
pvb_pat;
pvb_expr;
pvb_constraint = None;
pvb_attributes;
pvb_loc;
};
] );
})
| Pstr_attribute ({txt = "config"}, _) -> str
| _ -> default_mapper.structure_item self str
Expand Down Expand Up @@ -732,7 +749,7 @@ let rec structure_mapper ~await_context (self : mapper) (stru : Ast_structure.t)
| Pexp_ifthenelse (_, then_expr, Some else_expr) ->
aux then_expr @ aux else_expr
| Pexp_construct (_, Some expr) -> aux expr
| Pexp_fun {body = expr} | Pexp_newtype (_, expr) -> aux expr
| Pexp_fun {body = expr} -> aux expr
| Pexp_constraint (expr, _) -> aux expr
| Pexp_match (expr, cases) ->
let case_results =
Expand Down
3 changes: 1 addition & 2 deletions compiler/ml/ast_async.ml
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
let rec dig_async_payload_from_function (expr : Parsetree.expression) =
let dig_async_payload_from_function (expr : Parsetree.expression) =
match expr.pexp_desc with
| Pexp_fun {async} -> async
| Pexp_newtype (_, body) -> dig_async_payload_from_function body
| _ -> false

let add_promise_type ?(loc = Location.none) ~async
Expand Down
Loading
Loading