Skip to content

Commit b1d5a43

Browse files
authored
@Directives in functions (#6756)
* base implementation for directives in functions * prevent inlining of functions with directives * changelog
1 parent 1e822bb commit b1d5a43

21 files changed

+93
-30
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@
1212
1313
# 12.0.0-alpha.1 (Unreleased)
1414

15+
#### :rocket: New Feature
16+
17+
- Allow `@directive` on functions for emitting function level directive code (`let serverAction = @directive("'use server'") (~name) => {...}`). https://github.com/rescript-lang/rescript-compiler/pull/6756
18+
1519
#### :boom: Breaking Change
1620

1721
- `lazy` syntax is no longer supported. If you're using it, use `Lazy` module or `React.lazy_` instead. https://github.com/rescript-lang/rescript-compiler/pull/6342

jscomp/core/j.ml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ and expression_desc =
135135
env : Js_fun_env.t;
136136
return_unit : bool;
137137
async : bool;
138+
directive : string option;
138139
}
139140
| Str of { delim : delim; txt : string }
140141
(* A string is UTF-8 encoded, and may contain

jscomp/core/js_dump.ml

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,7 @@ let rec try_optimize_curry cxt f len function_id =
282282
Curry_gen.pp_optimize_curry f len;
283283
P.paren_group f 1 (fun _ -> expression ~level:1 cxt f function_id)
284284

285-
and pp_function ~return_unit ~async ~is_method cxt (f : P.t) ~fn_state
285+
and pp_function ~return_unit ~async ~is_method ?directive cxt (f : P.t) ~fn_state
286286
(l : Ident.t list) (b : J.block) (env : Js_fun_env.t) : cxt =
287287
match b with
288288
| [
@@ -363,13 +363,13 @@ and pp_function ~return_unit ~async ~is_method cxt (f : P.t) ~fn_state
363363
if Js_fun_env.get_unused env 0 then cxt
364364
else pp_var_assign_this cxt f this
365365
in
366-
function_body ~return_unit cxt f b))
366+
function_body ?directive ~return_unit cxt f b))
367367
else
368368
let cxt =
369369
P.paren_group f 1 (fun _ -> formal_parameter_list inner_cxt f l)
370370
in
371371
P.space f;
372-
P.brace_vgroup f 1 (fun _ -> function_body ~return_unit cxt f b)
372+
P.brace_vgroup f 1 (fun _ -> function_body ?directive ~return_unit cxt f b)
373373
in
374374
let enclose () =
375375
let handle () =
@@ -483,9 +483,9 @@ and expression_desc cxt ~(level : int) f x : cxt =
483483
let cxt = expression ~level:0 cxt f e1 in
484484
comma_sp f;
485485
expression ~level:0 cxt f e2)
486-
| Fun { is_method; params; body; env; return_unit; async } ->
486+
| Fun { is_method; params; body; env; return_unit; async; directive } ->
487487
(* TODO: dump for comments *)
488-
pp_function ~is_method cxt f ~fn_state:default_fn_exp_state params body
488+
pp_function ?directive ~is_method cxt f ~fn_state:default_fn_exp_state params body
489489
env ~return_unit ~async
490490
(* TODO:
491491
when [e] is [Js_raw_code] with arity
@@ -515,10 +515,11 @@ and expression_desc cxt ~(level : int) f x : cxt =
515515
env;
516516
return_unit;
517517
async;
518+
directive;
518519
};
519520
};
520521
] ->
521-
pp_function ~is_method ~return_unit ~async cxt f
522+
pp_function ?directive ~is_method ~return_unit ~async cxt f
522523
~fn_state:(No_name { single_arg = true })
523524
params body env
524525
| _ ->
@@ -920,8 +921,8 @@ and variable_declaration top cxt f (variable : J.variable_declaration) : cxt =
920921
statement_desc top cxt f (J.Exp e)
921922
| _ -> (
922923
match e.expression_desc with
923-
| Fun { is_method; params; body; env; return_unit; async } ->
924-
pp_function ~is_method cxt f ~return_unit ~async
924+
| Fun { is_method; params; body; env; return_unit; async; directive } ->
925+
pp_function ?directive ~is_method cxt f ~return_unit ~async
925926
~fn_state:(if top then Name_top name else Name_non_top name)
926927
params body env
927928
| _ ->
@@ -1124,9 +1125,9 @@ and statement_desc top cxt f (s : J.statement_desc) : cxt =
11241125
cxt
11251126
| Return e -> (
11261127
match e.expression_desc with
1127-
| Fun { is_method; params; body; env; return_unit; async } ->
1128+
| Fun { is_method; params; body; env; return_unit; async; directive } ->
11281129
let cxt =
1129-
pp_function ~return_unit ~is_method ~async cxt f ~fn_state:Is_return
1130+
pp_function ?directive ~return_unit ~is_method ~async cxt f ~fn_state:Is_return
11301131
params body env
11311132
in
11321133
semi f;
@@ -1216,8 +1217,15 @@ and statement_desc top cxt f (s : J.statement_desc) : cxt =
12161217
P.string f L.finally;
12171218
P.space f;
12181219
brace_block cxt f b))
1220+
12191221

