Skip to content

Commit 500977d

Browse files
authored
Represent 'let f _ = function' in the CST (ocaml-ppx#2596)
* extended: Missing Printast for pvb_is_pun and pvb_args * Pass the right context when formatting let bindings This fixes various inconsistencies and will help write parens rules for functions. * Represent 'let f _ = function' in the CST Currently, the CST represents the arguments of 'let f _ =' in a way that is incompatible with the changed function representation from OCaml 5.2. These two are represented the same way in the CST: let f _ = function ... let f _ = (function ...) To fix this problem, the representation for let bindings bodies is changed to 'function_body', matching the 5.2 representation. * Remove unecessary parentheses around functions in bindings By implementing stronger Ast checks.
1 parent dca7513 commit 500977d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+1252
-386
lines changed

CHANGES.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ profile. This started with version 0.26.0.
88

99
### Added
1010

11-
- \* Support OCaml 5.2 syntax (#2519, #2544, #2590, @Julow, @EmileTrotignon)
11+
- \* Support OCaml 5.2 syntax (#2519, #2544, #2590, #2596, @Julow, @EmileTrotignon)
1212
This includes local open in types and changed syntax for functions.
1313
This might change the formatting of some functions due to the formatting code
1414
being completely rewritten.

lib/Ast.ml

Lines changed: 142 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -812,6 +812,8 @@ module rec In_ctx : sig
812812
val sub_sig : ctx:T.t -> signature_item -> signature_item xt
813813

814814
val sub_str : ctx:T.t -> structure_item -> structure_item xt
815+
816+
val sub_fun_body : ctx:T.t -> function_body -> function_body xt
815817
end = struct
816818
open Requires_sub_terms
817819

@@ -846,6 +848,8 @@ end = struct
846848
let sub_sig ~ctx sig_ = {ctx; ast= sig_}
847849

848850
let sub_str ~ctx str = {ctx; ast= str}
851+
852+
let sub_fun_body ~ctx ast = {ctx; ast}
849853
end
850854

851855
(** Operations determining precedence and necessary parenthesization of terms
@@ -1202,9 +1206,15 @@ end = struct
12021206
| Ppat_constraint (p, _) -> p == pat
12031207
| _ -> false
12041208
in
1205-
let check_bindings l =
1206-
List.exists l ~f:(fun {pvb_pat; _} -> check_subpat pvb_pat)
1209+
let check_cases = List.exists ~f:(fun c -> c.pc_lhs == pat) in
1210+
let check_binding {pvb_pat; pvb_body; _} =
1211+
check_subpat pvb_pat
1212+
||
1213+
match pvb_body with
1214+
| Pfunction_body _ -> false
1215+
| Pfunction_cases (cases, _, _) -> check_cases cases
12071216
in
1217+
let check_bindings l = List.exists l ~f:check_binding in
12081218
let check_param_val (_, _, p) = p == pat in
12091219
let check_expr_function_param param =
12101220
match param.pparam_desc with
@@ -1217,7 +1227,6 @@ end = struct
12171227
let check_class_function_params =
12181228
List.exists ~f:check_class_function_param
12191229
in
1220-
let check_cases = List.exists ~f:(fun c -> c.pc_lhs == pat) in
12211230
match ctx with
12221231
| Pld (PPat (p1, _)) -> assert (p1 == pat)
12231232
| Pld _ -> assert false
@@ -1283,7 +1292,7 @@ end = struct
12831292
| Fpe ctx -> assert (check_expr_function_param ctx)
12841293
| Fpc ctx -> assert (check_class_function_param ctx)
12851294
| Vc _ -> assert false
1286-
| Lb x -> assert (x.pvb_pat == pat)
1295+
| Lb x -> assert (check_binding x)
12871296
| Bo x -> assert (x.pbop_pat == pat)
12881297
| Mb _ -> assert false
12891298
| Md _ -> assert false
@@ -1351,6 +1360,10 @@ end = struct
13511360
| {pc_rhs; _} when pc_rhs == exp -> true
13521361
| _ -> false )
13531362
in
1363+
let check_fun_body = function
1364+
| Pfunction_body body -> body == exp
1365+
| Pfunction_cases (cases, _, _) -> check_cases cases
1366+
in
13541367
match ctx with
13551368
| Pld (PPat (_, Some e1)) -> assert (e1 == exp)
13561369
| Pld _ -> assert false
@@ -1365,8 +1378,8 @@ end = struct
13651378
| Pexp_object _ -> assert false
13661379
| Pexp_let ({pvbs_bindings; _}, e, _) ->
13671380
assert (
1368-
List.exists pvbs_bindings ~f:(fun {pvb_expr; _} ->
1369-
pvb_expr == exp )
1381+
List.exists pvbs_bindings ~f:(fun {pvb_body; _} ->
1382+
check_fun_body pvb_body )
13701383
|| e == exp )
13711384
| Pexp_letop {let_; ands; body; loc_in= _} ->
13721385
let f {pbop_exp; _} = pbop_exp == exp in
@@ -1375,13 +1388,9 @@ end = struct
13751388
| Pexp_match (_, cases) | Pexp_try (_, cases) ->
13761389
assert (check_cases cases)
13771390
| Pexp_function (params, _, body) ->
1378-
let check_body =
1379-
match body with
1380-
| Pfunction_body body -> body == exp
1381-
| Pfunction_cases (cases, _, _) -> check_cases cases
1382-
in
13831391
assert (
1384-
List.exists ~f:check_expr_function_param params || check_body )
1392+
List.exists ~f:check_expr_function_param params
1393+
|| check_fun_body body )
13851394
| Pexp_indexop_access {pia_lhs; pia_kind= Builtin idx; pia_rhs; _} ->
13861395
assert (
13871396
pia_lhs == exp || idx == exp
@@ -1431,7 +1440,7 @@ end = struct
14311440
| Fpe ctx -> assert (check_expr_function_param ctx)
14321441
| Fpc ctx -> assert (check_class_function_param ctx)
14331442
| Vc _ -> assert false
1434-
| Lb x -> assert (x.pvb_expr == exp)
1443+
| Lb x -> assert (check_fun_body x.pvb_body)
14351444
| Bo x -> assert (x.pbop_exp == exp)
14361445
| Mb _ -> assert false
14371446
| Md _ -> assert false
@@ -1440,8 +1449,8 @@ end = struct
14401449
| Pstr_eval (e0, _) -> assert (e0 == exp)
14411450
| Pstr_value {pvbs_bindings; _} ->
14421451
assert (
1443-
List.exists pvbs_bindings ~f:(fun {pvb_expr; _} ->
1444-
pvb_expr == exp ) )
1452+
List.exists pvbs_bindings ~f:(fun {pvb_body; _} ->
1453+
check_fun_body pvb_body ) )
14451454
| Pstr_extension ((_, ext), _) -> assert (check_extensions ext)
14461455
| Pstr_primitive _ | Pstr_type _ | Pstr_typext _ | Pstr_exception _
14471456
|Pstr_module _ | Pstr_recmodule _ | Pstr_modtype _ | Pstr_open _
@@ -1457,8 +1466,8 @@ end = struct
14571466
| Pcl_structure _ -> false
14581467
| Pcl_apply (_, l) -> List.exists l ~f:(fun (_, e) -> e == exp)
14591468
| Pcl_let ({pvbs_bindings; _}, _, _) ->
1460-
List.exists pvbs_bindings ~f:(fun {pvb_expr; _} ->
1461-
pvb_expr == exp )
1469+
List.exists pvbs_bindings ~f:(fun {pvb_body; _} ->
1470+
check_fun_body pvb_body )
14621471
| Pcl_constraint _ -> false
14631472
| Pcl_extension _ -> false
14641473
| Pcl_open _ -> false
@@ -1866,6 +1875,23 @@ end = struct
18661875
| Ppat_tuple _ -> true
18671876
| _ -> false
18681877

1878+
let parenze_pat_in_bindings bindings pat =
1879+
let parenze_pat_in_binding ~pvb_constraint =
1880+
(* Some patterns must be parenthesed when followed by a colon. *)
1881+
(exposed_right_colon pat && Option.is_some pvb_constraint)
1882+
||
1883+
match pat.ppat_desc with
1884+
| Ppat_construct (_, Some _)
1885+
|Ppat_variant (_, Some _)
1886+
|Ppat_cons _ | Ppat_alias _ | Ppat_or _ ->
1887+
(* Add disambiguation parentheses that are not necessary. *)
1888+
true
1889+
| _ -> false
1890+
in
1891+
List.exists bindings ~f:(fun {pvb_pat; pvb_constraint; _} ->
1892+
(* [pat] appears on the left side of a binding. *)
1893+
pvb_pat == pat && parenze_pat_in_binding ~pvb_constraint )
1894+
18691895
(** [parenze_pat {ctx; ast}] holds when pattern [ast] should be
18701896
parenthesized in context [ctx]. *)
18711897
let parenze_pat ({ctx; ast= pat} as xpat) =
@@ -1902,6 +1928,11 @@ end = struct
19021928
| Ppat_or _ | Ppat_alias _ ) ) ->
19031929
true
19041930
| Bo {pbop_typ= Some _; _}, (Ppat_any | Ppat_tuple _) -> true
1931+
| Exp {pexp_desc= Pexp_function (_, _, Pfunction_body _); _}, Ppat_or _
1932+
|( Exp {pexp_desc= Pexp_function (_, _, Pfunction_body _); _}
1933+
, ( Ppat_construct _ | Ppat_cons _ | Ppat_lazy _ | Ppat_tuple _
1934+
| Ppat_variant _ ) ) ->
1935+
true
19051936
| _, Ppat_constraint _
19061937
|_, Ppat_unpack _
19071938
|( Pat
@@ -1931,18 +1962,14 @@ end = struct
19311962
|Pat {ppat_desc= Ppat_tuple _; _}, Ppat_tuple _
19321963
|Pat _, Ppat_lazy _
19331964
|Pat _, Ppat_exception _
1934-
|Exp {pexp_desc= Pexp_function (_, _, Pfunction_body _); _}, Ppat_or _
19351965
|Cl {pcl_desc= Pcl_fun _; _}, Ppat_variant (_, Some _)
19361966
|Cl {pcl_desc= Pcl_fun _; _}, Ppat_tuple _
19371967
|Cl {pcl_desc= Pcl_fun _; _}, Ppat_construct _
19381968
|Cl {pcl_desc= Pcl_fun _; _}, Ppat_alias _
19391969
|Cl {pcl_desc= Pcl_fun _; _}, Ppat_lazy _
1940-
|(Exp {pexp_desc= Pexp_letop _; _} | Bo _), Ppat_exception _
1941-
|( Exp {pexp_desc= Pexp_function (_, _, Pfunction_body _); _}
1942-
, ( Ppat_construct _ | Ppat_cons _ | Ppat_lazy _ | Ppat_tuple _
1943-
| Ppat_variant _ ) ) ->
1970+
|(Exp {pexp_desc= Pexp_letop _; _} | Bo _), Ppat_exception _ ->
19441971
true
1945-
| (Str _ | Exp _), Ppat_lazy _ -> true
1972+
| (Str _ | Exp _ | Lb _), Ppat_lazy _ -> true
19461973
| ( (Fpe _ | Fpc _)
19471974
, ( Ppat_tuple _ | Ppat_construct _ | Ppat_alias _ | Ppat_variant _
19481975
| Ppat_lazy _ | Ppat_exception _ | Ppat_or _ ) )
@@ -1953,23 +1980,36 @@ end = struct
19531980
| _, Ppat_var _ when List.is_empty pat.ppat_attributes -> false
19541981
| ( ( Exp {pexp_desc= Pexp_let ({pvbs_bindings; _}, _, _); _}
19551982
| Str {pstr_desc= Pstr_value {pvbs_bindings; _}; _} )
1956-
, pat_desc ) -> (
1957-
match pat_desc with
1958-
| Ppat_construct (_, Some _)
1959-
|Ppat_variant (_, Some _)
1960-
|Ppat_cons _ | Ppat_alias _ | Ppat_constraint _ | Ppat_lazy _
1961-
|Ppat_or _ ->
1962-
(* Add disambiguation parentheses that are not necessary. *)
1963-
true
1964-
| _ when exposed_right_colon pat ->
1965-
(* Some patterns must be parenthesed when followed by a colon. *)
1966-
let pvb =
1967-
List.find_exn pvbs_bindings ~f:(fun pvb -> pvb.pvb_pat == pat)
1968-
in
1969-
Option.is_some pvb.pvb_constraint
1970-
| _ -> false )
1983+
, _ )
1984+
when parenze_pat_in_bindings pvbs_bindings pat ->
1985+
true
1986+
| ( Lb {pvb_pat; _}
1987+
, ( Ppat_construct (_, Some _)
1988+
| Ppat_variant (_, Some _)
1989+
| Ppat_cons _ | Ppat_alias _ | Ppat_or _ ) )
1990+
when pvb_pat == pat ->
1991+
(* Disambiguation parentheses *)
1992+
true
1993+
| Lb {pvb_pat; pvb_constraint= Some _; _}, _
1994+
when pvb_pat == pat && exposed_right_colon pat ->
1995+
true
19711996
| _ -> false
19721997

