Skip to content

Commit de9b806

Browse files
authored
Dynamic import in expression (#6310)
1 parent 508e2b3 commit de9b806

File tree

12 files changed

+222
-26
lines changed

12 files changed

+222
-26
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717
- Semantic-based optimization of code generated for untagged variants https://github.com/rescript-lang/rescript-compiler/issues/6108
1818
- Record type spreads: Allow using type variables in type spreads. Both uninstantiated and instantiated ones https://github.com/rescript-lang/rescript-compiler/pull/6309
1919

20+
#### :bug: Bug Fix
21+
- Fix issue where dynamic import of module in the expression https://github.com/rescript-lang/rescript-compiler/pull/6310
22+
2023
# 11.0.0-beta.2
2124

2225
#### :rocket: New Feature

jscomp/frontend/ast_await.ml

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ let create_await_expression (e : Parsetree.expression) =
77
Ast_helper.Exp.apply ~loc unsafe_await [(Nolabel, e)]
88

99
(* Transform `@res.await M` to unpack(@res.await Js.import(module(M: __M0__))) *)
10-
let create_await_module_expression ~module_type_name (e : Parsetree.module_expr)
10+
let create_await_module_expression ~module_type_lid (e : Parsetree.module_expr)
1111
=
1212
let open Ast_helper in
1313
let remove_await_attribute =
@@ -33,8 +33,6 @@ let create_await_module_expression ~module_type_name (e : Parsetree.module_expr)
3333
pmod_attributes =
3434
remove_await_attribute e.pmod_attributes;
3535
})
36-
(Typ.package ~loc:e.pmod_loc
37-
{txt = Lident module_type_name; loc = e.pmod_loc}
38-
[]) );
36+
(Typ.package ~loc:e.pmod_loc module_type_lid []) );
3937
]));
4038
}

jscomp/frontend/bs_builtin_ppx.ml

Lines changed: 86 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,13 @@ let pat_mapper (self : mapper) (p : Parsetree.pattern) =
7272
Ast_utf8_string_interp.transform_pat p s delim
7373
| _ -> default_pat_mapper self p
7474

75+
(* Unpack requires core_type package for type inference:
76+
Generate a module type name eg. __Belt_List__*)
77+
let local_module_type_name txt =
78+
"_"
79+
^ (Longident.flatten txt |> List.fold_left (fun ll l -> ll ^ "_" ^ l) "")
80+
^ "__"
81+
7582
let expr_mapper ~async_context ~in_function_def (self : mapper)
7683
(e : Parsetree.expression) =
7784
let old_in_function_def = !in_function_def in
@@ -214,6 +221,42 @@ let expr_mapper ~async_context ~in_function_def (self : mapper)
214221
the attribute to the whole expression, in general, when shuffuling the ast
215222
it is very hard to place attributes correctly
216223
*)
224+
(* module M = await Belt.List *)
225+
| Pexp_letmodule
226+
(lid, ({pmod_desc = Pmod_ident {txt}; pmod_attributes} as me), expr)
227+
when Res_parsetree_viewer.hasAwaitAttribute pmod_attributes ->
228+
let safe_module_type_lid : Ast_helper.lid =
229+
{txt = Lident (local_module_type_name txt); loc = me.pmod_loc}
230+
in
231+
{
232+
e with
233+
pexp_desc =
234+
Pexp_letmodule
235+
( lid,
236+
Ast_await.create_await_module_expression
237+
~module_type_lid:safe_module_type_lid me,
238+
self.expr self expr );
239+
}
240+
(* module M = await (Belt.List: BeltList) *)
241+
| Pexp_letmodule
242+
( lid,
243+
({
244+
pmod_desc =
245+
Pmod_constraint
246+
({pmod_desc = Pmod_ident _}, {pmty_desc = Pmty_ident mtyp_lid});
247+
pmod_attributes;
248+
} as me),
249+
expr )
250+
when Res_parsetree_viewer.hasAwaitAttribute pmod_attributes ->
251+
{
252+
e with
253+
pexp_desc =
254+
Pexp_letmodule
255+
( lid,
256+
Ast_await.create_await_module_expression ~module_type_lid:mtyp_lid
257+
me,
258+
self.expr self expr );
259+
}
217260
| _ -> default_expr_mapper self e
218261

219262
let expr_mapper ~async_context ~in_function_def (self : mapper)
@@ -424,13 +467,6 @@ let local_module_name =
424467
incr v;
425468
"local_" ^ string_of_int !v
426469

