From 4c55c63c9e7045e0fb308297f09658bf2b4611b7 Mon Sep 17 00:00:00 2001 From: Chris Casinghino Date: Mon, 27 Jan 2025 16:21:30 -0500 Subject: [PATCH] Fix precedence of .# --- lib/Ast.ml | 37 ++++++++++++--------- test/passing/tests/unboxed_record.ml | 3 ++ test/passing/tests/unboxed_record.ml.js-ref | 3 ++ test/passing/tests/unboxed_record.ml.ref | 3 ++ 4 files changed, 31 insertions(+), 15 deletions(-) diff --git a/lib/Ast.ml b/lib/Ast.ml index 708546f8ff..64853c591e 100644 --- a/lib/Ast.ml +++ b/lib/Ast.ml @@ -149,7 +149,9 @@ module Exp = struct let rec is_trivial exp = match exp.pexp_desc with | Pexp_constant {pconst_desc= Pconst_string (_, _, None); _} -> true - | Pexp_constant _ | Pexp_field _ | Pexp_ident _ | Pexp_send _ -> true + | Pexp_constant _ | Pexp_field _ | Pexp_unboxed_field _ | Pexp_ident _ + |Pexp_send _ -> + true | Pexp_construct (_, exp) -> Option.for_all exp ~f:is_trivial | Pexp_prefix (_, e) -> is_trivial e | Pexp_apply @@ -164,7 +166,7 @@ module Exp = struct match e.pexp_desc with | Pexp_prefix _ -> true | Pexp_apply (op, _) -> exposed_left op - | Pexp_field (e, _) -> exposed_left e + | Pexp_field (e, _) | Pexp_unboxed_field (e, _) -> exposed_left e | _ -> false (** [mem_cls cls exp] holds if [exp] is in the named class of expressions @@ -206,7 +208,10 @@ module Exp = struct |Pexp_list _ | Pexp_list_comprehension _ | Pexp_array_comprehension _ |Pexp_unboxed_tuple _ -> true - | Pexp_prefix (_, e) | Pexp_field (e, _) | Pexp_send (e, _) -> + | Pexp_prefix (_, e) + |Pexp_field (e, _) + |Pexp_unboxed_field (e, _) + |Pexp_send (e, _) -> is_simple_in_parser e | Pexp_infix ({txt; _}, e1, e2) -> String.length txt > 0 @@ -217,12 +222,12 @@ module Exp = struct |Pexp_variant (_, Some _) |Pexp_unreachable | Pexp_let _ | Pexp_function _ | Pexp_fun _ |Pexp_apply _ | Pexp_match _ | Pexp_try _ | Pexp_tuple _ - |Pexp_unboxed_field _ | Pexp_setfield _ | Pexp_ifthenelse _ - |Pexp_sequence _ | Pexp_while _ | Pexp_for _ | Pexp_constraint _ - |Pexp_coerce _ | Pexp_setinstvar _ | Pexp_letmodule _ - |Pexp_letexception _ | Pexp_assert _ | Pexp_lazy _ | Pexp_poly _ - |Pexp_newtype _ | Pexp_pack _ | Pexp_letopen _ | Pexp_letop _ - |Pexp_stack _ | Pexp_beginend _ | Pexp_parens _ | Pexp_cons _ -> + |Pexp_setfield _ | Pexp_ifthenelse _ | Pexp_sequence _ | Pexp_while _ + |Pexp_for _ | Pexp_constraint _ | Pexp_coerce _ | Pexp_setinstvar _ + |Pexp_letmodule _ | Pexp_letexception _ | Pexp_assert _ | Pexp_lazy _ + |Pexp_poly _ | Pexp_newtype _ | Pexp_pack _ | Pexp_letopen _ + |Pexp_letop _ | Pexp_stack _ | Pexp_beginend _ | Pexp_parens _ + |Pexp_cons _ -> false end @@ -1657,7 +1662,7 @@ end = struct let ctx = Exp exp in match exp.pexp_desc with | Pexp_constant _ -> Exp.is_trivial exp - | Pexp_field _ | Pexp_ident _ | Pexp_send _ + | Pexp_field _ | Pexp_unboxed_field _ | Pexp_ident _ | Pexp_send _ |Pexp_construct (_, None) |Pexp_variant (_, None) -> true @@ -1838,7 +1843,7 @@ end = struct | Pexp_setfield (e0, _, _) when e0 == exp -> Some (Dot, Left) | Pexp_setfield (_, _, e0) when e0 == exp -> Some (LessMinus, Non) | Pexp_setinstvar _ -> Some (LessMinus, Non) - | Pexp_field _ -> Some (Dot, Left) + | Pexp_field _ | Pexp_unboxed_field _ -> Some (Dot, Left) (* We use [Dot] so [x#y] has the same precedence as [x.y], it is different to what is done in the parser, but it is intended. *) | Pexp_send _ -> Some (Dot, Left) @@ -1945,7 +1950,7 @@ end = struct prec_ast (Exp e) | Pexp_setfield _ -> Some LessMinus | Pexp_setinstvar _ -> Some LessMinus - | Pexp_field _ -> Some Dot + | Pexp_field _ | Pexp_unboxed_field _ -> Some Dot | Pexp_send _ -> Some Dot | _ -> None ) | Fp _ -> None @@ -2590,7 +2595,7 @@ end = struct ; _ } ) when exp == lhs -> true - | ( Exp {pexp_desc= Pexp_field (e, _); _} + | ( Exp {pexp_desc= Pexp_field (e, _) | Pexp_unboxed_field (e, _); _} , {pexp_desc= Pexp_construct _ | Pexp_cons _; _} ) when e == exp -> true @@ -2673,14 +2678,16 @@ end = struct , Some ( { pexp_desc= ( Pexp_ident _ | Pexp_constant _ | Pexp_record _ - | Pexp_constraint _ | Pexp_field _ ) + | Pexp_constraint _ | Pexp_unboxed_field _ + | Pexp_field _ ) ; _ } as e0 ) ) |Pexp_record_unboxed_product ( _ , Some ( { pexp_desc= ( Pexp_ident _ | Pexp_constant _ | Pexp_record _ - | Pexp_constraint _ | Pexp_field _ ) + | Pexp_constraint _ | Pexp_unboxed_field _ + | Pexp_field _ ) ; _ } as e0 ) ) when e0 == exp -> false diff --git a/test/passing/tests/unboxed_record.ml b/test/passing/tests/unboxed_record.ml index 00795a3e8f..546aa27f74 100644 --- a/test/passing/tests/unboxed_record.ml +++ b/test/passing/tests/unboxed_record.ml @@ -217,3 +217,6 @@ let _ = #{a = 1; b = 2; c = 3; short} ;; (* make sure to not drop parens for local open. *) let _ = A.(#{a = 1; b = 2}) + +(* make sure not to drop parens around thing being projected from. *) +let _ = (f x).#foo diff --git a/test/passing/tests/unboxed_record.ml.js-ref b/test/passing/tests/unboxed_record.ml.js-ref index a716e96347..d73b158d6f 100644 --- a/test/passing/tests/unboxed_record.ml.js-ref +++ b/test/passing/tests/unboxed_record.ml.js-ref @@ -265,3 +265,6 @@ let _ = #{ a = 1; b = 2; c = 3; short };; (* make sure to not drop parens for local open. *) let _ = A.(#{ a = 1; b = 2 }) + +(* make sure not to drop parens around thing being projected from. *) +let _ = (f x).#foo diff --git a/test/passing/tests/unboxed_record.ml.ref b/test/passing/tests/unboxed_record.ml.ref index 3812bc201a..c64fbb3573 100644 --- a/test/passing/tests/unboxed_record.ml.ref +++ b/test/passing/tests/unboxed_record.ml.ref @@ -222,3 +222,6 @@ let _ = #{a= 1; b= 2; c= 3; short} ;; (* make sure to not drop parens for local open. *) let _ = A.(#{a= 1; b= 2}) + +(* make sure not to drop parens around thing being projected from. *) +let _ = (f x).#foo