Skip to content
Draft
9 changes: 3 additions & 6 deletions analysis/examples/larger-project/src/TestImmutableArray.res
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
@genType
let testImmutableArrayGet = arr => {
open ImmutableArray
arr[3]
ImmutableArray.Array.get(arr, 3)
}

/*
Expand All @@ -10,11 +9,9 @@ let testImmutableArrayGet = arr => {
*/

let testBeltArrayGet = arr => {
open Belt
arr[3]
Belt.Array.get(arr, 3)
}

let testBeltArraySet = arr => {
open Belt
arr[3] = 4
Belt.Array.set(arr, 3, 4)
}
2 changes: 2 additions & 0 deletions analysis/src/Utils.ml
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ let identifyPexp pexp =
| Pexp_record _ -> "Pexp_record"
| 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"
Expand Down
4 changes: 4 additions & 0 deletions compiler/frontend/bs_ast_mapper.ml
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +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) ->
index ~loc ~attrs (sub.expr sub e1) (sub.expr sub e2)
| 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)
Expand Down
2 changes: 2 additions & 0 deletions compiler/ml/ast_helper.ml
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +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 = 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))
Expand Down
8 changes: 8 additions & 0 deletions compiler/ml/ast_helper.mli
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,14 @@ 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
val setindex :
?loc:loc ->
?attrs:attrs ->
expression ->
expression ->
expression ->
expression
val array : ?loc:loc -> ?attrs:attrs -> expression list -> expression
val ifthenelse :
?loc:loc ->
Expand Down
7 changes: 7 additions & 0 deletions compiler/ml/ast_iterator.ml
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,13 @@ module E = struct
sub.expr sub e1;
iter_loc sub lid;
sub.expr sub e2
| 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;
sub.expr sub e3
| Pexp_array el -> List.iter (sub.expr sub) el
| Pexp_ifthenelse (e1, e2, e3) ->
sub.expr sub e1;
Expand Down
4 changes: 4 additions & 0 deletions compiler/ml/ast_mapper.ml
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +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) ->
index ~loc ~attrs (sub.expr sub e1) (sub.expr sub e2)
| 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)
Expand Down
18 changes: 18 additions & 0 deletions compiler/ml/ast_mapper_to0.ml
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +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) ->
(* Map back to Array.get for parsetree0 compatibility *)
let container = sub.expr sub e1 in
let index = sub.expr sub e2 in
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)
Expand Down
7 changes: 7 additions & 0 deletions compiler/ml/depend.ml
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,13 @@ let rec add_expr bv exp =
add_expr bv e1;
add bv fld;
add_expr bv e2
| 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_expr bv e3
| Pexp_array el -> List.iter (add_expr bv) el
| Pexp_ifthenelse (e1, e2, opte3) ->
add_expr bv e1;
Expand Down
2 changes: 2 additions & 0 deletions compiler/ml/parsetree.ml
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +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 (* 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 *)
Expand Down
5 changes: 5 additions & 0 deletions compiler/ml/pprintast.ml
Original file line number Diff line number Diff line change
Expand Up @@ -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) ->
pp f "%a.(%a)" (simple_expr ctxt) e1 (expression ctxt) e2
| Pexp_setindex (e1, e2, 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 =
Expand Down
12 changes: 12 additions & 0 deletions compiler/ml/printast.ml
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,18 @@ and expression i ppf x =
expression i ppf e1;
longident_loc i ppf li;
expression i ppf e2
| 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;
line i ppf "value:\n";
expression i ppf e3
| Pexp_array l ->
line i ppf "Pexp_array\n";
list i expression ppf l
Expand Down
12 changes: 12 additions & 0 deletions compiler/ml/printtyped.ml
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,18 @@ and expression i ppf x =
expression i ppf e1;
longident i ppf li;
expression i ppf e2
| 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;
line i ppf "value:\n";
expression i ppf e3
| Texp_array l ->
line i ppf "Texp_array\n";
list i expression ppf l
Expand Down
11 changes: 9 additions & 2 deletions compiler/ml/rec_check.ml
Original file line number Diff line number Diff line change
Expand Up @@ -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_setindex _ | Texp_while _ | Texp_pack _
| Texp_function _ | Texp_extension_constructor _ ->
Static
| Texp_apply {funct = {exp_desc = Texp_ident (_, _, vd)}} when is_ref vd ->
Static
Expand Down Expand Up @@ -273,6 +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) ->
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 (expression env e3)))
| Texp_sequence (e1, e2) ->
Use.(join (discard (expression env e1)) (expression env e2))
| Texp_while (e1, e2) ->
Expand Down
7 changes: 7 additions & 0 deletions compiler/ml/tast_iterator.ml
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +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) ->
sub.expr sub exp1;
sub.expr sub exp2
| Texp_setindex (exp1, exp2, exp3) ->
sub.expr sub exp1;
sub.expr sub exp2;
sub.expr sub exp3
| Texp_array list -> List.iter (sub.expr sub) list
| Texp_ifthenelse (exp1, exp2, expo) ->
sub.expr sub exp1;
Expand Down
10 changes: 10 additions & 0 deletions compiler/ml/tast_mapper.ml
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,16 @@ 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) ->
(* Use let bindings to ensure left-to-right evaluation order *)
let exp1 = sub.expr sub exp1 in
let exp2 = sub.expr sub exp2 in
Texp_index (exp1, exp2)
| Texp_setindex (exp1, exp2, exp3) ->
let exp1 = sub.expr sub exp1 in
let exp2 = sub.expr sub exp2 in
let exp3 = sub.expr sub exp3 in
Texp_setindex (exp1, exp2, exp3)
| Texp_array list -> Texp_array (List.map (sub.expr sub) list)
| Texp_ifthenelse (exp1, exp2, expo) ->
Texp_ifthenelse
Expand Down
11 changes: 11 additions & 0 deletions compiler/ml/translcore.ml
Original file line number Diff line number Diff line change
Expand Up @@ -891,6 +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) ->
(* Read: translate to Parrayrefu primitive (unsafe array get) *)
let container_lambda = transl_exp container in
let index_lambda = transl_exp index in
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)
Expand Down
57 changes: 55 additions & 2 deletions compiler/ml/typecore.ml
Original file line number Diff line number Diff line change
Expand Up @@ -178,10 +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_setindex (e1, e2, e3) ->
expr e1;
expr e2;
expr e3
| Pexp_ifthenelse (e1, e2, eo) ->
expr e1;
expr e2;
Expand Down Expand Up @@ -2834,6 +2840,53 @@ and type_expect_ ?deprecated_context ~context ?in_function ?(recarg = Rejected)
exp_attributes = sexp.pexp_attributes;
exp_env = env;
}
| Pexp_index (scontainer, sindex) ->
(* Read access: arr[i] -> array<'a> -> int -> option<'a>
Returns option because JS bracket access returns undefined for
out-of-bounds indices, which maps to None in ReScript's option type. *)
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 = newvar () in
let array_type = 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 = type_option 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
(* 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
{
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
Expand Down
2 changes: 2 additions & 0 deletions compiler/ml/typedtree.ml
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +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
| Texp_setindex of expression * expression * expression
| Texp_array of expression list
| Texp_ifthenelse of expression * expression * expression option
| Texp_sequence of expression * expression
Expand Down
2 changes: 2 additions & 0 deletions compiler/ml/typedtree.mli
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +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
| Texp_setindex of expression * expression * expression
| Texp_array of expression list
| Texp_ifthenelse of expression * expression * expression option
| Texp_sequence of expression * expression
Expand Down
7 changes: 7 additions & 0 deletions compiler/ml/typedtreeIter.ml
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,13 @@ end = struct
| Texp_setfield (exp1, _, _label, exp2) ->
iter_expression exp1;
iter_expression exp2
| Texp_index (exp1, exp2) ->
iter_expression exp1;
iter_expression exp2
| Texp_setindex (exp1, exp2, exp3) ->
iter_expression exp1;
iter_expression exp2;
iter_expression exp3
| Texp_array list -> List.iter iter_expression list
| Texp_ifthenelse (exp1, exp2, expo) -> (
iter_expression exp1;
Expand Down
10 changes: 10 additions & 0 deletions compiler/syntax/src/res_ast_debugger.ml
Original file line number Diff line number Diff line change
Expand Up @@ -641,6 +641,16 @@ module SexpAst = struct
longident longident_loc.Asttypes.txt;
expression expr2;
]
| Pexp_index (e1, e2) ->
Sexp.list [Sexp.atom "Pexp_index"; expression e1; expression e2]
| Pexp_setindex (e1, e2, e3) ->
Sexp.list
[
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)]
Expand Down
Loading
Loading