427-
(* Unpack requires core_type package for type inference:
428-
Generate a module type name eg. __Belt_List__*)
429-
let local_module_type_name txt =
430-
"_"
431-
^ (Longident.flatten txt |> List.fold_left (fun ll l -> ll ^ "_" ^ l) "")
432-
^ "__"
433-
434470
let expand_reverse (stru : Ast_structure.t) (acc : Ast_structure.t) :
435471
Ast_structure.t =
436472
if stru = [] then acc
@@ -509,15 +545,18 @@ let rec structure_mapper ~await_context (self : mapper) (stru : Ast_structure.t)
509545
match has_local_module_name with
510546
| Some _ -> []
511547
| None ->
512-
let open Ast_helper in
513548
Hashtbl.add !await_context safe_module_type_name safe_module_type_name;
514549
[
515-
Str.modtype ~loc
516-
(Mtd.mk ~loc
517-
{txt = safe_module_type_name; loc}
518-
~typ:(Mty.typeof_ ~loc me));
550+
Ast_helper.(
551+
Str.modtype ~loc
552+
(Mtd.mk ~loc
553+
{txt = safe_module_type_name; loc}
554+
~typ:(Mty.typeof_ ~loc me)));
519555
]
520556
in
557+
let safe_module_type_lid : Ast_helper.lid =
558+
{txt = Lident safe_module_type_name; loc = mb.pmb_expr.pmod_loc}
559+
in
521560
module_type_decl
522561
@ (* module M = @res.await Belt.List *)
523562
{
@@ -528,10 +567,44 @@ let rec structure_mapper ~await_context (self : mapper) (stru : Ast_structure.t)
528567
mb with
529568
pmb_expr =
530569
Ast_await.create_await_module_expression
531-
~module_type_name:safe_module_type_name mb.pmb_expr;
570+
~module_type_lid:safe_module_type_lid mb.pmb_expr;
532571
};
533572
}
534573
:: structure_mapper ~await_context self rest
574+
| Pstr_value (_, vbs) ->
575+
let item = self.structure_item self item in
576+
(* [ module __Belt_List__ = module type of Belt.List ] *)
577+
let module_type_decls =
578+
vbs
579+
|> List.filter_map (fun ({pvb_expr} : Parsetree.value_binding) ->
580+
match pvb_expr.pexp_desc with
581+
| Pexp_letmodule
582+
( _,
583+
({pmod_desc = Pmod_ident {txt; loc}; pmod_attributes} as
584+
me),
585+
_ )
586+
when Res_parsetree_viewer.hasAwaitAttribute pmod_attributes
587+
-> (
588+
let safe_module_type_name = local_module_type_name txt in
589+
let has_local_module_name =
590+
Hashtbl.find_opt !await_context safe_module_type_name
591+
in
592+
593+
match has_local_module_name with
594+
| Some _ -> None
595+
| None ->
596+
Hashtbl.add !await_context safe_module_type_name
597+
safe_module_type_name;
598+
Some
599+
Ast_helper.(
600+
Str.modtype ~loc
601+
(Mtd.mk ~loc
602+
{txt = safe_module_type_name; loc}
603+
~typ:(Mty.typeof_ ~loc me))))
604+
| _ -> None)
605+
in
606+
607+
module_type_decls @ (item :: structure_mapper ~await_context self rest)
535608
| _ ->
536609
self.structure_item self item :: structure_mapper ~await_context self rest
537610
)

jscomp/syntax/src/res_printer.ml

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -705,16 +705,14 @@ and printModuleBinding ~state ~isRec moduleBinding cmtTbl i =
705705
in
706706
let modExprDoc, modConstraintDoc =
707707
match moduleBinding.pmb_expr with
708-
| {pmod_desc = Pmod_constraint (modExpr, modType)} ->
708+
| {pmod_desc = Pmod_constraint (modExpr, modType)}
709+
when not
710+
(ParsetreeViewer.hasAwaitAttribute
711+
moduleBinding.pmb_expr.pmod_attributes) ->
709712
( printModExpr ~state modExpr cmtTbl,
710713
Doc.concat [Doc.text ": "; printModType ~state modType cmtTbl] )
711714
| modExpr -> (printModExpr ~state modExpr cmtTbl, Doc.nil)
712715
in
713-
let modExprDoc =
714-
if ParsetreeViewer.hasAwaitAttribute moduleBinding.pmb_expr.pmod_attributes
715-
then Doc.concat [Doc.text "await "; modExprDoc]
716-
else modExprDoc
717-
in
718716
let modName =
719717
let doc = Doc.text moduleBinding.pmb_name.Location.txt in
720718
printComments doc cmtTbl moduleBinding.pmb_name.loc
@@ -4967,11 +4965,13 @@ and printExpressionBlock ~state ~braces expr cmtTbl =
49674965
in
49684966
let name, modExpr =
49694967
match modExpr.pmod_desc with
4970-
| Pmod_constraint (modExpr, modType) ->
4968+
| Pmod_constraint (modExpr2, modType)
4969+
when not (ParsetreeViewer.hasAwaitAttribute modExpr.pmod_attributes)
4970+
->
49714971
let name =
49724972
Doc.concat [name; Doc.text ": "; printModType ~state modType cmtTbl]
49734973
in
4974-
(name, modExpr)
4974+
(name, modExpr2)
49754975
| _ -> (name, modExpr)
49764976
in
49774977
let letModuleDoc =
@@ -5455,6 +5455,14 @@ and printModExpr ~state modExpr cmtTbl =
54555455
]
54565456
| Pmod_functor _ -> printModFunctor ~state modExpr cmtTbl
54575457
in
5458+
let doc =
5459+
if ParsetreeViewer.hasAwaitAttribute modExpr.pmod_attributes then
5460+
match modExpr.pmod_desc with
5461+
| Pmod_constraint _ ->
5462+
Doc.concat [Doc.text "await "; Doc.lparen; doc; Doc.rparen]
5463+
| _ -> Doc.concat [Doc.text "await "; doc]
5464+
else doc
5465+
in
54585466
printComments doc cmtTbl modExpr.pmod_loc
54595467