1220-
and function_body (cxt : cxt) f ~return_unit (b : J.block) : unit =
1222+
and function_body ?directive (cxt : cxt) f ~return_unit (b : J.block) : unit =
1223+
(match directive with
1224+
| None -> ()
1225+
| Some directive ->
1226+
P.newline f;
1227+
P.string f directive; P.string f ";";
1228+
P.newline f);
12211229
match b with
12221230
| [] -> ()
12231231
| [ s ] -> (

jscomp/core/js_exp_make.ml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ let unit : t = { expression_desc = Undefined {isUnit = true}; comment = None }
207207
[Js_fun_env.empty] is a mutable state ..
208208
*)
209209

210-
let ocaml_fun ?comment ?immutable_mask ~return_unit ~async ~oneUnitArg params body : t =
210+
let ocaml_fun ?comment ?immutable_mask ~return_unit ~async ~oneUnitArg ?directive params body : t =
211211
let params = if oneUnitArg then [] else params in
212212
let len = List.length params in
213213
{
@@ -220,6 +220,7 @@ let ocaml_fun ?comment ?immutable_mask ~return_unit ~async ~oneUnitArg params bo
220220
env = Js_fun_env.make ?immutable_mask len;
221221
return_unit;
222222
async;
223+
directive;
223224
};
224225
comment;
225226
}
@@ -236,6 +237,7 @@ let method_ ?comment ?immutable_mask ~return_unit params body : t =
236237
env = Js_fun_env.make ?immutable_mask len;
237238
return_unit;
238239
async = false;
240+
directive = None;
239241
};
240242
comment;
241243
}
@@ -1301,6 +1303,7 @@ let of_block ?comment ?e block : t =
13011303
env = Js_fun_env.make 0;
13021304
return_unit;
13031305
async = false;
1306+
directive = None;
13041307
};
13051308
}
13061309
[]

jscomp/core/js_exp_make.mli

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ val ocaml_fun :
9191
return_unit:bool ->
9292
async:bool ->
9393
oneUnitArg:bool ->
94+
?directive:string ->
9495
J.ident list ->
9596
J.block ->
9697
t

