diff --git a/CHANGELOG.md b/CHANGELOG.md index 22769c4fd6..ae21718c62 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ #### :boom: Breaking Change - Fix return type of `String.charCodeAt`. https://github.com/rescript-lang/rescript/pull/7864 +- Remove support of JSX children spread. https://github.com/rescript-lang/rescript/pull/7869 #### :eyeglasses: Spec Compliance diff --git a/analysis/src/CompletionFrontEnd.ml b/analysis/src/CompletionFrontEnd.ml index 510db09f65..65a26a1467 100644 --- a/analysis/src/CompletionFrontEnd.ml +++ b/analysis/src/CompletionFrontEnd.ml @@ -1353,7 +1353,7 @@ let completionWithParser1 ~currentFile ~debug ~offset ~path ~posCursor (Jsx_container_element {jsx_container_element_children = children}) -> children - | _ -> JSXChildrenItems [] + | _ -> [] in let compName_loc = compName.loc in let compName_lid = @@ -1412,8 +1412,7 @@ let completionWithParser1 ~currentFile ~debug ~offset ~path ~posCursor (Jsx_container_element { jsx_container_element_closing_tag = None; - jsx_container_element_children = - JSXChildrenSpreading _ | JSXChildrenItems (_ :: _); + jsx_container_element_children = _ :: _; }) ) -> None | Some jsxProps, _ -> diff --git a/analysis/src/CompletionJsx.ml b/analysis/src/CompletionJsx.ml index 0dcadf7e5b..4ddba8c642 100644 --- a/analysis/src/CompletionJsx.ml +++ b/analysis/src/CompletionJsx.ml @@ -460,8 +460,8 @@ let extractJsxProps ~(compName : Longident.t Location.loc) ~props ~children = let open Parsetree in let childrenStart = match children with - | JSXChildrenItems [] -> None - | JSXChildrenSpreading child | JSXChildrenItems (child :: _) -> + | [] -> None + | child :: _ -> if child.pexp_loc.loc_ghost then None else Some (Loc.start child.pexp_loc) in let props = diff --git a/analysis/src/SemanticTokens.ml b/analysis/src/SemanticTokens.ml index 7868f01cd1..ddccba9b2b 100644 --- a/analysis/src/SemanticTokens.ml +++ b/analysis/src/SemanticTokens.ml @@ -311,10 +311,7 @@ let command ~debug ~emitter ~path = ~pos:(Pos.ofLexing posOfGreatherthanAfterProps); (* children *) - (match children with - | Parsetree.JSXChildrenSpreading child -> iterator.expr iterator child - | Parsetree.JSXChildrenItems children -> - List.iter (iterator.expr iterator) children); + List.iter (iterator.expr iterator) children; (* closing tag *) closing_tag_opt diff --git a/compiler/frontend/bs_ast_mapper.ml b/compiler/frontend/bs_ast_mapper.ml index 216761f515..292e199b5a 100644 --- a/compiler/frontend/bs_ast_mapper.ml +++ b/compiler/frontend/bs_ast_mapper.ml @@ -292,9 +292,7 @@ module M = struct end module E = struct - let map_jsx_children sub = function - | JSXChildrenSpreading e -> JSXChildrenSpreading (sub.expr sub e) - | JSXChildrenItems xs -> JSXChildrenItems (List.map (sub.expr sub) xs) + let map_jsx_children sub xs = List.map (sub.expr sub) xs let map_jsx_prop sub = function | JSXPropPunning (optional, name) -> diff --git a/compiler/ml/ast_iterator.ml b/compiler/ml/ast_iterator.ml index 4380ca1af2..a430bb0b7b 100644 --- a/compiler/ml/ast_iterator.ml +++ b/compiler/ml/ast_iterator.ml @@ -267,9 +267,7 @@ module M = struct end module E = struct - let iter_jsx_children sub = function - | JSXChildrenSpreading e -> sub.expr sub e - | JSXChildrenItems xs -> List.iter (sub.expr sub) xs + let iter_jsx_children sub xs = List.iter (sub.expr sub) xs let iter_jsx_prop sub = function | JSXPropPunning (_, name) -> iter_loc sub name diff --git a/compiler/ml/ast_mapper.ml b/compiler/ml/ast_mapper.ml index e2f4d6cad0..673465477b 100644 --- a/compiler/ml/ast_mapper.ml +++ b/compiler/ml/ast_mapper.ml @@ -263,9 +263,7 @@ module M = struct end module E = struct - let map_jsx_children sub = function - | JSXChildrenSpreading e -> JSXChildrenSpreading (sub.expr sub e) - | JSXChildrenItems xs -> JSXChildrenItems (List.map (sub.expr sub) xs) + let map_jsx_children sub xs = List.map (sub.expr sub) xs let map_jsx_prop sub = function | JSXPropPunning (optional, name) -> diff --git a/compiler/ml/ast_mapper_from0.ml b/compiler/ml/ast_mapper_from0.ml index eb01c014f7..3f91d6ac1e 100644 --- a/compiler/ml/ast_mapper_from0.ml +++ b/compiler/ml/ast_mapper_from0.ml @@ -326,8 +326,8 @@ module E = struct match e.pexp_desc with | Pexp_construct ({txt = Longident.Lident "[]" | Longident.Lident "::"}, _) -> - JSXChildrenItems (visit e) - | _ -> JSXChildrenSpreading (sub.expr sub e) + visit e + | _ -> [sub.expr sub e] let try_map_jsx_prop (sub : mapper) (lbl : Asttypes.Noloc.arg_label) (e : expression) : Parsetree.jsx_prop option = diff --git a/compiler/ml/ast_mapper_to0.ml b/compiler/ml/ast_mapper_to0.ml index 978ba001c3..d0ac43d737 100644 --- a/compiler/ml/ast_mapper_to0.ml +++ b/compiler/ml/ast_mapper_to0.ml @@ -340,8 +340,7 @@ module E = struct let map_jsx_children sub loc children = match children with - | JSXChildrenSpreading e -> sub.expr sub e - | JSXChildrenItems xs -> + | xs -> let list_expr = Ast_helper.Exp.make_list_expression loc xs None in sub.expr sub list_expr diff --git a/compiler/ml/depend.ml b/compiler/ml/depend.ml index bb467ef592..e5e39eb4b5 100644 --- a/compiler/ml/depend.ml +++ b/compiler/ml/depend.ml @@ -312,9 +312,7 @@ let rec add_expr bv exp = and_jsx_props bv props; add_jsx_children bv children -and add_jsx_children bv = function - | JSXChildrenSpreading e -> add_expr bv e - | JSXChildrenItems xs -> List.iter (add_expr bv) xs +and add_jsx_children bv xs = List.iter (add_expr bv) xs and add_jsx_prop bv = function | JSXPropPunning (_, _) -> () diff --git a/compiler/ml/parsetree.ml b/compiler/ml/parsetree.ml index cc99af9b92..78c9899f74 100644 --- a/compiler/ml/parsetree.ml +++ b/compiler/ml/parsetree.ml @@ -372,9 +372,7 @@ and jsx_prop = Location.t * expression -and jsx_children = - | JSXChildrenSpreading of expression - | JSXChildrenItems of expression list +and jsx_children = expression list and jsx_props = jsx_prop list diff --git a/compiler/ml/pprintast.ml b/compiler/ml/pprintast.ml index 2a91e8fd1f..585ac64b81 100644 --- a/compiler/ml/pprintast.ml +++ b/compiler/ml/pprintast.ml @@ -798,7 +798,7 @@ and simple_expr ctxt f x = pp f fmt (pattern ctxt) s expression e1 direction_flag df expression e2 expression e3 | Pexp_jsx_element (Jsx_fragment {jsx_fragment_children = children}) -> - pp f "<>%a>" (list (simple_expr ctxt)) (collect_jsx_children children) + pp f "<>%a>" (list (simple_expr ctxt)) children | Pexp_jsx_element (Jsx_unary_element { @@ -828,21 +828,13 @@ and simple_expr ctxt f x = in match props with | [] -> - pp f "<%s>%a%s" name - (list (simple_expr ctxt)) - (collect_jsx_children children) - closing_name + pp f "<%s>%a%s" name (list (simple_expr ctxt)) children closing_name | _ -> pp f "<%s %a>%a%s" name (print_jsx_props ctxt) props (list (simple_expr ctxt)) - (collect_jsx_children children) - closing_name) + children closing_name) | _ -> paren true (expression ctxt) f x -and collect_jsx_children = function - | JSXChildrenSpreading e -> [e] - | JSXChildrenItems xs -> xs - and print_jsx_prop ctxt f = function | JSXPropPunning (is_optional, name) -> pp f "%s" (if is_optional then "?" ^ name.txt else name.txt) diff --git a/compiler/ml/printast.ml b/compiler/ml/printast.ml index 756511f0bb..44d699eb38 100644 --- a/compiler/ml/printast.ml +++ b/compiler/ml/printast.ml @@ -383,9 +383,7 @@ and expression i ppf x = and jsx_children i ppf children = line i ppf "jsx_children =\n"; - match children with - | JSXChildrenSpreading e -> expression (i + 1) ppf e - | JSXChildrenItems xs -> list (i + 1) expression ppf xs + list (i + 1) expression ppf children and jsx_prop i ppf = function | JSXPropPunning (opt, name) -> diff --git a/compiler/syntax/src/jsx_v4.ml b/compiler/syntax/src/jsx_v4.ml index 68f791ca7a..f35e3014ab 100644 --- a/compiler/syntax/src/jsx_v4.ml +++ b/compiler/syntax/src/jsx_v4.ml @@ -1182,8 +1182,8 @@ let append_children_prop (config : Jsx_common.jsx_config) mapper (component_description : componentDescription) (props : jsx_props) (children : jsx_children) : jsx_props = match children with - | JSXChildrenItems [] -> props - | JSXChildrenItems [child] | JSXChildrenSpreading child -> + | [] -> props + | [child] -> let expr = (* I don't quite know why fragment and uppercase don't do this additional ReactDOM.someElement wrapping *) match component_description with @@ -1209,7 +1209,7 @@ let append_children_prop (config : Jsx_common.jsx_config) mapper JSXPropValue ({txt = "children"; loc = child.pexp_loc}, is_optional, expr); ] - | JSXChildrenItems (head :: _ as xs) -> + | head :: _ as xs -> let loc = match List.rev xs with | [] -> head.pexp_loc @@ -1230,11 +1230,7 @@ let append_children_prop (config : Jsx_common.jsx_config) mapper let mk_react_jsx (config : Jsx_common.jsx_config) mapper loc attrs (component_description : componentDescription) (elementTag : expression) (props : jsx_props) (children : jsx_children) : expression = - let more_than_one_children = - match children with - | JSXChildrenSpreading _ -> false - | JSXChildrenItems xs -> List.length xs > 1 - in + let more_than_one_children = List.length children > 1 in let props_with_children = append_children_prop config mapper component_description props children in @@ -1314,12 +1310,12 @@ let expr ~(config : Jsx_common.jsx_config) mapper expression = (* For example 'input' *) let component_name_expr = constant_string ~loc:tag_loc name in mk_react_jsx config mapper loc attrs LowercasedComponent - component_name_expr props (JSXChildrenItems []) + component_name_expr props [] | JsxUpperTag _ | JsxQualifiedLowerTag _ -> (* MyModule.make *) let make_id = mk_uppercase_tag_name_expr tag_name in mk_react_jsx config mapper loc attrs UppercasedComponent make_id props - (JSXChildrenItems []) + [] | JsxTagInvalid name -> Jsx_common.raise_error ~loc "JSX: element name is neither upper- or lowercase, got \"%s\"" name) diff --git a/compiler/syntax/src/res_ast_debugger.ml b/compiler/syntax/src/res_ast_debugger.ml index a4f3a405f2..52a57b89c5 100644 --- a/compiler/syntax/src/res_ast_debugger.ml +++ b/compiler/syntax/src/res_ast_debugger.ml @@ -707,12 +707,7 @@ module SexpAst = struct | Pexp_extension ext -> Sexp.list [Sexp.atom "Pexp_extension"; extension ext] | Pexp_await e -> Sexp.list [Sexp.atom "Pexp_await"; expression e] - | Pexp_jsx_element (Jsx_fragment {jsx_fragment_children = children}) -> - let xs = - match children with - | JSXChildrenSpreading e -> [e] - | JSXChildrenItems xs -> xs - in + | Pexp_jsx_element (Jsx_fragment {jsx_fragment_children = xs}) -> Sexp.list [ Sexp.atom "Pexp_jsx_fragment"; Sexp.list (map_empty ~f:expression xs); @@ -728,13 +723,8 @@ module SexpAst = struct (Jsx_container_element { jsx_container_element_props = props; - jsx_container_element_children = children; + jsx_container_element_children = xs; }) -> - let xs = - match children with - | JSXChildrenSpreading e -> [e] - | JSXChildrenItems xs -> xs - in Sexp.list [ Sexp.atom "Pexp_jsx_container_element"; diff --git a/compiler/syntax/src/res_comments_table.ml b/compiler/syntax/src/res_comments_table.ml index 2c4608476f..b9a81d53a9 100644 --- a/compiler/syntax/src/res_comments_table.ml +++ b/compiler/syntax/src/res_comments_table.ml @@ -1658,12 +1658,7 @@ and walk_expression expr t comments = let opening_token = {expr.pexp_loc with loc_end = opening_greater_than} in let on_same_line, rest = partition_by_on_same_line opening_token comments in attach t.trailing opening_token on_same_line; - let exprs = - match children with - | Parsetree.JSXChildrenSpreading e -> [e] - | Parsetree.JSXChildrenItems xs -> xs - in - let xs = exprs |> List.map (fun e -> Expression e) in + let xs = children |> List.map (fun e -> Expression e) in walk_list xs t rest | Pexp_jsx_element (Jsx_unary_element @@ -1769,7 +1764,7 @@ and walk_expression expr t comments = partition_leading_trailing rest closing_tag_loc in match children with - | Parsetree.JSXChildrenItems [] -> ( + | [] -> ( (* attach all comments to the closing tag if there are no children *) match closing_tag with | None -> @@ -1801,11 +1796,7 @@ and walk_expression expr t comments = (* if the closing tag is on the same line, attach comments to the opening tag *) attach t.leading closing_tag_loc comments_for_children) | children -> - let children_nodes = - match children with - | Parsetree.JSXChildrenSpreading e -> [Expression e] - | Parsetree.JSXChildrenItems xs -> List.map (fun e -> Expression e) xs - in + let children_nodes = List.map (fun e -> Expression e) children in walk_list children_nodes t comments_for_children (* It is less likely that there are comments inside the closing tag, diff --git a/compiler/syntax/src/res_core.ml b/compiler/syntax/src/res_core.ml index 805874b161..c8ae7659c8 100644 --- a/compiler/syntax/src/res_core.ml +++ b/compiler/syntax/src/res_core.ml @@ -188,6 +188,9 @@ module ErrorMessages = struct let type_definition_in_function = "Type definitions are not allowed inside functions.\n" ^ " Move this `type` declaration to the top level or into a module." + + let spread_children_no_longer_supported = + "Spreading JSX children is no longer supported." end module InExternal = struct @@ -2999,19 +3002,13 @@ and parse_jsx_children p : Parsetree.jsx_children = loop p (child :: children) | _ -> children in - let children = - match p.Parser.token with - | DotDotDot -> - Parser.next p; - let expr = - parse_primary_expr ~operand:(parse_atomic_expr p) ~no_call:true p - in - Parsetree.JSXChildrenSpreading expr - | _ -> - let children = List.rev (loop p []) in - Parsetree.JSXChildrenItems children - in - children + match p.Parser.token with + | DotDotDot -> + Parser.err ~start_pos:p.start_pos ~end_pos:p.end_pos p + (Diagnostics.message ErrorMessages.spread_children_no_longer_supported); + Parser.next p; + [parse_primary_expr ~operand:(parse_atomic_expr p) ~no_call:true p] + | _ -> List.rev (loop p []) and parse_braced_or_record_expr p = let start_pos = p.Parser.start_pos in diff --git a/compiler/syntax/src/res_printer.ml b/compiler/syntax/src/res_printer.ml index 1bf0a714ed..2f73bd2684 100644 --- a/compiler/syntax/src/res_printer.ml +++ b/compiler/syntax/src/res_printer.ml @@ -4516,8 +4516,8 @@ and print_jsx_container_tag ~state tag_name (*
*) let has_children = match children with - | JSXChildrenSpreading _ | JSXChildrenItems (_ :: _) -> true - | JSXChildrenItems [] -> false + | _ :: _ -> true + | [] -> false in let line_sep = get_line_sep_for_jsx_children children in let print_children children = @@ -4606,8 +4606,8 @@ and print_jsx_fragment ~state (opening_greater_than : Lexing.position) in let has_children = match children with - | JSXChildrenItems [] -> false - | JSXChildrenSpreading _ | JSXChildrenItems (_ :: _) -> true + | [] -> false + | _ :: _ -> true in let line_sep = get_line_sep_for_jsx_children children in Doc.group @@ -4621,18 +4621,15 @@ and print_jsx_fragment ~state (opening_greater_than : Lexing.position) ]) and get_line_sep_for_jsx_children (children : Parsetree.jsx_children) = - match children with - | JSXChildrenSpreading _ -> Doc.line - | JSXChildrenItems children -> - if - List.length children > 1 - || List.exists - (function - | {Parsetree.pexp_desc = Pexp_jsx_element _} -> true - | _ -> false) - children - then Doc.hard_line - else Doc.line + if + List.length children > 1 + || List.exists + (function + | {Parsetree.pexp_desc = Pexp_jsx_element _} -> true + | _ -> false) + children + then Doc.hard_line + else Doc.line and print_jsx_children ~state (children : Parsetree.jsx_children) cmt_tbl = let open Parsetree in @@ -4669,9 +4666,8 @@ and print_jsx_children ~state (children : Parsetree.jsx_children) cmt_tbl = print_comments (add_parens_or_braces expr_doc) cmt_tbl braces_loc in match children with - | JSXChildrenItems [] -> Doc.nil - | JSXChildrenSpreading child -> Doc.concat [Doc.dotdotdot; print_expr child] - | JSXChildrenItems children -> + | [] -> Doc.nil + | children -> let rec visit acc children = match children with | [] -> acc diff --git a/tests/syntax_tests/data/conversion/reason/expected/jsxProps.res.txt b/tests/syntax_tests/data/conversion/reason/expected/jsxProps.res.txt index d368bc9529..3d98360833 100644 --- a/tests/syntax_tests/data/conversion/reason/expected/jsxProps.res.txt +++ b/tests/syntax_tests/data/conversion/reason/expected/jsxProps.res.txt @@ -7,11 +7,3 @@ let handleClick = (href, event) => @react.component let make = (~href, ~className="", ~children) => handleClick(href, event)}> children - -