54605468
and printModFunctor ~state modExpr cmtTbl =

jscomp/syntax/tests/parsing/grammar/expressions/await.res

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,25 @@ let () = {
2828
let forEach = await @a @b Js.Import(Belt.List.forEach)
2929

3030
module M = await @a @b Belt.List
31+
32+
let f = () => {
33+
module M = await @a @b Belt.List
34+
M.forEach
35+
}
36+
37+
let () = {
38+
module M = await @a @b Belt.List
39+
M.forEach
40+
}
41+
42+
module type BeltList = module type of Belt.List
43+
44+
let f = () => {
45+
module M = await @a @b (Belt.List: BeltList)
46+
M.forEach
47+
}
48+
49+
let () = {
50+
module M = await @a @b (Belt.List: BeltList)
51+
M.forEach
52+
}

jscomp/syntax/tests/parsing/grammar/expressions/expected/await.res.txt

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,18 @@ let () = ((delay 10)[@res.braces ][@res.await ])
1717
let () = ((((delay 10)[@res.await ]); ((delay 20)[@res.await ]))
1818
[@res.braces ])
1919
let forEach = ((Js.Import Belt.List.forEach)[@res.await ][@a ][@b ])
20-
module M = ((Belt.List)[@res.await ][@a ][@b ])
20+
module M = ((Belt.List)[@res.await ][@a ][@b ])
21+
let f () =
22+
((let module M = ((Belt.List)[@res.await ][@a ][@b ]) in M.forEach)
23+
[@res.braces ])
24+
let () = ((let module M = ((Belt.List)[@res.await ][@a ][@b ]) in M.forEach)
25+
[@res.braces ])
26+
module type BeltList = module type of Belt.List
27+
let f () =
28+
((let module M = (((Belt.List : BeltList))[@res.await ][@a ][@b ]) in
29+
M.forEach)
30+
[@res.braces ])
31+
let () =
32+
((let module M = (((Belt.List : BeltList))[@res.await ][@a ][@b ]) in
33+
M.forEach)
34+
[@res.braces ])

jscomp/syntax/tests/printer/expr/expected/letmodule.res.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,13 @@ let x = {
22
module M = ME
33
Me.x
44
}
5+
6+
let x = {
7+
module M = await ME
8+
M.x
9+
}
10+
11+
let x = {
12+
module M = await (ME: MT)
13+
M.x
14+
}

jscomp/syntax/tests/printer/expr/letmodule.res

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,13 @@ let x = {
22
module M = ME
33
Me.x
44
}
5+
6+
let x = {
7+
module M = await ME
8+
M.x
9+
}
10+
11+
let x = {
12+
module M = await (ME: MT)
13+
M.x
14+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module M = await ME
2+
3+
module M = await (ME: MT)
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module M = await ME
2+
3+
module M = await (ME: MT)

jscomp/test/Import.js

Lines changed: 30 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

jscomp/test/Import.res

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,25 @@ let each = M1.forEach
3737

3838
module M2 = N.N1.O
3939
let each2 = M2.forEach
40+
41+
let f = async () => {
42+
module M3 = await Belt.List
43+
M3.forEach
44+
}
45+
46+
let f1 = async () => {
47+
module M3 = await (Belt.List: BeltList)
48+
M3.forEach
49+
}
50+
51+
let f2 = async () => {
52+
module M3 = await (Belt.List: BeltList)
53+
module M4 = await (Belt.List: BeltList)
54+
(M3.forEach, M4.forEach)
55+
}
56+
57+
let f3 = async () => {
58+
module M3 = await Belt.List
59+
module M4 = await Belt.List
60+
(M3.forEach, M4.forEach)
61+
}

0 commit comments

Comments
 (0)