1998+
(* Whether an expression in a let binding shouldn't be parenthesed,
1999+
bypassing the other Ast rules. *)
2000+
let dont_parenze_exp_in_bindings bindings exp =
2001+
match exp.pexp_desc with
2002+
| Pexp_function ([], None, (Pfunction_cases _ as fun_body)) ->
2003+
(* [fun_body] is the body of the let binding and shouldn't be
2004+
parenthesed. [exp] is a synthetic expression constructed in the
2005+
formatting code. *)
2006+
List.exists bindings ~f:(fun {pvb_body; _} -> pvb_body == fun_body)
2007+
| _ -> false
2008+
2009+
let ctx_sensitive_to_trailing_attributes = function
2010+
| Lb _ -> false
2011+
| _ -> true
2012+
19732013
let marked_parenzed_inner_nested_match =
19742014
let memo = Hashtbl.Poly.create () in
19752015
register_reset (fun () -> Hashtbl.clear memo) ;
@@ -2119,6 +2159,31 @@ end = struct
21192159
~default:exposed_
21202160
|> (ignore : bool -> _)
21212161

2162+
(* Whether to parenze an expr on the RHS of a match/try/function case. *)
2163+
and parenze_exp_in_match_case cases exp =
2164+
if !leading_nested_match_parens then
2165+
List.iter cases ~f:(fun {pc_rhs; _} ->
2166+
mark_parenzed_inner_nested_match pc_rhs ) ;
2167+
List.exists cases ~f:(fun {pc_rhs; _} -> pc_rhs == exp)
2168+
&& exposed_right_exp Match exp
2169+
2170+
(* Whether to parenze an expr on the RHS of a let binding.
2171+
[dont_parenze_exp_in_bindings] must have been checked before. *)
2172+
and parenze_exp_in_bindings bindings exp =
2173+
List.exists bindings ~f:(fun {pvb_body; pvb_args; _} ->
2174+
match pvb_body with
2175+
| Pfunction_body
2176+
( {pexp_desc= Pexp_function ([], None, Pfunction_cases _); _} as
2177+
let_body )
2178+
when let_body == exp ->
2179+
(* Function with cases and no 'fun' keyword is in the body of a
2180+
binding, parentheses are needed if the binding also defines
2181+
arguments. *)
2182+
not (List.is_empty pvb_args)
2183+
| Pfunction_cases (cases, _, _) ->
2184+
parenze_exp_in_match_case cases exp
2185+
| _ -> false )
2186+
21222187
(** [parenze_exp {ctx; ast}] holds when expression [ast] should be
21232188
parenthesized in context [ctx]. *)
21242189
and parenze_exp ({ctx; ast= exp} as xexp) =
@@ -2173,7 +2238,19 @@ end = struct
21732238
||
21742239
match (ctx, exp) with
21752240
| Str {pstr_desc= Pstr_eval _; _}, _ -> false
2176-
| _, {pexp_desc= Pexp_infix _; pexp_attributes= _ :: _; _} -> true
2241+
| Lb pvb, _ when dont_parenze_exp_in_bindings [pvb] exp -> false
2242+
| Exp {pexp_desc= Pexp_let ({pvbs_bindings; _}, _, _); _}, _
2243+
|Cl {pcl_desc= Pcl_let ({pvbs_bindings; _}, _, _); _}, _
2244+
when dont_parenze_exp_in_bindings pvbs_bindings exp ->
2245+
false
2246+
| Lb pvb, _ when parenze_exp_in_bindings [pvb] exp -> true
2247+
| Exp {pexp_desc= Pexp_let ({pvbs_bindings; _}, _, _); _}, _
2248+
|Cl {pcl_desc= Pcl_let ({pvbs_bindings; _}, _, _); _}, _
2249+
when parenze_exp_in_bindings pvbs_bindings exp ->
2250+
true
2251+
| _, {pexp_desc= Pexp_infix _; pexp_attributes= _ :: _; _}
2252+
when ctx_sensitive_to_trailing_attributes ctx ->
2253+
true
21772254
| ( Str
21782255
{ pstr_desc=
21792256
Pstr_value
@@ -2260,32 +2337,32 @@ end = struct
22602337
when e == exp ->
22612338
true
22622339
| ( Exp {pexp_desc= Pexp_function (_, _, Pfunction_body e); _}
2263-
, {pexp_desc= Pexp_function (_, _, Pfunction_cases _); _} )
2340+
, {pexp_desc= Pexp_function ([], None, Pfunction_cases _); _} )
22642341
when e == exp ->
22652342
true
2343+
| ( Exp
2344+
{ pexp_desc=
2345+
( Pexp_extension
2346+
( _
2347+
, PStr
2348+
[ { pstr_desc=
2349+
Pstr_eval
2350+
( { pexp_desc=
2351+
( Pexp_function
2352+
(_, _, Pfunction_cases (cases, _, _))
2353+
| Pexp_match (_, cases)
2354+
| Pexp_try (_, cases) )
2355+
; _ }
2356+
, _ )
2357+
; _ } ] )
2358+
| Pexp_function (_, _, Pfunction_cases (cases, _, _))
2359+
| Pexp_match (_, cases)
2360+
| Pexp_try (_, cases) )
2361+
; _ }
2362+
, _ ) ->
2363+
parenze_exp_in_match_case cases exp
22662364
| Exp {pexp_desc; _}, _ -> (
22672365
match pexp_desc with
2268-
| Pexp_extension
2269-
( _
2270-
, PStr
2271-
[ { pstr_desc=
2272-
Pstr_eval
2273-
( { pexp_desc=
2274-
( Pexp_function
2275-
(_, _, Pfunction_cases (cases, _, _))
2276-
| Pexp_match (_, cases)
2277-
| Pexp_try (_, cases) )
2278-
; _ }
2279-
, _ )
2280-
; _ } ] )
2281-
|Pexp_function (_, _, Pfunction_cases (cases, _, _))
2282-
|Pexp_match (_, cases)
2283-
|Pexp_try (_, cases) ->
2284-
if !leading_nested_match_parens then
2285-
List.iter cases ~f:(fun {pc_rhs; _} ->
2286-
mark_parenzed_inner_nested_match pc_rhs ) ;
2287-
List.exists cases ~f:(fun {pc_rhs; _} -> pc_rhs == exp)
2288-
&& exposed_right_exp Match exp
22892366
| Pexp_ifthenelse (eN, _)
22902367
when List.exists eN ~f:(fun x -> x.if_cond == exp) ->
22912368
false
@@ -2347,7 +2424,10 @@ end = struct
23472424
| _ -> Exp.has_trailing_attributes exp || parenze () ) )
23482425
| _, {pexp_desc= Pexp_list _; _} -> false
23492426
| _, {pexp_desc= Pexp_array _; _} -> false
2350-
| _, exp when Exp.has_trailing_attributes exp -> true
2427+
| _, exp
2428+
when ctx_sensitive_to_trailing_attributes ctx
2429+
&& Exp.has_trailing_attributes exp ->
2430+
true
23512431
| _ -> false
23522432

23532433
(** [parenze_cl {ctx; ast}] holds when class expr [ast] should be

lib/Ast.mli

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,8 @@ val sub_sig : ctx:t -> signature_item -> signature_item xt
188188
val sub_str : ctx:t -> structure_item -> structure_item xt
189189
(** Construct a structure_item-in-context. *)
190190

191+
val sub_fun_body : ctx:t -> function_body -> function_body xt
192+
191193
val is_simple : Conf.t -> (expression xt -> int) -> expression xt -> bool
192194
(** Holds of "simple" expressions: constants and constructor and function
193195
applications of other simple expressions. *)

0 commit comments

Comments
 (0)