A dynamic import `module M = await List` fails with `Unbound module type __List__` after a statement, in a callback and in other positions
Maintainer thường phản hồi trong vòng 1 ngày
Chưa có ai nhận issue này.
Đánh giá
- Độ khó
- 4/5
- Thời gian dự kiến
- 3-5 ngày
- Mức phù hợp với người mới
- 55/100
- Loại issue
- Lỗi
- Độ rõ ràng
- Đặc tả rõ ràng
- Mức độ hoạt động
- Sôi nổi
- Công nghệ
- ocaml
- Lĩnh vực
- compilers
Hướng nghiên cứu
Start by reading compiler/frontend/bs_builtin_ppx.ml, especially the Pexp_letmodule case in expr_mapper and aux in spelunk_vbs; then trace Ast_await.create_await_module_expression and structure_mapper's Pstr_value case. Reproduce the listed failing and working positions, including a Pstr_eval expression, and inspect existing coverage around #6431 and #7783. Done means every import rewritten by expr_mapper has its module type declared, with regression tests covering the reported positions.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
A dynamic import of a module, module M = await List, is rejected with Unbound module type __List__ depending on where it appears in the async function. A statement before it is enough:
let f = async () => {
Console.log("start")
module M = await List
M.length(list{1, 2})
}
f()->Promise.thenResolve(Console.log)->ignore
We've found a bug for you!
Repro.res:3:14-23
1 │ let f = async () => {
2 │ Console.log("start")
3 │ module M = await List
4 │ M.length(list{1, 2})
5 │ }
Unbound module type __List__
The source is valid and should log start and then 2. __List__ is a name generated by the compiler, not one the source uses. Without the Console.log("start") line, the same function compiles to a dynamic import and logs 2:
async function f() {
let M = await import("@rescript/runtime/lib/js/Stdlib_List.cjs");
return M.length({hd: 1, tl: {hd: 2, tl: /* [] */0}});
}
The same error (__List__, or __Array__ for await Array) comes from an import
- after any statement (
e; module M = await List), also in aswitcharm, - in an async function passed as an argument, e.g.
[1]->Array.map(async _ => {...})orp->Promise.then(async _ => {...}), or written in a record field, an array or a tuple, - in the body of a
try, aforor awhile, or in anifwithoutelse, - after
open U, a localexception E, a plain local modulemodule L = List, or a constrained importmodule L = await (List: ListT), - in an expression at the top level of a file, e.g.
run(async () => { module M = await List; ... })->ignore, or of a nested module.
It compiles directly in the body of a function bound by let, after a let, in a nested block, in both branches of if/else and of a ternary, as the first expression of a switch arm, under a return type annotation, in an async function bound by let inside another function, in Some(async () => ...), and after another unconstrained import.
Whether an import compiles also depends on the rest of the file. The function from the first example compiles when an earlier binding imports List in one of the positions that work:
let g = async () => {
module M = await List
M.length(list{1})
}
let f = async () => {
Console.log("start")
module M = await List
M.length(list{1, 2})
}
f()->Promise.thenResolve(Console.log)->ignore
async function f() {
console.log("start");
let M = await import("@rescript/runtime/lib/js/Stdlib_List.cjs");
return M.length({hd: 1, tl: {hd: 2, tl: /* [] */0}});
}
This logs start and 2. With g placed after f, f fails again with Unbound module type __List__.
In compiler/frontend/bs_builtin_ppx.ml, the Pexp_letmodule case of expr_mapper rewrites every module M = await List into an unpack of import at the package type module(__List__) (Ast_await.create_await_module_expression), wherever the expression is. The declaration module type __List__ = module type of List is added separately, before the binding, by the Pstr_value case of structure_mapper. To find the imports, aux in spelunk_vbs follows only Pexp_letmodule, Pexp_let, Pexp_braces, Pexp_ifthenelse with an else, Pexp_ternary, Pexp_construct with one argument, Pexp_fun, Pexp_constraint and Pexp_match. Every other expression ends the search (| _ -> acc), among them Pexp_sequence, Pexp_apply, Pexp_try, Pexp_for, Pexp_while, Pexp_open, Pexp_letexception, Pexp_record, Pexp_array and Pexp_tuple. A Pexp_letmodule that is not an unconstrained import ends it too, without its body being searched. A Pstr_eval item, an expression at the top level of a file or of a module, is not searched at all. local_module_type_decl declares each name once per structure, so a declaration found for an earlier binding also serves every later import of the same module, which is why f compiles when g comes before it. Searching every subexpression, and Pstr_eval items too, would declare the module type for each import that expr_mapper rewrites.
Writing the module type out avoids the hoisting: with module type ListT = module type of List at the top level, module M = await (List: ListT) compiles to await import(...) in all of the positions above.
Reproduced with 11.1.4 (with Js.log for Console.log), 12.0.0-alpha.6, 12.3.1, 13.0.0-alpha.6 and master (fc7444266). The search has followed a fixed list of expression shapes since #6431 (11.0.0-rc.5). #7783, the fix for #7173, added Pexp_constraint and Pexp_match to it in 12.0.0-beta.7, so 12.0.0-alpha.6 also fails in a switch arm and under a return type annotation.
Related: #7173, #7783.
- Ngôn ngữ chính
- OCaml
- Star
- 7.5k
- Fork
- 484
- Merge trung bình
- 17 giờ 9 phút
- Pull request đã merge (30 ngày)
- 264
Chuẩn bị môi trường
Khởi chạy dev container của dự án ngay trên trình duyệt, bằng tài khoản GitHub của bạn.
- Không có Dockerfile hay tệp Docker Compose
- Có mẫu pull request
- Đọc hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của rescript-lang/rescript
-
Exception analysis does not know the Temporal `fromStringOrThrow` functionsCó thể đã có người làm @cknitt đã nhận 1 ngày trước. Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
rescript-lang/rescript#9182 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 5/5 Hơn một tuần Mức phù hợp với người mới 25/100
rescript-lang/rescript#9233 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 3/5 1-2 ngày Mức phù hợp với người mới 72/100
rescript-lang/rescript#9229 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 4/5 3-5 ngày Mức phù hợp với người mới 44/100
rescript-lang/rescript#9228 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 4/5 3-5 ngày Mức phù hợp với người mới 45/100
rescript-lang/rescript#9227 ·
Maintainer thường phản hồi trong vòng 1 ngày
Tất cả issue của rescript-lang/rescript
Issue tương tự
-
A match arm above the largest i64 is compared as 0Có thể đã có người làm Có pull request liên kết đang mở hoặc đã được merge. Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 86/100
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 65/100
paradigmxyz/solar#2436 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
bug bulk-filed needs triage
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 76/100
Maintainer thường phản hồi trong vòng 2 ngày
-
area:codegen backend:slang bug direction:output
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 73/100
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 87/100
gleam-lang/gleam#6491 ·
Maintainer thường phản hồi trong vòng 1 ngày