jscomp/core/js_pass_tailcall_inline.ml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ let subst (export_set : Set_ident.t) stats =
165165
Some
166166
{
167167
expression_desc =
168-
Fun {is_method=false; params; body; env; async=false};
168+
Fun {is_method=false; params; body; env; async=false; directive=None};
169169
comment = _;
170170
};
171171
(*TODO: don't inline method tail call yet,
@@ -200,7 +200,7 @@ let subst (export_set : Set_ident.t) stats =
200200
Call
201201
( {
202202
expression_desc =
203-
Fun {is_method=false; params; body; env; async=false};
203+
Fun {is_method=false; params; body; env; async=false; directive=None};
204204
},
205205
args,
206206
_info );

jscomp/core/lam_analysis.ml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -249,8 +249,8 @@ let destruct_pattern (body : Lam.t) params args =
249249
| _ -> false
250250

251251
(* Async functions cannot be beta reduced *)
252-
let lfunction_can_be_beta_reduced (lfunction : Lam.lfunction) =
253-
not lfunction.attr.async
252+
let lfunction_can_be_inlined (lfunction : Lam.lfunction) =
253+
not lfunction.attr.async && lfunction.attr.directive = None
254254

255255
(** Hints to inlining *)
256256
let ok_to_inline_fun_when_app (m : Lam.lfunction) (args : Lam.t list) =

jscomp/core/lam_analysis.mli

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ val no_side_effects : Lam.t -> bool
2929

3030
val size : Lam.t -> int
3131

32-
val lfunction_can_be_beta_reduced : Lam.lfunction -> bool
32+
val lfunction_can_be_inlined : Lam.lfunction -> bool
3333

3434
val ok_to_inline_fun_when_app : Lam.lfunction -> Lam.t list -> bool
3535

jscomp/core/lam_compile.ml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,7 @@ and compile_external_field_apply ?(dynamic_import = false) (appinfo : Lam.apply)
272272
let ap_args = appinfo.ap_args in
273273
match ident_info.persistent_closed_lambda with
274274
| Some (Lfunction ({ params; body; _ } as lfunction))
275-
when Ext_list.same_length params ap_args && Lam_analysis.lfunction_can_be_beta_reduced lfunction ->
275+
when Ext_list.same_length params ap_args && Lam_analysis.lfunction_can_be_inlined lfunction ->
276276
(* TODO: serialize it when exporting to save compile time *)
277277
let _, param_map =
278278
Lam_closure.is_closed_with_map Set_ident.empty params body
@@ -319,7 +319,7 @@ and compile_external_field_apply ?(dynamic_import = false) (appinfo : Lam.apply)
319319
and compile_recursive_let ~all_bindings (cxt : Lam_compile_context.t)
320320
(id : Ident.t) (arg : Lam.t) : Js_output.t * initialization =
321321
match arg with
322-
| Lfunction { params; body; attr = { return_unit; async; oneUnitArg } } ->
322+
| Lfunction { params; body; attr = { return_unit; async; oneUnitArg; directive } } ->
323323
(* TODO: Think about recursive value
324324
{[
325325
let rec v = ref (fun _ ...
@@ -357,7 +357,7 @@ and compile_recursive_let ~all_bindings (cxt : Lam_compile_context.t)
357357
it will be renamed into [method]
358358
when it is detected by a primitive
359359
*)
360-
~return_unit ~async ~oneUnitArg ~immutable_mask:ret.immutable_mask
360+
~return_unit ~async ~oneUnitArg ?directive ~immutable_mask:ret.immutable_mask
361361
(Ext_list.map params (fun x ->
362362
Map_ident.find_default ret.new_params x x))
363363
[
@@ -368,7 +368,7 @@ and compile_recursive_let ~all_bindings (cxt : Lam_compile_context.t)
368368
]
369369
else
370370
(* TODO: save computation of length several times *)
371-
E.ocaml_fun params (Js_output.output_as_block output) ~return_unit ~async ~oneUnitArg
371+
E.ocaml_fun params (Js_output.output_as_block output) ~return_unit ~async ~oneUnitArg ?directive
372372
in
373373
( Js_output.output_of_expression
374374
(Declare (Alias, id))
@@ -1670,10 +1670,10 @@ and compile_prim (prim_info : Lam.prim_info)
16701670
and compile_lambda (lambda_cxt : Lam_compile_context.t) (cur_lam : Lam.t) :
16711671
Js_output.t =
16721672
match cur_lam with
1673-
| Lfunction { params; body; attr = { return_unit; async; oneUnitArg } } ->
1673+
| Lfunction { params; body; attr = { return_unit; async; oneUnitArg; directive } } ->
16741674
Js_output.output_of_expression lambda_cxt.continuation
16751675
~no_effects:no_effects_const
1676-
(E.ocaml_fun params ~return_unit ~async ~oneUnitArg
1676+
(E.ocaml_fun params ~return_unit ~async ~oneUnitArg ?directive
16771677
(* Invariant: jmp_table can not across function boundary,
16781678
here we share env
16791679
*)

jscomp/core/lam_pass_count.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ let collect_occurs lam : occ_tbl =
144144
count bv body
145145
(* Note there is a difference here when do beta reduction for *)
146146
| Lapply { ap_func = Lfunction ({ params; body } as lfunction); ap_args = args; _ }
147-
when Ext_list.same_length params args && Lam_analysis.lfunction_can_be_beta_reduced lfunction ->
147+
when Ext_list.same_length params args && Lam_analysis.lfunction_can_be_inlined lfunction ->
148148
count bv (Lam_beta_reduce.no_names_beta_reduce params body args)
149149
(* | Lapply{fn = Lfunction{function_kind = Tupled; params; body}; *)
150150
(* args = [Lprim {primitive = Pmakeblock _; args; _}]; _} *)

0 commit comments

Comments
 (0)