From 0c2ff7e07eebee2c0840a451bb065348392a92ba Mon Sep 17 00:00:00 2001 From: Shulhi Sapli <913103+shulhi@users.noreply.github.com> Date: Mon, 12 Jan 2026 21:28:11 +0800 Subject: [PATCH 1/9] New ast to represent index access --- compiler/ml/ast_helper.ml | 1 + compiler/ml/ast_helper.mli | 7 +++++++ compiler/ml/ast_iterator.ml | 4 ++++ compiler/ml/ast_mapper.ml | 3 +++ compiler/ml/parsetree.ml | 3 +++ compiler/ml/pprintast.ml | 5 +++++ compiler/ml/printast.ml | 10 +++++++++ compiler/ml/tast_iterator.ml | 4 ++++ compiler/ml/tast_mapper.ml | 2 ++ compiler/ml/translcore.ml | 12 +++++++++++ compiler/ml/typecore.ml | 40 ++++++++++++++++++++++++++++++++++++ compiler/ml/typedtree.ml | 1 + compiler/ml/typedtree.mli | 1 + 13 files changed, 93 insertions(+) diff --git a/compiler/ml/ast_helper.ml b/compiler/ml/ast_helper.ml index 2fae640eb0..98e08031a4 100644 --- a/compiler/ml/ast_helper.ml +++ b/compiler/ml/ast_helper.ml @@ -174,6 +174,7 @@ module Exp = struct let record ?loc ?attrs a b = mk ?loc ?attrs (Pexp_record (a, b)) let field ?loc ?attrs a b = mk ?loc ?attrs (Pexp_field (a, b)) let setfield ?loc ?attrs a b c = mk ?loc ?attrs (Pexp_setfield (a, b, c)) + let index ?loc ?attrs a b c = mk ?loc ?attrs (Pexp_index (a, b, c)) let array ?loc ?attrs a = mk ?loc ?attrs (Pexp_array a) let ifthenelse ?loc ?attrs a b c = mk ?loc ?attrs (Pexp_ifthenelse (a, b, c)) let sequence ?loc ?attrs a b = mk ?loc ?attrs (Pexp_sequence (a, b)) diff --git a/compiler/ml/ast_helper.mli b/compiler/ml/ast_helper.mli index 11227b903a..a161433f95 100644 --- a/compiler/ml/ast_helper.mli +++ b/compiler/ml/ast_helper.mli @@ -163,6 +163,13 @@ module Exp : sig val field : ?loc:loc -> ?attrs:attrs -> expression -> lid -> expression val setfield : ?loc:loc -> ?attrs:attrs -> expression -> lid -> expression -> expression + val index : + ?loc:loc -> + ?attrs:attrs -> + expression -> + expression -> + expression option -> + expression val array : ?loc:loc -> ?attrs:attrs -> expression list -> expression val ifthenelse : ?loc:loc -> diff --git a/compiler/ml/ast_iterator.ml b/compiler/ml/ast_iterator.ml index a430bb0b7b..77320bd5ce 100644 --- a/compiler/ml/ast_iterator.ml +++ b/compiler/ml/ast_iterator.ml @@ -321,6 +321,10 @@ module E = struct sub.expr sub e1; iter_loc sub lid; sub.expr sub e2 + | Pexp_index (e1, e2, e3) -> + sub.expr sub e1; + sub.expr sub e2; + iter_opt (sub.expr sub) e3 | Pexp_array el -> List.iter (sub.expr sub) el | Pexp_ifthenelse (e1, e2, e3) -> sub.expr sub e1; diff --git a/compiler/ml/ast_mapper.ml b/compiler/ml/ast_mapper.ml index 673465477b..6f59d04aec 100644 --- a/compiler/ml/ast_mapper.ml +++ b/compiler/ml/ast_mapper.ml @@ -313,6 +313,9 @@ module E = struct field ~loc ~attrs (sub.expr sub e) (map_loc sub lid) | Pexp_setfield (e1, lid, e2) -> setfield ~loc ~attrs (sub.expr sub e1) (map_loc sub lid) (sub.expr sub e2) + | Pexp_index (e1, e2, e3) -> + index ~loc ~attrs (sub.expr sub e1) (sub.expr sub e2) + (map_opt (sub.expr sub) e3) | Pexp_array el -> array ~loc ~attrs (List.map (sub.expr sub) el) | Pexp_ifthenelse (e1, e2, e3) -> ifthenelse ~loc ~attrs (sub.expr sub e1) (sub.expr sub e2) diff --git a/compiler/ml/parsetree.ml b/compiler/ml/parsetree.ml index 78c9899f74..3d0870f503 100644 --- a/compiler/ml/parsetree.ml +++ b/compiler/ml/parsetree.ml @@ -279,6 +279,9 @@ and expression_desc = *) | Pexp_field of expression * Longident.t loc (* E.l *) | Pexp_setfield of expression * Longident.t loc * expression (* E1.l <- E2 *) + | Pexp_index of expression * expression * expression option + (* E1[E2] (None) - read access + E1[E2] = E3 (Some E3) - write access *) | Pexp_array of expression list (* [| E1; ...; En |] *) | Pexp_ifthenelse of expression * expression * expression option (* if E1 then E2 else E3 *) diff --git a/compiler/ml/pprintast.ml b/compiler/ml/pprintast.ml index 585ac64b81..9ea76c16d9 100644 --- a/compiler/ml/pprintast.ml +++ b/compiler/ml/pprintast.ml @@ -691,6 +691,11 @@ and expression ctxt f x = | Pexp_setfield (e1, li, e2) -> pp f "@[<2>%a.%a@ <-@ %a@]" (simple_expr ctxt) e1 longident_loc li (simple_expr ctxt) e2 + | Pexp_index (e1, e2, None) -> + pp f "%a.(%a)" (expression ctxt) e1 (expression ctxt) e2 + | Pexp_index (e1, e2, Some e3) -> + pp f "%a.(%a)@ <-@ %a" (expression ctxt) e1 (expression ctxt) e2 + (expression ctxt) e3 | Pexp_ifthenelse (e1, e2, eo) -> (* @;@[<2>else@ %a@]@] *) let fmt : (_, _, _) format = diff --git a/compiler/ml/printast.ml b/compiler/ml/printast.ml index 44d699eb38..ed0e68c2ef 100644 --- a/compiler/ml/printast.ml +++ b/compiler/ml/printast.ml @@ -294,6 +294,16 @@ and expression i ppf x = expression i ppf e1; longident_loc i ppf li; expression i ppf e2 + | Pexp_index (e1, e2, e3) -> ( + line i ppf "Pexp_index\n"; + expression i ppf e1; + line i ppf "index:\n"; + expression i ppf e2; + match e3 with + | None -> line i ppf "read access\n" + | Some e -> + line i ppf "write access:\n"; + expression i ppf e) | Pexp_array l -> line i ppf "Pexp_array\n"; list i expression ppf l diff --git a/compiler/ml/tast_iterator.ml b/compiler/ml/tast_iterator.ml index 5c12d3da4d..2641e7d77a 100644 --- a/compiler/ml/tast_iterator.ml +++ b/compiler/ml/tast_iterator.ml @@ -176,6 +176,10 @@ let expr sub {exp_extra; exp_desc; exp_env; _} = | Texp_setfield (exp1, _, _, exp2) -> sub.expr sub exp1; sub.expr sub exp2 + | Texp_index (exp1, exp2, expo) -> + sub.expr sub exp1; + sub.expr sub exp2; + Option.iter (sub.expr sub) expo | Texp_array list -> List.iter (sub.expr sub) list | Texp_ifthenelse (exp1, exp2, expo) -> sub.expr sub exp1; diff --git a/compiler/ml/tast_mapper.ml b/compiler/ml/tast_mapper.ml index 54eba02869..935c39d9c4 100644 --- a/compiler/ml/tast_mapper.ml +++ b/compiler/ml/tast_mapper.ml @@ -232,6 +232,8 @@ let expr sub x = | Texp_field (exp, lid, ld) -> Texp_field (sub.expr sub exp, lid, ld) | Texp_setfield (exp1, lid, ld, exp2) -> Texp_setfield (sub.expr sub exp1, lid, ld, sub.expr sub exp2) + | Texp_index (exp1, exp2, expo) -> + Texp_index (sub.expr sub exp1, sub.expr sub exp2, opt (sub.expr sub) expo) | Texp_array list -> Texp_array (List.map (sub.expr sub) list) | Texp_ifthenelse (exp1, exp2, expo) -> Texp_ifthenelse diff --git a/compiler/ml/translcore.ml b/compiler/ml/translcore.ml index 078cbf133a..be9556c4fe 100644 --- a/compiler/ml/translcore.ml +++ b/compiler/ml/translcore.ml @@ -891,6 +891,18 @@ and transl_exp0 (e : Typedtree.expression) : Lambda.lambda = Psetfield (lbl.lbl_pos + 1, Lambda.fld_record_extension_set lbl) in Lprim (access, [transl_exp arg; transl_exp newval], e.exp_loc) + | Texp_index (container, index, value_opt) -> ( + let container_lambda = transl_exp container in + let index_lambda = transl_exp index in + match value_opt with + | None -> + (* Read: translate to Parrayrefu primitive (unsafe array get) *) + Lprim (Parrayrefu, [container_lambda; index_lambda], e.exp_loc) + | Some value -> + (* Write: translate to Parraysetu primitive (unsafe array set) *) + let value_lambda = transl_exp value in + Lprim + (Parraysetu, [container_lambda; index_lambda; value_lambda], e.exp_loc)) | Texp_array expr_list -> let ll = transl_list expr_list in Lprim (Pmakearray Mutable, ll, e.exp_loc) diff --git a/compiler/ml/typecore.ml b/compiler/ml/typecore.ml index ee304dff7d..457c5e84be 100644 --- a/compiler/ml/typecore.ml +++ b/compiler/ml/typecore.ml @@ -182,6 +182,10 @@ let iter_expression f e = -> expr e1; expr e2 + | Pexp_index (e1, e2, eo) -> + expr e1; + expr e2; + may expr eo | Pexp_ifthenelse (e1, e2, eo) -> expr e1; expr e2; @@ -2834,6 +2838,42 @@ and type_expect_ ?deprecated_context ~context ?in_function ?(recarg = Rejected) exp_attributes = sexp.pexp_attributes; exp_env = env; } + | Pexp_index (scontainer, sindex, svalue_opt) -> ( + (* Type check as array access (same as current Array.get/set behavior) *) + let container = type_exp ~context:None env scontainer in + let index = + type_expect ~context:None env sindex (instance_def Predef.type_int) + in + match svalue_opt with + | None -> + (* Read access: arr[i] -> array<'a> -> int -> 'a *) + let element_type = newgenvar () in + let array_type = instance_def (Predef.type_array element_type) in + unify_exp ~context:None env container array_type; + rue + { + exp_desc = Texp_index (container, index, None); + exp_loc = loc; + exp_extra = []; + exp_type = instance env element_type; + exp_attributes = sexp.pexp_attributes; + exp_env = env; + } + | Some svalue -> + (* Write access: arr[i] = v -> array<'a> -> int -> 'a -> unit *) + let element_type = newgenvar () in + let array_type = instance_def (Predef.type_array element_type) in + unify_exp ~context:None env container array_type; + let value = type_expect ~context:None env svalue element_type in + rue + { + exp_desc = Texp_index (container, index, Some value); + exp_loc = loc; + exp_extra = []; + exp_type = instance_def Predef.type_unit; + exp_attributes = sexp.pexp_attributes; + exp_env = env; + }) | Pexp_array sargl -> let ty = newgenvar () in let to_unify = Predef.type_array ty in diff --git a/compiler/ml/typedtree.ml b/compiler/ml/typedtree.ml index e7274f1245..6dccdb2599 100644 --- a/compiler/ml/typedtree.ml +++ b/compiler/ml/typedtree.ml @@ -106,6 +106,7 @@ and expression_desc = | Texp_field of expression * Longident.t loc * label_description | Texp_setfield of expression * Longident.t loc * label_description * expression + | Texp_index of expression * expression * expression option | Texp_array of expression list | Texp_ifthenelse of expression * expression * expression option | Texp_sequence of expression * expression diff --git a/compiler/ml/typedtree.mli b/compiler/ml/typedtree.mli index b1e7083fc7..416577153b 100644 --- a/compiler/ml/typedtree.mli +++ b/compiler/ml/typedtree.mli @@ -207,6 +207,7 @@ and expression_desc = | Texp_field of expression * Longident.t loc * label_description | Texp_setfield of expression * Longident.t loc * label_description * expression + | Texp_index of expression * expression * expression option | Texp_array of expression list | Texp_ifthenelse of expression * expression * expression option | Texp_sequence of expression * expression From 5b3a4b11d18d5c8ba9b16e582e412120bdf3fddb Mon Sep 17 00:00:00 2001 From: Shulhi Sapli <913103+shulhi@users.noreply.github.com> Date: Mon, 12 Jan 2026 21:36:02 +0800 Subject: [PATCH 2/9] Handle printer --- compiler/syntax/src/res_ast_debugger.ml | 7 +++++++ compiler/syntax/src/res_comments_table.ml | 7 +++++++ compiler/syntax/src/res_printer.ml | 25 +++++++++++++++++++++++ 3 files changed, 39 insertions(+) diff --git a/compiler/syntax/src/res_ast_debugger.ml b/compiler/syntax/src/res_ast_debugger.ml index 52a57b89c5..cdfe67b6ad 100644 --- a/compiler/syntax/src/res_ast_debugger.ml +++ b/compiler/syntax/src/res_ast_debugger.ml @@ -641,6 +641,13 @@ module SexpAst = struct longident longident_loc.Asttypes.txt; expression expr2; ] + | Pexp_index (e1, e2, e3) -> + Sexp.list + ([Sexp.atom "Pexp_index"; expression e1; expression e2] + @ + match e3 with + | None -> [] + | Some e -> [expression e]) | Pexp_array exprs -> Sexp.list [Sexp.atom "Pexp_array"; Sexp.list (map_empty ~f:expression exprs)] diff --git a/compiler/syntax/src/res_comments_table.ml b/compiler/syntax/src/res_comments_table.ml index 6774b2bc2b..4d414bfb79 100644 --- a/compiler/syntax/src/res_comments_table.ml +++ b/compiler/syntax/src/res_comments_table.ml @@ -476,6 +476,7 @@ let rec is_block_expr expr = | Pexp_constraint (expr, _) when is_block_expr expr -> true | Pexp_field (expr, _) when is_block_expr expr -> true | Pexp_setfield (expr, _, _) when is_block_expr expr -> true + | Pexp_index (expr, _, _) when is_block_expr expr -> true | _ -> false let is_if_then_else_expr expr = @@ -1313,6 +1314,12 @@ and walk_expression expr t comments = attach t.leading expr2.pexp_loc leading; walk_expression expr2 t inside; attach t.trailing expr2.pexp_loc trailing + | Pexp_index (container, index, value_opt) -> ( + walk_expression container t comments; + walk_expression index t comments; + match value_opt with + | None -> () + | Some value -> walk_expression value t comments) | Pexp_ifthenelse (if_expr, then_expr, else_expr) -> ( let leading, rest = partition_leading_trailing comments expr.pexp_loc in attach t.leading expr.pexp_loc leading; diff --git a/compiler/syntax/src/res_printer.ml b/compiler/syntax/src/res_printer.ml index 2010d23f6d..b157466d8e 100644 --- a/compiler/syntax/src/res_printer.ml +++ b/compiler/syntax/src/res_printer.ml @@ -3374,6 +3374,31 @@ and print_expression ~state (e : Parsetree.expression) cmt_tbl = | Pexp_setfield (expr1, longident_loc, expr2) -> print_set_field_expr ~state e.pexp_attributes expr1 longident_loc expr2 e.pexp_loc cmt_tbl + | Pexp_index (container, index, value_opt) -> ( + let container_doc = + let doc = print_expression_with_comments ~state container cmt_tbl in + match Parens.field_expr container with + | Parens.Parenthesized -> add_parens doc + | Braced braces -> print_braces doc container braces + | Nothing -> doc + in + let index_doc = print_expression_with_comments ~state index cmt_tbl in + match value_opt with + | None -> + (* Read: container[index] *) + Doc.concat [container_doc; Doc.lbracket; index_doc; Doc.rbracket] + | Some value -> + (* Write: container[index] = value *) + let value_doc = print_expression_with_comments ~state value cmt_tbl in + Doc.concat + [ + container_doc; + Doc.lbracket; + index_doc; + Doc.rbracket; + Doc.text " = "; + value_doc; + ]) | Pexp_ifthenelse (_ifExpr, _thenExpr, _elseExpr) when ParsetreeViewer.is_ternary_expr e -> let parts, alternate = ParsetreeViewer.collect_ternary_parts e in From fe433c7dffe2774cae01c3161902f3924ce06b4e Mon Sep 17 00:00:00 2001 From: Shulhi Sapli <913103+shulhi@users.noreply.github.com> Date: Mon, 12 Jan 2026 21:36:28 +0800 Subject: [PATCH 3/9] Fix build errors --- analysis/src/Utils.ml | 1 + compiler/frontend/bs_ast_mapper.ml | 3 +++ compiler/ml/ast_mapper_to0.ml | 21 +++++++++++++++++++++ compiler/ml/depend.ml | 4 ++++ compiler/ml/printtyped.ml | 10 ++++++++++ compiler/ml/rec_check.ml | 9 +++++++-- compiler/ml/typedtreeIter.ml | 6 ++++++ 7 files changed, 52 insertions(+), 2 deletions(-) diff --git a/analysis/src/Utils.ml b/analysis/src/Utils.ml index 863598dc56..d930b7edc2 100644 --- a/analysis/src/Utils.ml +++ b/analysis/src/Utils.ml @@ -95,6 +95,7 @@ let identifyPexp pexp = | Pexp_record _ -> "Pexp_record" | Pexp_field _ -> "Pexp_field" | Pexp_setfield _ -> "Pexp_setfield" + | Pexp_index _ -> "Pexp_index" | Pexp_array _ -> "Pexp_array" | Pexp_ifthenelse _ -> "Pexp_ifthenelse" | Pexp_sequence _ -> "Pexp_sequence" diff --git a/compiler/frontend/bs_ast_mapper.ml b/compiler/frontend/bs_ast_mapper.ml index 292e199b5a..1ce6f542bc 100644 --- a/compiler/frontend/bs_ast_mapper.ml +++ b/compiler/frontend/bs_ast_mapper.ml @@ -350,6 +350,9 @@ module E = struct field ~loc ~attrs (sub.expr sub e) (map_loc sub lid) | Pexp_setfield (e1, lid, e2) -> setfield ~loc ~attrs (sub.expr sub e1) (map_loc sub lid) (sub.expr sub e2) + | Pexp_index (e1, e2, e3) -> + index ~loc ~attrs (sub.expr sub e1) (sub.expr sub e2) + (map_opt (sub.expr sub) e3) | Pexp_array el -> array ~loc ~attrs (List.map (sub.expr sub) el) | Pexp_ifthenelse (e1, e2, e3) -> ifthenelse ~loc ~attrs (sub.expr sub e1) (sub.expr sub e2) diff --git a/compiler/ml/ast_mapper_to0.ml b/compiler/ml/ast_mapper_to0.ml index d0ac43d737..23bc01cd72 100644 --- a/compiler/ml/ast_mapper_to0.ml +++ b/compiler/ml/ast_mapper_to0.ml @@ -439,6 +439,27 @@ module E = struct field ~loc ~attrs (sub.expr sub e) (map_loc sub lid) | Pexp_setfield (e1, lid, e2) -> setfield ~loc ~attrs (sub.expr sub e1) (map_loc sub lid) (sub.expr sub e2) + | Pexp_index (e1, e2, e3) -> ( + (* Map back to Array.get/Array.set for parsetree0 compatibility *) + let container = sub.expr sub e1 in + let index = sub.expr sub e2 in + match e3 with + | None -> + (* Read: Array.get(container, index) *) + let array_get = + ident ~loc + (mknoloc (Longident.Ldot (Longident.Lident "Array", "get"))) + in + apply ~loc ~attrs array_get [(Nolabel, container); (Nolabel, index)] + | Some value -> + (* Write: Array.set(container, index, value) *) + let array_set = + ident ~loc + (mknoloc (Longident.Ldot (Longident.Lident "Array", "set"))) + in + let value_expr = sub.expr sub value in + apply ~loc ~attrs array_set + [(Nolabel, container); (Nolabel, index); (Nolabel, value_expr)]) | Pexp_array el -> array ~loc ~attrs (List.map (sub.expr sub) el) | Pexp_ifthenelse (e1, e2, e3) -> ifthenelse ~loc ~attrs (sub.expr sub e1) (sub.expr sub e2) diff --git a/compiler/ml/depend.ml b/compiler/ml/depend.ml index e5e39eb4b5..011b556ab5 100644 --- a/compiler/ml/depend.ml +++ b/compiler/ml/depend.ml @@ -248,6 +248,10 @@ let rec add_expr bv exp = add_expr bv e1; add bv fld; add_expr bv e2 + | Pexp_index (e1, e2, e3) -> + add_expr bv e1; + add_expr bv e2; + add_opt add_expr bv e3 | Pexp_array el -> List.iter (add_expr bv) el | Pexp_ifthenelse (e1, e2, opte3) -> add_expr bv e1; diff --git a/compiler/ml/printtyped.ml b/compiler/ml/printtyped.ml index 6e36b4276c..a74e1d823c 100644 --- a/compiler/ml/printtyped.ml +++ b/compiler/ml/printtyped.ml @@ -329,6 +329,16 @@ and expression i ppf x = expression i ppf e1; longident i ppf li; expression i ppf e2 + | Texp_index (e1, e2, e3) -> ( + line i ppf "Texp_index\n"; + expression i ppf e1; + line i ppf "index:\n"; + expression i ppf e2; + match e3 with + | None -> line i ppf "read access\n" + | Some e -> + line i ppf "write access:\n"; + expression i ppf e) | Texp_array l -> line i ppf "Texp_array\n"; list i expression ppf l diff --git a/compiler/ml/rec_check.ml b/compiler/ml/rec_check.ml index 3d016a7438..6c18a20a08 100644 --- a/compiler/ml/rec_check.ml +++ b/compiler/ml/rec_check.ml @@ -196,8 +196,8 @@ let rec classify_expression : Typedtree.expression -> sd = classify_expression e | Texp_ident _ | Texp_for _ | Texp_constant _ | Texp_tuple _ | Texp_array _ | Texp_construct _ | Texp_variant _ | Texp_record _ | Texp_setfield _ - | Texp_while _ | Texp_pack _ | Texp_function _ | Texp_extension_constructor _ - -> + | Texp_index _ | Texp_while _ | Texp_pack _ | Texp_function _ + | Texp_extension_constructor _ -> Static | Texp_apply {funct = {exp_desc = Texp_ident (_, _, vd)}} when is_ref vd -> Static @@ -273,6 +273,11 @@ let rec expression : Env.env -> Typedtree.expression -> Use.t = (join (expression env ifso) (option expression env ifnot))) | Texp_setfield (e1, _, _, e2) -> Use.(join (inspect (expression env e1)) (inspect (expression env e2))) + | Texp_index (e1, e2, e3) -> + Use.( + join + (join (inspect (expression env e1)) (inspect (expression env e2))) + (inspect (option expression env e3))) | Texp_sequence (e1, e2) -> Use.(join (discard (expression env e1)) (expression env e2)) | Texp_while (e1, e2) -> diff --git a/compiler/ml/typedtreeIter.ml b/compiler/ml/typedtreeIter.ml index 9a31b9b5b9..ea864004eb 100644 --- a/compiler/ml/typedtreeIter.ml +++ b/compiler/ml/typedtreeIter.ml @@ -261,6 +261,12 @@ end = struct | Texp_setfield (exp1, _, _label, exp2) -> iter_expression exp1; iter_expression exp2 + | Texp_index (exp1, exp2, expo) -> ( + iter_expression exp1; + iter_expression exp2; + match expo with + | None -> () + | Some exp -> iter_expression exp) | Texp_array list -> List.iter iter_expression list | Texp_ifthenelse (exp1, exp2, expo) -> ( iter_expression exp1; From ce51bf024e4e2d66803f01df229411f8f8bd0d67 Mon Sep 17 00:00:00 2001 From: Shulhi Sapli <913103+shulhi@users.noreply.github.com> Date: Mon, 12 Jan 2026 23:25:13 +0800 Subject: [PATCH 4/9] Split to two separate nodes --- compiler/frontend/bs_ast_mapper.ml | 5 +- compiler/ml/ast_helper.ml | 3 +- compiler/ml/ast_helper.mli | 5 +- compiler/ml/ast_iterator.ml | 7 ++- compiler/ml/ast_mapper.ml | 5 +- compiler/ml/ast_mapper_to0.ml | 35 +++++++------- compiler/ml/depend.ml | 7 ++- compiler/ml/parsetree.ml | 5 +- compiler/ml/pprintast.ml | 4 +- compiler/ml/printast.ml | 14 +++--- compiler/ml/printtyped.ml | 14 +++--- compiler/ml/rec_check.ml | 10 ++-- compiler/ml/tast_iterator.ml | 7 ++- compiler/ml/tast_mapper.ml | 6 ++- compiler/ml/translcore.ml | 19 ++++---- compiler/ml/typecore.ml | 75 ++++++++++++++++-------------- compiler/ml/typedtree.ml | 3 +- compiler/ml/typedtree.mli | 3 +- compiler/ml/typedtreeIter.ml | 9 ++-- 19 files changed, 129 insertions(+), 107 deletions(-) diff --git a/compiler/frontend/bs_ast_mapper.ml b/compiler/frontend/bs_ast_mapper.ml index 1ce6f542bc..afa7a7559f 100644 --- a/compiler/frontend/bs_ast_mapper.ml +++ b/compiler/frontend/bs_ast_mapper.ml @@ -350,9 +350,10 @@ module E = struct field ~loc ~attrs (sub.expr sub e) (map_loc sub lid) | Pexp_setfield (e1, lid, e2) -> setfield ~loc ~attrs (sub.expr sub e1) (map_loc sub lid) (sub.expr sub e2) - | Pexp_index (e1, e2, e3) -> + | Pexp_index (e1, e2) -> index ~loc ~attrs (sub.expr sub e1) (sub.expr sub e2) - (map_opt (sub.expr sub) e3) + | Pexp_setindex (e1, e2, e3) -> + setindex ~loc ~attrs (sub.expr sub e1) (sub.expr sub e2) (sub.expr sub e3) | Pexp_array el -> array ~loc ~attrs (List.map (sub.expr sub) el) | Pexp_ifthenelse (e1, e2, e3) -> ifthenelse ~loc ~attrs (sub.expr sub e1) (sub.expr sub e2) diff --git a/compiler/ml/ast_helper.ml b/compiler/ml/ast_helper.ml index 98e08031a4..cd55b743ca 100644 --- a/compiler/ml/ast_helper.ml +++ b/compiler/ml/ast_helper.ml @@ -174,7 +174,8 @@ module Exp = struct let record ?loc ?attrs a b = mk ?loc ?attrs (Pexp_record (a, b)) let field ?loc ?attrs a b = mk ?loc ?attrs (Pexp_field (a, b)) let setfield ?loc ?attrs a b c = mk ?loc ?attrs (Pexp_setfield (a, b, c)) - let index ?loc ?attrs a b c = mk ?loc ?attrs (Pexp_index (a, b, c)) + let index ?loc ?attrs a b = mk ?loc ?attrs (Pexp_index (a, b)) + let setindex ?loc ?attrs a b c = mk ?loc ?attrs (Pexp_setindex (a, b, c)) let array ?loc ?attrs a = mk ?loc ?attrs (Pexp_array a) let ifthenelse ?loc ?attrs a b c = mk ?loc ?attrs (Pexp_ifthenelse (a, b, c)) let sequence ?loc ?attrs a b = mk ?loc ?attrs (Pexp_sequence (a, b)) diff --git a/compiler/ml/ast_helper.mli b/compiler/ml/ast_helper.mli index a161433f95..ba3830aac0 100644 --- a/compiler/ml/ast_helper.mli +++ b/compiler/ml/ast_helper.mli @@ -163,12 +163,13 @@ module Exp : sig val field : ?loc:loc -> ?attrs:attrs -> expression -> lid -> expression val setfield : ?loc:loc -> ?attrs:attrs -> expression -> lid -> expression -> expression - val index : + val index : ?loc:loc -> ?attrs:attrs -> expression -> expression -> expression + val setindex : ?loc:loc -> ?attrs:attrs -> expression -> expression -> - expression option -> + expression -> expression val array : ?loc:loc -> ?attrs:attrs -> expression list -> expression val ifthenelse : diff --git a/compiler/ml/ast_iterator.ml b/compiler/ml/ast_iterator.ml index 77320bd5ce..ad61a99377 100644 --- a/compiler/ml/ast_iterator.ml +++ b/compiler/ml/ast_iterator.ml @@ -321,10 +321,13 @@ module E = struct sub.expr sub e1; iter_loc sub lid; sub.expr sub e2 - | Pexp_index (e1, e2, e3) -> + | Pexp_index (e1, e2) -> + sub.expr sub e1; + sub.expr sub e2 + | Pexp_setindex (e1, e2, e3) -> sub.expr sub e1; sub.expr sub e2; - iter_opt (sub.expr sub) e3 + sub.expr sub e3 | Pexp_array el -> List.iter (sub.expr sub) el | Pexp_ifthenelse (e1, e2, e3) -> sub.expr sub e1; diff --git a/compiler/ml/ast_mapper.ml b/compiler/ml/ast_mapper.ml index 6f59d04aec..20683bfa98 100644 --- a/compiler/ml/ast_mapper.ml +++ b/compiler/ml/ast_mapper.ml @@ -313,9 +313,10 @@ module E = struct field ~loc ~attrs (sub.expr sub e) (map_loc sub lid) | Pexp_setfield (e1, lid, e2) -> setfield ~loc ~attrs (sub.expr sub e1) (map_loc sub lid) (sub.expr sub e2) - | Pexp_index (e1, e2, e3) -> + | Pexp_index (e1, e2) -> index ~loc ~attrs (sub.expr sub e1) (sub.expr sub e2) - (map_opt (sub.expr sub) e3) + | Pexp_setindex (e1, e2, e3) -> + setindex ~loc ~attrs (sub.expr sub e1) (sub.expr sub e2) (sub.expr sub e3) | Pexp_array el -> array ~loc ~attrs (List.map (sub.expr sub) el) | Pexp_ifthenelse (e1, e2, e3) -> ifthenelse ~loc ~attrs (sub.expr sub e1) (sub.expr sub e2) diff --git a/compiler/ml/ast_mapper_to0.ml b/compiler/ml/ast_mapper_to0.ml index 23bc01cd72..3f0b10345f 100644 --- a/compiler/ml/ast_mapper_to0.ml +++ b/compiler/ml/ast_mapper_to0.ml @@ -439,27 +439,24 @@ module E = struct field ~loc ~attrs (sub.expr sub e) (map_loc sub lid) | Pexp_setfield (e1, lid, e2) -> setfield ~loc ~attrs (sub.expr sub e1) (map_loc sub lid) (sub.expr sub e2) - | Pexp_index (e1, e2, e3) -> ( - (* Map back to Array.get/Array.set for parsetree0 compatibility *) + | Pexp_index (e1, e2) -> + (* Map back to Array.get for parsetree0 compatibility *) let container = sub.expr sub e1 in let index = sub.expr sub e2 in - match e3 with - | None -> - (* Read: Array.get(container, index) *) - let array_get = - ident ~loc - (mknoloc (Longident.Ldot (Longident.Lident "Array", "get"))) - in - apply ~loc ~attrs array_get [(Nolabel, container); (Nolabel, index)] - | Some value -> - (* Write: Array.set(container, index, value) *) - let array_set = - ident ~loc - (mknoloc (Longident.Ldot (Longident.Lident "Array", "set"))) - in - let value_expr = sub.expr sub value in - apply ~loc ~attrs array_set - [(Nolabel, container); (Nolabel, index); (Nolabel, value_expr)]) + let array_get = + ident ~loc (mknoloc (Longident.Ldot (Longident.Lident "Array", "get"))) + in + apply ~loc ~attrs array_get [(Nolabel, container); (Nolabel, index)] + | Pexp_setindex (e1, e2, e3) -> + (* Map back to Array.set for parsetree0 compatibility *) + let container = sub.expr sub e1 in + let index = sub.expr sub e2 in + let value_expr = sub.expr sub e3 in + let array_set = + ident ~loc (mknoloc (Longident.Ldot (Longident.Lident "Array", "set"))) + in + apply ~loc ~attrs array_set + [(Nolabel, container); (Nolabel, index); (Nolabel, value_expr)] | Pexp_array el -> array ~loc ~attrs (List.map (sub.expr sub) el) | Pexp_ifthenelse (e1, e2, e3) -> ifthenelse ~loc ~attrs (sub.expr sub e1) (sub.expr sub e2) diff --git a/compiler/ml/depend.ml b/compiler/ml/depend.ml index 011b556ab5..6b396bb618 100644 --- a/compiler/ml/depend.ml +++ b/compiler/ml/depend.ml @@ -248,10 +248,13 @@ let rec add_expr bv exp = add_expr bv e1; add bv fld; add_expr bv e2 - | Pexp_index (e1, e2, e3) -> + | Pexp_index (e1, e2) -> + add_expr bv e1; + add_expr bv e2 + | Pexp_setindex (e1, e2, e3) -> add_expr bv e1; add_expr bv e2; - add_opt add_expr bv e3 + add_expr bv e3 | Pexp_array el -> List.iter (add_expr bv) el | Pexp_ifthenelse (e1, e2, opte3) -> add_expr bv e1; diff --git a/compiler/ml/parsetree.ml b/compiler/ml/parsetree.ml index 3d0870f503..1d35143d99 100644 --- a/compiler/ml/parsetree.ml +++ b/compiler/ml/parsetree.ml @@ -279,9 +279,8 @@ and expression_desc = *) | Pexp_field of expression * Longident.t loc (* E.l *) | Pexp_setfield of expression * Longident.t loc * expression (* E1.l <- E2 *) - | Pexp_index of expression * expression * expression option - (* E1[E2] (None) - read access - E1[E2] = E3 (Some E3) - write access *) + | Pexp_index of expression * expression (* E1[E2] *) + | Pexp_setindex of expression * expression * expression (* E1[E2] = E3 *) | Pexp_array of expression list (* [| E1; ...; En |] *) | Pexp_ifthenelse of expression * expression * expression option (* if E1 then E2 else E3 *) diff --git a/compiler/ml/pprintast.ml b/compiler/ml/pprintast.ml index 9ea76c16d9..743b1dfba9 100644 --- a/compiler/ml/pprintast.ml +++ b/compiler/ml/pprintast.ml @@ -691,9 +691,9 @@ and expression ctxt f x = | Pexp_setfield (e1, li, e2) -> pp f "@[<2>%a.%a@ <-@ %a@]" (simple_expr ctxt) e1 longident_loc li (simple_expr ctxt) e2 - | Pexp_index (e1, e2, None) -> + | Pexp_index (e1, e2) -> pp f "%a.(%a)" (expression ctxt) e1 (expression ctxt) e2 - | Pexp_index (e1, e2, Some e3) -> + | Pexp_setindex (e1, e2, e3) -> pp f "%a.(%a)@ <-@ %a" (expression ctxt) e1 (expression ctxt) e2 (expression ctxt) e3 | Pexp_ifthenelse (e1, e2, eo) -> diff --git a/compiler/ml/printast.ml b/compiler/ml/printast.ml index ed0e68c2ef..22d7aaa8a3 100644 --- a/compiler/ml/printast.ml +++ b/compiler/ml/printast.ml @@ -294,16 +294,18 @@ and expression i ppf x = expression i ppf e1; longident_loc i ppf li; expression i ppf e2 - | Pexp_index (e1, e2, e3) -> ( + | Pexp_index (e1, e2) -> line i ppf "Pexp_index\n"; expression i ppf e1; line i ppf "index:\n"; + expression i ppf e2 + | Pexp_setindex (e1, e2, e3) -> + line i ppf "Pexp_setindex\n"; + expression i ppf e1; + line i ppf "index:\n"; expression i ppf e2; - match e3 with - | None -> line i ppf "read access\n" - | Some e -> - line i ppf "write access:\n"; - expression i ppf e) + line i ppf "value:\n"; + expression i ppf e3 | Pexp_array l -> line i ppf "Pexp_array\n"; list i expression ppf l diff --git a/compiler/ml/printtyped.ml b/compiler/ml/printtyped.ml index a74e1d823c..a334dd07ab 100644 --- a/compiler/ml/printtyped.ml +++ b/compiler/ml/printtyped.ml @@ -329,16 +329,18 @@ and expression i ppf x = expression i ppf e1; longident i ppf li; expression i ppf e2 - | Texp_index (e1, e2, e3) -> ( + | Texp_index (e1, e2) -> line i ppf "Texp_index\n"; expression i ppf e1; line i ppf "index:\n"; + expression i ppf e2 + | Texp_setindex (e1, e2, e3) -> + line i ppf "Texp_setindex\n"; + expression i ppf e1; + line i ppf "index:\n"; expression i ppf e2; - match e3 with - | None -> line i ppf "read access\n" - | Some e -> - line i ppf "write access:\n"; - expression i ppf e) + line i ppf "value:\n"; + expression i ppf e3 | Texp_array l -> line i ppf "Texp_array\n"; list i expression ppf l diff --git a/compiler/ml/rec_check.ml b/compiler/ml/rec_check.ml index 6c18a20a08..95217d1318 100644 --- a/compiler/ml/rec_check.ml +++ b/compiler/ml/rec_check.ml @@ -196,8 +196,8 @@ let rec classify_expression : Typedtree.expression -> sd = classify_expression e | Texp_ident _ | Texp_for _ | Texp_constant _ | Texp_tuple _ | Texp_array _ | Texp_construct _ | Texp_variant _ | Texp_record _ | Texp_setfield _ - | Texp_index _ | Texp_while _ | Texp_pack _ | Texp_function _ - | Texp_extension_constructor _ -> + | Texp_index _ | Texp_setindex _ | Texp_while _ | Texp_pack _ + | Texp_function _ | Texp_extension_constructor _ -> Static | Texp_apply {funct = {exp_desc = Texp_ident (_, _, vd)}} when is_ref vd -> Static @@ -273,11 +273,13 @@ let rec expression : Env.env -> Typedtree.expression -> Use.t = (join (expression env ifso) (option expression env ifnot))) | Texp_setfield (e1, _, _, e2) -> Use.(join (inspect (expression env e1)) (inspect (expression env e2))) - | Texp_index (e1, e2, e3) -> + | Texp_index (e1, e2) -> + Use.(join (inspect (expression env e1)) (inspect (expression env e2))) + | Texp_setindex (e1, e2, e3) -> Use.( join (join (inspect (expression env e1)) (inspect (expression env e2))) - (inspect (option expression env e3))) + (inspect (expression env e3))) | Texp_sequence (e1, e2) -> Use.(join (discard (expression env e1)) (expression env e2)) | Texp_while (e1, e2) -> diff --git a/compiler/ml/tast_iterator.ml b/compiler/ml/tast_iterator.ml index 2641e7d77a..56658826f1 100644 --- a/compiler/ml/tast_iterator.ml +++ b/compiler/ml/tast_iterator.ml @@ -176,10 +176,13 @@ let expr sub {exp_extra; exp_desc; exp_env; _} = | Texp_setfield (exp1, _, _, exp2) -> sub.expr sub exp1; sub.expr sub exp2 - | Texp_index (exp1, exp2, expo) -> + | Texp_index (exp1, exp2) -> + sub.expr sub exp1; + sub.expr sub exp2 + | Texp_setindex (exp1, exp2, exp3) -> sub.expr sub exp1; sub.expr sub exp2; - Option.iter (sub.expr sub) expo + sub.expr sub exp3 | Texp_array list -> List.iter (sub.expr sub) list | Texp_ifthenelse (exp1, exp2, expo) -> sub.expr sub exp1; diff --git a/compiler/ml/tast_mapper.ml b/compiler/ml/tast_mapper.ml index 935c39d9c4..8547012c97 100644 --- a/compiler/ml/tast_mapper.ml +++ b/compiler/ml/tast_mapper.ml @@ -232,8 +232,10 @@ let expr sub x = | Texp_field (exp, lid, ld) -> Texp_field (sub.expr sub exp, lid, ld) | Texp_setfield (exp1, lid, ld, exp2) -> Texp_setfield (sub.expr sub exp1, lid, ld, sub.expr sub exp2) - | Texp_index (exp1, exp2, expo) -> - Texp_index (sub.expr sub exp1, sub.expr sub exp2, opt (sub.expr sub) expo) + | Texp_index (exp1, exp2) -> + Texp_index (sub.expr sub exp1, sub.expr sub exp2) + | Texp_setindex (exp1, exp2, exp3) -> + Texp_setindex (sub.expr sub exp1, sub.expr sub exp2, sub.expr sub exp3) | Texp_array list -> Texp_array (List.map (sub.expr sub) list) | Texp_ifthenelse (exp1, exp2, expo) -> Texp_ifthenelse diff --git a/compiler/ml/translcore.ml b/compiler/ml/translcore.ml index be9556c4fe..4f31957aa1 100644 --- a/compiler/ml/translcore.ml +++ b/compiler/ml/translcore.ml @@ -891,18 +891,17 @@ and transl_exp0 (e : Typedtree.expression) : Lambda.lambda = Psetfield (lbl.lbl_pos + 1, Lambda.fld_record_extension_set lbl) in Lprim (access, [transl_exp arg; transl_exp newval], e.exp_loc) - | Texp_index (container, index, value_opt) -> ( + | Texp_index (container, index) -> + (* Read: translate to Parrayrefu primitive (unsafe array get) *) let container_lambda = transl_exp container in let index_lambda = transl_exp index in - match value_opt with - | None -> - (* Read: translate to Parrayrefu primitive (unsafe array get) *) - Lprim (Parrayrefu, [container_lambda; index_lambda], e.exp_loc) - | Some value -> - (* Write: translate to Parraysetu primitive (unsafe array set) *) - let value_lambda = transl_exp value in - Lprim - (Parraysetu, [container_lambda; index_lambda; value_lambda], e.exp_loc)) + Lprim (Parrayrefu, [container_lambda; index_lambda], e.exp_loc) + | Texp_setindex (container, index, value) -> + (* Write: translate to Parraysetu primitive (unsafe array set) *) + let container_lambda = transl_exp container in + let index_lambda = transl_exp index in + let value_lambda = transl_exp value in + Lprim (Parraysetu, [container_lambda; index_lambda; value_lambda], e.exp_loc) | Texp_array expr_list -> let ll = transl_list expr_list in Lprim (Pmakearray Mutable, ll, e.exp_loc) diff --git a/compiler/ml/typecore.ml b/compiler/ml/typecore.ml index 457c5e84be..6934d9f80b 100644 --- a/compiler/ml/typecore.ml +++ b/compiler/ml/typecore.ml @@ -178,14 +178,16 @@ let iter_expression f e = | Pexp_letexception (_, e) | Pexp_field (e, _) -> expr e - | Pexp_while (e1, e2) | Pexp_sequence (e1, e2) | Pexp_setfield (e1, _, e2) - -> + | Pexp_while (e1, e2) + | Pexp_sequence (e1, e2) + | Pexp_setfield (e1, _, e2) + | Pexp_index (e1, e2) -> expr e1; expr e2 - | Pexp_index (e1, e2, eo) -> + | Pexp_setindex (e1, e2, e3) -> expr e1; expr e2; - may expr eo + expr e3 | Pexp_ifthenelse (e1, e2, eo) -> expr e1; expr e2; @@ -2838,42 +2840,43 @@ and type_expect_ ?deprecated_context ~context ?in_function ?(recarg = Rejected) exp_attributes = sexp.pexp_attributes; exp_env = env; } - | Pexp_index (scontainer, sindex, svalue_opt) -> ( - (* Type check as array access (same as current Array.get/set behavior) *) + | Pexp_index (scontainer, sindex) -> + (* Read access: arr[i] -> array<'a> -> int -> 'a *) let container = type_exp ~context:None env scontainer in let index = type_expect ~context:None env sindex (instance_def Predef.type_int) in - match svalue_opt with - | None -> - (* Read access: arr[i] -> array<'a> -> int -> 'a *) - let element_type = newgenvar () in - let array_type = instance_def (Predef.type_array element_type) in - unify_exp ~context:None env container array_type; - rue - { - exp_desc = Texp_index (container, index, None); - exp_loc = loc; - exp_extra = []; - exp_type = instance env element_type; - exp_attributes = sexp.pexp_attributes; - exp_env = env; - } - | Some svalue -> - (* Write access: arr[i] = v -> array<'a> -> int -> 'a -> unit *) - let element_type = newgenvar () in - let array_type = instance_def (Predef.type_array element_type) in - unify_exp ~context:None env container array_type; - let value = type_expect ~context:None env svalue element_type in - rue - { - exp_desc = Texp_index (container, index, Some value); - exp_loc = loc; - exp_extra = []; - exp_type = instance_def Predef.type_unit; - exp_attributes = sexp.pexp_attributes; - exp_env = env; - }) + let element_type = newgenvar () in + let array_type = instance_def (Predef.type_array element_type) in + unify_exp ~context:None env container array_type; + rue + { + exp_desc = Texp_index (container, index); + exp_loc = loc; + exp_extra = []; + exp_type = instance env element_type; + exp_attributes = sexp.pexp_attributes; + exp_env = env; + } + | Pexp_setindex (scontainer, sindex, svalue) -> + (* Write access: arr[i] = v -> array<'a> -> int -> 'a -> unit *) + let container = type_exp ~context:None env scontainer in + let index = + type_expect ~context:None env sindex (instance_def Predef.type_int) + in + let element_type = newgenvar () in + let array_type = instance_def (Predef.type_array element_type) in + unify_exp ~context:None env container array_type; + let value = type_expect ~context:None env svalue element_type in + rue + { + exp_desc = Texp_setindex (container, index, value); + exp_loc = loc; + exp_extra = []; + exp_type = instance_def Predef.type_unit; + exp_attributes = sexp.pexp_attributes; + exp_env = env; + } | Pexp_array sargl -> let ty = newgenvar () in let to_unify = Predef.type_array ty in diff --git a/compiler/ml/typedtree.ml b/compiler/ml/typedtree.ml index 6dccdb2599..2c9c8b5433 100644 --- a/compiler/ml/typedtree.ml +++ b/compiler/ml/typedtree.ml @@ -106,7 +106,8 @@ and expression_desc = | Texp_field of expression * Longident.t loc * label_description | Texp_setfield of expression * Longident.t loc * label_description * expression - | Texp_index of expression * expression * expression option + | Texp_index of expression * expression + | Texp_setindex of expression * expression * expression | Texp_array of expression list | Texp_ifthenelse of expression * expression * expression option | Texp_sequence of expression * expression diff --git a/compiler/ml/typedtree.mli b/compiler/ml/typedtree.mli index 416577153b..13f5fcaba3 100644 --- a/compiler/ml/typedtree.mli +++ b/compiler/ml/typedtree.mli @@ -207,7 +207,8 @@ and expression_desc = | Texp_field of expression * Longident.t loc * label_description | Texp_setfield of expression * Longident.t loc * label_description * expression - | Texp_index of expression * expression * expression option + | Texp_index of expression * expression + | Texp_setindex of expression * expression * expression | Texp_array of expression list | Texp_ifthenelse of expression * expression * expression option | Texp_sequence of expression * expression diff --git a/compiler/ml/typedtreeIter.ml b/compiler/ml/typedtreeIter.ml index ea864004eb..5596b4dda3 100644 --- a/compiler/ml/typedtreeIter.ml +++ b/compiler/ml/typedtreeIter.ml @@ -261,12 +261,13 @@ end = struct | Texp_setfield (exp1, _, _label, exp2) -> iter_expression exp1; iter_expression exp2 - | Texp_index (exp1, exp2, expo) -> ( + | Texp_index (exp1, exp2) -> + iter_expression exp1; + iter_expression exp2 + | Texp_setindex (exp1, exp2, exp3) -> iter_expression exp1; iter_expression exp2; - match expo with - | None -> () - | Some exp -> iter_expression exp) + iter_expression exp3 | Texp_array list -> List.iter iter_expression list | Texp_ifthenelse (exp1, exp2, expo) -> ( iter_expression exp1; From c68bc30a2d0fbb8d72a952ec78ca9038f021fad8 Mon Sep 17 00:00:00 2001 From: Shulhi Sapli <913103+shulhi@users.noreply.github.com> Date: Mon, 12 Jan 2026 23:25:23 +0800 Subject: [PATCH 5/9] Handle printer --- analysis/src/Utils.ml | 1 + compiler/syntax/src/res_ast_debugger.ml | 15 +++++---- compiler/syntax/src/res_comments_table.ml | 12 ++++--- compiler/syntax/src/res_printer.ml | 40 +++++++++++++---------- 4 files changed, 40 insertions(+), 28 deletions(-) diff --git a/analysis/src/Utils.ml b/analysis/src/Utils.ml index d930b7edc2..33bee9ad16 100644 --- a/analysis/src/Utils.ml +++ b/analysis/src/Utils.ml @@ -96,6 +96,7 @@ let identifyPexp pexp = | Pexp_field _ -> "Pexp_field" | Pexp_setfield _ -> "Pexp_setfield" | Pexp_index _ -> "Pexp_index" + | Pexp_setindex _ -> "Pexp_setindex" | Pexp_array _ -> "Pexp_array" | Pexp_ifthenelse _ -> "Pexp_ifthenelse" | Pexp_sequence _ -> "Pexp_sequence" diff --git a/compiler/syntax/src/res_ast_debugger.ml b/compiler/syntax/src/res_ast_debugger.ml index cdfe67b6ad..8d283c9f7f 100644 --- a/compiler/syntax/src/res_ast_debugger.ml +++ b/compiler/syntax/src/res_ast_debugger.ml @@ -641,13 +641,16 @@ module SexpAst = struct longident longident_loc.Asttypes.txt; expression expr2; ] - | Pexp_index (e1, e2, e3) -> + | Pexp_index (e1, e2) -> + Sexp.list [Sexp.atom "Pexp_index"; expression e1; expression e2] + | Pexp_setindex (e1, e2, e3) -> Sexp.list - ([Sexp.atom "Pexp_index"; expression e1; expression e2] - @ - match e3 with - | None -> [] - | Some e -> [expression e]) + [ + Sexp.atom "Pexp_setindex"; + expression e1; + expression e2; + expression e3; + ] | Pexp_array exprs -> Sexp.list [Sexp.atom "Pexp_array"; Sexp.list (map_empty ~f:expression exprs)] diff --git a/compiler/syntax/src/res_comments_table.ml b/compiler/syntax/src/res_comments_table.ml index 4d414bfb79..6338380827 100644 --- a/compiler/syntax/src/res_comments_table.ml +++ b/compiler/syntax/src/res_comments_table.ml @@ -476,7 +476,8 @@ let rec is_block_expr expr = | Pexp_constraint (expr, _) when is_block_expr expr -> true | Pexp_field (expr, _) when is_block_expr expr -> true | Pexp_setfield (expr, _, _) when is_block_expr expr -> true - | Pexp_index (expr, _, _) when is_block_expr expr -> true + | Pexp_index (expr, _) when is_block_expr expr -> true + | Pexp_setindex (expr, _, _) when is_block_expr expr -> true | _ -> false let is_if_then_else_expr expr = @@ -1314,12 +1315,13 @@ and walk_expression expr t comments = attach t.leading expr2.pexp_loc leading; walk_expression expr2 t inside; attach t.trailing expr2.pexp_loc trailing - | Pexp_index (container, index, value_opt) -> ( + | Pexp_index (container, index) -> + walk_expression container t comments; + walk_expression index t comments + | Pexp_setindex (container, index, value) -> walk_expression container t comments; walk_expression index t comments; - match value_opt with - | None -> () - | Some value -> walk_expression value t comments) + walk_expression value t comments | Pexp_ifthenelse (if_expr, then_expr, else_expr) -> ( let leading, rest = partition_leading_trailing comments expr.pexp_loc in attach t.leading expr.pexp_loc leading; diff --git a/compiler/syntax/src/res_printer.ml b/compiler/syntax/src/res_printer.ml index b157466d8e..fd4acb9cda 100644 --- a/compiler/syntax/src/res_printer.ml +++ b/compiler/syntax/src/res_printer.ml @@ -3374,7 +3374,8 @@ and print_expression ~state (e : Parsetree.expression) cmt_tbl = | Pexp_setfield (expr1, longident_loc, expr2) -> print_set_field_expr ~state e.pexp_attributes expr1 longident_loc expr2 e.pexp_loc cmt_tbl - | Pexp_index (container, index, value_opt) -> ( + | Pexp_index (container, index) -> + (* Read: container[index] *) let container_doc = let doc = print_expression_with_comments ~state container cmt_tbl in match Parens.field_expr container with @@ -3383,22 +3384,27 @@ and print_expression ~state (e : Parsetree.expression) cmt_tbl = | Nothing -> doc in let index_doc = print_expression_with_comments ~state index cmt_tbl in - match value_opt with - | None -> - (* Read: container[index] *) - Doc.concat [container_doc; Doc.lbracket; index_doc; Doc.rbracket] - | Some value -> - (* Write: container[index] = value *) - let value_doc = print_expression_with_comments ~state value cmt_tbl in - Doc.concat - [ - container_doc; - Doc.lbracket; - index_doc; - Doc.rbracket; - Doc.text " = "; - value_doc; - ]) + Doc.concat [container_doc; Doc.lbracket; index_doc; Doc.rbracket] + | Pexp_setindex (container, index, value) -> + (* Write: container[index] = value *) + let container_doc = + let doc = print_expression_with_comments ~state container cmt_tbl in + match Parens.field_expr container with + | Parens.Parenthesized -> add_parens doc + | Braced braces -> print_braces doc container braces + | Nothing -> doc + in + let index_doc = print_expression_with_comments ~state index cmt_tbl in + let value_doc = print_expression_with_comments ~state value cmt_tbl in + Doc.concat + [ + container_doc; + Doc.lbracket; + index_doc; + Doc.rbracket; + Doc.text " = "; + value_doc; + ] | Pexp_ifthenelse (_ifExpr, _thenExpr, _elseExpr) when ParsetreeViewer.is_ternary_expr e -> let parts, alternate = ParsetreeViewer.collect_ternary_parts e in From 6905665c39dbffbedae9e74a2a535e30fc18ed78 Mon Sep 17 00:00:00 2001 From: Shulhi Sapli <913103+shulhi@users.noreply.github.com> Date: Thu, 15 Jan 2026 21:52:49 +0800 Subject: [PATCH 6/9] Change parser --- compiler/syntax/src/res_core.ml | 27 +++++---------------------- 1 file changed, 5 insertions(+), 22 deletions(-) diff --git a/compiler/syntax/src/res_core.ml b/compiler/syntax/src/res_core.ml index aab15e930f..3ab19af28f 100644 --- a/compiler/syntax/src/res_core.ml +++ b/compiler/syntax/src/res_core.ml @@ -2156,7 +2156,6 @@ and parse_first_class_module_expr ~start_pos p = and parse_bracket_access p expr start_pos = Parser.leave_breadcrumb p Grammar.ExprArrayAccess; - let lbracket = p.start_pos in Parser.expect Lbracket p; let string_start = p.start_pos in match p.Parser.token with @@ -2189,38 +2188,22 @@ and parse_bracket_access p expr start_pos = let access_expr = parse_constrained_or_coerced_expr p in Parser.expect Rbracket p; Parser.eat_breadcrumb p; - let rbracket = p.prev_end_pos in - let array_loc = mk_loc lbracket rbracket in match p.token with | Equal -> Parser.leave_breadcrumb p ExprArrayMutation; Parser.next p; let rhs_expr = parse_expr p in - (* FIXME: Do not implicitly rely on specific module name, even primitive one - - This can be abused like - module Array = MyModule - - Find better mechanism to support it - *) - let array_set = - Location.mkloc (Longident.Ldot (Lident "Array", "set")) array_loc - in let end_pos = p.prev_end_pos in - let array_set = - Ast_helper.Exp.apply ~loc:(mk_loc start_pos end_pos) - (Ast_helper.Exp.ident ~loc:array_loc array_set) - [(Nolabel, expr); (Nolabel, access_expr); (Nolabel, rhs_expr)] + let setindex_expr = + Ast_helper.Exp.setindex ~loc:(mk_loc start_pos end_pos) expr access_expr + rhs_expr in Parser.eat_breadcrumb p; - array_set + setindex_expr | _ -> let end_pos = p.prev_end_pos in let e = - Ast_helper.Exp.apply ~loc:(mk_loc start_pos end_pos) - (Ast_helper.Exp.ident ~loc:array_loc - (Location.mkloc (Longident.Ldot (Lident "Array", "get")) array_loc)) - [(Nolabel, expr); (Nolabel, access_expr)] + Ast_helper.Exp.index ~loc:(mk_loc start_pos end_pos) expr access_expr in parse_primary_expr ~operand:e p) From de2dc1865be8fe55c47cf5f07feb97ab20b90a63 Mon Sep 17 00:00:00 2001 From: Shulhi Sapli <913103+shulhi@users.noreply.github.com> Date: Mon, 19 Jan 2026 11:39:06 +0800 Subject: [PATCH 7/9] Include existing arity information --- compiler/ml/typecore.ml | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/compiler/ml/typecore.ml b/compiler/ml/typecore.ml index 6934d9f80b..96adf873ff 100644 --- a/compiler/ml/typecore.ml +++ b/compiler/ml/typecore.ml @@ -2864,9 +2864,17 @@ and type_expect_ ?deprecated_context ~context ?in_function ?(recarg = Rejected) let index = type_expect ~context:None env sindex (instance_def Predef.type_int) in - let element_type = newgenvar () in - let array_type = instance_def (Predef.type_array element_type) in - unify_exp ~context:None env container array_type; + (* Extract element type from container to preserve arity information *) + let element_type = + match (expand_head env container.exp_type).desc with + | Tconstr (Pident {name = "array"}, [element_ty], _) -> element_ty + | _ -> + (* Fallback: create fresh type variable and unify *) + let element_type = newgenvar () in + let array_type = instance_def (Predef.type_array element_type) in + unify_exp ~context:None env container array_type; + element_type + in let value = type_expect ~context:None env svalue element_type in rue { From c4b741e18276b3f8810c4bc8d3cbe20a37844fc5 Mon Sep 17 00:00:00 2001 From: Shulhi Sapli <913103+shulhi@users.noreply.github.com> Date: Wed, 28 Jan 2026 20:19:30 +0800 Subject: [PATCH 8/9] Handle comments attachment --- compiler/syntax/src/res_comments_table.ml | 72 +++++++++++++++++++++-- 1 file changed, 67 insertions(+), 5 deletions(-) diff --git a/compiler/syntax/src/res_comments_table.ml b/compiler/syntax/src/res_comments_table.ml index 6338380827..c14b6a1852 100644 --- a/compiler/syntax/src/res_comments_table.ml +++ b/compiler/syntax/src/res_comments_table.ml @@ -1316,12 +1316,74 @@ and walk_expression expr t comments = walk_expression expr2 t inside; attach t.trailing expr2.pexp_loc trailing | Pexp_index (container, index) -> - walk_expression container t comments; - walk_expression index t comments + let leading, inside, trailing = + partition_by_loc comments container.pexp_loc + in + let rest = + if is_block_expr container then ( + let after_expr, rest = + partition_adjacent_trailing container.pexp_loc trailing + in + walk_expression container t (List.concat [leading; inside; after_expr]); + rest) + else + let after_expr, rest = + partition_adjacent_trailing container.pexp_loc trailing + in + attach t.leading container.pexp_loc leading; + walk_expression container t inside; + attach t.trailing container.pexp_loc after_expr; + rest + in + if is_block_expr index then walk_expression index t rest + else + let leading, inside, trailing = partition_by_loc rest index.pexp_loc in + attach t.leading index.pexp_loc leading; + walk_expression index t inside; + attach t.trailing index.pexp_loc trailing | Pexp_setindex (container, index, value) -> - walk_expression container t comments; - walk_expression index t comments; - walk_expression value t comments + let leading, inside, trailing = + partition_by_loc comments container.pexp_loc + in + let rest = + if is_block_expr container then ( + let after_expr, rest = + partition_adjacent_trailing container.pexp_loc trailing + in + walk_expression container t (List.concat [leading; inside; after_expr]); + rest) + else + let after_expr, rest = + partition_adjacent_trailing container.pexp_loc trailing + in + attach t.leading container.pexp_loc leading; + walk_expression container t inside; + attach t.trailing container.pexp_loc after_expr; + rest + in + let leading, inside, trailing = partition_by_loc rest index.pexp_loc in + let rest = + if is_block_expr index then ( + let after_expr, rest = + partition_adjacent_trailing index.pexp_loc trailing + in + walk_expression index t (List.concat [leading; inside; after_expr]); + rest) + else + let after_expr, rest = + partition_adjacent_trailing index.pexp_loc trailing + in + attach t.leading index.pexp_loc leading; + walk_expression index t inside; + attach t.trailing index.pexp_loc after_expr; + rest + in + if is_block_expr value then walk_expression value t rest + else + let leading, inside, trailing = partition_by_loc rest value.pexp_loc in + attach t.leading value.pexp_loc leading; + walk_expression value t inside; + attach t.trailing value.pexp_loc trailing | Pexp_ifthenelse (if_expr, then_expr, else_expr) -> ( let leading, rest = partition_leading_trailing comments expr.pexp_loc in attach t.leading expr.pexp_loc leading; From 9e884e1f24c460932028f050af3d6b18c3f9143a Mon Sep 17 00:00:00 2001 From: Shulhi Sapli <913103+shulhi@users.noreply.github.com> Date: Wed, 28 Jan 2026 20:19:47 +0800 Subject: [PATCH 9/9] Handle printer --- compiler/ml/pprintast.ml | 6 +- compiler/syntax/src/res_parsetree_viewer.ml | 2 + compiler/syntax/src/res_printer.ml | 71 ++++++++++++++++++--- 3 files changed, 66 insertions(+), 13 deletions(-) diff --git a/compiler/ml/pprintast.ml b/compiler/ml/pprintast.ml index 743b1dfba9..9688f606cd 100644 --- a/compiler/ml/pprintast.ml +++ b/compiler/ml/pprintast.ml @@ -692,10 +692,10 @@ and expression ctxt f x = pp f "@[<2>%a.%a@ <-@ %a@]" (simple_expr ctxt) e1 longident_loc li (simple_expr ctxt) e2 | Pexp_index (e1, e2) -> - pp f "%a.(%a)" (expression ctxt) e1 (expression ctxt) e2 + pp f "%a.(%a)" (simple_expr ctxt) e1 (expression ctxt) e2 | Pexp_setindex (e1, e2, e3) -> - pp f "%a.(%a)@ <-@ %a" (expression ctxt) e1 (expression ctxt) e2 - (expression ctxt) e3 + pp f "%a.(%a)@ <-@ %a" (simple_expr ctxt) e1 (expression ctxt) e2 + (simple_expr ctxt) e3 | Pexp_ifthenelse (e1, e2, eo) -> (* @;@[<2>else@ %a@]@] *) let fmt : (_, _, _) format = diff --git a/compiler/syntax/src/res_parsetree_viewer.ml b/compiler/syntax/src/res_parsetree_viewer.ml index 391e51bede..1715bd0cf4 100644 --- a/compiler/syntax/src/res_parsetree_viewer.ml +++ b/compiler/syntax/src/res_parsetree_viewer.ml @@ -429,6 +429,8 @@ let has_attributes attrs = let is_array_access expr = match expr.pexp_desc with + | Pexp_index _ -> true + (* TODO: Now we have dedicated index access, we can clean up the below AST? *) | Pexp_apply { funct = diff --git a/compiler/syntax/src/res_printer.ml b/compiler/syntax/src/res_printer.ml index fd4acb9cda..5541031c71 100644 --- a/compiler/syntax/src/res_printer.ml +++ b/compiler/syntax/src/res_printer.ml @@ -3383,8 +3383,28 @@ and print_expression ~state (e : Parsetree.expression) cmt_tbl = | Braced braces -> print_braces doc container braces | Nothing -> doc in - let index_doc = print_expression_with_comments ~state index cmt_tbl in - Doc.concat [container_doc; Doc.lbracket; index_doc; Doc.rbracket] + let index_has_braces, index_doc = + let doc = print_expression_with_comments ~state index cmt_tbl in + match Parens.expr index with + | Parens.Parenthesized -> (false, add_parens doc) + | Braced braces -> (true, print_braces doc index braces) + | Nothing -> (false, doc) + in + if index_has_braces then + Doc.concat [container_doc; Doc.lbracket; index_doc; Doc.rbracket] + else + Doc.concat + [ + container_doc; + Doc.group + (Doc.concat + [ + Doc.lbracket; + Doc.indent (Doc.concat [Doc.soft_line; index_doc]); + Doc.soft_line; + Doc.rbracket; + ]); + ] | Pexp_setindex (container, index, value) -> (* Write: container[index] = value *) let container_doc = @@ -3394,16 +3414,47 @@ and print_expression ~state (e : Parsetree.expression) cmt_tbl = | Braced braces -> print_braces doc container braces | Nothing -> doc in - let index_doc = print_expression_with_comments ~state index cmt_tbl in - let value_doc = print_expression_with_comments ~state value cmt_tbl in + let index_has_braces, index_doc = + let doc = print_expression_with_comments ~state index cmt_tbl in + match Parens.expr index with + | Parens.Parenthesized -> (false, add_parens doc) + | Braced braces -> (true, print_braces doc index braces) + | Nothing -> (false, doc) + in + let value_has_braces, value_doc = + let doc = print_expression_with_comments ~state value cmt_tbl in + match Parens.set_field_expr_rhs value with + | Parens.Parenthesized -> (false, add_parens doc) + | Braced braces -> (true, print_braces doc value braces) + | Nothing -> (false, doc) + in + let should_indent = + (not value_has_braces) && ParsetreeViewer.is_binary_expression value + in + let bracket_doc = + if index_has_braces then + Doc.concat [container_doc; Doc.lbracket; index_doc; Doc.rbracket] + else + Doc.concat + [ + container_doc; + Doc.group + (Doc.concat + [ + Doc.lbracket; + Doc.indent (Doc.concat [Doc.soft_line; index_doc]); + Doc.soft_line; + Doc.rbracket; + ]); + ] + in Doc.concat [ - container_doc; - Doc.lbracket; - index_doc; - Doc.rbracket; - Doc.text " = "; - value_doc; + bracket_doc; + Doc.text " ="; + (if should_indent then + Doc.group (Doc.indent (Doc.concat [Doc.line; value_doc])) + else Doc.concat [Doc.space; value_doc]); ] | Pexp_ifthenelse (_ifExpr, _thenExpr, _elseExpr) when ParsetreeViewer.is_ternary_expr e ->